diff --git a/.babelrc-deno.json b/.babelrc-deno.json index 4b9b17ddad..0e173bfb4e 100644 --- a/.babelrc-deno.json +++ b/.babelrc-deno.json @@ -1,13 +1,7 @@ { "plugins": [ - "@babel/plugin-transform-flow-strip-types", - ["./resources/add-extension-to-import-paths", { "extension": "js" }], + "@babel/plugin-syntax-typescript", + ["./resources/add-extension-to-import-paths", { "extension": "ts" }], "./resources/inline-invariant" - ], - "overrides": [ - { - "include": "src/error/GraphQLError.js", - "plugins": [["@babel/plugin-transform-classes", { "loose": false }]] - } ] } diff --git a/.babelrc-npm.json b/.babelrc-npm.json new file mode 100644 index 0000000000..357c91dbc0 --- /dev/null +++ b/.babelrc-npm.json @@ -0,0 +1,27 @@ +{ + "plugins": [ + "@babel/plugin-transform-typescript", + "./resources/inline-invariant" + ], + "env": { + "cjs": { + "presets": [ + [ + "@babel/preset-env", + { "modules": "commonjs", "targets": { "node": "12" } } + ] + ], + "plugins": [ + ["./resources/add-extension-to-import-paths", { "extension": "js" }] + ] + }, + "mjs": { + "presets": [ + ["@babel/preset-env", { "modules": false, "targets": { "node": "12" } }] + ], + "plugins": [ + ["./resources/add-extension-to-import-paths", { "extension": "mjs" }] + ] + } + } +} diff --git a/.babelrc.json b/.babelrc.json index 8c98e626b2..caa5300ad7 100644 --- a/.babelrc.json +++ b/.babelrc.json @@ -1,42 +1,9 @@ { - "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]], - "plugins": ["@babel/plugin-transform-flow-strip-types"], - "overrides": [ - { - "exclude": ["src/__testUtils__/**/*", "**/__tests__/**/*"], - "presets": ["@babel/preset-env"], - "plugins": [ - ["@babel/plugin-transform-classes", { "loose": true }], - ["@babel/plugin-transform-destructuring", { "loose": true }], - ["@babel/plugin-transform-spread", { "loose": true }], - ["@babel/plugin-transform-for-of", { "assumeArray": true }] - ], - "env": { - "cjs": { - "presets": [["@babel/preset-env", { "modules": "commonjs" }]], - "plugins": [ - [ - "./resources/add-extension-to-import-paths", - { "extension": "js" } - ], - "./resources/inline-invariant" - ] - }, - "mjs": { - "presets": [["@babel/preset-env", { "modules": false }]], - "plugins": [ - [ - "./resources/add-extension-to-import-paths", - { "extension": "mjs" } - ], - "./resources/inline-invariant" - ] - } - } - }, - { - "include": "src/error/GraphQLError.js", - "plugins": [["@babel/plugin-transform-classes", { "loose": false }]] - } + "plugins": ["@babel/plugin-transform-typescript"], + "presets": [ + [ + "@babel/preset-env", + { "bugfixes": true, "targets": { "node": "current" } } + ] ] } diff --git a/.browserslistrc b/.browserslistrc deleted file mode 100644 index 7871455921..0000000000 --- a/.browserslistrc +++ /dev/null @@ -1,6 +0,0 @@ -node 8 -ie 9 -ios 9 -last 2 chrome versions -last 2 edge versions -last 2 firefox versions diff --git a/.c8rc.json b/.c8rc.json new file mode 100644 index 0000000000..22bb450ee4 --- /dev/null +++ b/.c8rc.json @@ -0,0 +1,23 @@ +{ + "all": true, + "include": ["src/"], + "exclude": [ + "src/**/index.ts", + "src/**/*-fuzz.ts", + "src/jsutils/Maybe.ts", + "src/jsutils/ObjMap.ts", + "src/jsutils/PromiseOrValue.ts", + "src/utilities/assertValidName.ts", + "src/utilities/typedQueryDocumentNode.ts" + ], + "clean": true, + "temp-directory": "coverage", + "report-dir": "coverage", + "skip-full": true, + "reporter": ["json", "html", "text"], + "check-coverage": true, + "branches": 100, + "lines": 100, + "functions": 100, + "statements": 100 +} diff --git a/.eslintignore b/.eslintignore index 258461b7bf..74aca39c9d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,10 +4,8 @@ /coverage /npmDist /denoDist -/npm -/deno +/websiteDist +/website -# Ignore Flow typings for 3rd-party libraries -/flow-typed # Ignore TS files inside integration test /integrationTests/ts/*.ts diff --git a/.eslintrc.yml b/.eslintrc.yml index 74d28bdc78..b548dcad93 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,18 +1,16 @@ parserOptions: sourceType: script - ecmaVersion: 2020 env: - es6: true - node: true + es2022: true reportUnusedDisableDirectives: true plugins: - internal-rules - node - - istanbul - import + - simple-import-sort settings: node: - tryExtensions: ['.js', '.json', '.node', '.ts', '.d.ts'] + tryExtensions: ['.js', '.jsx', '.json', '.node', '.ts', '.d.ts'] rules: ############################################################################## @@ -20,15 +18,9 @@ rules: # See './resources/eslint-internal-rules/README.md' ############################################################################## + internal-rules/only-ascii: error internal-rules/no-dir-import: error - - ############################################################################## - # `eslint-plugin-istanbul` rule list based on `v0.1.2` - # https://github.com/istanbuljs/eslint-plugin-istanbul#rules - ############################################################################## - - istanbul/no-ignore-file: error - istanbul/prefer-ignore-reason: error + internal-rules/require-to-string-tag: off ############################################################################## # `eslint-plugin-node` rule list based on `v11.1.x` @@ -51,8 +43,8 @@ rules: node/no-unpublished-import: error node/no-unpublished-require: error node/no-unsupported-features/es-builtins: error - node/no-unsupported-features/es-syntax: off # TODO enable - node/no-unsupported-features/node-builtins: off # TODO enable + node/no-unsupported-features/es-syntax: [error, { ignores: [modules] }] + node/no-unsupported-features/node-builtins: error node/process-exit-as-throw: error node/shebang: error @@ -83,7 +75,7 @@ rules: node/prefer-promises/fs: off ############################################################################## - # `eslint-plugin-import` rule list based on `v2.22.x` + # `eslint-plugin-import` rule list based on `v2.26.x` ############################################################################## # Static analysis @@ -105,6 +97,7 @@ rules: import/no-cycle: error import/no-useless-path-segments: error import/no-relative-parent-imports: off + import/no-relative-packages: off # Helpful warnings # https://github.com/benmosher/eslint-plugin-import#helpful-warnings @@ -122,6 +115,7 @@ rules: import/no-commonjs: error import/no-amd: error import/no-nodejs-modules: error + import/no-import-module-exports: off # Style guide # https://github.com/benmosher/eslint-plugin-import#style-guide @@ -129,21 +123,56 @@ rules: import/exports-last: off import/no-duplicates: error import/no-namespace: error - import/extensions: [error, never] # TODO: switch to ignorePackages + import/extensions: + - error + - ignorePackages + - ts: never # TODO: remove once TS supports extensions import/order: [error, { newlines-between: always-and-inside-groups }] import/newline-after-import: error import/prefer-default-export: off import/max-dependencies: off import/no-unassigned-import: error import/no-named-default: error - import/no-default-export: off + import/no-default-export: error import/no-named-export: off import/no-anonymous-default-export: error import/group-exports: off import/dynamic-import-chunkname: off ############################################################################## - # ESLint builtin rules list based on `v7.18.x` + # `eslint-plugin-simple-import-sort` rule list based on `v2.25.x` + # https://github.com/lydell/eslint-plugin-simple-import-sort + ############################################################################## + simple-import-sort/imports: + - error + - groups: + # Packages. + # Things that start with a letter (or digit or underscore), or `@` followed by a letter. + - ["^@?\\w"] + + # General utilities + - ["^(\\./|(\\.\\./)+)__testUtils__/"] + - ["^(\\./|(\\.\\./)+)jsutils/"] + + # Top-level directories + - ["^(\\./|(\\.\\./)+)error/"] + - ["^(\\./|(\\.\\./)+)language/"] + - ["^(\\./|(\\.\\./)+)type/"] + - ["^(\\./|(\\.\\./)+)validation/"] + - ["^(\\./|(\\.\\./)+)execution/"] + - ["^(\\./|(\\.\\./)+)utilities/"] + + # Relative imports. + # Anything that starts with a dot. + - ["^(\\.\\./){4,}"] + - ["^(\\.\\./){3}"] + - ["^(\\.\\./){2}"] + - ["^(\\.\\./){1}"] + - ["^\\./"] + simple-import-sort/exports: off # TODO + + ############################################################################## + # ESLint builtin rules list based on `v8.13.x` ############################################################################## # Possible Errors @@ -186,6 +215,7 @@ rules: no-unsafe-finally: error no-unsafe-negation: error no-unsafe-optional-chaining: [error, { disallowArithmeticOperators: true }] + no-unused-private-class-members: error no-useless-backreference: error require-atomic-updates: error use-isnan: error @@ -298,7 +328,7 @@ rules: capitalized-comments: off # maybe consistent-this: off func-name-matching: off - func-names: off + func-names: [error, as-needed] # improve debug experience func-style: off id-denylist: off id-length: off @@ -325,13 +355,7 @@ rules: no-nested-ternary: off no-new-object: error no-plusplus: off - no-restricted-syntax: - - error - - selector: 'FunctionDeclaration[async=true]' - message: > - async functions are not allowed inside package source code because - older versions of NodeJS do not support them without additional - runtime dependencies. Instead, use explicit Promises. + no-restricted-syntax: off no-tabs: error no-ternary: off no-underscore-dangle: off # TODO @@ -368,6 +392,7 @@ rules: prefer-const: error prefer-destructuring: off prefer-numeric-literals: error + prefer-object-has-own: off # TODO requires Node.js v16.9.0 prefer-rest-params: off # TODO prefer-spread: error prefer-template: off @@ -441,72 +466,28 @@ rules: yield-star-spacing: off overrides: - - files: 'src/**/*.js' - parser: babel-eslint - parserOptions: - sourceType: module - plugins: - - flowtype - - rules: - ############################################################################## - # `eslint-plugin-flowtype` rule list based on `v5.2.x` - # https://github.com/gajus/eslint-plugin-flowtype#eslint-plugin-flowtype - ############################################################################## - - flowtype/array-style-complex-type: error - flowtype/array-style-simple-type: error - flowtype/define-flow-type: error - flowtype/newline-after-flow-annotation: error - flowtype/no-dupe-keys: error - flowtype/no-existential-type: off # checked by Flow - flowtype/no-flow-fix-me-comments: off - flowtype/no-mixed: off - flowtype/no-mutable-array: off - flowtype/no-primitive-constructor-types: error - flowtype/no-types-missing-file-annotation: off - flowtype/no-unused-expressions: off - flowtype/no-weak-types: [error, { any: false }] - flowtype/require-compound-type-alias: off - flowtype/require-exact-type: off - flowtype/require-indexer-name: error - flowtype/require-inexact-type: off # checked by Flow - flowtype/require-parameter-type: off - flowtype/require-readonly-react-props: off - flowtype/require-return-type: off - flowtype/require-types-at-top: off - flowtype/require-valid-file-annotation: off - flowtype/require-variable-type: off - flowtype/sort-keys: off - flowtype/spread-exact-type: off - flowtype/type-id-match: [error, '^[A-Z]'] - flowtype/type-import-style: [error, declaration] - flowtype/use-flow-type: error - - # Bellow rules are disabled because coflicts with Prettier, see: - # https://github.com/prettier/eslint-config-prettier/blob/master/flowtype.js - flowtype/arrow-parens: off - flowtype/boolean-style: off - flowtype/delimiter-dangle: off - flowtype/generic-spacing: off - flowtype/object-type-delimiter: off - flowtype/semi: off - flowtype/space-after-type-colon: off - flowtype/space-before-generic-bracket: off - flowtype/space-before-type-colon: off - flowtype/union-intersection-spacing: off - - files: '**/*.ts' + - files: + - '**/*.ts' + - '**/*.tsx' parser: '@typescript-eslint/parser' parserOptions: sourceType: module - project: ['tsconfig.json'] + project: ['./tsconfig.json', './website/tsconfig.json'] plugins: - '@typescript-eslint' + - 'eslint-plugin-tsdoc' extends: - plugin:import/typescript rules: ########################################################################## - # `@typescript-eslint/eslint-plugin` rule list based on `v4.13.x` + # `eslint-plugin-tsdoc` rule list based on `v0.2.x` + # https://github.com/microsoft/tsdoc/tree/master/eslint-plugin + ########################################################################## + + tsdoc/syntax: error + + ########################################################################## + # `@typescript-eslint/eslint-plugin` rule list based on `v5.19.x` ########################################################################## # Supported Rules @@ -516,22 +497,23 @@ overrides: '@typescript-eslint/await-thenable': error '@typescript-eslint/ban-ts-comment': [error, { 'ts-expect-error': false }] '@typescript-eslint/ban-tslint-comment': error - '@typescript-eslint/ban-types': error + '@typescript-eslint/ban-types': off # TODO temporarily disabled '@typescript-eslint/class-literal-property-style': off # TODO enable after TS conversion - '@typescript-eslint/consistent-indexed-object-style': off # TODO enable after TS conversion - '@typescript-eslint/consistent-type-assertions': - [error, { assertionStyle: as, objectLiteralTypeAssertions: never }] - '@typescript-eslint/consistent-type-definitions': off # TODO consider - '@typescript-eslint/consistent-type-imports': off # TODO enable after TS conversion + '@typescript-eslint/consistent-indexed-object-style': + [error, index-signature] + '@typescript-eslint/consistent-type-assertions': off # TODO temporarily disable + '@typescript-eslint/consistent-type-definitions': error + '@typescript-eslint/consistent-type-exports': error + '@typescript-eslint/consistent-type-imports': error '@typescript-eslint/explicit-function-return-type': off # TODO consider '@typescript-eslint/explicit-member-accessibility': off # TODO consider '@typescript-eslint/explicit-module-boundary-types': off # TODO consider - '@typescript-eslint/member-ordering': off # TODO consider + '@typescript-eslint/member-ordering': error '@typescript-eslint/method-signature-style': error '@typescript-eslint/naming-convention': off # TODO consider '@typescript-eslint/no-base-to-string': error '@typescript-eslint/no-confusing-non-null-assertion': error - '@typescript-eslint/no-confusing-void-expression': error + '@typescript-eslint/no-confusing-void-expression': off # TODO enable with ignoreArrowShorthand '@typescript-eslint/no-dynamic-delete': off '@typescript-eslint/no-empty-interface': error '@typescript-eslint/no-explicit-any': off # TODO error @@ -539,53 +521,56 @@ overrides: '@typescript-eslint/no-extraneous-class': off # TODO consider '@typescript-eslint/no-floating-promises': error '@typescript-eslint/no-for-in-array': error - '@typescript-eslint/no-implicit-any-catch': off # TODO: Enable after TS convertion + '@typescript-eslint/no-implicit-any-catch': off # TODO: Enable after TS conversion '@typescript-eslint/no-implied-eval': error '@typescript-eslint/no-inferrable-types': [error, { ignoreParameters: true, ignoreProperties: true }] '@typescript-eslint/no-misused-new': error '@typescript-eslint/no-misused-promises': error '@typescript-eslint/no-namespace': error + '@typescript-eslint/no-non-null-asserted-nullish-coalescing': error '@typescript-eslint/no-non-null-asserted-optional-chain': error '@typescript-eslint/no-non-null-assertion': error '@typescript-eslint/no-parameter-properties': error + '@typescript-eslint/no-redundant-type-constituents': error '@typescript-eslint/no-invalid-void-type': error '@typescript-eslint/no-require-imports': error '@typescript-eslint/no-this-alias': error - '@typescript-eslint/no-throw-literal': error '@typescript-eslint/no-type-alias': off # TODO consider '@typescript-eslint/no-unnecessary-boolean-literal-compare': error - '@typescript-eslint/no-unnecessary-condition': error + '@typescript-eslint/no-unnecessary-condition': off # TODO temporary disable '@typescript-eslint/no-unnecessary-qualifier': error '@typescript-eslint/no-unnecessary-type-arguments': error '@typescript-eslint/no-unnecessary-type-assertion': error - '@typescript-eslint/no-unnecessary-type-constraint': off # TODO consider + '@typescript-eslint/no-unnecessary-type-constraint': error + '@typescript-eslint/no-unsafe-argument': off # TODO consider '@typescript-eslint/no-unsafe-assignment': off # TODO consider '@typescript-eslint/no-unsafe-call': off # TODO consider '@typescript-eslint/no-unsafe-member-access': off # TODO consider '@typescript-eslint/no-unsafe-return': off # TODO consider + '@typescript-eslint/no-useless-empty-export': error '@typescript-eslint/no-var-requires': error - '@typescript-eslint/non-nullable-type-assertion-style': error - '@typescript-eslint/prefer-as-const': off # TODO consider - '@typescript-eslint/prefer-enum-initializers': off # TODO consider - '@typescript-eslint/prefer-for-of': off # TODO switch to error after TS migration + '@typescript-eslint/non-nullable-type-assertion-style': off #TODO temporarily disabled + '@typescript-eslint/prefer-as-const': error + '@typescript-eslint/prefer-enum-initializers': error + '@typescript-eslint/prefer-for-of': error '@typescript-eslint/prefer-function-type': error - '@typescript-eslint/prefer-includes': off # TODO switch to error after IE11 drop + '@typescript-eslint/prefer-includes': error '@typescript-eslint/prefer-literal-enum-member': error '@typescript-eslint/prefer-namespace-keyword': error '@typescript-eslint/prefer-nullish-coalescing': error '@typescript-eslint/prefer-optional-chain': error - '@typescript-eslint/prefer-readonly': error + '@typescript-eslint/prefer-readonly': off '@typescript-eslint/prefer-readonly-parameter-types': off # TODO consider '@typescript-eslint/prefer-reduce-type-parameter': error - '@typescript-eslint/prefer-regexp-exec': error + '@typescript-eslint/prefer-regexp-exec': off + '@typescript-eslint/prefer-return-this-type': error + '@typescript-eslint/prefer-string-starts-ends-with': error '@typescript-eslint/prefer-ts-expect-error': error - '@typescript-eslint/prefer-string-starts-ends-with': off # TODO switch to error after IE11 drop '@typescript-eslint/promise-function-async': off '@typescript-eslint/require-array-sort-compare': error - '@typescript-eslint/restrict-plus-operands': - [error, { checkCompoundAssignments: true }] - '@typescript-eslint/restrict-template-expressions': error + '@typescript-eslint/restrict-plus-operands': off #TODO temporarily disabled + '@typescript-eslint/restrict-template-expressions': off #TODO temporarily disabled '@typescript-eslint/sort-type-union-intersection-members': off # TODO consider '@typescript-eslint/strict-boolean-expressions': off # TODO consider '@typescript-eslint/switch-exhaustiveness-check': error @@ -608,6 +593,7 @@ overrides: no-loop-func: off no-loss-of-precision: off no-redeclare: off + no-throw-literal: off no-shadow: off no-unused-expressions: off no-unused-vars: off @@ -625,6 +611,7 @@ overrides: '@typescript-eslint/no-loop-func': error '@typescript-eslint/no-loss-of-precision': error '@typescript-eslint/no-redeclare': error + '@typescript-eslint/no-throw-literal': error # TODO [error, { allowThrowingAny: false, allowThrowingUnknown: false }] '@typescript-eslint/no-shadow': error '@typescript-eslint/no-unused-expressions': error '@typescript-eslint/no-unused-vars': @@ -641,14 +628,15 @@ overrides: '@typescript-eslint/require-await': error '@typescript-eslint/return-await': error - # Disable for JS, Flow and TS + # Disable for JS and TS '@typescript-eslint/init-declarations': off '@typescript-eslint/no-magic-numbers': off + '@typescript-eslint/no-restricted-imports': off '@typescript-eslint/no-use-before-define': off '@typescript-eslint/no-duplicate-imports': off # Superseded by `import/no-duplicates` - # Bellow rules are disabled because coflicts with Prettier, see: - # https://github.com/prettier/eslint-config-prettier/blob/master/%40typescript-eslint.js + # Below rules are disabled because they conflict with Prettier, see: + # https://github.com/prettier/eslint-config-prettier/blob/main/index.js '@typescript-eslint/object-curly-spacing': off '@typescript-eslint/quotes': off '@typescript-eslint/brace-style': off @@ -661,47 +649,82 @@ overrides: '@typescript-eslint/no-extra-parens': off '@typescript-eslint/no-extra-semi': off '@typescript-eslint/semi': off + '@typescript-eslint/space-before-blocks': off '@typescript-eslint/space-before-function-paren': off '@typescript-eslint/space-infix-ops': off '@typescript-eslint/type-annotation-spacing': off + - files: 'src/**' + rules: + internal-rules/require-to-string-tag: error - files: 'src/**/__*__/**' rules: + internal-rules/require-to-string-tag: off node/no-unpublished-import: [error, { allowModules: ['chai', 'mocha'] }] + import/no-deprecated: off import/no-restricted-paths: off import/no-extraneous-dependencies: [error, { devDependencies: true }] - no-restricted-syntax: off - files: 'integrationTests/*' + env: + node: true rules: - node/no-unpublished-require: off node/no-sync: off + node/no-unpublished-require: [error, { allowModules: ['mocha'] }] import/no-extraneous-dependencies: [error, { devDependencies: true }] import/no-nodejs-modules: off - files: 'integrationTests/*/**' + env: + node: true rules: node/no-sync: off - node/no-missing-require: off + node/no-missing-require: [error, { allowModules: ['graphql'] }] + import/no-commonjs: off import/no-nodejs-modules: off no-console: off - files: 'benchmark/**' + env: + node: true rules: + internal-rules/only-ascii: [error, { allowEmoji: true }] node/no-sync: off node/no-missing-require: off import/no-nodejs-modules: off import/no-commonjs: off no-console: off no-await-in-loop: off - no-restricted-syntax: off - files: 'resources/**' + env: + node: true rules: - node/no-unpublished-import: off + internal-rules/only-ascii: [error, { allowEmoji: true }] node/no-unpublished-require: off - node/no-missing-require: off node/no-sync: off - node/global-require: off - import/no-dynamic-require: off import/no-extraneous-dependencies: [error, { devDependencies: true }] import/no-nodejs-modules: off import/no-commonjs: off - no-await-in-loop: off - no-restricted-syntax: off no-console: off + - files: '**/*.jsx' + parserOptions: + sourceType: module + ecmaFeatures: + jsx: true + rules: + node/no-unpublished-import: off + import/no-default-export: off + - files: 'website/**' + env: + node: true + plugins: + - 'react' + extends: + - 'plugin:react/recommended' + - 'plugin:react-hooks/recommended' + settings: + react: + version: detect + rules: + node/no-unpublished-require: off + node/no-missing-import: off + import/no-default-export: off + import/no-commonjs: off + import/no-nodejs-modules: off + import/no-extraneous-dependencies: off diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index ff14bd9da5..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,42 +0,0 @@ -[ignore] -.* -!/src - -[include] - -[lints] -sketchy-null-bool=error -sketchy-null-string=error -sketchy-null-number=error -sketchy-null-mixed=error -sketchy-number=error -untyped-type-import=error -nonstrict-import=off -untyped-import=error -unclear-type=off -deprecated-type=error -deprecated-utility=error -unsafe-getters-setters=error -unnecessary-optional-chain=error -unnecessary-invariant=error -signature-verification-failure=error -implicit-inexact-object=error -ambiguous-object-type=error -uninitialized-instance-property=error -default-import-access=error -invalid-import-star-use=error -non-const-var-export=error -this-in-exported-function=error -mixed-import-and-require=error -export-renamed-default=error - -[options] -all=true -types_first=false -module.use_strict=true -babel_loose_array_spread=true -experimental.const_params=true -include_warnings=true - -[version] -^0.142.0 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..fffb2cb1dc --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @graphql/graphql-js-reviewers diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9b2eef0b2b..d935f6d400 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -11,10 +11,6 @@ We use GitHub issues to track public bugs and requests. Please ensure your bug description is clear and has sufficient instructions to be able to reproduce the issue. The best way is to provide a reduced test case on jsFiddle or jsBin. -Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe -disclosure of security bugs. In those cases, please go through the process -outlined on that page and do not file a public issue. - ## Pull Requests All active development of graphql-js happens on GitHub. We actively welcome @@ -28,12 +24,15 @@ with this spec will be considered. If you have a change in mind which requires a change to the spec, please first open an [issue](https://github.com/graphql/graphql-spec/issues/) against the spec. -### Contributor License Agreement ("CLA") +### GraphQL Specification Membership Agreement + +This repository is managed by EasyCLA. Project participants must sign the free ([GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) before making a contribution. You only need to do this one time, and it can be signed by [individual contributors](http://individual-spec-membership.graphql.org/) or their [employers](http://corporate-spec-membership.graphql.org/). + +To initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you. -In order to accept your pull request, we need you to submit a CLA. You only need -to do this once to work on any of Facebook's open source projects. +You can find [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). If you have issues, please email [operations@graphql.org](mailto:operations@graphql.org). -Complete your CLA here: +If your company benefits from GraphQL and you would like to provide essential financial support for the systems and people that power our community, please also consider membership in the [GraphQL Foundation](https://foundation.graphql.org/join). ### Getting Started @@ -70,7 +69,7 @@ ensure your pull request matches the style guides, run `npm run prettier`. - 80 character line length strongly preferred. - Prefer `'` over `"` - ES6 syntax when possible. However do not rely on ES6-specific functions to be available. -- Use [Flow types](https://flowtype.org/). +- Use [TypeScript](https://www.typescriptlang.org). - Use semicolons; - Trailing commas, - Avd abbr wrds. @@ -82,7 +81,8 @@ _Only core contributors may release to NPM._ To release a new version on NPM, first ensure all tests pass with `npm test`, then use `npm version patch|minor|major` in order to increment the version in package.json and tag and commit a release. Then `git push && git push --tags` -this change so Travis CI can deploy to NPM. _Do not run `npm publish` directly._ +to sync this change with source control. Then `npm publish npmDist` to actually +publish the release to NPM. Once published, add [release notes](https://github.com/graphql/graphql-js/tags). Use [semver](https://semver.org/) to determine which version part to increment. @@ -92,6 +92,7 @@ Example for a patch release: npm test npm version patch git push --follow-tags +npm publish npmDist ``` ## License diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19607a519f..01b738ab18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,9 @@ name: CI -on: [push, pull_request] -env: - NODE_VERSION_USED_FOR_DEVELOPMENT: 14 +on: + workflow_call: + secrets: + codecov_token: + required: true jobs: lint: name: Lint source files @@ -9,27 +11,22 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v2 - - - name: Setup Node.js - uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} + persist-credentials: false - - name: Cache Node.js modules - uses: actions/cache@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 with: - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- + cache: npm + node-version-file: '.node-version' - name: Install Dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Lint ESLint run: npm run lint - - name: Lint Flow + - name: Check Types run: npm run check - name: Lint Prettier @@ -44,6 +41,8 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v2 + with: + persist-credentials: false - name: Check if commit contains files that should be ignored run: | @@ -55,28 +54,48 @@ jobs: exit 1 fi - integrationTests: - name: Run integration tests + checkPackageLock: + name: Check health of package-lock.json file runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v2 + with: + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: - node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} + cache: npm + node-version-file: '.node-version' - # We install bunch of packages during integration tests without locking them - # so we skip cache action to not pollute cache for other jobs. - name: Install Dependencies - run: npm ci + run: npm ci --ignore-scripts - - name: Build NPM package - run: npm run build:npm + - name: Run npm install + run: npm install --ignore-scripts --force --package-lock-only --engine-strict --strict-peer-deps - - name: Build Deno package - run: npm run build:deno + - name: Check that package-lock.json is in sync with package.json + run: git diff --exit-code package-lock.json + + integrationTests: + name: Run integration tests + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version-file: '.node-version' + # We install bunch of packages during integration tests without locking them + # so we skip cache action to not pollute cache for other jobs. + + - name: Install Dependencies + run: npm ci --ignore-scripts - name: Run Integration Tests run: npm run check:integrations @@ -87,22 +106,17 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v2 - - - name: Setup Node.js - uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} + persist-credentials: false - - name: Cache Node.js modules - uses: actions/cache@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 with: - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- + cache: npm + node-version-file: '.node-version' - name: Install Dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Run Tests run: npm run fuzzonly @@ -113,158 +127,104 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v2 - - - name: Setup Node.js - uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} + persist-credentials: false - - name: Cache Node.js modules - uses: actions/cache@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 with: - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- + cache: npm + node-version-file: '.node-version' - name: Install Dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Run tests and measure code coverage run: npm run testonly:cover - name: Upload coverage to Codecov if: ${{ always() }} - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 with: file: ./coverage/coverage-final.json fail_ci_if_error: true + token: ${{ secrets.codecov_token }} test: name: Run tests on Node v${{ matrix.node_version_to_setup }} runs-on: ubuntu-latest strategy: matrix: - node_version_to_setup: [10, 12, 14, 15] + node_version_to_setup: [12, 14, 16, 17] steps: - name: Checkout repo uses: actions/checkout@v2 + with: + persist-credentials: false - name: Setup Node.js v${{ matrix.node_version_to_setup }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: + cache: npm node-version: ${{ matrix.node_version_to_setup }} - - name: Cache Node.js modules - uses: actions/cache@v2 - with: - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- - - name: Install Dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Run Tests run: npm run testonly - benchmark: - name: Run benchmark + build-npm-dist: + name: Build 'npmDist' artifact runs-on: ubuntu-latest + needs: [test, fuzz, lint, integrationTests] steps: - name: Checkout repo uses: actions/checkout@v2 with: - fetch-depth: 2 - - - name: Setup Node.js - uses: actions/setup-node@v1 - with: - node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} - - - name: Cache Node.js modules - uses: actions/cache@v2 - with: - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- - - - name: Install Dependencies - run: npm ci - - - name: Run Benchmark - run: 'npm run benchmark -- --revs HEAD HEAD~1' - - deploy-to-npm-branch: - name: Deploy to `npm` branch - runs-on: ubuntu-latest - if: | - github.event_name == 'push' && - github.repository == 'graphql/graphql-js' && - github.ref == 'refs/heads/main' - needs: [test, fuzz, lint, checkForCommonlyIgnoredFiles, integrationTests] - steps: - - name: Checkout repo - uses: actions/checkout@v2 + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: - node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} - - - name: Cache Node.js modules - uses: actions/cache@v2 - with: - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- + cache: npm + node-version-file: '.node-version' - name: Install Dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Build NPM package run: npm run build:npm - - name: Deploy to `npm` branch - run: npm run gitpublish:npm - env: - GH_TOKEN: ${{ secrets.GH_NPM_BRANCH_PUBLISH_TOKEN }} + - name: Upload npmDist package + uses: actions/upload-artifact@v4 + with: + name: npmDist + path: ./npmDist - deploy-to-deno-branch: - name: Deploy to `deno` branch + build-deno-dist: + name: Build 'denoDist' artifact runs-on: ubuntu-latest - if: | - github.event_name == 'push' && - github.repository == 'graphql/graphql-js' && - github.ref == 'refs/heads/main' - needs: [test, fuzz, lint, checkForCommonlyIgnoredFiles, integrationTests] + needs: [test, fuzz, lint, integrationTests] steps: - name: Checkout repo uses: actions/checkout@v2 - - - name: Setup Node.js - uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} + persist-credentials: false - - name: Cache Node.js modules - uses: actions/cache@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 with: - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- + node-version-file: '.node-version' - name: Install Dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Build Deno package run: npm run build:deno - - name: Deploy to `deno` branch - run: npm run gitpublish:deno - env: - GH_TOKEN: ${{ secrets.GH_NPM_BRANCH_PUBLISH_TOKEN }} + - name: Upload denoDist package + uses: actions/upload-artifact@v4 + with: + name: denoDist + path: ./denoDist diff --git a/.github/workflows/cmd-publish-pr-on-npm.yml b/.github/workflows/cmd-publish-pr-on-npm.yml new file mode 100644 index 0000000000..9cc2b7b951 --- /dev/null +++ b/.github/workflows/cmd-publish-pr-on-npm.yml @@ -0,0 +1,116 @@ +name: publish-pr-on-npm +on: + workflow_call: + inputs: + pullRequestJSON: + required: true + type: string + secrets: + NPM_CANARY_PR_PUBLISH_TOKEN: + required: true +jobs: + build-npm-dist: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + persist-credentials: false + ref: ${{ fromJSON(inputs.pullRequestJSON).merge_commit_sha }} + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + cache: npm + node-version-file: '.node-version' + + - name: Install Dependencies + run: npm ci --ignore-scripts + + - name: Build NPM package + run: npm run build:npm + + - name: Upload npmDist package + uses: actions/upload-artifact@v4 + with: + name: npmDist + path: ./npmDist + + publish-canary: + runs-on: ubuntu-latest + name: Publish Canary + environment: canary-pr-npm + needs: [build-npm-dist] + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + cache: npm + node-version-file: '.node-version' + # 'registry-url' is required for 'npm publish' + registry-url: 'https://registry.npmjs.org' + + - uses: actions/download-artifact@v4 + with: + name: npmDist + path: npmDist + + - name: Modify NPM package to be canary release + env: + PULL_REQUEST_JSON: ${{ inputs.pullRequestJSON }} + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assert = require('assert'); + + const pull_request = JSON.parse(process.env.PULL_REQUEST_JSON); + const packageJSONPath = './npmDist/package.json'; + const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, 'utf-8')); + + // Override entire 'publishConfig' since it can contain untrusted data. + packageJSON.publishConfig = { tag: `canary-pr-${pull_request.number}` }; + + assert(!packageJSON.version.includes('+'), 'Can not append after metadata'); + packageJSON.version += packageJSON.version.includes('-') ? '.' : '-'; + packageJSON.version += `canary.pr.${pull_request.number}.${pull_request.merge_commit_sha}`; + + packageJSON.deprecated = + `You are using canary version build from ${pull_request.html_url}, no gurantees provided so please use your own discretion.`; + + assert( + packageJSON.scripts == null, + 'No scripts allowed for security reasons!', + ); + + fs.writeFileSync( + packageJSONPath, + JSON.stringify(packageJSON, null, 2), + 'utf-8', + ); + + const replyMessage = ` + The latest changes of this PR are available on NPM as + [graphql@${packageJSON.version}](https://www.npmjs.com/package/graphql/v/${packageJSON.version}) + **Note: no gurantees provided so please use your own discretion.** + + Also you can depend on latest version built from this PR: + \`npm install --save graphql@${packageJSON.publishConfig.tag}\` + `; + fs.writeFileSync('./replyMessage.txt', replyMessage.trim(), 'utf-8'); + + - name: Publish NPM package + run: npm publish --ignore-scripts ./npmDist + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_CANARY_PR_PUBLISH_TOKEN }} + + - name: Upload replyMessage + uses: actions/upload-artifact@v4 + with: + name: replyMessage + path: ./replyMessage.txt diff --git a/.github/workflows/cmd-run-benchmark.yml b/.github/workflows/cmd-run-benchmark.yml new file mode 100644 index 0000000000..e007a0e94d --- /dev/null +++ b/.github/workflows/cmd-run-benchmark.yml @@ -0,0 +1,48 @@ +name: run-benchmark +on: + workflow_call: + inputs: + pullRequestJSON: + required: true + type: string +jobs: + benchmark: + name: Run benchmark + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + persist-credentials: false + ref: ${{ fromJSON(inputs.pullRequestJSON).merge_commit_sha }} + + - name: Deepen cloned repo + env: + BASE_SHA: ${{ fromJSON(inputs.pullRequestJSON).base.sha }} + run: 'git fetch --depth=1 origin $BASE_SHA:refs/tags/BASE' + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + cache: npm + node-version-file: '.node-version' + + - name: Install Dependencies + run: npm ci --ignore-scripts + + - name: Run Benchmark + run: | + cat <> replyMessage.txt +
+ Benchmark output + EOF + npm run benchmark -- --revs HEAD BASE | tee -a replyMessage.txt + cat <> replyMessage.txt +
+ EOF + + - name: Upload replyMessage + uses: actions/upload-artifact@v4 + with: + name: replyMessage + path: ./replyMessage.txt diff --git a/.github/workflows/deploy-artifact-as-branch.yml b/.github/workflows/deploy-artifact-as-branch.yml new file mode 100644 index 0000000000..82f38729c4 --- /dev/null +++ b/.github/workflows/deploy-artifact-as-branch.yml @@ -0,0 +1,51 @@ +name: Deploy specified artifact as a branch +on: + workflow_call: + inputs: + environment: + required: true + type: string + artifact_name: + required: true + type: string + target_branch: + required: true + type: string + commit_message: + required: true + type: string +jobs: + deploy-artifact-as-branch: + environment: + name: ${{ inputs.environment }} + url: ${{ github.server_url }}/${{ github.repository }}/tree/${{ inputs.target_branch }} + runs-on: ubuntu-latest + steps: + - name: Checkout `${{ inputs.target_branch }}` branch + uses: actions/checkout@v2 + with: + ref: ${{ inputs.target_branch }} + + - name: Remove existing files first + run: git rm -r . + + - uses: actions/download-artifact@v4 + with: + name: ${{ inputs.artifact_name }} + + - name: Publish target branch + run: | + git add -A + if git diff --staged --quiet; then + echo 'Nothing to publish' + else + git config user.name 'GitHub Action Script' + git config user.email 'please@open.issue' + + git commit -a -m "$COMMIT_MESSAGE" + git push + echo 'Pushed' + fi + env: + TARGET_BRANCH: ${{ inputs.target_branch }} + COMMIT_MESSAGE: ${{ inputs.commit_message }} diff --git a/.github/workflows/github-actions-bot.yml b/.github/workflows/github-actions-bot.yml new file mode 100644 index 0000000000..711bc73d0e --- /dev/null +++ b/.github/workflows/github-actions-bot.yml @@ -0,0 +1,159 @@ +name: GitHubActionsBot +on: + issue_comment: + types: + - created + + # We need to be call in context of the main branch to have write permissions + # "pull_request" target is called in context of a fork + # "pull_request_target" is called in context of the repository but not necessary latest main + workflow_run: + workflows: + - PullRequestOpened + types: + - completed +env: + SUPPORTED_COMMANDS: | +
+ Supported commands + + Please post this commands in separate comments and only one per comment: + * `@github-actions run-benchmark` - Run benchmark comparing base and merge commits for this PR + * `@github-actions publish-pr-on-npm` - Build package from this PR and publish it on NPM +
+jobs: + hello-message: + if: github.event_name == 'workflow_run' + runs-on: ubuntu-latest + steps: + - name: Download event.json + run: gh run download "$WORKFLOW_ID" --repo "$REPO" --name event.json + env: + REPO: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_ID: ${{github.event.workflow_run.id}} + + - name: Add comment on PR + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + + const event = JSON.parse(fs.readFileSync('./event.json', 'utf8')); + github.rest.issues.createComment({ + ...context.repo, + issue_number: event.pull_request.number, + body: + `Hi @${event.sender.login}, I'm @github-actions bot happy to help you with this PR 👋\n\n` + + process.env.SUPPORTED_COMMANDS, + }) + + accept-cmd: + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + startsWith(github.event.comment.body, '@github-actions ') + runs-on: ubuntu-latest + outputs: + cmd: ${{ steps.parse-cmd.outputs.cmd }} + pullRequestJSON: ${{ steps.parse-cmd.outputs.pullRequestJSON }} + steps: + - uses: actions/github-script@v7 + with: + script: | + github.rest.reactions.createForIssueComment({ + ...context.repo, + comment_id: context.payload.comment.id, + content: 'eyes', + }); + + - id: parse-cmd + uses: actions/github-script@v7 + with: + script: | + const comment = context.payload.comment.body; + core.setOutput('cmd', comment.replace('@github-actions ', '').trim()); + + const { url } = context.payload.issue.pull_request; + const { data } = await github.request(url); + core.setOutput('pullRequestJSON', JSON.stringify(data, null, 2)); + + cmd-publish-pr-on-npm: + needs: [accept-cmd] + if: needs.accept-cmd.outputs.cmd == 'publish-pr-on-npm' + uses: ./.github/workflows/cmd-publish-pr-on-npm.yml + with: + pullRequestJSON: ${{ needs.accept-cmd.outputs.pullRequestJSON }} + secrets: + NPM_CANARY_PR_PUBLISH_TOKEN: ${{ secrets.NPM_CANARY_PR_PUBLISH_TOKEN }} + + cmd-run-benchmark: + needs: [accept-cmd] + if: needs.accept-cmd.outputs.cmd == 'run-benchmark' + uses: ./.github/workflows/cmd-run-benchmark.yml + with: + pullRequestJSON: ${{ needs.accept-cmd.outputs.pullRequestJSON }} + + respond-to-cmd: + needs: + - accept-cmd + - cmd-publish-pr-on-npm + - cmd-run-benchmark + if: needs.accept-cmd.result != 'skipped' && always() + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + with: + name: replyMessage + + - if: failure() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + + const needs = JSON.parse(process.env.NEEDS); + + let allSkipped = true; + for (const [ name, job ] of Object.entries(needs)) { + if (name.startsWith('cmd-')) { + allSkipped = allSkipped && job.result === 'skipped'; + } + } + + const replyMessage = allSkipped + ? 'Unknown command 😕\n\n' + process.env.SUPPORTED_COMMANDS + : `Something went wrong, [please check log](${process.env.RUN_URL}).`; + + fs.writeFileSync('./replyMessage.txt', replyMessage, 'utf-8'); + env: + NEEDS: ${{ toJSON(needs) }} + RUN_URL: ${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}} + + - if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + + const replyMessage = fs.readFileSync('./replyMessage.txt', 'utf-8'); + const { issue, comment, sender } = context.payload; + + const quoteRequest = comment.body + .split('\n') + .map((line) => '> ' + line) + .join('\n'); + + github.rest.issues.createComment({ + ...context.repo, + issue_number: issue.number, + body: quoteRequest + `\n\n@${sender.login} ` + replyMessage, + }); + + // `github.rest` doesn't have this method :( so use graphql instead + github.graphql(` + mutation ($subjectId: ID!) { + minimizeComment(input: { subjectId: $subjectId, classifier: RESOLVED}) + { __typename } + } + `, { subjectId: comment.node_id }); diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000000..dd844e5a32 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,40 @@ +name: PullRequest +on: pull_request +jobs: + ci: + uses: ./.github/workflows/ci.yml + secrets: + codecov_token: ${{ secrets.CODECOV_TOKEN }} + + diff-npm-package: + name: Diff content of NPM package + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + persist-credentials: false + + - name: Deepen cloned repo + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + run: 'git fetch --depth=1 origin $BASE_SHA:refs/tags/BASE' + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + cache: npm + node-version-file: '.node-version' + + - name: Install Dependencies + run: npm ci --ignore-scripts + + - name: Generate report + run: 'node resources/diff-npm-package.js BASE HEAD' + + - name: Upload generated report + uses: actions/upload-artifact@v4 + with: + name: npm-dist-diff.html + path: ./npm-dist-diff.html + if-no-files-found: ignore diff --git a/.github/workflows/pull_request_opened.yml b/.github/workflows/pull_request_opened.yml new file mode 100644 index 0000000000..ccb9c92171 --- /dev/null +++ b/.github/workflows/pull_request_opened.yml @@ -0,0 +1,14 @@ +name: PullRequestOpened +on: + pull_request: + types: [opened] +jobs: + save-github-event: + name: "Save `github.event` as an artifact to use in subsequent 'workflow_run' actions" + runs-on: ubuntu-latest + steps: + - name: Upload event.json + uses: actions/upload-artifact@v4 + with: + name: event.json + path: ${{ github.event_path }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000000..0df1bac4ec --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,28 @@ +name: Push +on: push +jobs: + ci: + uses: ./.github/workflows/ci.yml + secrets: + codecov_token: ${{ secrets.CODECOV_TOKEN }} + deploy-to-npm-branch: + name: Deploy to `npm` branch + needs: ci + if: github.ref == 'refs/heads/main' + uses: ./.github/workflows/deploy-artifact-as-branch.yml + with: + environment: npm-branch + artifact_name: npmDist + target_branch: npm + commit_message: "Deploy ${{github.event.workflow_run.head_sha}} to 'npm' branch" + + deploy-to-deno-branch: + name: Deploy to `deno` branch + needs: ci + if: github.ref == 'refs/heads/main' + uses: ./.github/workflows/deploy-artifact-as-branch.yml + with: + environment: deno-branch + artifact_name: denoDist + target_branch: deno + commit_message: "Deploy ${{github.event.workflow_run.head_sha}} to 'deno' branch" diff --git a/.gitignore b/.gitignore index 9e07128cb8..bc35ca93a3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,13 @@ # https://help.github.com/articles/ignoring-files/#create-a-global-gitignore # https://www.gitignore.io/ +/diff-npm-package.html /.eslintcache -/node_modules +/.cspellcache +node_modules /coverage /npmDist /denoDist -/npm -/deno +/websiteDist +/website/.next +/website/out diff --git a/.mocharc.yml b/.mocharc.yml index 5e75d26389..5050fbe4ac 100644 --- a/.mocharc.yml +++ b/.mocharc.yml @@ -1,4 +1,7 @@ +fail-zero: true throw-deprecation: true check-leaks: true require: - - '@babel/register' + - 'resources/ts-register.js' +extension: + - 'ts' diff --git a/.node-version b/.node-version new file mode 100644 index 0000000000..703a257b8b --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v17 diff --git a/.nycrc.yml b/.nycrc.yml deleted file mode 100644 index 6856b3bc46..0000000000 --- a/.nycrc.yml +++ /dev/null @@ -1,26 +0,0 @@ -all: true -include: - - 'src/' -exclude: - - 'src/polyfills' - - '**/*-fuzz.js' - - '**/*.d.ts' - - 'src/validation/rules/ExecutableDefinitions.js' - - 'src/validation/rules/LoneSchemaDefinition.js' - - 'src/validation/rules/PossibleTypeExtensions.js' - - 'src/validation/rules/UniqueDirectiveNames.js' - - 'src/validation/rules/UniqueEnumValueNames.js' - - 'src/validation/rules/UniqueFieldDefinitionNames.js' - - 'src/validation/rules/UniqueTypeNames.js' - - 'src/validation/rules/UniqueOperationTypes.js' - - 'src/utilities/findDeprecatedUsages.js' -clean: true -temp-directory: 'coverage' -report-dir: 'coverage' -skip-full: true -reporter: [json, html, text] -check-coverage: true -branches: 100 -lines: 100 -functions: 100 -statements: 100 diff --git a/.prettierignore b/.prettierignore index 475f5e22fd..1801e9556e 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,8 +1,11 @@ # Copied from '.gitignore', please keep it in sync. +/diff-npm-package.html /.eslintcache /node_modules /coverage /npmDist /denoDist -/npm -/deno +/websiteDist +/website/out +/website/**/*.mdx +.next diff --git a/README.md b/README.md index f3429d2219..773635ff7b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![GraphQLConf 2024 Banner: September 10-12, San Francisco. Hosted by the GraphQL Foundation](https://github.com/user-attachments/assets/2d048502-e5b2-4e9d-a02a-50b841824de6)](https://graphql.org/conf/2024/?utm_source=github&utm_medium=graphql_js&utm_campaign=readme) + # GraphQL.js The JavaScript reference implementation for GraphQL, a query language for APIs created by Facebook. @@ -71,9 +73,9 @@ or an array of promises. A more complex example is included in the top-level [te Then, serve the result of a query against that type schema. ```js -var query = '{ hello }'; +var source = '{ hello }'; -graphql(schema, query).then((result) => { +graphql({ schema, source }).then((result) => { // Prints // { // data: { hello: "world" } @@ -87,9 +89,9 @@ first ensure the query is syntactically and semantically valid before executing it, reporting errors otherwise. ```js -var query = '{ BoyHowdy }'; +var source = '{ BoyHowdy }'; -graphql(schema, query).then((result) => { +graphql({ schema, source }).then((result) => { // Prints // { // errors: [ @@ -141,6 +143,14 @@ custom build configurations look for `.mjs` files! We actively welcome pull requests. Learn how to [contribute](./.github/CONTRIBUTING.md). +This repository is managed by EasyCLA. Project participants must sign the free ([GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) before making a contribution. You only need to do this one time, and it can be signed by [individual contributors](http://individual-spec-membership.graphql.org/) or their [employers](http://corporate-spec-membership.graphql.org/). + +To initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you. + +You can find [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). If you have issues, please email [operations@graphql.org](mailto:operations@graphql.org). + +If your company benefits from GraphQL and you would like to provide essential financial support for the systems and people that power our community, please also consider membership in the [GraphQL Foundation](https://foundation.graphql.org/join). + ### Changelog Changes are tracked as [GitHub releases](https://github.com/graphql/graphql-js/releases). @@ -148,30 +158,3 @@ Changes are tracked as [GitHub releases](https://github.com/graphql/graphql-js/r ### License GraphQL.js is [MIT-licensed](./LICENSE). - -### Credits - -The `*.d.ts` files in this project are based on [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/54712a7e28090c5b1253b746d1878003c954f3ff/types/graphql) definitions written by: - - - -- TonyYang https://github.com/TonyPythoneer -- Caleb Meredith https://github.com/calebmer -- Dominic Watson https://github.com/intellix -- Firede https://github.com/firede -- Kepennar https://github.com/kepennar -- Mikhail Novikov https://github.com/freiksenet -- Ivan Goncharov https://github.com/IvanGoncharov -- Hagai Cohen https://github.com/DxCx -- Ricardo Portugal https://github.com/rportugal -- Tim Griesser https://github.com/tgriesser -- Dylan Stewart https://github.com/dyst5422 -- Alessio Dionisi https://github.com/adnsio -- Divyendu Singh https://github.com/divyenduz -- Brad Zacher https://github.com/bradzacher -- Curtis Layne https://github.com/clayne11 -- Jonathan Cardoso https://github.com/JCMais -- Pavel Lang https://github.com/langpavel -- Mark Caudill https://github.com/mc0 -- Martijn Walraven https://github.com/martijnwalraven -- Jed Mao https://github.com/jedmao diff --git a/benchmark/benchmark.js b/benchmark/benchmark.js index 0f83a2efdc..9288d1f273 100644 --- a/benchmark/benchmark.js +++ b/benchmark/benchmark.js @@ -14,6 +14,17 @@ const maxTime = 5; // The minimum sample size required to perform statistical analysis. const minSamples = 5; +// Get the revisions and make things happen! +if (require.main === module) { + const { benchmarks, revisions } = getArguments(process.argv.slice(2)); + const benchmarkProjects = prepareBenchmarkProjects(revisions); + + runBenchmarks(benchmarks, benchmarkProjects).catch((error) => { + console.error(error); + process.exit(1); + }); +} + function localDir(...paths) { return path.join(__dirname, '..', ...paths); } @@ -24,33 +35,33 @@ function exec(command, options = {}) { stdio: ['inherit', 'pipe', 'inherit'], ...options, }); - return result && result.trimEnd(); + return result?.trimEnd(); } // Build a benchmark-friendly environment for the given revision // and returns path to its 'dist' directory. function prepareBenchmarkProjects(revisionList) { const tmpDir = path.join(os.tmpdir(), 'graphql-js-benchmark'); - fs.rmdirSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true }); fs.mkdirSync(tmpDir); const setupDir = path.join(tmpDir, 'setup'); - fs.rmdirSync(setupDir, { recursive: true, force: true }); fs.mkdirSync(setupDir); return revisionList.map((revision) => { console.log(`🍳 Preparing ${revision}...`); const projectPath = path.join(setupDir, revision); - fs.rmdirSync(projectPath, { recursive: true }); + fs.rmSync(projectPath, { recursive: true, force: true }); fs.mkdirSync(projectPath); fs.writeFileSync( path.join(projectPath, 'package.json'), '{ "private": true }', ); - exec('npm --quiet install ' + prepareNPMPackage(revision), { - cwd: projectPath, - }); + exec( + 'npm --quiet install --ignore-scripts ' + prepareNPMPackage(revision), + { cwd: projectPath }, + ); exec(`cp -R ${localDir('benchmark')} ${projectPath}`); return { revision, projectPath }; @@ -73,12 +84,12 @@ function prepareBenchmarkProjects(revisionList) { } const repoDir = path.join(tmpDir, hash); - fs.rmdirSync(repoDir, { recursive: true, force: true }); + fs.rmSync(repoDir, { recursive: true, force: true }); fs.mkdirSync(repoDir); exec(`git archive "${hash}" | tar -xC "${repoDir}"`); - exec('npm --quiet ci', { cwd: repoDir }); + exec('npm --quiet ci --ignore-scripts', { cwd: repoDir }); fs.renameSync(buildNPMArchive(repoDir), archivePath); - fs.rmdirSync(repoDir, { recursive: true, force: true }); + fs.rmSync(repoDir, { recursive: true }); return archivePath; } @@ -107,7 +118,8 @@ async function collectSamples(modulePath) { // T-Distribution two-tailed critical values for 95% confidence. // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm. -const tTable = /* prettier-ignore */ { +// prettier-ignore +const tTable = { '1': 12.706, '2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, @@ -230,9 +242,7 @@ function maxBy(array, fn) { } // Prepare all revisions and run benchmarks matching a pattern against them. -async function runBenchmarks(benchmarks, revisions) { - const benchmarkProjects = prepareBenchmarkProjects(revisions); - +async function runBenchmarks(benchmarks, benchmarkProjects) { for (const benchmark of benchmarks) { const results = []; for (let i = 0; i < benchmarkProjects.length; ++i) { @@ -241,7 +251,7 @@ async function runBenchmarks(benchmarks, revisions) { if (i === 0) { const { name } = await sampleModule(modulePath); - console.log('⏱️ ' + name); + console.log('⏱ ' + name); } try { @@ -265,32 +275,37 @@ async function runBenchmarks(benchmarks, revisions) { } function getArguments(argv) { - const revsIdx = argv.indexOf('--revs'); - const revsArgs = revsIdx === -1 ? [] : argv.slice(revsIdx + 1); - const specificBenchmarks = revsIdx === -1 ? argv : argv.slice(0, revsIdx); - let assumeArgs; - let revisions; - switch (revsArgs.length) { + const revsIndex = argv.indexOf('--revs'); + const revisions = revsIndex === -1 ? [] : argv.slice(revsIndex + 1); + const benchmarks = revsIndex === -1 ? argv : argv.slice(0, revsIndex); + + switch (revisions.length) { case 0: - assumeArgs = [...specificBenchmarks, '--revs', 'local', 'HEAD']; - revisions = [LOCAL, 'HEAD']; - break; - case 1: - assumeArgs = [...specificBenchmarks, '--revs', 'local', revsArgs[0]]; - revisions = [LOCAL, revsArgs[0]]; - break; - default: - revisions = revsArgs; + revisions.unshift('HEAD'); + // fall through + case 1: { + revisions.unshift('local'); + + const assumeArgv = ['benchmark', ...benchmarks, '--revs', ...revisions]; + console.warn('Assuming you meant: ' + bold(assumeArgv.join(' '))); break; + } } - if (assumeArgs) { - console.warn( - 'Assuming you meant: ' + bold('benchmark ' + assumeArgs.join(' ')), - ); + if (benchmarks.length === 0) { + benchmarks.push(...findAllBenchmarks()); } - return { specificBenchmarks, revisions }; + return { benchmarks, revisions }; +} + +function findAllBenchmarks() { + return fs + .readdirSync(localDir('benchmark'), { withFileTypes: true }) + .filter((dirent) => dirent.isFile()) + .map((dirent) => dirent.name) + .filter((name) => name.endsWith('-benchmark.js')) + .map((name) => path.join('benchmark', name)); } function bold(str) { @@ -317,26 +332,6 @@ function grey(str) { return '\u001b[90m' + str + '\u001b[0m'; } -function findAllBenchmarks() { - return fs - .readdirSync(localDir('benchmark'), { withFileTypes: true }) - .filter((dirent) => dirent.isFile()) - .map((dirent) => dirent.name) - .filter((name) => name.endsWith('-benchmark.js')) - .map((name) => path.join('benchmark', name)); -} - -// Get the revisions and make things happen! -if (require.main === module) { - const { specificBenchmarks, revisions } = getArguments(process.argv.slice(2)); - const benchmarks = - specificBenchmarks.length > 0 ? specificBenchmarks : findAllBenchmarks(); - runBenchmarks(benchmarks, revisions).catch((error) => { - console.error(error); - process.exit(1); - }); -} - function sampleModule(modulePath) { const sampleCode = ` const assert = require('assert'); @@ -371,7 +366,7 @@ function sampleModule(modulePath) { const child = cp.spawn( process.argv[0], [ - '--noconcurrent_sweeping', + '--no-concurrent-sweeping', '--predictable', '--expose-gc', '--eval', diff --git a/benchmark/repeated-fields-benchmark.js b/benchmark/repeated-fields-benchmark.js new file mode 100644 index 0000000000..7dd5b179b7 --- /dev/null +++ b/benchmark/repeated-fields-benchmark.js @@ -0,0 +1,15 @@ +'use strict'; + +const { graphqlSync } = require('graphql/graphql.js'); +const { buildSchema } = require('graphql/utilities/buildASTSchema.js'); + +const schema = buildSchema('type Query { hello: String! }'); +const source = `{ ${'hello '.repeat(250)}}`; + +module.exports = { + name: 'Many repeated fields', + count: 5, + measure() { + graphqlSync({ schema, source }); + }, +}; diff --git a/benchmark/visit-benchmark.js b/benchmark/visit-benchmark.js new file mode 100644 index 0000000000..ab6a2baac2 --- /dev/null +++ b/benchmark/visit-benchmark.js @@ -0,0 +1,25 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { visit } = require('graphql/language/visitor.js'); + +const { bigSchemaSDL } = require('./fixtures.js'); + +const documentAST = parse(bigSchemaSDL); + +const visitor = { + enter() { + /* do nothing */ + }, + leave() { + /* do nothing */ + }, +}; + +module.exports = { + name: 'Visit all AST nodes', + count: 10, + measure() { + visit(documentAST, visitor); + }, +}; diff --git a/benchmark/visitInParallel-benchmark.js b/benchmark/visitInParallel-benchmark.js new file mode 100644 index 0000000000..cd835dd19c --- /dev/null +++ b/benchmark/visitInParallel-benchmark.js @@ -0,0 +1,25 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { visit, visitInParallel } = require('graphql/language/visitor.js'); + +const { bigSchemaSDL } = require('./fixtures.js'); + +const documentAST = parse(bigSchemaSDL); + +const visitors = new Array(50).fill({ + enter() { + /* do nothing */ + }, + leave() { + /* do nothing */ + }, +}); + +module.exports = { + name: 'Visit all AST nodes in parallel', + count: 10, + measure() { + visit(documentAST, visitInParallel(visitors)); + }, +}; diff --git a/codecov.yml b/codecov.yml index ca5256f76c..7c05fac380 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,12 +1,12 @@ codecov: notify: - require_ci_to_pass: yes + require_ci_to_pass: true parsers: javascript: - enable_partials: yes + enable_partials: true -comment: no +comment: false coverage: status: project: diff --git a/cspell.json b/cspell.json deleted file mode 100644 index 137edea6f3..0000000000 --- a/cspell.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "language": "en", - "ignorePaths": [ - // Copied from '.gitignore', please keep it in sync. - ".eslintcache", - "node_modules", - "coverage", - "npmDist", - "denoDist", - "npm", - "deno", - - // Excluded from spelling check - "cspell.json", - "package.json", - "package-lock.json", - "tsconfig.json", - "benchmark/github-schema.graphql", - "benchmark/github-schema.json" - ], - "overrides": [ - { - "filename": "**/docs/APIReference-*.md", - "ignoreRegExpList": ["/href=\"[^\"]*\"/"] - } - ], - "words": [ - "graphiql", - "sublinks", - "subcommand", - "transpilation", - "instanceof", - "flowtype", - "noconcurrent", - - // Different names used inside tests - "Skywalker", - "Leia", - "Wilhuff", - "Tarkin", - "Artoo", - "Threepio", - "Odie", - "Odie's", - "Damerau", - "Alderaan", - "Tatooine", - "astromech", - - // TODO: contribute upstream - "deno", - "codecov", - - // TODO: remove bellow words - "Graphi", // GraphiQL - "QL's", // GraphQL's - "QLIs", // GraphQLIs* - "QLID", // GraphQLID - "QLJS", // GraphQLJS - "iface", - "Reqs", - "ORing", - "FXXX", - "XXXF", - "bfnrt", - "wrds" - ] -} diff --git a/cspell.yml b/cspell.yml new file mode 100644 index 0000000000..ff26b0902b --- /dev/null +++ b/cspell.yml @@ -0,0 +1,117 @@ +language: en +useGitignore: true +# TODO enableGlobDot: true +ignorePaths: + # Excluded from spelling check + - cspell.yml + - package.json + - package-lock.json + - tsconfig.json + - benchmark/github-schema.graphql + - benchmark/github-schema.json + - website/icons + - website/css +overrides: + - filename: 'website/**' + dictionaries: + - fullstack + words: + - clsx + - infima + - noopener + - Vite + - craco + - esbuild + - swcrc + - noreferrer + - xlink + +ignoreRegExpList: + - u\{[0-9a-f]{1,8}\} + +words: + - graphiql + - sublinks + - instanceof + + # Different names used inside tests + - Skywalker + - Leia + - Wilhuff + - Tarkin + - Artoo + - Threepio + - Odie + - Odie's + - Damerau + - Alderaan + - Tatooine + - astromech + + # TODO: contribute upstream + - deno + - codecov + + # Website tech + - Nextra + - headlessui + - Fastify + - tailwindcss + - svgr + - ruru + - oneof + + # used as href anchors + - graphqlerror + - syntaxerror + - formaterror + - graphqlschema + - graphqlscalartype + - graphqlobjecttype + - graphqlinterfacetype + - graphqluniontype + - graphqlenumtype + - graphqlinputobjecttype + - graphqllist + - graphqlnonnull + - graphqlint + - graphqlfloat + - graphqlstring + - graphqlboolean + - graphqlid + - getlocation + - isinputtype + - isoutputtype + - isleaftype + - iscompositetype + - isabstracttype + - getnullabletype + - getnamedtype + - introspectionquery + - buildclientschema + - buildschema + - printschema + - printintrospectionschema + - buildastschema + - typefromast + - astfromvalue + - typeinfo + - isvalidjsvalue + - isvalidliteralvalue + - specifiedrules + - Wordmark + - codeofconduct + - graphqlconf + + # website words + - runtimes + + # TODO: remove bellow words + - QLID # GraphQLID + - QLJS # GraphQLJS + - iface + - Reqs + - FXXX + - XXXF + - bfnrt + - wrds diff --git a/docs/APIReference-ExpressGraphQL.md b/docs/APIReference-ExpressGraphQL.md deleted file mode 100644 index eac9f42b0d..0000000000 --- a/docs/APIReference-ExpressGraphQL.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: express-graphql -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/express-graphql/ -sublinks: graphqlHTTP -next: /graphql-js/graphql/ ---- - -The `express-graphql` module provides a simple way to create an [Express](https://expressjs.com/) server that runs a GraphQL API. - -```js -import { graphqlHTTP } from 'express-graphql'; // ES6 -var { graphqlHTTP } = require('express-graphql'); // CommonJS -``` - -### graphqlHTTP - -```js -graphqlHTTP({ - schema: GraphQLSchema, - graphiql?: ?boolean, - rootValue?: ?any, - context?: ?any, - pretty?: ?boolean, - formatError?: ?Function, - validationRules?: ?Array, -}): Middleware -``` - -Constructs an Express application based on a GraphQL schema. - -See the [express-graphql tutorial](/graphql-js/running-an-express-graphql-server/) for sample usage. - -See the [GitHub README](https://github.com/graphql/express-graphql) for more extensive documentation of the details of this method. diff --git a/docs/APIReference-GraphQL.md b/docs/APIReference-GraphQL.md deleted file mode 100644 index 3aea9e87ba..0000000000 --- a/docs/APIReference-GraphQL.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -title: graphql -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/graphql/ -sublinks: graphql -next: /graphql-js/error/ ---- - -The `graphql` module exports a core subset of GraphQL functionality for creation -of GraphQL type systems and servers. - -```js -import { graphql } from 'graphql'; // ES6 -var { graphql } = require('graphql'); // CommonJS -``` - -## Overview - -_Entry Point_ - - - -_Schema_ - - - -_Type Definitions_ - - - -_Scalars_ - - - -_Errors_ - - - -## Entry Point - -### graphql - -```js -graphql( - schema: GraphQLSchema, - requestString: string, - rootValue?: ?any, - contextValue?: ?any, - variableValues?: ?{[key: string]: any}, - operationName?: ?string -): Promise -``` - -The `graphql` function lexes, parses, validates and executes a GraphQL request. -It requires a `schema` and a `requestString`. Optional arguments include a -`rootValue`, which will get passed as the root value to the executor, a `contextValue`, -which will get passed to all resolve functions, -`variableValues`, which will get passed to the executor to provide values for -any variables in `requestString`, and `operationName`, which allows the caller -to specify which operation in `requestString` will be run, in cases where -`requestString` contains multiple top-level operations. - -## Schema - -See the [Type System API Reference](../type#schema). - -## Type Definitions - -See the [Type System API Reference](../type#definitions). - -## Scalars - -See the [Type System API Reference](../type#scalars). - -## Errors - -See the [Errors API Reference](../error) diff --git a/docs/APIReference-Utilities.md b/docs/APIReference-Utilities.md deleted file mode 100644 index a9455aadd5..0000000000 --- a/docs/APIReference-Utilities.md +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: graphql/utilities -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/utilities/ -sublinks: astFromValue,buildASTSchema,buildClientSchema,buildSchema,introspectionQuery,isValidJSValue,isValidLiteralValue,printIntrospectionSchema,printSchema,typeFromAST,TypeInfo -next: /graphql-js/validation/ ---- - -The `graphql/utilities` module contains common useful computations to use with -the GraphQL language and type objects. You can import either from the `graphql/utilities` module, or from the root `graphql` module. For example: - -```js -import { introspectionQuery } from 'graphql'; // ES6 -var { introspectionQuery } = require('graphql'); // CommonJS -``` - -## Overview - -_Introspection_ - - - -_Schema Language_ - - - -_Visitors_ - - - -_Value Validation_ - - - -## Introspection - -### getIntrospectionQuery - -```js -interface IntrospectionOptions { - // Whether to include descriptions in the introspection result. - // Default: true - descriptions?: boolean; - - // Whether to include `specifiedByUrl` in the introspection result. - // Default: false - specifiedByUrl?: boolean; - - // Whether to include `isRepeatable` flag on directives. - // Default: false - directiveIsRepeatable?: boolean; - - // Whether to include `description` field on schema. - // Default: false - schemaDescription?: boolean; -} - -function getIntrospectionQuery( - options: IntrospectionOptions -): string; -``` - -Build a GraphQL query that queries a server's introspection system for enough -information to reproduce that server's type system. - -### buildClientSchema - -```js -function buildClientSchema( - introspection: IntrospectionQuery -): GraphQLSchema -``` - -Build a GraphQLSchema for use by client tools. - -Given the result of a client running the introspection query, creates and -returns a GraphQLSchema instance which can be then used with all GraphQL.js -tools, but cannot be used to execute a query, as introspection does not -represent the "resolver", "parse" or "serialize" functions or any other -server-internal mechanisms. - -## Schema Representation - -### buildSchema - -```js -function buildSchema(source: string | Source): GraphQLSchema { -``` - -Creates a GraphQLSchema object from GraphQL schema language. The schema will use default resolvers. For more detail on the GraphQL schema language, see the [schema language docs](/learn/schema/) or this [schema language cheat sheet](https://wehavefaces.net/graphql-shorthand-notation-cheatsheet-17cd715861b6#.9oztv0a7n). - -### printSchema - -```js -function printSchema(schema: GraphQLSchema): string { -``` - -Prints the provided schema in the Schema Language format. - -### printIntrospectionSchema - -```js -function printIntrospectionSchema(schema: GraphQLSchema): string { -``` - -Prints the built-in introspection schema in the Schema Language format. - -### buildASTSchema - -```js -function buildASTSchema( - ast: SchemaDocument, - queryTypeName: string, - mutationTypeName: ?string -): GraphQLSchema -``` - -This takes the ast of a schema document produced by `parse` in -`graphql/language` and constructs a GraphQLSchema instance which can be -then used with all GraphQL.js tools, but cannot be used to execute a query, as -introspection does not represent the "resolver", "parse" or "serialize" -functions or any other server-internal mechanisms. - -### typeFromAST - -```js -function typeFromAST( - schema: GraphQLSchema, - inputTypeAST: Type -): ?GraphQLType -``` - -Given the name of a Type as it appears in a GraphQL AST and a Schema, return the -corresponding GraphQLType from that schema. - -### astFromValue - -```js -function astFromValue( - value: any, - type?: ?GraphQLType -): ?Value -``` - -Produces a GraphQL Input Value AST given a JavaScript value. - -Optionally, a GraphQL type may be provided, which will be used to -disambiguate between value primitives. - -## Visitors - -### TypeInfo - -```js -class TypeInfo { - constructor(schema: GraphQLSchema) - getType(): ?GraphQLOutputType { - getParentType(): ?GraphQLCompositeType { - getInputType(): ?GraphQLInputType { - getFieldDef(): ?GraphQLFieldDefinition { - getDirective(): ?GraphQLDirective { - getArgument(): ?GraphQLArgument { -} -``` - -TypeInfo is a utility class which, given a GraphQL schema, can keep track -of the current field and type definitions at any point in a GraphQL document -AST during a recursive descent by calling `enter(node)` and `leave(node)`. - -## Value Validation - -### isValidJSValue - -```js -function isValidJSValue(value: any, type: GraphQLInputType): string[] -``` - -Given a JavaScript value and a GraphQL type, determine if the value will be -accepted for that type. This is primarily useful for validating the -runtime values of query variables. - -### isValidLiteralValue - -```js -function isValidLiteralValue( - type: GraphQLInputType, - valueAST: Value -): string[] -``` - -Utility for validators which determines if a value literal AST is valid given -an input type. - -Note that this only validates literal values, variables are assumed to -provide values of the correct type. diff --git a/docs/Guides-ConstructingTypes.md b/docs/Guides-ConstructingTypes.md deleted file mode 100644 index e8737c33e1..0000000000 --- a/docs/Guides-ConstructingTypes.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Constructing Types -layout: ../_core/GraphQLJSLayout -category: Advanced Guides -permalink: /graphql-js/constructing-types/ -next: /graphql-js/express-graphql/ ---- - -For many apps, you can define a fixed schema when the application starts, and define it using GraphQL schema language. In some cases, it's useful to construct a schema programmatically. You can do this using the `GraphQLSchema` constructor. - -When you are using the `GraphQLSchema` constructor to create a schema, instead of defining `Query` and `Mutation` types solely using schema language, you create them as separate object types. - -For example, let's say we are building a simple API that lets you fetch user data for a few hardcoded users based on an id. Using `buildSchema` we could write a server with: - -```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); - -var schema = buildSchema(` - type User { - id: String - name: String - } - - type Query { - user(id: String): User - } -`); - -// Maps id to User object -var fakeDatabase = { - a: { - id: 'a', - name: 'alice', - }, - b: { - id: 'b', - name: 'bob', - }, -}; - -var root = { - user: function ({ id }) { - return fakeDatabase[id]; - }, -}; - -var app = express(); -app.use( - '/graphql', - graphqlHTTP({ - schema: schema, - rootValue: root, - graphiql: true, - }), -); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); -}); -``` - -We can implement this same API without using GraphQL schema language: - -```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var graphql = require('graphql'); - -// Maps id to User object -var fakeDatabase = { - a: { - id: 'a', - name: 'alice', - }, - b: { - id: 'b', - name: 'bob', - }, -}; - -// Define the User type -var userType = new graphql.GraphQLObjectType({ - name: 'User', - fields: { - id: { type: graphql.GraphQLString }, - name: { type: graphql.GraphQLString }, - }, -}); - -// Define the Query type -var queryType = new graphql.GraphQLObjectType({ - name: 'Query', - fields: { - user: { - type: userType, - // `args` describes the arguments that the `user` query accepts - args: { - id: { type: graphql.GraphQLString }, - }, - resolve: function (_, { id }) { - return fakeDatabase[id]; - }, - }, - }, -}); - -var schema = new graphql.GraphQLSchema({ query: queryType }); - -var app = express(); -app.use( - '/graphql', - graphqlHTTP({ - schema: schema, - graphiql: true, - }), -); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); -}); -``` - -When we use this method of creating the API, the root level resolvers are implemented on the `Query` and `Mutation` types rather than on a `root` object. - -This is particularly useful if you want to create a GraphQL schema automatically from something else, like a database schema. You might have a common format for something like creating and updating database records. This is also useful for implementing features like union types which don't map cleanly to ES6 classes and schema language. diff --git a/docs/Tutorial-BasicTypes.md b/docs/Tutorial-BasicTypes.md deleted file mode 100644 index 2367b7d352..0000000000 --- a/docs/Tutorial-BasicTypes.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Basic Types -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/basic-types/ -next: /graphql-js/passing-arguments/ ---- - -In most situations, all you need to do is to specify the types for your API using the GraphQL schema language, taken as an argument to the `buildSchema` function. - -The GraphQL schema language supports the scalar types of `String`, `Int`, `Float`, `Boolean`, and `ID`, so you can use these directly in the schema you pass to `buildSchema`. - -By default, every type is nullable - it's legitimate to return `null` as any of the scalar types. Use an exclamation point to indicate a type cannot be nullable, so `String!` is a non-nullable string. - -To use a list type, surround the type in square brackets, so `[Int]` is a list of integers. - -Each of these types maps straightforwardly to JavaScript, so you can just return plain old JavaScript objects in APIs that return these types. Here's an example that shows how to use some of these basic types: - -```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); - -// Construct a schema, using GraphQL schema language -var schema = buildSchema(` - type Query { - quoteOfTheDay: String - random: Float! - rollThreeDice: [Int] - } -`); - -// The root provides a resolver function for each API endpoint -var root = { - quoteOfTheDay: () => { - return Math.random() < 0.5 ? 'Take it easy' : 'Salvation lies within'; - }, - random: () => { - return Math.random(); - }, - rollThreeDice: () => { - return [1, 2, 3].map((_) => 1 + Math.floor(Math.random() * 6)); - }, -}; - -var app = express(); -app.use( - '/graphql', - graphqlHTTP({ - schema: schema, - rootValue: root, - graphiql: true, - }), -); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); -}); -``` - -If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out these APIs. - -These examples show you how to call APIs that return different types. To send different types of data into an API, you will also need to learn about [passing arguments to a GraphQL API](/graphql-js/passing-arguments/). diff --git a/docs/Tutorial-ExpressGraphQL.md b/docs/Tutorial-ExpressGraphQL.md deleted file mode 100644 index 69b49c0a48..0000000000 --- a/docs/Tutorial-ExpressGraphQL.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Running an Express GraphQL Server -sidebarTitle: Running Express + GraphQL -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/running-an-express-graphql-server/ -next: /graphql-js/graphql-clients/ ---- - -The simplest way to run a GraphQL API server is to use [Express](https://expressjs.com), a popular web application framework for Node.js. You will need to install two additional dependencies: - -```bash -npm install express express-graphql graphql --save -``` - -Let's modify our “hello world” example so that it's an API server rather than a script that runs a single query. We can use the 'express' module to run a webserver, and instead of executing a query directly with the `graphql` function, we can use the `express-graphql` library to mount a GraphQL API server on the “/graphql” HTTP endpoint: - -```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); - -// Construct a schema, using GraphQL schema language -var schema = buildSchema(` - type Query { - hello: String - } -`); - -// The root provides a resolver function for each API endpoint -var root = { - hello: () => { - return 'Hello world!'; - }, -}; - -var app = express(); -app.use( - '/graphql', - graphqlHTTP({ - schema: schema, - rootValue: root, - graphiql: true, - }), -); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); -}); -``` - -You can run this GraphQL server with: - -```bash -node server.js -``` - -Since we configured `graphqlHTTP` with `graphiql: true`, you can use the GraphiQL tool to manually issue GraphQL queries. If you navigate in a web browser to `http://localhost:4000/graphql`, you should see an interface that lets you enter queries. It should look like: - -![hello world graphql example](/img/hello.png) - -This screen shot shows the GraphQL query `{ hello }` being issued and giving a result of `{ data: { hello: 'Hello world!' } }`. GraphiQL is a great tool for debugging and inspecting a server, so we recommend running it whenever your application is in development mode. - -At this point you have learned how to run a GraphQL server and how to use GraphiQL interface to issue queries. The next step is to learn how to [issue GraphQL queries from client code](/graphql-js/graphql-clients/). diff --git a/docs/Tutorial-GettingStarted.md b/docs/Tutorial-GettingStarted.md deleted file mode 100644 index 19c4cfb11f..0000000000 --- a/docs/Tutorial-GettingStarted.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Getting Started With GraphQL.js -sidebarTitle: Getting Started -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/ -next: /graphql-js/running-an-express-graphql-server/ ---- - -## Prerequisites - -Before getting started, you should have Node v6 installed, although the examples should mostly work in previous versions of Node as well. For this guide, we won't use any language features that require transpilation, but we will use some ES6 features like [Promises](http://www.html5rocks.com/en/tutorials/es6/promises/), [classes](http://javascriptplayground.com/blog/2014/07/introduction-to-es6-classes-tutorial/), and [fat arrow functions](https://strongloop.com/strongblog/an-introduction-to-javascript-es6-arrow-functions/), so if you aren't familiar with them you might want to read up on them first. - -To create a new project and install GraphQL.js in your current directory: - -```bash -npm init -npm install graphql --save -``` - -## Writing Code - -To handle GraphQL queries, we need a schema that defines the `Query` type, and we need an API root with a function called a “resolver” for each API endpoint. For an API that just returns “Hello world!”, we can put this code in a file named `server.js`: - -```js -var { graphql, buildSchema } = require('graphql'); - -// Construct a schema, using GraphQL schema language -var schema = buildSchema(` - type Query { - hello: String - } -`); - -// The root provides a resolver function for each API endpoint -var root = { - hello: () => { - return 'Hello world!'; - }, -}; - -// Run the GraphQL query '{ hello }' and print out the response -graphql(schema, '{ hello }', root).then((response) => { - console.log(response); -}); -``` - -If you run this with: - -```bash -node server.js -``` - -You should see the GraphQL response printed out: - -```js -{ - data: { - hello: 'Hello world!'; - } -} -``` - -Congratulations - you just executed a GraphQL query! - -For practical applications, you'll probably want to run GraphQL queries from an API server, rather than executing GraphQL with a command line tool. To use GraphQL for an API server over HTTP, check out [Running an Express GraphQL Server](/graphql-js/running-an-express-graphql-server/). diff --git a/docs/Tutorial-Mutations.md b/docs/Tutorial-Mutations.md deleted file mode 100644 index 4b19fc0e38..0000000000 --- a/docs/Tutorial-Mutations.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -title: Mutations and Input Types -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/mutations-and-input-types/ -next: /graphql-js/authentication-and-express-middleware/ ---- - -If you have an API endpoint that alters data, like inserting data into a database or altering data already in a database, you should make this endpoint a `Mutation` rather than a `Query`. This is as simple as making the API endpoint part of the top-level `Mutation` type instead of the top-level `Query` type. - -Let's say we have a “message of the day” server, where anyone can update the message of the day, and anyone can read the current one. The GraphQL schema for this is simply: - -```graphql -type Mutation { - setMessage(message: String): String -} - -type Query { - getMessage: String -} -``` - -It's often convenient to have a mutation that maps to a database create or update operation, like `setMessage`, return the same thing that the server stored. That way, if you modify the data on the server, the client can learn about those modifications. - -Both mutations and queries can be handled by root resolvers, so the root that implements this schema can simply be: - -```js -var fakeDatabase = {}; -var root = { - setMessage: function ({ message }) { - fakeDatabase.message = message; - return message; - }, - getMessage: function () { - return fakeDatabase.message; - }, -}; -``` - -You don't need anything more than this to implement mutations. But in many cases, you will find a number of different mutations that all accept the same input parameters. A common example is that creating an object in a database and updating an object in a database often take the same parameters. To make your schema simpler, you can use “input types” for this, by using the `input` keyword instead of the `type` keyword. - -For example, instead of a single message of the day, let's say we have many messages, indexed in a database by the `id` field, and each message has both a `content` string and an `author` string. We want a mutation API both for creating a new message and for updating an old message. We could use the schema: - -```graphql -input MessageInput { - content: String - author: String -} - -type Message { - id: ID! - content: String - author: String -} - -type Query { - getMessage(id: ID!): Message -} - -type Mutation { - createMessage(input: MessageInput): Message - updateMessage(id: ID!, input: MessageInput): Message -} -``` - -Here, the mutations return a `Message` type, so that the client can get more information about the newly-modified `Message` in the same request as the request that mutates it. - -Input types can't have fields that are other objects, only basic scalar types, list types, and other input types. - -Naming input types with `Input` on the end is a useful convention, because you will often want both an input type and an output type that are slightly different for a single conceptual object. - -Here's some runnable code that implements this schema, keeping the data in memory: - -```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); - -// Construct a schema, using GraphQL schema language -var schema = buildSchema(` - input MessageInput { - content: String - author: String - } - - type Message { - id: ID! - content: String - author: String - } - - type Query { - getMessage(id: ID!): Message - } - - type Mutation { - createMessage(input: MessageInput): Message - updateMessage(id: ID!, input: MessageInput): Message - } -`); - -// If Message had any complex fields, we'd put them on this object. -class Message { - constructor(id, { content, author }) { - this.id = id; - this.content = content; - this.author = author; - } -} - -// Maps username to content -var fakeDatabase = {}; - -var root = { - getMessage: function ({ id }) { - if (!fakeDatabase[id]) { - throw new Error('no message exists with id ' + id); - } - return new Message(id, fakeDatabase[id]); - }, - createMessage: function ({ input }) { - // Create a random id for our "database". - var id = require('crypto').randomBytes(10).toString('hex'); - - fakeDatabase[id] = input; - return new Message(id, input); - }, - updateMessage: function ({ id, input }) { - if (!fakeDatabase[id]) { - throw new Error('no message exists with id ' + id); - } - // This replaces all old data, but some apps might want partial update. - fakeDatabase[id] = input; - return new Message(id, input); - }, -}; - -var app = express(); -app.use( - '/graphql', - graphqlHTTP({ - schema: schema, - rootValue: root, - graphiql: true, - }), -); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); -}); -``` - -To call a mutation, you must use the keyword `mutation` before your GraphQL query. To pass an input type, provide the data written as if it's a JSON object. For example, with the server defined above, you can create a new message and return the `id` of the new message with this operation: - -```graphql -mutation { - createMessage(input: { author: "andy", content: "hope is a good thing" }) { - id - } -} -``` - -You can use variables to simplify mutation client logic just like you can with queries. For example, some JavaScript code that calls the server to execute this mutation is: - -```js -var author = 'andy'; -var content = 'hope is a good thing'; -var query = `mutation CreateMessage($input: MessageInput) { - createMessage(input: $input) { - id - } -}`; - -fetch('/graphql', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - body: JSON.stringify({ - query, - variables: { - input: { - author, - content, - }, - }, - }), -}) - .then((r) => r.json()) - .then((data) => console.log('data returned:', data)); -``` - -One particular type of mutation is operations that change users, like signing up a new user. While you can implement this using GraphQL mutations, you can reuse many existing libraries if you learn about [GraphQL with authentication and Express middleware](/graphql-js/authentication-and-express-middleware/). diff --git a/docs/Tutorial-ObjectTypes.md b/docs/Tutorial-ObjectTypes.md deleted file mode 100644 index 246aa67a51..0000000000 --- a/docs/Tutorial-ObjectTypes.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -title: Object Types -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/object-types/ -next: /graphql-js/mutations-and-input-types/ ---- - -In many cases, you don't want to return a number or a string from an API. You want to return an object that has its own complex behavior. GraphQL is a perfect fit for this. - -In GraphQL schema language, the way you define a new object type is the same way we have been defining the `Query` type in our examples. Each object can have fields that return a particular type, and methods that take arguments. For example, in the [Passing Arguments](/graphql-js/passing-arguments/) documentation, we had a method to roll some random dice: - -```graphql -type Query { - rollDice(numDice: Int!, numSides: Int): [Int] -} -``` - -If we wanted to have more and more methods based on a random die over time, we could implement this with a `RandomDie` object type instead. - -```graphql -type RandomDie { - roll(numRolls: Int!): [Int] -} - -type Query { - getDie(numSides: Int): RandomDie -} -``` - -Instead of a root-level resolver for the `RandomDie` type, we can instead use an ES6 class, where the resolvers are instance methods. This code shows how the `RandomDie` schema above can be implemented: - -```js -class RandomDie { - constructor(numSides) { - this.numSides = numSides; - } - - rollOnce() { - return 1 + Math.floor(Math.random() * this.numSides); - } - - roll({ numRolls }) { - var output = []; - for (var i = 0; i < numRolls; i++) { - output.push(this.rollOnce()); - } - return output; - } -} - -var root = { - getDie: function ({ numSides }) { - return new RandomDie(numSides || 6); - }, -}; -``` - -For fields that don't use any arguments, you can use either properties on the object or instance methods. So for the example code above, both `numSides` and `rollOnce` can actually be used to implement GraphQL fields, so that code also implements the schema of: - -```graphql -type RandomDie { - numSides: Int! - rollOnce: Int! - roll(numRolls: Int!): [Int] -} - -type Query { - getDie(numSides: Int): RandomDie -} -``` - -Putting this all together, here is some sample code that runs a server with this GraphQL API: - -```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); - -// Construct a schema, using GraphQL schema language -var schema = buildSchema(` - type RandomDie { - numSides: Int! - rollOnce: Int! - roll(numRolls: Int!): [Int] - } - - type Query { - getDie(numSides: Int): RandomDie - } -`); - -// This class implements the RandomDie GraphQL type -class RandomDie { - constructor(numSides) { - this.numSides = numSides; - } - - rollOnce() { - return 1 + Math.floor(Math.random() * this.numSides); - } - - roll({ numRolls }) { - var output = []; - for (var i = 0; i < numRolls; i++) { - output.push(this.rollOnce()); - } - return output; - } -} - -// The root provides the top-level API endpoints -var root = { - getDie: function ({ numSides }) { - return new RandomDie(numSides || 6); - }, -}; - -var app = express(); -app.use( - '/graphql', - graphqlHTTP({ - schema: schema, - rootValue: root, - graphiql: true, - }), -); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); -}); -``` - -When you issue a GraphQL query against an API that returns object types, you can call multiple methods on the object at once by nesting the GraphQL field names. For example, if you wanted to call both `rollOnce` to roll a die once, and `roll` to roll a die three times, you could do it with this query: - -```graphql -{ - getDie(numSides: 6) { - rollOnce - roll(numRolls: 3) - } -} -``` - -If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out these APIs with GraphiQL. - -This way of defining object types often provides advantages over a traditional REST API. Instead of doing one API request to get basic information about an object, and then multiple subsequent API requests to find out more information about that object, you can get all of that information in one API request. That saves bandwidth, makes your app run faster, and simplifies your client-side logic. - -So far, every API we've looked at is designed for returning data. In order to modify stored data or handle complex input, it helps to [learn about mutations and input types](/graphql-js/mutations-and-input-types/). diff --git a/flow-typed/core.js b/flow-typed/core.js deleted file mode 100644 index 44ef9c1fd0..0000000000 --- a/flow-typed/core.js +++ /dev/null @@ -1,5 +0,0 @@ -// Various hacks to compensate for outdated Flow core definitions - -declare class Symbol extends Symbol { - static asyncIterator: string; // polyfill '@@asyncIterator' -} diff --git a/flow-typed/npm/chai_vx.x.x.js b/flow-typed/npm/chai_vx.x.x.js deleted file mode 100644 index aa4cbe8e4f..0000000000 --- a/flow-typed/npm/chai_vx.x.x.js +++ /dev/null @@ -1,331 +0,0 @@ -declare module 'chai' { - declare type ExpectChain = { - and: ExpectChain, - at: ExpectChain, - be: ExpectChain, - been: ExpectChain, - have: ExpectChain, - has: ExpectChain, - is: ExpectChain, - of: ExpectChain, - same: ExpectChain, - that: ExpectChain, - to: ExpectChain, - which: ExpectChain, - with: ExpectChain, - not: ExpectChain, - deep: ExpectChain, - any: ExpectChain, - all: ExpectChain, - own: ExpectChain, - a: ExpectChain & ((type: string, message?: string) => ExpectChain), - an: ExpectChain & ((type: string, message?: string) => ExpectChain), - include: ExpectChain & - ((value: mixed, message?: string) => ExpectChain), - includes: ExpectChain & - ((value: mixed, message?: string) => ExpectChain), - contain: ExpectChain & - ((value: mixed, message?: string) => ExpectChain), - contains: ExpectChain & - ((value: mixed, message?: string) => ExpectChain), - eq: (value: T, message?: string) => ExpectChain, - eql: (value: T, message?: string) => ExpectChain, - equal: (value: T, message?: string) => ExpectChain, - equals: (value: T, message?: string) => ExpectChain, - above: (value: T & number, message?: string) => ExpectChain, - gt: (value: T & number, message?: string) => ExpectChain, - greaterThan: (value: T & number, message?: string) => ExpectChain, - least: (value: T & number, message?: string) => ExpectChain, - below: (value: T & number, message?: string) => ExpectChain, - lessThan: (value: T & number, message?: string) => ExpectChain, - lt: (value: T & number, message?: string) => ExpectChain, - most: (value: T & number, message?: string) => ExpectChain, - within: ( - start: T & number, - finish: T & number, - message?: string, - ) => ExpectChain, - instanceof: (constructor: mixed, message?: string) => ExpectChain, - instanceOf: (constructor: mixed, message?: string) => ExpectChain, - nested: ExpectChain, - property:

( - name: string, - value?: P, - message?: string, - ) => ExpectChain

& ((name: string) => ExpectChain), - length: ExpectChain & - ((value: number, message?: string) => ExpectChain), - lengthOf: ExpectChain & - ((value: number, message?: string) => ExpectChain), - match: (regex: RegExp, message?: string) => ExpectChain, - matches: (regex: RegExp, message?: string) => ExpectChain, - string: (string: string, message?: string) => ExpectChain, - key: (key: string) => ExpectChain, - keys: ( - key: string | Array, - ...keys: Array - ) => ExpectChain, - throw: ( - err?: Class | Error | RegExp | string, - errMsgMatcher?: RegExp | string, - msg?: string, - ) => ExpectChain, - respondTo: (method: string, message?: string) => ExpectChain, - itself: ExpectChain, - satisfy: ( - method: (value: T) => boolean, - message?: string, - ) => ExpectChain, - closeTo: ( - expected: T & number, - delta: number, - message?: string, - ) => ExpectChain, - members: (set: mixed, message?: string) => ExpectChain, - oneOf: (list: Array, message?: string) => ExpectChain, - change: (obj: mixed, key: string, message?: string) => ExpectChain, - increase: (obj: mixed, key: string, message?: string) => ExpectChain, - decrease: (obj: mixed, key: string, message?: string) => ExpectChain, - by: (delta: number, message?: string) => ExpectChain, - ordered: ExpectChain, - // dirty-chai - ok: () => ExpectChain, - true: () => ExpectChain, - false: () => ExpectChain, - null: () => ExpectChain, - undefined: () => ExpectChain, - exist: () => ExpectChain, - empty: () => ExpectChain, - extensible: () => ExpectChain, - sealed: () => ExpectChain, - frozen: () => ExpectChain, - NaN: () => ExpectChain, - // chai-immutable - size: (n: number) => ExpectChain, - // sinon-chai - called: () => ExpectChain, - callCount: (n: number) => ExpectChain, - calledOnce: () => ExpectChain, - calledTwice: () => ExpectChain, - calledThrice: () => ExpectChain, - calledBefore: (spy: mixed) => ExpectChain, - calledAfter: (spy: mixed) => ExpectChain, - calledImmediatelyBefore: (spy: mixed) => ExpectChain, - calledImmediatelyAfter: (spy: mixed) => ExpectChain, - calledWith: (...args: Array) => ExpectChain, - calledOnceWith: (...args: Array) => ExpectChain, - calledWithMatch: (...args: Array) => ExpectChain, - calledWithExactly: (...args: Array) => ExpectChain, - calledOnceWithExactly: (...args: Array) => ExpectChain, - returned: (returnVal: mixed) => ExpectChain, - alwaysReturned: (returnVal: mixed) => ExpectChain, - // chai-as-promised - eventually: ExpectChain, - resolvedWith: (value: mixed) => Promise & ExpectChain, - resolved: () => Promise & ExpectChain, - rejectedWith: ( - value: mixed, - errMsgMatcher?: RegExp | string, - msg?: string, - ) => Promise & ExpectChain, - rejected: () => Promise & ExpectChain, - notify: (callback: () => mixed) => ExpectChain, - fulfilled: () => Promise & ExpectChain, - // chai-subset - containSubset: (obj: { ... } | Array<{ ... }>) => ExpectChain, - // chai-redux-mock-store - dispatchedActions: ( - actions: Array<{ ... } | ((action: { ... }) => any)>, - ) => ExpectChain, - dispatchedTypes: (actions: Array) => ExpectChain, - // chai-enzyme - attr: (key: string, val?: any) => ExpectChain, - data: (key: string, val?: any) => ExpectChain, - prop: (key: string, val?: any) => ExpectChain, - state: (key: string, val?: any) => ExpectChain, - value: (val: string) => ExpectChain, - className: (val: string) => ExpectChain, - text: (val: string) => ExpectChain, - // chai-karma-snapshot - matchSnapshot: (lang?: any, update?: boolean, msg?: any) => ExpectChain, - ... - }; - - declare var expect: { - (actual: T, message?: string): ExpectChain, - fail: ((message?: string) => void) & - (( - actual: any, - expected: any, - message?: string, - operator?: string, - ) => void), - ... - }; - - declare function use(plugin: (chai: Object, utils: Object) => void): void; - - declare class assert { - static (expression: mixed, message?: string): void; - static fail( - actual: mixed, - expected: mixed, - message?: string, - operator?: string, - ): void; - - static isOk(object: mixed, message?: string): void; - static isNotOk(object: mixed, message?: string): void; - - static empty(object: mixed, message?: string): void; - static isEmpty(object: mixed, message?: string): void; - static notEmpty(object: mixed, message?: string): void; - static isNotEmpty(object: mixed, message?: string): void; - - static equal(actual: mixed, expected: mixed, message?: string): void; - static notEqual(actual: mixed, expected: mixed, message?: string): void; - - static strictEqual(act: mixed, exp: mixed, msg?: string): void; - static notStrictEqual(act: mixed, exp: mixed, msg?: string): void; - - static deepEqual(act: mixed, exp: mixed, msg?: string): void; - static notDeepEqual(act: mixed, exp: mixed, msg?: string): void; - - static ok(val: mixed, msg?: string): void; - static isTrue(val: mixed, msg?: string): void; - static isNotTrue(val: mixed, msg?: string): void; - static isFalse(val: mixed, msg?: string): void; - static isNotFalse(val: mixed, msg?: string): void; - - static isNull(val: mixed, msg?: string): void; - static isNotNull(val: mixed, msg?: string): void; - - static isUndefined(val: mixed, msg?: string): void; - static isDefined(val: mixed, msg?: string): void; - - static isNaN(val: mixed, msg?: string): void; - static isNotNaN(val: mixed, msg?: string): void; - - static isAbove(val: number, abv: number, msg?: string): void; - static isBelow(val: number, blw: number, msg?: string): void; - - static exists(val: mixed, msg?: string): void; - static notExists(val: mixed, msg?: string): void; - - static isAtMost(val: number, atmst: number, msg?: string): void; - static isAtLeast(val: number, atlst: number, msg?: string): void; - - static isFunction(val: mixed, msg?: string): void; - static isNotFunction(val: mixed, msg?: string): void; - - static isObject(val: mixed, msg?: string): void; - static isNotObject(val: mixed, msg?: string): void; - - static isArray(val: mixed, msg?: string): void; - static isNotArray(val: mixed, msg?: string): void; - - static isString(val: mixed, msg?: string): void; - static isNotString(val: mixed, msg?: string): void; - - static isNumber(val: mixed, msg?: string): void; - static isNotNumber(val: mixed, msg?: string): void; - - static isBoolean(val: mixed, msg?: string): void; - static isNotBoolean(val: mixed, msg?: string): void; - - static typeOf(val: mixed, type: string, msg?: string): void; - static notTypeOf(val: mixed, type: string, msg?: string): void; - - static instanceOf(val: mixed, constructor: Class<*>, msg?: string): void; - static notInstanceOf(val: mixed, constructor: Class<*>, msg?: string): void; - - static include(exp: string, inc: mixed, msg?: string): void; - static include(exp: Array, inc: T, msg?: string): void; - - static notInclude(exp: string, inc: mixed, msg?: string): void; - static notInclude(exp: Array, inc: T, msg?: string): void; - - static deepInclude( - haystack: T[] | string, - needle: $Shape, - msg?: string, - ): void; - static notDeepInclude( - haystack: T[] | string, - needle: $Shape, - msg?: string, - ): void; - - static match(exp: mixed, re: RegExp, msg?: string): void; - static notMatch(exp: mixed, re: RegExp, msg?: string): void; - - static property(obj: Object, prop: string, msg?: string): void; - static notProperty(obj: Object, prop: string, msg?: string): void; - static deepProperty(obj: Object, prop: string, msg?: string): void; - static notDeepProperty(obj: Object, prop: string, msg?: string): void; - - static propertyVal( - obj: Object, - prop: string, - val: mixed, - msg?: string, - ): void; - static propertyNotVal( - obj: Object, - prop: string, - val: mixed, - msg?: string, - ): void; - - static deepPropertyVal( - obj: Object, - prop: string, - val: mixed, - msg?: string, - ): void; - static deepPropertyNotVal( - obj: Object, - prop: string, - val: mixed, - msg?: string, - ): void; - - static lengthOf(exp: mixed, len: number, msg?: string): void; - - static throws( - func: () => any, - err?: Class | Error | RegExp | string, - errorMsgMatcher?: string | RegExp, - msg?: string, - ): void; - static doesNotThrow( - func: () => any, - err?: Class | Error | RegExp | string, - errorMsgMatcher?: string | RegExp, - msg?: string, - ): void; - - static closeTo( - actual: number, - expected: number, - delta: number, - msg?: string, - ): void; - static approximately( - actual: number, - expected: number, - delta: number, - msg?: string, - ): void; - - // chai-immutable - static sizeOf(val: mixed, length: number): void; - } - - declare var config: { - includeStack: boolean, - showDiff: boolean, - truncateThreshold: number, - ... - }; -} diff --git a/flow-typed/npm/mocha_vx.x.x.js b/flow-typed/npm/mocha_vx.x.x.js deleted file mode 100644 index b7c7c13128..0000000000 --- a/flow-typed/npm/mocha_vx.x.x.js +++ /dev/null @@ -1,305 +0,0 @@ -declare interface $npm$mocha$SetupOptions { - slow?: number; - timeout?: number; - ui?: string; - globals?: Array; - reporter?: any; - bail?: boolean; - ignoreLeaks?: boolean; - grep?: any; -} - -declare type $npm$mocha$done = (error?: any) => any; - -// declare interface $npm$mocha$SuiteCallbackContext { -// timeout(ms: number): void; -// retries(n: number): void; -// slow(ms: number): void; -// } - -// declare interface $npm$mocha$TestCallbackContext { -// skip(): void; -// timeout(ms: number): void; -// retries(n: number): void; -// slow(ms: number): void; -// [index: string]: any; -// } - -declare interface $npm$mocha$Suite { - parent: $npm$mocha$Suite; - title: string; - fullTitle(): string; -} - -declare interface $npm$mocha$ContextDefinition { - ( - description: string, - callback: () => /* this: $npm$mocha$SuiteCallbackContext */ void, - ): $npm$mocha$Suite; - only( - description: string, - callback: () => /* this: $npm$mocha$SuiteCallbackContext */ void, - ): $npm$mocha$Suite; - skip( - description: string, - callbac: () => /* this: $npm$mocha$SuiteCallbackContext */ void, - ): void; - timeout(ms: number): void; -} - -declare interface $npm$mocha$TestDefinition { - ( - expectation: string, - callback?: ( - /* this: $npm$mocha$TestCallbackContext, */ done: $npm$mocha$done, - ) => mixed, - ): $npm$mocha$Test; - only( - expectation: string, - callback?: ( - /* this: $npm$mocha$TestCallbackContext, */ done: $npm$mocha$done, - ) => mixed, - ): $npm$mocha$Test; - skip( - expectation: string, - callback?: ( - /* this: $npm$mocha$TestCallbackContext, */ done: $npm$mocha$done, - ) => mixed, - ): void; - timeout(ms: number): void; - state: 'failed' | 'passed'; -} - -declare interface $npm$mocha$Runner {} - -declare class $npm$mocha$BaseReporter { - stats: { - suites: number, - tests: number, - passes: number, - pending: number, - failures: number, - ... - }; - - constructor(runner: $npm$mocha$Runner): $npm$mocha$BaseReporter; -} - -declare class $npm$mocha$DocReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$DotReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$HTMLReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$HTMLCovReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$JSONReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$JSONCovReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$JSONStreamReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$LandingReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$ListReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$MarkdownReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$MinReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$NyanReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$ProgressReporter extends $npm$mocha$BaseReporter { - constructor( - runner: $npm$mocha$Runner, - options?: { - open?: string, - complete?: string, - incomplete?: string, - close?: string, - ... - }, - ): $npm$mocha$ProgressReporter; -} -declare class $npm$mocha$SpecReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$TAPReporter extends $npm$mocha$BaseReporter {} -declare class $npm$mocha$XUnitReporter extends $npm$mocha$BaseReporter { - constructor( - runner: $npm$mocha$Runner, - options?: any, - ): $npm$mocha$XUnitReporter; -} - -declare class $npm$mocha$Mocha { - currentTest: $npm$mocha$TestDefinition; - constructor(options?: { - grep?: RegExp, - ui?: string, - reporter?: string, - timeout?: number, - reporterOptions?: any, - slow?: number, - bail?: boolean, - ... - }): $npm$mocha$Mocha; - setup(options: $npm$mocha$SetupOptions): this; - bail(value?: boolean): this; - addFile(file: string): this; - reporter(name: string): this; - reporter(reporter: (runner: $npm$mocha$Runner, options: any) => any): this; - ui(value: string): this; - grep(value: string): this; - grep(value: RegExp): this; - invert(): this; - ignoreLeaks(value: boolean): this; - checkLeaks(): this; - throwError(error: Error): void; - growl(): this; - globals(value: string): this; - globals(values: Array): this; - useColors(value: boolean): this; - useInlineDiffs(value: boolean): this; - timeout(value: number): this; - slow(value: number): this; - enableTimeouts(value: boolean): this; - asyncOnly(value: boolean): this; - noHighlighting(value: boolean): this; - run(onComplete?: (failures: number) => void): $npm$mocha$Runner; - - static reporters: { - Doc: $npm$mocha$DocReporter, - Dot: $npm$mocha$DotReporter, - HTML: $npm$mocha$HTMLReporter, - HTMLCov: $npm$mocha$HTMLCovReporter, - JSON: $npm$mocha$JSONReporter, - JSONCov: $npm$mocha$JSONCovReporter, - JSONStream: $npm$mocha$JSONStreamReporter, - Landing: $npm$mocha$LandingReporter, - List: $npm$mocha$ListReporter, - Markdown: $npm$mocha$MarkdownReporter, - Min: $npm$mocha$MinReporter, - Nyan: $npm$mocha$NyanReporter, - Progress: $npm$mocha$ProgressReporter, - ... - }; -} - -// declare interface $npm$mocha$HookCallbackContext { -// skip(): void; -// timeout(ms: number): void; -// [index: string]: any; -// } - -declare interface $npm$mocha$Runnable { - title: string; - fn: Function; - async: boolean; - sync: boolean; - timedOut: boolean; -} - -declare interface $npm$mocha$Test extends $npm$mocha$Runnable { - parent: $npm$mocha$Suite; - pending: boolean; - state: 'failed' | 'passed' | void; - fullTitle(): string; - timeout(ms: number): void; -} - -// declare interface $npm$mocha$BeforeAndAfterContext extends $npm$mocha$HookCallbackContext { -// currentTest: $npm$mocha$Test; -// } - -declare var mocha: $npm$mocha$Mocha; -declare var describe: $npm$mocha$ContextDefinition; -declare var xdescribe: $npm$mocha$ContextDefinition; -declare var context: $npm$mocha$ContextDefinition; -declare var suite: $npm$mocha$ContextDefinition; -declare var it: $npm$mocha$TestDefinition; -declare var xit: $npm$mocha$TestDefinition; -declare var test: $npm$mocha$TestDefinition; -declare var specify: $npm$mocha$TestDefinition; - -declare function run(): void; - -declare function setup( - callback: ( - /* this: $npm$mocha$BeforeAndAfterContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function teardown( - callback: ( - /* this: $npm$mocha$BeforeAndAfterContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function suiteSetup( - callback: ( - /* this: $npm$mocha$HookCallbackContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function suiteTeardown( - callback: ( - /* this: $npm$mocha$HookCallbackContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function before( - callback: ( - /* this: $npm$mocha$HookCallbackContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function before( - description: string, - callback: ( - /* this: $npm$mocha$HookCallbackContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function after( - callback: ( - /* this: $npm$mocha$HookCallbackContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function after( - description: string, - callback: ( - /* this: $npm$mocha$HookCallbackContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function beforeEach( - callback: ( - /* this: $npm$mocha$BeforeAndAfterContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function beforeEach( - description: string, - callback: ( - /* this: $npm$mocha$BeforeAndAfterContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function afterEach( - callback: ( - /* this: $npm$mocha$BeforeAndAfterContext, */ done: $npm$mocha$done, - ) => mixed, -): void; -declare function afterEach( - description: string, - callback: ( - /* this: $npm$mocha$BeforeAndAfterContext, */ done: $npm$mocha$done, - ) => mixed, -): void; - -declare module 'mocha' { - declare export var mocha: typeof mocha; - declare export var describe: typeof describe; - declare export var xdescribe: typeof xdescribe; - declare export var context: typeof context; - declare export var suite: typeof suite; - declare export var it: typeof it; - declare export var xit: typeof xit; - declare export var test: typeof test; - declare export var specify: typeof specify; - - declare export var run: typeof run; - - declare export var setup: typeof setup; - declare export var teardown: typeof teardown; - declare export var suiteSetup: typeof suiteSetup; - declare export var suiteTeardown: typeof suiteTeardown; - declare export var before: typeof before; - declare export var before: typeof before; - declare export var after: typeof after; - declare export var after: typeof after; - declare export var beforeEach: typeof beforeEach; - declare export var beforeEach: typeof beforeEach; - declare export var afterEach: typeof afterEach; - declare export var afterEach: typeof afterEach; - - declare export default $npm$mocha$Mocha; -} diff --git a/integrationTests/flow/.flowconfig b/integrationTests/flow/.flowconfig deleted file mode 100644 index 872c3947a6..0000000000 --- a/integrationTests/flow/.flowconfig +++ /dev/null @@ -1,8 +0,0 @@ -[include] -./index.mjs - -[declarations] -.*/node_modules/.* - -[options] -include_warnings=true diff --git a/integrationTests/flow/index.mjs b/integrationTests/flow/index.mjs deleted file mode 100644 index ee14390b35..0000000000 --- a/integrationTests/flow/index.mjs +++ /dev/null @@ -1,54 +0,0 @@ -// @flow strict - -import { parse } from 'graphql/language'; -import { GraphQLString, GraphQLSchema, GraphQLObjectType } from 'graphql/type'; -import { type ExecutionResult, execute } from 'graphql/execution'; -import { graphqlSync } from 'graphql'; - -interface SomeExtension { - number: number; - string: string; -} - -const example: SomeExtension = { - number: 42, - string: 'Meaning of life', -}; - -const queryType: GraphQLObjectType = new GraphQLObjectType({ - name: 'Query', - fields: { - sayHi: { - type: GraphQLString, - args: { - who: { - type: GraphQLString, - extensions: { - someArgumentExtension: example, - }, - }, - }, - resolve: (_root, args) => 'Hello ' + (args.who || 'World'), - extensions: { - someFieldExtension: example, - }, - }, - }, - extensions: { - someObjectExtension: example, - }, -}); - -const schema: GraphQLSchema = new GraphQLSchema({ - query: queryType, -}); - -const result: ExecutionResult = graphqlSync({ - schema, - source: ` - query helloWho($who: String){ - test(who: $who) - } - `, - variableValues: { who: 'Dolly' }, -}); diff --git a/integrationTests/flow/package.json b/integrationTests/flow/package.json deleted file mode 100644 index 8a87590458..0000000000 --- a/integrationTests/flow/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "private": true, - "scripts": { - "test": "flow check" - }, - "dependencies": { - "graphql": "file:../graphql.tgz", - "flow-bin": "0.135.0" - } -} diff --git a/integrationTests/integration-test.js b/integrationTests/integration-test.js index 6f3d40cc88..41718d0605 100644 --- a/integrationTests/integration-test.js +++ b/integrationTests/integration-test.js @@ -8,16 +8,16 @@ const childProcess = require('child_process'); const { describe, it } = require('mocha'); function exec(command, options = {}) { - const result = childProcess.execSync(command, { + const output = childProcess.execSync(command, { encoding: 'utf-8', ...options, }); - return result != null ? result.trimEnd() : result; + return output && output.trimEnd(); } describe('Integration Tests', () => { const tmpDir = path.join(os.tmpdir(), 'graphql-js-integrationTmp'); - fs.rmdirSync(tmpDir, { recursive: true, force: true }); + fs.rmSync(tmpDir, { recursive: true, force: true }); fs.mkdirSync(tmpDir); const distDir = path.resolve('./npmDist'); @@ -28,22 +28,22 @@ describe('Integration Tests', () => { ); function testOnNodeProject(projectName) { - exec(`cp -R ${path.join(__dirname, projectName)} ${tmpDir}`); + const projectPath = path.join(__dirname, projectName); - const cwd = path.join(tmpDir, projectName); - exec('npm --quiet install', { cwd, stdio: 'inherit' }); - exec('npm --quiet test', { cwd, stdio: 'inherit' }); - } + const packageJSONPath = path.join(projectPath, 'package.json'); + const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, 'utf-8')); - it('Should compile with all supported TS versions', () => { - testOnNodeProject('ts'); - }).timeout(40000); + it(packageJSON.description, () => { + exec(`cp -R ${projectPath} ${tmpDir}`); - it('Should compile with Flow', () => { - testOnNodeProject('flow'); - }).timeout(10000); + const cwd = path.join(tmpDir, projectName); + // TODO: figure out a way to run it with --ignore-scripts + exec('npm --quiet install', { cwd, stdio: 'inherit' }); + exec('npm --quiet test', { cwd, stdio: 'inherit' }); + }).timeout(120000); + } - it('Should work on all supported node versions', () => { - testOnNodeProject('node'); - }).timeout(40000); + testOnNodeProject('ts'); + testOnNodeProject('node'); + testOnNodeProject('webpack'); }); diff --git a/integrationTests/node/package.json b/integrationTests/node/package.json index 0b6122b6de..e4e8d36d97 100644 --- a/integrationTests/node/package.json +++ b/integrationTests/node/package.json @@ -1,13 +1,10 @@ { "private": true, + "description": "graphql-js should work on all supported node versions", "scripts": { "test": "node test.js" }, "dependencies": { - "graphql": "file:../graphql.tgz", - "node-10": "npm:node@10.x.x", - "node-12": "npm:node@12.x.x", - "node-14": "npm:node@14.x.x", - "node-15": "npm:node@15.x.x" + "graphql": "file:../graphql.tgz" } } diff --git a/integrationTests/node/test.js b/integrationTests/node/test.js index 94cc957b47..3f9ea8d35e 100644 --- a/integrationTests/node/test.js +++ b/integrationTests/node/test.js @@ -1,17 +1,19 @@ 'use strict'; -const path = require('path'); const childProcess = require('child_process'); -const { dependencies } = require('./package.json'); +const graphqlPackageJSON = require('graphql/package.json'); -const nodeVersions = Object.keys(dependencies) - .filter((pkg) => pkg.startsWith('node-')) +const nodeVersions = graphqlPackageJSON.engines.node + .split(' || ') + .map((version) => version.replace(/^(\^|>=)/, '')) .sort((a, b) => b.localeCompare(a)); for (const version of nodeVersions) { - console.log(`Testing on ${version} ...`); + console.log(`Testing on node@${version} ...`); - const nodePath = path.join(__dirname, 'node_modules', version, 'bin/node'); - childProcess.execSync(nodePath + ' index.js', { stdio: 'inherit' }); + childProcess.execSync( + `docker run --rm --volume "$PWD":/usr/src/app -w /usr/src/app node:${version}-slim node ./index.js`, + { stdio: 'inherit' }, + ); } diff --git a/integrationTests/ts/TypedQueryDocumentNode-test.ts b/integrationTests/ts/TypedQueryDocumentNode-test.ts new file mode 100644 index 0000000000..89044efbfe --- /dev/null +++ b/integrationTests/ts/TypedQueryDocumentNode-test.ts @@ -0,0 +1,72 @@ +import type { ExecutionResult } from 'graphql/execution'; +import type { TypedQueryDocumentNode } from 'graphql/utilities'; + +import { parse } from 'graphql/language'; +import { execute } from 'graphql/execution'; +import { buildSchema } from 'graphql/utilities'; + +const schema = buildSchema(` + type Query { + test: String + } +`); + +// Tests for TS specific TypedQueryDocumentNode type +const queryDocument = parse('{ test }'); + +type ResponseData = { test: string }; +const typedQueryDocument = queryDocument as TypedQueryDocumentNode< + ResponseData, + {} +>; + +// Supports conversion to DocumentNode +execute({ schema, document: typedQueryDocument }); + +function wrappedExecute(document: TypedQueryDocumentNode) { + return execute({ schema, document }) as ExecutionResult; +} + +const response = wrappedExecute(typedQueryDocument); +const responseData: ResponseData | undefined | null = response.data; + +declare function runQueryA( + q: TypedQueryDocumentNode<{ output: string }, { input: string | null }>, +): void; + +// valid +declare const optionalInputRequiredOutput: TypedQueryDocumentNode< + { output: string }, + { input: string | null } +>; +runQueryA(optionalInputRequiredOutput); + +declare function runQueryB( + q: TypedQueryDocumentNode<{ output: string | null }, { input: string }>, +): void; + +// still valid: We still accept {output: string} as a valid result. +// We're now passing in {input: string} which is still assignable to {input: string | null} +runQueryB(optionalInputRequiredOutput); + +// valid: we now accept {output: null} as a valid Result +declare const optionalInputOptionalOutput: TypedQueryDocumentNode< + { output: string | null }, + { input: string | null } +>; +runQueryB(optionalInputOptionalOutput); + +// valid: we now only pass {input: string} to the query +declare const requiredInputRequiredOutput: TypedQueryDocumentNode< + { output: string }, + { input: string } +>; +runQueryB(requiredInputRequiredOutput); + +// valid: we now accept {output: null} as a valid Result AND +// we now only pass {input: string} to the query +declare const requiredInputOptionalOutput: TypedQueryDocumentNode< + { output: null }, + { input: string } +>; +runQueryB(requiredInputOptionalOutput); diff --git a/integrationTests/ts/basic-test.ts b/integrationTests/ts/basic-test.ts new file mode 100644 index 0000000000..a28bd840e7 --- /dev/null +++ b/integrationTests/ts/basic-test.ts @@ -0,0 +1,34 @@ +import type { ExecutionResult } from 'graphql/execution'; + +import { graphqlSync } from 'graphql'; +import { GraphQLString, GraphQLSchema, GraphQLObjectType } from 'graphql/type'; + +const queryType: GraphQLObjectType = new GraphQLObjectType({ + name: 'Query', + fields: () => ({ + sayHi: { + type: GraphQLString, + args: { + who: { + type: GraphQLString, + defaultValue: 'World', + }, + }, + resolve(_root, args: { who: string }) { + return 'Hello ' + args.who; + }, + }, + }), +}); + +const schema: GraphQLSchema = new GraphQLSchema({ query: queryType }); + +const result: ExecutionResult = graphqlSync({ + schema, + source: ` + query helloWho($who: String){ + test(who: $who) + } + `, + variableValues: { who: 'Dolly' }, +}); diff --git a/integrationTests/ts/extensions-test.ts b/integrationTests/ts/extensions-test.ts new file mode 100644 index 0000000000..689d943598 --- /dev/null +++ b/integrationTests/ts/extensions-test.ts @@ -0,0 +1,62 @@ +import { GraphQLError } from 'graphql/error'; +import { GraphQLString, GraphQLObjectType } from 'graphql/type'; + +interface SomeExtension { + meaningOfLife: 42; +} + +declare module 'graphql' { + interface GraphQLObjectTypeExtensions<_TSource, _TContext> { + someObjectExtension?: SomeExtension; + } + + interface GraphQLFieldExtensions<_TSource, _TContext, _TArgs> { + someFieldExtension?: SomeExtension; + } + + interface GraphQLArgumentExtensions { + someArgumentExtension?: SomeExtension; + } +} + +const queryType: GraphQLObjectType = new GraphQLObjectType({ + name: 'Query', + fields: () => ({ + sayHi: { + type: GraphQLString, + args: { + who: { + type: GraphQLString, + extensions: { + someArgumentExtension: { meaningOfLife: 42 }, + }, + }, + }, + resolve: (_root, args) => 'Hello ' + (args.who || 'World'), + extensions: { + someFieldExtension: { meaningOfLife: 42 }, + }, + }, + }), + extensions: { + someObjectExtension: { meaningOfLife: 42 }, + }, +}); + +function checkExtensionTypes(_test: SomeExtension | null | undefined) {} + +checkExtensionTypes(queryType.extensions.someObjectExtension); + +const sayHiField = queryType.getFields().sayHi; +checkExtensionTypes(sayHiField.extensions.someFieldExtension); + +checkExtensionTypes(sayHiField.args[0].extensions.someArgumentExtension); + +declare module 'graphql' { + export interface GraphQLErrorExtensions { + someErrorExtension?: SomeExtension; + } +} + +const error = new GraphQLError('foo'); +checkExtensionTypes(error.extensions.someErrorExtension); diff --git a/integrationTests/ts/index.ts b/integrationTests/ts/index.ts deleted file mode 100644 index 6ef6bea899..0000000000 --- a/integrationTests/ts/index.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { parse } from 'graphql/language'; -import { GraphQLString, GraphQLSchema, GraphQLObjectType } from 'graphql/type'; -import { ExecutionResult, execute } from 'graphql/execution'; -import { TypedQueryDocumentNode, graphqlSync } from 'graphql'; - -interface SomeExtension { - number: number; - string: string; -} - -const example: SomeExtension = { - number: 42, - string: 'Meaning of life', -}; - -// FIXME: The following code block requires a version of TypeScript >= 3.2 -/* - -declare module 'graphql' { - interface GraphQLObjectTypeExtensions { - someObjectExtension?: SomeExtension; - } - interface GraphQLFieldExtensions< - TSource, - TContext, - TArgs = { [argName: string]: any } - > { - someFieldExtension?: SomeExtension; - } - interface GraphQLArgumentExtensions { - someArgumentExtension?: SomeExtension; - } -} -*/ - -const queryType: GraphQLObjectType = new GraphQLObjectType({ - name: 'Query', - fields: { - sayHi: { - type: GraphQLString, - args: { - who: { - type: GraphQLString, - extensions: { - someArgumentExtension: example, - }, - }, - }, - resolve: (_root, args) => 'Hello ' + (args.who || 'World'), - extensions: { - someFieldExtension: example, - }, - }, - }, - extensions: { - someObjectExtension: example, - }, -}); - -const schema: GraphQLSchema = new GraphQLSchema({ - query: queryType, -}); - -const result: ExecutionResult = graphqlSync({ - schema, - source: ` - query helloWho($who: String){ - test(who: $who) - } - `, - variableValues: { who: 'Dolly' }, -}); - -// Tests for TS specific TypedQueryDocumentNode type -const queryDocument = parse(` - query helloWho($who: String){ - test(who: $who) - } -`); - -type ResponseData = { test: string }; -const typedQueryDocument = queryDocument as TypedQueryDocumentNode< - ResponseData, - {} ->; - -// Supports conversion to DocumentNode -execute({ schema, document: typedQueryDocument }); - -function wrappedExecute(document: TypedQueryDocumentNode) { - return execute({ schema, document }) as ExecutionResult; -} - -const { data } = wrappedExecute(typedQueryDocument); -if (data != null) { - const typedData: ResponseData = data; -} - -declare function runQueryA( - q: TypedQueryDocumentNode<{ output: string }, { input: string | null }>, -): void; - -// valid -declare const optionalInputRequiredOutput: TypedQueryDocumentNode< - { output: string }, - { input: string | null } ->; -runQueryA(optionalInputRequiredOutput); - -declare function runQueryB( - q: TypedQueryDocumentNode<{ output: string | null }, { input: string }>, -): void; - -// still valid: We still accept {output: string} as a valid result. -// We're now passing in {input: string} which is still assignable to {input: string | null} -runQueryB(optionalInputRequiredOutput); - -// valid: we now accept {output: null} as a valid Result -declare const optionalInputOptionalOutput: TypedQueryDocumentNode< - { output: string | null }, - { input: string | null } ->; -runQueryB(optionalInputOptionalOutput); - -// valid: we now only pass {input: string} to the query -declare const requiredInputRequiredOutput: TypedQueryDocumentNode< - { output: string }, - { input: string } ->; -runQueryB(requiredInputRequiredOutput); - -// valid: we now accept {output: null} as a valid Result AND -// we now only pass {input: string} to the query -declare const requiredInputOptionalOutput: TypedQueryDocumentNode< - { output: null }, - { input: string } ->; -runQueryB(requiredInputOptionalOutput); diff --git a/integrationTests/ts/internalImports-test.ts b/integrationTests/ts/internalImports-test.ts new file mode 100644 index 0000000000..62d9628df8 --- /dev/null +++ b/integrationTests/ts/internalImports-test.ts @@ -0,0 +1,8 @@ +import type { NameNode } from 'graphql/language'; + +// Parser class is internal API so so any changes to it are never considered breaking changes. +// We just want to test that we are able to import it. +import { Parser } from 'graphql/language/parser'; + +const parser = new Parser('foo'); +const ast: NameNode = parser.parseName(); diff --git a/integrationTests/ts/package.json b/integrationTests/ts/package.json index dd35e56464..413e1aec05 100644 --- a/integrationTests/ts/package.json +++ b/integrationTests/ts/package.json @@ -1,25 +1,16 @@ { "private": true, + "description": "graphql-js should compile with all supported TS versions", "scripts": { "test": "node test.js" }, "dependencies": { "graphql": "file:../graphql.tgz", - "typescript-2.6": "npm:typescript@2.6.x", - "typescript-2.7": "npm:typescript@2.7.x", - "typescript-2.8": "npm:typescript@2.8.x", - "typescript-2.9": "npm:typescript@2.9.x", - "typescript-3.0": "npm:typescript@3.0.x", - "typescript-3.1": "npm:typescript@3.1.x", - "typescript-3.2": "npm:typescript@3.2.x", - "typescript-3.3": "npm:typescript@3.3.x", - "typescript-3.4": "npm:typescript@3.4.x", - "typescript-3.5": "npm:typescript@3.5.x", - "typescript-3.6": "npm:typescript@3.6.x", - "typescript-3.7": "npm:typescript@3.7.x", - "typescript-3.8": "npm:typescript@3.8.x", - "typescript-3.9": "npm:typescript@3.9.x", - "typescript-4.0": "npm:typescript@4.0.x", - "typescript-4.1": "npm:typescript@4.1.x" + "typescript-4.1": "npm:typescript@4.1.x", + "typescript-4.2": "npm:typescript@4.2.x", + "typescript-4.3": "npm:typescript@4.3.x", + "typescript-4.4": "npm:typescript@4.4.x", + "typescript-4.5": "npm:typescript@4.5.x", + "typescript-4.6": "npm:typescript@4.6.x" } } diff --git a/integrationTests/ts/test.js b/integrationTests/ts/test.js index 158aee4cf6..b328fe160b 100644 --- a/integrationTests/ts/test.js +++ b/integrationTests/ts/test.js @@ -11,7 +11,9 @@ const tsVersions = Object.keys(dependencies) for (const version of tsVersions) { console.log(`Testing on ${version} ...`); + childProcess.execSync(tscPath(version), { stdio: 'inherit' }); +} - const tscPath = path.join(__dirname, 'node_modules', version, 'bin/tsc'); - childProcess.execSync(tscPath, { stdio: 'inherit' }); +function tscPath(version) { + return path.join(__dirname, 'node_modules', version, 'bin/tsc'); } diff --git a/integrationTests/ts/tsconfig.json b/integrationTests/ts/tsconfig.json index ea6266120c..403b4c213f 100644 --- a/integrationTests/ts/tsconfig.json +++ b/integrationTests/ts/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "module": "commonjs", - "lib": ["es6", "esnext.asynciterable"], + "lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string"], "strict": true, "noEmit": true, "types": [] diff --git a/integrationTests/webpack/entry.js b/integrationTests/webpack/entry.js new file mode 100644 index 0000000000..8f51030c5d --- /dev/null +++ b/integrationTests/webpack/entry.js @@ -0,0 +1,13 @@ +'use strict'; + +const { buildSchema, graphqlSync } = require('graphql'); + +const schema = buildSchema('type Query { hello: String }'); + +const result = graphqlSync({ + schema, + source: '{ hello }', + rootValue: { hello: 'world' }, +}); + +module.exports = { result }; diff --git a/integrationTests/webpack/package.json b/integrationTests/webpack/package.json new file mode 100644 index 0000000000..aec7a21afb --- /dev/null +++ b/integrationTests/webpack/package.json @@ -0,0 +1,12 @@ +{ + "private": true, + "description": "graphql-js should be compatible with Webpack", + "scripts": { + "test": "webpack && node test.js" + }, + "dependencies": { + "graphql": "file:../graphql.tgz", + "webpack": "5.x.x", + "webpack-cli": "4.x.x" + } +} diff --git a/integrationTests/webpack/test.js b/integrationTests/webpack/test.js new file mode 100644 index 0000000000..40c22233d4 --- /dev/null +++ b/integrationTests/webpack/test.js @@ -0,0 +1,14 @@ +'use strict'; + +const assert = require('assert'); + +// eslint-disable-next-line node/no-missing-require +const { result } = require('./dist/main.js'); + +assert.deepStrictEqual(result, { + data: { + __proto__: null, + hello: 'world', + }, +}); +console.log('Test script: Got correct result from Webpack bundle!'); diff --git a/integrationTests/webpack/webpack.config.json b/integrationTests/webpack/webpack.config.json new file mode 100644 index 0000000000..830b2bd52d --- /dev/null +++ b/integrationTests/webpack/webpack.config.json @@ -0,0 +1,7 @@ +{ + "mode": "production", + "entry": "./entry.js", + "output": { + "libraryTarget": "commonjs2" + } +} diff --git a/package-lock.json b/package-lock.json index 4f19d6f3d5..41d84cd068 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,75 +1,97 @@ { "name": "graphql", - "version": "15.4.0", + "version": "16.10.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "graphql", - "version": "15.4.0", + "version": "16.10.0", "license": "MIT", "devDependencies": { - "@babel/core": "7.12.10", - "@babel/plugin-transform-flow-strip-types": "7.12.10", - "@babel/preset-env": "7.12.11", - "@babel/register": "7.12.10", - "@typescript-eslint/eslint-plugin": "4.14.0", - "@typescript-eslint/parser": "4.14.0", - "babel-eslint": "10.1.0", - "chai": "4.2.0", - "cspell": "5.1.3", - "eslint": "7.18.0", - "eslint-plugin-flowtype": "5.2.0", - "eslint-plugin-import": "2.22.1", + "@babel/core": "7.17.9", + "@babel/plugin-syntax-typescript": "7.16.7", + "@babel/plugin-transform-typescript": "7.16.8", + "@babel/preset-env": "7.16.11", + "@babel/register": "7.17.7", + "@types/chai": "4.3.1", + "@types/mocha": "9.1.0", + "@types/node": "17.0.24", + "@typescript-eslint/eslint-plugin": "5.19.0", + "@typescript-eslint/parser": "5.19.0", + "c8": "7.11.0", + "chai": "4.3.6", + "cspell": "5.19.7", + "eslint": "8.13.0", + "eslint-plugin-import": "2.26.0", "eslint-plugin-internal-rules": "file:./resources/eslint-internal-rules", - "eslint-plugin-istanbul": "0.1.2", "eslint-plugin-node": "11.1.0", - "flow-bin": "0.142.0", - "mocha": "8.2.1", - "nyc": "15.1.0", - "prettier": "2.2.1", - "typescript": "4.1.3" + "eslint-plugin-react": "7.29.4", + "eslint-plugin-react-hooks": "4.4.0", + "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-tsdoc": "0.2.16", + "mocha": "9.2.2", + "prettier": "2.6.2", + "typescript": "4.6.3" }, "engines": { - "node": ">= 14.2" + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.0" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", - "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==", - "dev": true + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/core": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", - "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.10", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.10", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz", + "integrity": "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.9", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" @@ -80,278 +102,362 @@ } }, "node_modules/@babel/generator": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", - "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz", + "integrity": "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==", "dev": true, "dependencies": { - "@babel/types": "^7.12.11", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", - "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", - "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.12.5", - "@babel/helper-validator-option": "^7.12.1", - "browserslist": "^4.14.5", - "semver": "^5.5.0" + "@babel/compat-data": "^7.17.7", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", - "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz", + "integrity": "sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", - "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", - "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" } }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", - "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "dev": true, "dependencies": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", - "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/types": "^7.12.11" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", - "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", + "node_modules/@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dev": true, "dependencies": { - "@babel/types": "^7.12.10" + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", - "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, "dependencies": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", - "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "dependencies": { - "@babel/types": "^7.12.5" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", - "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "dependencies": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", - "dev": true + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", - "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/types": "^7.12.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", - "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.12.7", - "@babel/helper-optimise-call-expression": "^7.12.10", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.11" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", - "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, "dependencies": { - "@babel/types": "^7.12.11" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/helper-validator-option": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz", - "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==", - "dev": true + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", - "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", "dev": true, "dependencies": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz", + "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -360,173 +466,278 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", + "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.12.tgz", - "integrity": "sha512-nrz9y0a4xmUrRq51bYkWJIO5SBZyG2ys2qinHsN0zHDHVsUaModrkpyWWWXfGqYQmOL3x9sQIcTNN/pBGpo09A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", + "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", - "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", + "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.17.6", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", - "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", - "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", - "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", - "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", - "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", - "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", + "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" + "@babel/compat-data": "^7.17.0", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", - "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", - "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", - "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", - "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=4" @@ -548,12 +759,27 @@ } }, "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", - "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -583,18 +809,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.1.tgz", - "integrity": "sha512-1lBLLmtxrwpm4VKmtVFselI/P3pX+G63fAtUUt6b2Nzgao77KNDwyuRt90Mj2/9pKobtt68FdvjfqohZjg/FCA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -679,521 +893,666 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", - "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", - "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", - "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", - "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz", - "integrity": "sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", - "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", - "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", - "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz", + "integrity": "sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", - "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", - "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", - "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.10.tgz", - "integrity": "sha512-0ti12wLTLeUIzu9U7kjqIn4MyOL7+Wibc7avsHhj4o1l5C0ATs8p2IMHrVYjm9t9wzhfEO6S3kxax0Rpdo8LTg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-flow": "^7.12.1" + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", - "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", - "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", - "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", - "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", - "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", - "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz", + "integrity": "sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", - "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz", + "integrity": "sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", - "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", - "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", + "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", - "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", - "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", - "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", - "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", - "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", + "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", "dev": true, "dependencies": { - "regenerator-transform": "^0.14.2" + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", - "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", - "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", - "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", - "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", - "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", - "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-typescript": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", - "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", - "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/preset-env": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz", - "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.12.7", - "@babel/helper-compilation-targets": "^7.12.5", - "@babel/helper-module-imports": "^7.12.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-option": "^7.12.11", - "@babel/plugin-proposal-async-generator-functions": "^7.12.1", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-dynamic-import": "^7.12.1", - "@babel/plugin-proposal-export-namespace-from": "^7.12.1", - "@babel/plugin-proposal-json-strings": "^7.12.1", - "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", - "@babel/plugin-proposal-numeric-separator": "^7.12.7", - "@babel/plugin-proposal-object-rest-spread": "^7.12.1", - "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", - "@babel/plugin-proposal-optional-chaining": "^7.12.7", - "@babel/plugin-proposal-private-methods": "^7.12.1", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.12.1", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", + "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.12.1", - "@babel/plugin-transform-arrow-functions": "^7.12.1", - "@babel/plugin-transform-async-to-generator": "^7.12.1", - "@babel/plugin-transform-block-scoped-functions": "^7.12.1", - "@babel/plugin-transform-block-scoping": "^7.12.11", - "@babel/plugin-transform-classes": "^7.12.1", - "@babel/plugin-transform-computed-properties": "^7.12.1", - "@babel/plugin-transform-destructuring": "^7.12.1", - "@babel/plugin-transform-dotall-regex": "^7.12.1", - "@babel/plugin-transform-duplicate-keys": "^7.12.1", - "@babel/plugin-transform-exponentiation-operator": "^7.12.1", - "@babel/plugin-transform-for-of": "^7.12.1", - "@babel/plugin-transform-function-name": "^7.12.1", - "@babel/plugin-transform-literals": "^7.12.1", - "@babel/plugin-transform-member-expression-literals": "^7.12.1", - "@babel/plugin-transform-modules-amd": "^7.12.1", - "@babel/plugin-transform-modules-commonjs": "^7.12.1", - "@babel/plugin-transform-modules-systemjs": "^7.12.1", - "@babel/plugin-transform-modules-umd": "^7.12.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", - "@babel/plugin-transform-new-target": "^7.12.1", - "@babel/plugin-transform-object-super": "^7.12.1", - "@babel/plugin-transform-parameters": "^7.12.1", - "@babel/plugin-transform-property-literals": "^7.12.1", - "@babel/plugin-transform-regenerator": "^7.12.1", - "@babel/plugin-transform-reserved-words": "^7.12.1", - "@babel/plugin-transform-shorthand-properties": "^7.12.1", - "@babel/plugin-transform-spread": "^7.12.1", - "@babel/plugin-transform-sticky-regex": "^7.12.7", - "@babel/plugin-transform-template-literals": "^7.12.1", - "@babel/plugin-transform-typeof-symbol": "^7.12.10", - "@babel/plugin-transform-unicode-escapes": "^7.12.1", - "@babel/plugin-transform-unicode-regex": "^7.12.1", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.12.11", - "core-js-compat": "^3.8.0", - "semver": "^5.5.0" + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.16.8", + "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.16.8", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -1207,339 +1566,426 @@ } }, "node_modules/@babel/register": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.12.10.tgz", - "integrity": "sha512-EvX/BvMMJRAA3jZgILWgbsrHwBQvllC5T8B29McyME8DvkdOxk4ujESfrMvME8IHSDvWXrmMXxPvA/lx2gqPLQ==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.17.7.tgz", + "integrity": "sha512-fg56SwvXRifootQEDQAu1mKdjh5uthPzdO0N6t358FktfL4XjAVXuH58ULoiW8mesxiOgNIrxiImqEwv0+hRRA==", "dev": true, "dependencies": { + "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", - "lodash": "^4.17.19", "make-dir": "^2.1.0", - "pirates": "^4.0.0", + "pirates": "^4.0.5", "source-map-support": "^0.5.16" }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", - "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", - "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.11", - "@babel/generator": "^7.12.11", - "@babel/helper-function-name": "^7.12.11", - "@babel/helper-split-export-declaration": "^7.12.11", - "@babel/parser": "^7.12.11", - "@babel/types": "^7.12.12", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz", + "integrity": "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.9", + "@babel/types": "^7.17.0", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", - "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "node_modules/@cspell/cspell-bundled-dicts": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.1.0.tgz", - "integrity": "sha512-R7ZzZ4vy6rNIo85Ho5SYATLOcaiDkICCrBYu92Gq/7L4GsVdFkEZis9Rx9DEcPLNn+9DBXcsD8XO7eiOxwqZww==", - "dev": true, - "dependencies": { - "@cspell/dict-aws": "^1.0.13", - "@cspell/dict-bash": "^1.0.11", - "@cspell/dict-companies": "^1.0.35", - "@cspell/dict-cpp": "^1.1.37", - "@cspell/dict-cryptocurrencies": "^1.0.10", - "@cspell/dict-csharp": "^1.0.10", - "@cspell/dict-css": "^1.0.10", - "@cspell/dict-django": "^1.0.25", - "@cspell/dict-dotnet": "^1.0.24", - "@cspell/dict-elixir": "^1.0.23", - "@cspell/dict-en_us": "^1.2.38", - "@cspell/dict-en-gb": "^1.1.27", - "@cspell/dict-filetypes": "^1.1.5", - "@cspell/dict-fonts": "^1.0.13", - "@cspell/dict-fullstack": "^1.0.36", - "@cspell/dict-golang": "^1.1.24", - "@cspell/dict-haskell": "^1.0.12", - "@cspell/dict-html": "^1.1.5", - "@cspell/dict-html-symbol-entities": "^1.0.23", - "@cspell/dict-java": "^1.0.22", - "@cspell/dict-latex": "^1.0.23", - "@cspell/dict-lorem-ipsum": "^1.0.22", - "@cspell/dict-lua": "^1.0.16", - "@cspell/dict-node": "^1.0.9", - "@cspell/dict-npm": "^1.0.10", - "@cspell/dict-php": "^1.0.23", - "@cspell/dict-powershell": "^1.0.14", - "@cspell/dict-python": "^1.0.32", - "@cspell/dict-ruby": "^1.0.12", - "@cspell/dict-rust": "^1.0.22", - "@cspell/dict-scala": "^1.0.21", - "@cspell/dict-software-terms": "^1.0.23", - "@cspell/dict-typescript": "^1.0.16" - }, - "engines": { - "node": ">=12.0.0" - } + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.19.7.tgz", + "integrity": "sha512-9h2KdI3yKODc8rAxkgB5UZb6RLwwEO25Fo91vnOtM1xfwLhX/scMACU1DoqtnTVaE73HoQ46DYAZAAq/OloRFQ==", + "dev": true, + "dependencies": { + "@cspell/dict-ada": "^2.0.0", + "@cspell/dict-aws": "^2.0.0", + "@cspell/dict-bash": "^2.0.2", + "@cspell/dict-companies": "^2.0.3", + "@cspell/dict-cpp": "^2.0.2", + "@cspell/dict-cryptocurrencies": "^2.0.0", + "@cspell/dict-csharp": "^2.0.1", + "@cspell/dict-css": "^2.0.0", + "@cspell/dict-dart": "^1.1.0", + "@cspell/dict-django": "^2.0.0", + "@cspell/dict-dotnet": "^2.0.1", + "@cspell/dict-elixir": "^2.0.1", + "@cspell/dict-en_us": "^2.2.0", + "@cspell/dict-en-gb": "^1.1.33", + "@cspell/dict-filetypes": "^2.0.1", + "@cspell/dict-fonts": "^2.0.0", + "@cspell/dict-fullstack": "^2.0.4", + "@cspell/dict-git": "^1.0.1", + "@cspell/dict-golang": "^2.0.0", + "@cspell/dict-haskell": "^2.0.0", + "@cspell/dict-html": "^3.0.1", + "@cspell/dict-html-symbol-entities": "^2.0.0", + "@cspell/dict-java": "^2.0.0", + "@cspell/dict-latex": "^2.0.0", + "@cspell/dict-lorem-ipsum": "^2.0.0", + "@cspell/dict-lua": "^2.0.0", + "@cspell/dict-node": "^2.0.0", + "@cspell/dict-npm": "^2.0.2", + "@cspell/dict-php": "^2.0.0", + "@cspell/dict-powershell": "^2.0.0", + "@cspell/dict-public-licenses": "^1.0.4", + "@cspell/dict-python": "^2.0.6", + "@cspell/dict-r": "^1.0.2", + "@cspell/dict-ruby": "^2.0.1", + "@cspell/dict-rust": "^2.0.0", + "@cspell/dict-scala": "^2.0.0", + "@cspell/dict-software-terms": "^2.1.4", + "@cspell/dict-swift": "^1.0.2", + "@cspell/dict-typescript": "^2.0.0", + "@cspell/dict-vue": "^2.0.2" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@cspell/cspell-pipe": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-5.19.7.tgz", + "integrity": "sha512-C2+qovrXyZtoM+IcyMuwwYieoGBwwnWORat+j7bkIkVHf6Pa9spxY3D1IdLt04PqWBKWKHb1g9KzJzw5grBqZw==", + "dev": true, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@cspell/cspell-types": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-5.19.7.tgz", + "integrity": "sha512-xL9a0oE8kPQ/GCkE/bxE5DTCMTctCpk7tdrhYG26wVbMK1VRGo8fv9w+vRVzXgTfF5jTxolEA1LTtfVBuik1MA==", + "dev": true, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@cspell/dict-ada": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-2.0.0.tgz", + "integrity": "sha512-4gfJEYXVwz6IN2LBaT6QoUV4pqaR35i0z0u9O684vLuVczvNJIHa4vNaSEFBr9d6xxncUyqstgP9P73ajJjh9A==", + "dev": true }, "node_modules/@cspell/dict-aws": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-1.0.13.tgz", - "integrity": "sha512-9rq8BS5p418THq12PIkLQmGhg4kQ8tMH8vyB7gTF2lOrA+xMwV5HjZAepoYiJCxDQI5GAQJZlAaBi5DRG3AN2A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-2.0.0.tgz", + "integrity": "sha512-NKz7pDZ7pwj/b33i3f4WLpC1rOOUMmENwYgftxU+giU2YBeKM2wZbMTSEIzsrel56r0UlQYmdIVlP/B4nnVaoQ==", "dev": true }, "node_modules/@cspell/dict-bash": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-1.0.11.tgz", - "integrity": "sha512-DTOugbPacEFIav5s+VniByouu4apD1SKS5inwiBndw0TH3Pkm4MFTPUwfT1y7Ki4HEIyfRI2ughig2045SBqRw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-2.0.2.tgz", + "integrity": "sha512-ASIgI/LmV2TYrD4mtk+gm4XmUSTRomOyRt7NDWyBpEww/AeawC2O2NH6FosyUT6dUU3GaXt2wgJRN7R78n1SGg==", "dev": true }, "node_modules/@cspell/dict-companies": { - "version": "1.0.35", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-1.0.35.tgz", - "integrity": "sha512-lFoXFqXgAUjj14t7VJm+D/j9jU9kn4Eud+Q2gVQTKs6+oMivJ0hROpqZv/CEYHlm/4MpP5Livp0z0E6ARCE0kQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-2.0.3.tgz", + "integrity": "sha512-O622rMAaHm85AmqNyMki5je8HB/1XlTKbGOXh2UUhooI5qdgdfrjTQ6VBuHwHrfEfuODBHYTNYXVB2m23XqHCg==", "dev": true }, "node_modules/@cspell/dict-cpp": { - "version": "1.1.37", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-1.1.37.tgz", - "integrity": "sha512-1X48pxiOdAw5Q7zj0k8/L5B1YY2W0k4go4CB5rcsuGRzsWXsdnKXHQTeMTAw7epIe4lj+Ef9oWaU+ODQpDZOCQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-2.0.3.tgz", + "integrity": "sha512-aWRvI3CQW2M3XeJpDVffItw/9n4hxsN5EPwyBa6Po6EnCxZZZLOqpieZk4JNz4pH0/xbnOX+sMMuSeKWr71r/w==", "dev": true }, "node_modules/@cspell/dict-cryptocurrencies": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-1.0.10.tgz", - "integrity": "sha512-47ABvDJOkaST/rXipNMfNvneHUzASvmL6K/CbOFpYKfsd0x23Jc9k1yaOC7JAm82XSC/8a7+3Yu+Fk2jVJNnsA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-2.0.0.tgz", + "integrity": "sha512-nREysmmfOp7L2YCRAUufQahwD5/Punzb5AZ6eyg4zUamdRWHgBFphb5/9h2flt1vgdUfhc6hZcML21Ci7iXjaA==", "dev": true }, "node_modules/@cspell/dict-csharp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-1.0.10.tgz", - "integrity": "sha512-jAl4HeRTwbN2+tEqL8cjM7GLXSJr9Jde3k8CqfxKME7qwVRCoBW6RkhyDHfEyaQ1LomDhnr35uiHEVrw7xCHMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-2.0.1.tgz", + "integrity": "sha512-ZzAr+WRP2FUtXHZtfhe8f3j9vPjH+5i44Hcr5JqbWxmqciGoTbWBPQXwu9y+J4mbdC69HSWRrVGkNJ8rQk8pSw==", "dev": true }, "node_modules/@cspell/dict-css": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-1.0.10.tgz", - "integrity": "sha512-QQbh+GBAyTVU8Wlf1xZPxZQQ3uRzb1lYE5RjE7hnRTSc4HtWYcb2+6XpO51QDl/dRhCmP3vEHzFF/swzHRa5hw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-2.0.0.tgz", + "integrity": "sha512-MrFyswFHnPh4H0u6IlV4eHy+ZCUrrHzeL161LyTOqCvaKpbZavMgNYXzZqTF9xafO0iLgwKrl+Gkclu1KVBg0Q==", + "dev": true + }, + "node_modules/@cspell/dict-dart": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-1.1.0.tgz", + "integrity": "sha512-bBqZINm+RVjMgUrAhRzv/xx3jc3dkIqO0higPbsK+63IAtMNY3EiQnEO4eapbU+qAhyvICY9hZQZXy5Ux4p+Pw==", "dev": true }, "node_modules/@cspell/dict-django": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-1.0.25.tgz", - "integrity": "sha512-kQfZhvjAodb5CNgryYoEKlUaHA+IVGhZIpON5ZJBuxrPUZ4SyklACPXKxDyXnKAibrERoi4zNL6pBbsljEL03w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-2.0.0.tgz", + "integrity": "sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw==", "dev": true }, "node_modules/@cspell/dict-dotnet": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-1.0.24.tgz", - "integrity": "sha512-TxmMSh2T7C+DzF0rGTwVWFGCwqiwqLpyKar37kJt62bhadbxFKv+XxkLjOLVmgoqhA17BXM813hIjjZrICj4jg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz", + "integrity": "sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ==", "dev": true }, "node_modules/@cspell/dict-elixir": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-1.0.23.tgz", - "integrity": "sha512-UKDgNSZ36o31IX4NjCF/lCuOAoLEEsjSB2KwMD2ucT66MSFEPLk1womGY+iWblISeeBmB9EehfL1hjgoRwGlUw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz", + "integrity": "sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow==", "dev": true }, "node_modules/@cspell/dict-en_us": { - "version": "1.2.39", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-1.2.39.tgz", - "integrity": "sha512-rMn5pIm3bl+t3Qxdf3WMkLZ2kzs/FDHSCDR9ha+JOtCJ1yrJTLdlZvokGDLwMScztbgooEvabsN8AUqPutOSog==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.2.0.tgz", + "integrity": "sha512-IJWu8MI2NdLyPzekrMi9K+v71b0qjDE+z/BccoMA/APnphqgSNM8BDUAzhio6mPKi1AvPRCNUjk79oiUfp+1Gw==", "dev": true }, "node_modules/@cspell/dict-en-gb": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.27.tgz", - "integrity": "sha512-0tY939q0vzmsUotKQe/i8mDGqiiw4V3Kv/nkTvxFfVQAd6JRfpWBKlMbVV5Oy37nQkQiwkDLY4v90AbyqOvG8Q==", + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", + "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", "dev": true }, "node_modules/@cspell/dict-filetypes": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-1.1.5.tgz", - "integrity": "sha512-yfkB37J+hL6W8qa4AknFp7u6CGECrw2ql2/y0lUKruLQYid0ApK+bH+ll+Sqgl2YS5QAOhclskc72aQHAcRJIQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-2.0.1.tgz", + "integrity": "sha512-bQ7K3U/3hKO2lpQjObf0veNP/n50qk5CVezSwApMBckf/sAVvDTR1RGAvYdr+vdQnkdQrk6wYmhbshXi0sLDVg==", "dev": true }, "node_modules/@cspell/dict-fonts": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-1.0.13.tgz", - "integrity": "sha512-oCwcJhwWqAu4dijGkTjOgGCQftZGfKkf+oBXjFIySdkAKGtddV6eW6VFLLtimNUf53e9Cb5wils+1Gl4NqWx1w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-2.0.0.tgz", + "integrity": "sha512-AgkTalphfDPtKFPYmEExDcj8rRCh86xlOSXco8tehOEkYVYbksOk9XH0YVH34RFpy93YBd2nnVGLgyGVwagcPw==", "dev": true }, "node_modules/@cspell/dict-fullstack": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-1.0.36.tgz", - "integrity": "sha512-npScBMAoZsjVE5uC1I72vmM1FCYnqzHH1ujgiBkbKd6Dp73VZ1f6OtpSQgqq9/onb0mSmMVF2kw4gPj8BlwGHg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-2.0.4.tgz", + "integrity": "sha512-+JtYO58QAXnetRN+MGVzI8YbkbFTLpYfl/Cw/tmNqy7U1IDVC4sTXQ2pZvbbeKQWFHBqYvBs0YASV+mTouXYBw==", + "dev": true + }, + "node_modules/@cspell/dict-git": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-1.0.1.tgz", + "integrity": "sha512-Rk+eTof/9inF11lvxmkCRK+gODatA3qai8kSASv6OG/JfPvpj7fTHErx/rdgPw/LOTDUafnoTjTYmj7B2MOQXg==", "dev": true }, "node_modules/@cspell/dict-golang": { - "version": "1.1.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-1.1.24.tgz", - "integrity": "sha512-qq3Cjnx2U1jpeWAGJL1GL0ylEhUMqyaR36Xij6Y6Aq4bViCRp+HRRqk0x5/IHHbOrti45h3yy7ii1itRFo+Xkg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-2.0.0.tgz", + "integrity": "sha512-rUeZJR/S/ZjAsOURtxsAO6xDQhL0IzF458ScahaeOqe0zVL3tx7tCLikCgT92NWPs3BNqmsZGqYSDbn/1KsSIA==", "dev": true }, "node_modules/@cspell/dict-haskell": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-1.0.12.tgz", - "integrity": "sha512-JrSSuV2oY8Z1/qYi8j1w5M3eokiFkcpRtCrxpKlHYFXFEvmqTH9D8qvzVbAkrQpefMppy8uIUzknSzhwAc/MQA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-2.0.0.tgz", + "integrity": "sha512-cjX1Br+gSWqtcmJD/IMHz1UoP3pUaKIIKy/JfhEs7ANtRt6hhfEKe9dl2kQzDkkKt4pXol+YgdYxL/sVc/nLgQ==", "dev": true }, "node_modules/@cspell/dict-html": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-1.1.5.tgz", - "integrity": "sha512-ecwFDcponQgLpC9VJK7SRAbLu3CAlw6KUSlLtVOiN3zxlh27MDCCMp9jCD4UImZGACe0YQ1Zj0DW7PjXkHuKHg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-3.0.1.tgz", + "integrity": "sha512-sbuFd+nSjgbrGf5eYwSddFhm1eLLePKWyH6Zn8Zb0OODrBK5e4vGn1/scI/MOH5a2IvNs8W9wp84uMBFJcQZtw==", "dev": true }, "node_modules/@cspell/dict-html-symbol-entities": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-1.0.23.tgz", - "integrity": "sha512-PV0UBgcBFbBLf/m1wfkVMM8w96kvfHoiCGLWO6BR3Q9v70IXoE4ae0+T+f0CkxcEkacMqEQk/I7vuE9MzrjaNw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-2.0.0.tgz", + "integrity": "sha512-71S5wGCe7dq6C+zGDwsEAe5msub/irrLi6SExeG11a/EkpA3RKAEheDGPk0hOY4+vOcIFHaApxOjLTtgQfYWfA==", "dev": true }, "node_modules/@cspell/dict-java": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-1.0.22.tgz", - "integrity": "sha512-CVAJ29dx1XwwutgsMgaj5eCl1Nc7X7qFhWL2KkAdu78A/NUIaS+1I9KS0hHhdZx/wLke9dH8TR7NyPQGpGxeAw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-2.0.0.tgz", + "integrity": "sha512-9f5LDATlAiXRGqxLxgqbOLlQxuMW2zcN7tBgxwtN+4u90vM03ZUOR/gKIuDV/y0ZuAiWBIjA73cjk8DJ13Q1eA==", "dev": true }, "node_modules/@cspell/dict-latex": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-1.0.23.tgz", - "integrity": "sha512-xn9VvX5+q9xxELiOl5o8W/0nKympOc9i6Bq6PqX3fxhVWV4xURT18sp14OI9dNXxOSm5TRzL96vgLYvK/FYQVw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-2.0.0.tgz", + "integrity": "sha512-H6RRwbHhQ9ARoO1R57SDqB+q/J5jUDdVnkdfukJkA+HNlJBhCcDuzGOIJqr+GBkJYDkF3obZ3LEOk2lUfT+Eyg==", "dev": true }, "node_modules/@cspell/dict-lorem-ipsum": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-1.0.22.tgz", - "integrity": "sha512-yqzspR+2ADeAGUxLTfZ4pXvPl7FmkENMRcGDECmddkOiuEwBCWMZdMP5fng9B0Q6j91hQ8w9CLvJKBz10TqNYg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-2.0.0.tgz", + "integrity": "sha512-jKogAKtqvgPMleL6usyj3rZ0m8sVUR6drrD+wMnWSfdx1BmUyTsYiuh/mPEfLAebaYHELWSLQG3rDZRvV9Riqg==", "dev": true }, "node_modules/@cspell/dict-lua": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-1.0.16.tgz", - "integrity": "sha512-YiHDt8kmHJ8nSBy0tHzaxiuitYp+oJ66ffCYuFWTNB3//Y0SI4OGHU3omLsQVeXIfCeVrO4DrVvRDoCls9B5zQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-2.0.0.tgz", + "integrity": "sha512-7WUEBEspSKtsq104WdIys1+DLqAxpJPzw74Py1TuE3fI5GvlzeSZkRFP2ya54GB2lCO4C3mq4M8EnitpibVDfw==", "dev": true }, "node_modules/@cspell/dict-node": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-1.0.10.tgz", - "integrity": "sha512-MnLy0pOcd+Zo8+M8VmumrIQN5SuAduZZrYKHhvXfxdVfX5vl5BfD6Gl25hzH0DrlAVlJOWAnkMZZFMYh4nGWRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-2.0.0.tgz", + "integrity": "sha512-tPPl3liJORa/l6AoYqh/7rjoM7bdtaIXnIN6ox7CE0flZcBS5rWOB6mzEY3rpu/XJX0pjbBiIoqrolDkVl1RTQ==", "dev": true }, "node_modules/@cspell/dict-npm": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-1.0.10.tgz", - "integrity": "sha512-LxLjMOyELWtVBHpive60G3MJseid30M9GR5Vodo9cT6lqT1CkbdsNP9j3oTwVXHTMKB3I+IOHNapuFG1ILcEew==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-2.0.2.tgz", + "integrity": "sha512-Q5ua0aeKTxW4WxvtU+UMdct46hCStOTeEiiG8iinTh/mH5brmdtMEj4olO8+mmkAKPpIC4TI3TmaaN6RN+Vpgw==", "dev": true }, "node_modules/@cspell/dict-php": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-1.0.23.tgz", - "integrity": "sha512-rRLf/09rXDrzs0DJuNXNmFVTw2b2zLmZKNF4LIPrFHYHvdfsMvwVqxkr/SAyhF8C6zi5sW0XYC/J0S/3IE927w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-2.0.0.tgz", + "integrity": "sha512-29WgU77eTO985LvMHwPi1pcpfopfCWfTdffDyqya0JIfOSaFUrlYKzGPkE4mRxcz2G3hXsaM0SRvBNdIRwEdUg==", "dev": true }, "node_modules/@cspell/dict-powershell": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-1.0.14.tgz", - "integrity": "sha512-hisOXXi5PBXB5YKtrJQIis2FIRHgSW1U0/sd4yI36lzb3ZMEvGJwdAdyhXN3IGiqRUNxMzJiXAeXfhnia4xPtQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-2.0.0.tgz", + "integrity": "sha512-6uvEhLiGmG3u9TFkM1TYcky6aL9Yk7Sk3KJwoTYBaQJY2KqrprgyQtW6yxIw9oU52VRHlq3KKvSAA9Q26+SIkQ==", + "dev": true + }, + "node_modules/@cspell/dict-public-licenses": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.4.tgz", + "integrity": "sha512-h4xULfVEDUeWyvp1OO19pcGDqWcBEQ7WGMp3QBHyYpjsamlzsyYYjCRSY2ZvpM7wruDmywSRFmRHJ/+uNFT7nA==", "dev": true }, "node_modules/@cspell/dict-python": { - "version": "1.0.33", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-1.0.33.tgz", - "integrity": "sha512-tRmE4TzHDFPs7sJ1a3XbfyFrvRHwefVz+z1wkm6tkXK9TPrCbIS+rV/T8xhj205q4lpZQ/TkNB3lT40eLB9O8A==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-2.0.6.tgz", + "integrity": "sha512-54ICgMRiGwavorg8UJC38Fwx8tW8WKj8pimJmFUd0F/ImQ8wmeg4VrmyMach5MZVUaw1qUe2aP5uSyqA15Q0mg==", + "dev": true + }, + "node_modules/@cspell/dict-r": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-1.0.2.tgz", + "integrity": "sha512-Rp3d4sgD6izW9TW5yVI3D//3HTl9oOGBuzTvXRdoHksVPRvzIu2liVhj8MnQ3XIRe5Kc6IhLBAm6izuV2BpGwQ==", "dev": true }, "node_modules/@cspell/dict-ruby": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-1.0.12.tgz", - "integrity": "sha512-1qGZpVbfWfGLujKFyt2Nd9bc7rNXdkjYIRfpGmn/fwVDhWz/D4Q8GLMQPB2ixocSuF3pjfsRTh1D+rKK17WFjg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-2.0.1.tgz", + "integrity": "sha512-qGqhYfFeoBOashv/l0Kj5o4ilyvfq0s+t+r32juPOkOnbHz+hzxnJo2tMMg/L/UdjVV7Y8ovg4LDBC/seVrMYQ==", "dev": true }, "node_modules/@cspell/dict-rust": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-1.0.22.tgz", - "integrity": "sha512-7WOIzv0BPiU+MssZbbMk8K+HR/g9Bcvd0+jXJC3/AKT8L6l0Mx0Tr/oF7cJ4xvCYgA84nBz3PhMZkabGSz/Nkg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-2.0.0.tgz", + "integrity": "sha512-EWlQivTKXMU3TTcq/Pi6KPKTQADknasQ700UrxRPzxhwQ4sKVZ88GDu6VZJlsbFUz8Vko289KS6wjiox/7WpmQ==", "dev": true }, "node_modules/@cspell/dict-scala": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-1.0.21.tgz", - "integrity": "sha512-5V/R7PRbbminTpPS3ywgdAalI9BHzcEjEj9ug4kWYvBIGwSnS7T6QCFCiu+e9LvEGUqQC+NHgLY4zs1NaBj2vA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-2.0.0.tgz", + "integrity": "sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g==", "dev": true }, "node_modules/@cspell/dict-software-terms": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-1.0.24.tgz", - "integrity": "sha512-617u+fn0T/9vx1UBK4qMghhyVNe90iG9BzpeRrtARLVkz2bOADwAp+VwTYwOgDlbvim6dcfWEQgVfVu4Ape0kg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-2.1.4.tgz", + "integrity": "sha512-MB2eT9qhbnIEJajGv+ndzzi6S8NCJ9cMyeGJYMoRAiJobTKP6xPrT37VjPzhckRtrHJGG//UgtQ4NsiK5aBITw==", + "dev": true + }, + "node_modules/@cspell/dict-swift": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-1.0.2.tgz", + "integrity": "sha512-IrMcRO7AYB2qU5cj4ttZyEbd04DRNOG6Iha106qGGmn4P096m+Y7lOnSLJx/rZbD/cAT3Z/7i465Lr1J93j7yg==", "dev": true }, "node_modules/@cspell/dict-typescript": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-1.0.16.tgz", - "integrity": "sha512-DEKi6vD605ebDhCC4Hrtz29k59TcijPVsmVKheTpMrL1MD/S96Ftb19gW0pEIVK9vwYZIljmGwgz4qYyuM5Liw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-2.0.0.tgz", + "integrity": "sha512-WFBahxsnD2y4Os14tE5Zxh31Ggn4DzGOAu3UoxYl1lLLxaszx4RH7LmAeFuznySboiaBeRBbpfJOjQA796O6VQ==", + "dev": true + }, + "node_modules/@cspell/dict-vue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-2.0.2.tgz", + "integrity": "sha512-/MB0RS0Gn01s4pgmjy0FvsLfr3RRMrRphEuvTRserNcM8XVtoIVAtrjig/Gg0DPwDrN8Clm0L1j7iQay6S8D0g==", "dev": true }, "node_modules/@eslint/eslintrc": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", - "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.20", + "js-yaml": "^4.1.0", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "dependencies": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" @@ -1548,90 +1994,110 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" }, "engines": { - "node": ">=8" + "node": ">=10.10.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, "engines": { "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "node_modules/@microsoft/tsdoc": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", + "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz", + "integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "@microsoft/tsdoc": "0.14.1", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" }, "engines": { @@ -1639,31 +2105,43 @@ } }, "node_modules/@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" }, "engines": { "node": ">= 8" } }, + "node_modules/@types/chai": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz", + "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, "node_modules/@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "node_modules/@types/json5": { @@ -1672,31 +2150,50 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "node_modules/@types/mocha": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", + "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.24.tgz", + "integrity": "sha512-aveCYRQbgTH9Pssp1voEP7HiuWlD2jW2BO56w+bVrJn04i61yh6mRfoKO6hEYQD9vF+W8Chkwc6j1M36uPkx4g==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.0.tgz", - "integrity": "sha512-IJ5e2W7uFNfg4qh9eHkHRUCbgZ8VKtGwD07kannJvM5t/GU8P8+24NX8gi3Hf5jST5oWPY8kyV1s/WtfiZ4+Ww==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.19.0.tgz", + "integrity": "sha512-w59GpFqDYGnWFim9p6TGJz7a3qWeENJuAKCqjGSx+Hq/bwq3RZwXYqy98KIfN85yDqz9mq6QXiY5h0FjGQLyEg==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "4.14.0", - "@typescript-eslint/scope-manager": "4.14.0", - "debug": "^4.1.1", + "@typescript-eslint/scope-manager": "5.19.0", + "@typescript-eslint/type-utils": "5.19.0", + "@typescript-eslint/utils": "5.19.0", + "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -1705,9 +2202,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1719,81 +2216,83 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.0.tgz", - "integrity": "sha512-6i6eAoiPlXMKRbXzvoQD5Yn9L7k9ezzGRvzC/x1V3650rUk3c3AOjQyGYyF9BDxQQDK2ElmKOZRD0CbtdkMzQQ==", + "node_modules/@typescript-eslint/parser": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.19.0.tgz", + "integrity": "sha512-yhktJjMCJX8BSBczh1F/uY8wGRYrBeyn84kH6oyqdIJwTGKmzX5Qiq49LRQ0Jh0LXnWijEziSo6BRqny8nqLVQ==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.14.0", - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/typescript-estree": "4.14.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "@typescript-eslint/scope-manager": "5.19.0", + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/typescript-estree": "5.19.0", + "debug": "^4.3.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/parser": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.14.0.tgz", - "integrity": "sha512-sUDeuCjBU+ZF3Lzw0hphTyScmDDJ5QVkyE21pRoBo8iDl7WBtVFS+WDN3blY1CH3SBt7EmYCw6wfmJjF0l/uYg==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.19.0.tgz", + "integrity": "sha512-Fz+VrjLmwq5fbQn5W7cIJZ066HxLMKvDEmf4eu1tZ8O956aoX45jAuBB76miAECMTODyUxH61AQM7q4/GOMQ5g==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.14.0", - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/typescript-estree": "4.14.0", - "debug": "^4.1.1" + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/visitor-keys": "5.19.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.14.0.tgz", - "integrity": "sha512-/J+LlRMdbPh4RdL4hfP1eCwHN5bAhFAGOTsvE6SxsrM/47XQiPSgF5MDgLyp/i9kbZV9Lx80DW0OpPkzL+uf8Q==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.19.0.tgz", + "integrity": "sha512-O6XQ4RI4rQcBGshTQAYBUIGsKqrKeuIOz9v8bckXZnSeXjn/1+BDZndHLe10UplQeJLXDNbaZYrAytKNQO2T4Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/visitor-keys": "4.14.0" + "@typescript-eslint/utils": "5.19.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/types": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.14.0.tgz", - "integrity": "sha512-VsQE4VvpldHrTFuVPY1ZnHn/Txw6cZGjL48e+iBxTi2ksa9DmebKjAeFmTVAYoSkTk7gjA7UqJ7pIsyifTsI4A==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.19.0.tgz", + "integrity": "sha512-zR1ithF4Iyq1wLwkDcT+qFnhs8L5VUtjgac212ftiOP/ZZUOCuuF2DeGiZZGQXGoHA50OreZqLH5NjDcDqn34w==", "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -1801,22 +2300,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.0.tgz", - "integrity": "sha512-wRjZ5qLao+bvS2F7pX4qi2oLcOONIB+ru8RGBieDptq/SudYwshveORwCVU4/yMAd4GK7Fsf8Uq1tjV838erag==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.19.0.tgz", + "integrity": "sha512-dRPuD4ocXdaE1BM/dNR21elSEUPKaWgowCA0bqJ6YbYkvtrPVEvZ+zqcX5a8ECYn3q5iBSSUcBBD42ubaOp0Hw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/visitor-keys": "4.14.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/visitor-keys": "5.19.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -1829,9 +2327,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1843,17 +2341,41 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/utils": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.19.0.tgz", + "integrity": "sha512-ZuEckdupXpXamKvFz/Ql8YnePh2ZWcwz7APICzJL985Rp5C2AYcHO62oJzIqNhAMtMK6XvrlBTZeNG8n7gS3lQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.19.0", + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/typescript-estree": "5.19.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.0.tgz", - "integrity": "sha512-MeHHzUyRI50DuiPgV9+LxcM52FCJFYjJiWHtXlbyC27b80mfOwKeiKI+MHOTEpcpfmoPFm/vvQS88bYIx6PZTA==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.19.0.tgz", + "integrity": "sha512-Ym7zZoMDZcAKWsULi2s7UMLREdVQdScPQ/fKWMYefarCztWlHPFVJo8racf8R0Gc8FAEJ2eD4of8As1oFtnQlQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.14.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.19.0", + "eslint-visitor-keys": "^3.0.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -1867,9 +2389,9 @@ "dev": true }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1879,27 +2401,14 @@ } }, "node_modules/acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1926,9 +2435,9 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { "node": ">=8" @@ -1947,9 +2456,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -1959,44 +2468,23 @@ "node": ">= 8" } }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "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-includes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", - "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "get-intrinsic": "^1.0.1", - "is-string": "^1.0.5" + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" }, "engines": { "node": ">= 0.4" @@ -2021,14 +2509,33 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -2046,66 +2553,58 @@ "node": "*" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dev": true, - "engines": { - "node": ">= 4.0.0" + "dependencies": { + "object.assign": "^4.1.0" } }, - "node_modules/babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "engines": { - "node": ">=6" + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" }, "peerDependencies": { - "eslint": ">= 4.12.1" + "@babel/core": "^7.0.0-0" } }, - "node_modules/babel-eslint/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "dev": true, - "engines": { - "node": ">=4" + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "dev": true, "dependencies": { - "object.assign": "^4.1.0" + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "node_modules/binary-extensions": { @@ -2146,71 +2645,64 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", - "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001173", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.634", + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", "escalade": "^3.1.1", - "node-releases": "^1.1.69" + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "node_modules/c8": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", + "integrity": "sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw==", "dev": true, "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.2", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.0.1", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.0.2", + "rimraf": "^3.0.0", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^8.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.7" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/caching-transform/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" + "bin": { + "c8": "bin/c8.js" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caching-transform/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=10.12.0" } }, "node_modules/call-bind": { @@ -2236,31 +2728,45 @@ } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001179", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz", - "integrity": "sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA==", - "dev": true + "version": "1.0.30001332", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", + "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", "deep-eql": "^3.0.1", "get-func-name": "^2.0.0", - "pathval": "^1.1.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", "type-detect": "^4.0.5" }, "engines": { @@ -2291,98 +2797,144 @@ } }, "node_modules/chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.10.0" }, "optionalDependencies": { - "fsevents": "~2.1.2" + "fsevents": "~2.3.2" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", "dev": true, + "dependencies": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/cliui/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/color-convert": { + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cliui/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 + }, + "node_modules/cliui/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, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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, + "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/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", @@ -2397,29 +2949,14 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "node_modules/colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", - "dev": true - }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/comment-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.1.0.tgz", - "integrity": "sha512-WEghmVYaNq9NlWbrkzQTSsya9ycLyxJxpTQfZEan6a5Jomnjw18zS3Podf8q1Zf9BvonvQd/+Z7Z39L7KKzzdQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.2.tgz", + "integrity": "sha512-H8T+kl3nZesZu41zO2oNXIJWojNeK3mHxCLrsBNu6feksBXsgb+PtYz5daP5P86A0F3sz3840KVYehr04enISQ==", "dev": true, "dependencies": { "array-timsort": "^1.0.3", - "core-util-is": "^1.0.2", + "core-util-is": "^1.0.3", "esprima": "^4.0.1", "has-own-prop": "^2.0.0", "repeat-string": "^1.6.1" @@ -2472,40 +3009,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/configstore/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "dependencies": { "safe-buffer": "~5.1.1" } }, "node_modules/core-js-compat": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz", - "integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==", + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", + "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", "dev": true, "dependencies": { - "browserslist": "^4.16.1", + "browserslist": "^4.19.1", "semver": "7.0.0" }, "funding": { @@ -2523,11 +3042,27 @@ } }, "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2552,97 +3087,116 @@ } }, "node_modules/cspell": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.1.3.tgz", - "integrity": "sha512-pZ5EecESCQUmV1pD6/ehBjS+iNUfoJDjH22TCVF1P+ClHvtkiStSxIAtBPdzrVuFyUtYxTB5m6DnHInoVhx7eQ==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "commander": "^6.2.1", - "comment-json": "^4.1.0", - "cspell-glob": "^5.1.3", - "cspell-lib": "^5.1.3", - "fs-extra": "^9.0.1", + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.19.7.tgz", + "integrity": "sha512-7/y+k708tv68+5lpN23Ew1/djx/EnG838zZ8W2ZDWCc6uRHutqRhpxsjMZr/MT3RHN44iKUj2MgT5+sfnhr4eg==", + "dev": true, + "dependencies": { + "@cspell/cspell-pipe": "^5.19.7", + "chalk": "^4.1.2", + "commander": "^9.1.0", + "cspell-gitignore": "^5.19.7", + "cspell-glob": "^5.19.7", + "cspell-lib": "^5.19.7", + "fast-json-stable-stringify": "^2.1.0", + "file-entry-cache": "^6.0.1", + "fs-extra": "^10.0.1", "get-stdin": "^8.0.0", - "glob": "^7.1.6", - "minimatch": "^3.0.4", - "strip-ansi": "^6.0.0" + "glob": "^7.2.0", + "imurmurhash": "^0.1.4", + "semver": "^7.3.6", + "strip-ansi": "^6.0.1", + "vscode-uri": "^3.0.3" }, "bin": { "cspell": "bin.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=12.13.0" + }, + "funding": { + "url": "https://github.com/streetsidesoftware/cspell?sponsor=1" } }, - "node_modules/cspell-glob": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-5.1.3.tgz", - "integrity": "sha512-l9N6nb2yU+rhU+IAPmFdxDvblYbZCc1LAyk3MxmvoY7N+eKgrF7ZG8G85029qmVI8eepEMP0UxBHLeV9GDC2TA==", + "node_modules/cspell-gitignore": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.19.7.tgz", + "integrity": "sha512-rEqlN6wigNj4P/4Z3QCI1P56KhKkPtXNBpGMXC5CbxIK/NTtn3cLaqHKIZp92pypEnU077lxSCSqRRYCPbg/6A==", "dev": true, "dependencies": { - "micromatch": "^4.0.2" + "cspell-glob": "^5.19.7", + "find-up": "^5.0.0" + }, + "bin": { + "cspell-gitignore": "bin.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=12.13.0" } }, - "node_modules/cspell-io": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-5.1.3.tgz", - "integrity": "sha512-B62hnk5O1p54MW9Gm72ulivjyEKKxpO6mnv01Q8Im+vsdJdJHyBoIBDaT1Y/qGh3Nd4CgbhvcXvWIT2vzbx/ag==", + "node_modules/cspell-glob": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-5.19.7.tgz", + "integrity": "sha512-fqlF7oqYTT2A3SRfQr7gzN21fwPoRO9IGKec1L3QeGkni5UPDxGrM2a5z+oLaYs2GN5pEf29BXVlN7dq0jVxIg==", "dev": true, "dependencies": { - "iconv-lite": "^0.6.2", - "iterable-to-stream": "^1.0.1" + "micromatch": "^4.0.5" }, "engines": { - "node": ">=12.0.0" + "node": ">=12.13.0" + } + }, + "node_modules/cspell-io": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-5.19.7.tgz", + "integrity": "sha512-SEy8XkuOhvwleGjh336EBYj5HlH1J5FrCI5GxxGiU2g8zvWlBPQmaCfQPPO4tnDrrXtK76rZvolBu1jfCmWwQA==", + "dev": true, + "engines": { + "node": ">=12.13.0" } }, "node_modules/cspell-lib": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.1.3.tgz", - "integrity": "sha512-/jXWiZHMzRWcLT3ErxVOpRETUnwXqYMD5vkKiUYiQOsDz54p9odR1r+Y4hMUsQLK29506UDiKBVkYrhCNyPuWA==", + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.19.7.tgz", + "integrity": "sha512-d4ewH1RBgcBE9NqAh0FexmVQ6YvkDQv9XOysskeDH+G9wm975owENUU/mBd8AyBt2b4YXL/FoLtaKd/7MRoNDA==", "dev": true, "dependencies": { - "@cspell/cspell-bundled-dicts": "^5.1.0", - "comment-json": "^4.1.0", + "@cspell/cspell-bundled-dicts": "^5.19.7", + "@cspell/cspell-pipe": "^5.19.7", + "@cspell/cspell-types": "^5.19.7", + "clear-module": "^4.1.2", + "comment-json": "^4.2.2", "configstore": "^5.0.1", - "cspell-io": "^5.1.3", - "cspell-trie-lib": "^5.1.3", - "cspell-util-bundle": "^5.1.3", - "fs-extra": "^9.0.1", + "cosmiconfig": "^7.0.1", + "cspell-glob": "^5.19.7", + "cspell-io": "^5.19.7", + "cspell-trie-lib": "^5.19.7", + "fast-equals": "^3.0.1", + "find-up": "^5.0.0", + "fs-extra": "^10.0.1", "gensequence": "^3.1.1", - "minimatch": "^3.0.4", + "import-fresh": "^3.3.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", - "vscode-uri": "^3.0.2" + "vscode-languageserver-textdocument": "^1.0.4", + "vscode-uri": "^3.0.3" }, "engines": { - "node": ">=12.0.0" + "node": ">=12.13.0" } }, "node_modules/cspell-trie-lib": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.1.3.tgz", - "integrity": "sha512-rNfPZpBwCDsZuK2CJFxjFTk2WnbFfscWyAWN3djyKPbt1TZen0dd/kIPOIzAZxhealx+xfvJwt0kk2nZq5g8Lg==", + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.19.7.tgz", + "integrity": "sha512-qr0HS2hGuyIQhDGG5li0nqIjVi039iPRHR8wpeDoSO0YIBCll22i/VlvW3CSmqXLaP5RRoAc9txiZkIGob6DkQ==", "dev": true, "dependencies": { - "fs-extra": "^9.0.1", + "@cspell/cspell-pipe": "^5.19.7", + "fs-extra": "^10.0.1", "gensequence": "^3.1.1" }, "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/cspell-util-bundle": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-util-bundle/-/cspell-util-bundle-5.1.3.tgz", - "integrity": "sha512-FDxs0sw4gYMKKHdSobypvLQTRsZB96n9QNewRuyMv6nVwOcD1JsboClMpYigeE3rxBvyiGbj0V+Vf94+RTWWWA==", - "dev": true, - "engines": { - "node": ">=12.0.0" + "node": ">=12.13.0" } }, "node_modules/cspell/node_modules/ansi-styles": { @@ -2661,9 +3215,9 @@ } }, "node_modules/cspell/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -2694,6 +3248,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/cspell/node_modules/commander": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.1.0.tgz", + "integrity": "sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/cspell/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2703,6 +3266,21 @@ "node": ">=8" } }, + "node_modules/cspell/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cspell/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2716,9 +3294,9 @@ } }, "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2733,12 +3311,15 @@ } }, "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/deep-eql": { @@ -2754,23 +3335,11 @@ } }, "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -2784,9 +3353,9 @@ } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true, "engines": { "node": ">=0.3.1" @@ -2829,29 +3398,11 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.643", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.643.tgz", - "integrity": "sha512-TGomM4gj8adt/uqRgPbu9F0yhUVAR1deww5X0fvbQgpGr9suSMjLgc4IwQ9YKGkp1t03cDbZum20OfAkiTYjAg==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "1.4.107", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.107.tgz", + "integrity": "sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg==", "dev": true }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2862,25 +3413,31 @@ } }, "node_modules/es-abstract": { - "version": "1.18.0-next.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", - "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.1", - "object-inspect": "^1.9.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.3", - "string.prototype.trimstart": "^1.0.3" + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -2889,6 +3446,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -2906,12 +3472,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2931,46 +3491,44 @@ } }, "node_modules/eslint": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", - "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.13.0.tgz", + "integrity": "sha512-D+Xei61eInqauAyTJ6C0q6x9mx7kTUC1KZ0m0LSEexR0V+e94K12LmWX076ZIsldwfQ2RONdaJe0re0TRGQbRQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.3.0", + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.2.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^6.0.0", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.20", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -2978,64 +3536,119 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "dependencies": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "debug": "^3.2.7", + "resolve": "^1.20.0" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "node_modules/eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "dev": true, "dependencies": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" + "debug": "^3.2.7", + "find-up": "^2.1.0" }, "engines": { "node": ">=4" } }, "node_modules/eslint-module-utils/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/eslint-module-utils/node_modules/ms": { + "node_modules/eslint-module-utils/node_modules/locate-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } }, "node_modules/eslint-plugin-es": { "version": "3.0.1", @@ -3056,47 +3669,55 @@ "eslint": ">=4.19.1" } }, - "node_modules/eslint-plugin-flowtype": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.2.0.tgz", - "integrity": "sha512-z7ULdTxuhlRJcEe1MVljePXricuPOrsWfScRXFhNzVD5dmTHWjIF57AxD0e7AbEoLSbjSsaA5S+hCg43WvpXJQ==", + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "dependencies": { - "lodash": "^4.17.15", - "string-natural-compare": "^3.0.1" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=6" }, - "peerDependencies": { - "eslint": "^7.1.0" + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/eslint-plugin-import": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", - "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "dependencies": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.0", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, "node_modules/eslint-plugin-import/node_modules/debug": { @@ -3109,13 +3730,12 @@ } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "dependencies": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "^2.0.2" }, "engines": { "node": ">=0.10.0" @@ -3131,18 +3751,6 @@ "resolved": "resources/eslint-internal-rules", "link": true }, - "node_modules/eslint-plugin-istanbul": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-istanbul/-/eslint-plugin-istanbul-0.1.2.tgz", - "integrity": "sha512-lkH0DnPxdPUZ9HMG8wpcJcl481IXRHJX1Jj1SqTWtiNgeuz/s2OOJLbCEyrIoz4HJxC4OOS4tbbGOlqeovqHaw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0" - } - }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -3163,22 +3771,112 @@ "eslint": ">=5.16.0" } }, - "node_modules/eslint-plugin-node/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "node_modules/eslint-plugin-node/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, "engines": { - "node": ">= 4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/eslint-plugin-node/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz", + "integrity": "sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.4.0.tgz", + "integrity": "sha512-U3RVIfdzJaeKDQKEJbz5p3NW8/L80PCATJAfuojwbaEL+gBjfGdhUcGde+WGUW46Q5sr/NgxevsIiDtNXrvZaQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz", + "integrity": "sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-plugin-tsdoc": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.16.tgz", + "integrity": "sha512-F/RWMnyDQuGlg82vQEFHQtGyWi7++XJKdYNn0ulIbyMOFqYIjoJOUdE6olORxgwgLkpJxsCJpJbTHgxJ/ggfXw==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.1", + "@microsoft/tsdoc-config": "0.16.1" } }, "node_modules/eslint-scope": { @@ -3194,37 +3892,49 @@ "node": ">=8.0.0" } }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "engines": { - "node": ">=6" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "engines": { - "node": ">=4" + "node": ">=10" } }, "node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/eslint/node_modules/ansi-styles": { @@ -3243,9 +3953,9 @@ } }, "node_modules/eslint/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -3276,13 +3986,50 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/eslint/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "dependencies": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" @@ -3300,21 +4047,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3327,27 +4059,30 @@ "node": ">=8" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/esprima": { @@ -3364,9 +4099,9 @@ } }, "node_modules/esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -3375,15 +4110,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3396,19 +4122,10 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -3429,21 +4146,26 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-equals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-3.0.1.tgz", + "integrity": "sha512-J9FxqqC9E/ja0C+SYhoG3Jl6pQuhP92HNcVC75xDEhB+GUzPnjEp3vMfPIxPprYZFfXS5hpVvvPCWUMiDSMS8Q==", + "dev": true + }, "node_modules/fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-json-stable-stringify": { @@ -3459,18 +4181,18 @@ "dev": true }, "node_modules/fastq": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", - "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "dependencies": { "reusify": "^1.0.4" } }, "node_modules/file-entry-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", - "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "dependencies": { "flat-cache": "^3.0.4" @@ -3505,181 +4227,75 @@ "node": ">=6" } }, - "node_modules/find-cache-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "locate-path": "^3.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-cache-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=6" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/find-cache-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.0.0" } }, - "node_modules/find-cache-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "node_modules/fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", "dev": true, "dependencies": { - "p-limit": "^2.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/find-cache-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "node_modules/flow-bin": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.142.0.tgz", - "integrity": "sha512-YgiapK/wrJjcgSgOWfoncbZ4vZrZWdHs+p7V9duI9zo4ehW2nM/VRrpSaWoZ+CWu3t+duGyAvupJvC6MM2l07w==", - "dev": true, - "bin": { - "flow": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/fs.realpath": { @@ -3689,10 +4305,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, "optional": true, @@ -3752,9 +4367,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", - "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "dependencies": { "function-bind": "^1.1.1", @@ -3765,15 +4380,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -3786,10 +4392,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -3807,9 +4429,9 @@ } }, "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { "is-glob": "^4.0.1" @@ -3840,16 +4462,16 @@ } }, "node_modules/globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -3859,19 +4481,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/growl": { @@ -3895,6 +4508,15 @@ "node": ">= 0.4.0" } }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3914,9 +4536,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { "node": ">= 0.4" @@ -3925,20 +4547,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" + "has-symbols": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/he": { @@ -3950,34 +4571,16 @@ "he": "bin/he" } }, - "node_modules/hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { "node": ">= 4" @@ -3999,6 +4602,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-fresh/node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/import-fresh/node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4017,15 +4632,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4048,12 +4654,38 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4066,10 +4698,26 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true, "engines": { "node": ">= 0.4" @@ -4079,9 +4727,9 @@ } }, "node_modules/is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -4091,10 +4739,13 @@ } }, "node_modules/is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -4121,9 +4772,9 @@ } }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -4133,9 +4784,9 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, "engines": { "node": ">= 0.4" @@ -4153,6 +4804,21 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -4171,13 +4837,26 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "dependencies": { - "has-symbols": "^1.0.1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4186,20 +4865,26 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -4208,12 +4893,12 @@ } }, "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "dependencies": { - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4228,112 +4913,52 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" + "node": ">=10" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "call-bind": "^1.0.2" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/istanbul-lib-processinfo/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" } }, "node_modules/istanbul-lib-report": { @@ -4374,15 +4999,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4395,33 +5011,10 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -4431,14 +5024,11 @@ "node": ">=8" } }, - "node_modules/iterable-to-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/iterable-to-stream/-/iterable-to-stream-1.0.1.tgz", - "integrity": "sha512-O62gD5ADMUGtJoOoM9U6LQ7i4byPXUNoHJ6mqsmkQJcom331ZJGDApWgDESWyBMEHEJRjtHozgIiTzYo9RU4UA==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", + "dev": true }, "node_modules/js-tokens": { "version": "4.0.0", @@ -4447,13 +5037,12 @@ "dev": true }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -4471,6 +5060,12 @@ "node": ">=4" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4484,13 +5079,10 @@ "dev": true }, "node_modules/json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -4504,59 +5096,53 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "node_modules/jsx-ast-utils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.2.tgz", + "integrity": "sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "array-includes": "^3.1.4", + "object.assign": "^4.1.2" }, "engines": { - "node": ">=4" + "node": ">=4.0" } }, - "node_modules/load-json-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, "engines": { - "node": ">=4" + "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4572,28 +5158,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "dependencies": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-symbols/node_modules/ansi-styles": { @@ -4612,9 +5202,9 @@ } }, "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -4666,6 +5256,27 @@ "node": ">=8" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4691,6 +5302,15 @@ "node": ">=6" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4701,22 +5321,22 @@ } }, "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=8" + "node": ">=8.6" } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -4726,41 +5346,40 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/mocha": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", - "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "dependencies": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.1.6", + "glob": "7.2.0", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", + "supports-color": "8.1.1", "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "bin": { @@ -4768,7 +5387,7 @@ "mocha": "bin/mocha" }, "engines": { - "node": ">= 10.12.0" + "node": ">= 12.0.0" }, "funding": { "type": "opencollective", @@ -4776,10 +5395,9 @@ } }, "node_modules/mocha/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -4793,6 +5411,12 @@ } } }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4814,29 +5438,46 @@ "node": ">=8" } }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "brace-expansion": "^1.1.7" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=10" } }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, "node_modules/mocha/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" } }, "node_modules/ms": { @@ -4846,15 +5487,15 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^10 || ^12 || >=13.7" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/natural-compare": { @@ -4863,339 +5504,119 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "node_modules/node-releases": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", + "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/node-releases": { - "version": "1.1.70", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz", - "integrity": "sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/nyc/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/nyc/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/nyc/node_modules/find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/nyc/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "node": ">= 0.4" }, - "engines": { - "node": ">=6" - } - }, - "node_modules/object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "node_modules/object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" + "es-abstract": "^1.19.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.values": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", - "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" @@ -5260,18 +5681,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -5281,43 +5690,34 @@ "node": ">=6" } }, - "node_modules/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", "dev": true, "dependencies": { - "callsites": "^3.0.0" + "callsites": "^3.1.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "dependencies": { - "error-ex": "^1.2.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/path-exists": { @@ -5348,9 +5748,9 @@ } }, "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "node_modules/path-type": { @@ -5363,18 +5763,24 @@ } }, "node_modules/pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, "engines": { "node": "*" } }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -5393,85 +5799,76 @@ } }, "node_modules/pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, - "dependencies": { - "node-modules-regexp": "^1.0.0" - }, "engines": { "node": ">= 6" } }, "node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "dependencies": { - "find-up": "^2.1.0" + "find-up": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-dir/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "dependencies": { - "locate-path": "^2.0.0" + "locate-path": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-dir/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "dependencies": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-dir/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-dir/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "dependencies": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-dir/node_modules/path-exists": { @@ -5493,46 +5890,50 @@ } }, "node_modules/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" - } - }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, - "engines": { - "node": ">=0.4.0" + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "engines": { - "node": ">=6" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/randombytes": { "version": "2.1.0", @@ -5543,125 +5944,16 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "dependencies": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "dependencies": { - "pify": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "dependencies": { "picomatch": "^2.2.1" @@ -5677,36 +5969,52 @@ "dev": true }, "node_modules/regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dev": true, "dependencies": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" }, "engines": { "node": ">=4" } }, "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "dev": true }, "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dev": true, "dependencies": { "@babel/runtime": "^7.8.4" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.2.tgz", + "integrity": "sha512-Ynz8fTQW5/1elh+jWU2EDDzeoNbD0OQ0R+D1VJU5ATOkUaro4A9YEkdN2ODQl/8UQFPPpZNw91fOcLFamM7Pww==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, "engines": { "node": ">=8" @@ -5716,32 +6024,32 @@ } }, "node_modules/regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dev": true, "dependencies": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" }, "engines": { "node": ">=4" } }, "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", "dev": true }, "node_modules/regjsparser": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.6.tgz", - "integrity": "sha512-jjyuCp+IEMIm3N1H1LLTJW1EISEJV9+5oHdEyrt43Pg9cDSb6rrLZei2cVWpl0xTjmmlpec/lEQGYgM7xfpGCQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dev": true, "dependencies": { "jsesc": "~0.5.0" @@ -5759,18 +6067,6 @@ "jsesc": "bin/jsesc" } }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -5789,29 +6085,18 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5864,9 +6149,9 @@ } }, "node_modules/run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -5881,7 +6166,10 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } }, "node_modules/safe-buffer": { "version": "5.1.2", @@ -5889,35 +6177,35 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" } }, "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } }, "node_modules/shebang-command": { "version": "2.0.0", @@ -5932,79 +6220,43 @@ } }, "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -6015,9 +6267,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -6033,112 +6285,32 @@ "node": ">=0.10.0" } }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/spawn-wrap/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", "dev": true, "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/spawn-wrap/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" }, "funding": { @@ -6146,12 +6318,12 @@ } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" }, "funding": { @@ -6159,24 +6331,24 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/strip-json-comments": { @@ -6203,43 +6375,18 @@ "node": ">=4" } }, - "node_modules/table": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", - "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "dependencies": { - "ajv": "^7.0.2", - "lodash": "^4.17.20", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" - }, "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz", - "integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -6282,14 +6429,14 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, @@ -6305,25 +6452,10 @@ "json5": "lib/cli.js" } }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/tsutils": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.19.1.tgz", - "integrity": "sha512-GEdoBf5XI324lu7ycad7s6laADfnAqCw6wLGI+knxvw9vsIYBaJfYdmeCEG3FMMUiSm3OGgNb+m6utsWf5h9Vw==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "dependencies": { "tslib": "^1.8.1" @@ -6335,6 +6467,12 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6356,15 +6494,6 @@ "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -6375,9 +6504,9 @@ } }, "node_modules/typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -6387,41 +6516,56 @@ "node": ">=4.2.0" } }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "dependencies": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" }, "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true, "engines": { "node": ">=4" @@ -6457,189 +6601,102 @@ "punycode": "^2.1.0" } }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vscode-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz", - "integrity": "sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/uri-js/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/wide-align/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "dependencies": { - "ansi-regex": "^3.0.0" + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" }, "engines": { - "node": ">=4" + "node": ">=10.12.0" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz", + "integrity": "sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ==", "dev": true }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "node_modules/vscode-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.3.tgz", + "integrity": "sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA==", "dev": true }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, "engines": { - "node": ">=4" + "node": ">= 8" } }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6668,10 +6725,13 @@ } }, "node_modules/y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "dev": true + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } }, "node_modules/yallist": { "version": "4.0.0", @@ -6679,32 +6739,40 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" } }, "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "engines": { + "node": ">=10" } }, "node_modules/yargs-unparser": { @@ -6722,139 +6790,24 @@ "node": ">=10" } }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yargs/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "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 }, - "node_modules/yargs/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yargs/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/yargs/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "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, "dependencies": { - "ansi-regex": "^4.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/yocto-queue": { @@ -6872,445 +6825,508 @@ "resources/eslint-internal-rules": { "name": "eslint-plugin-graphql-internal", "version": "0.0.0", - "dev": true + "dev": true, + "engines": { + "node": ">= 14.0.0" + } } }, "dependencies": { + "@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.0" + } + }, "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.16.7" } }, "@babel/compat-data": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", - "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", "dev": true }, "@babel/core": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", - "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.10", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.10", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz", + "integrity": "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.9", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" } }, "@babel/generator": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", - "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz", + "integrity": "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==", "dev": true, "requires": { - "@babel/types": "^7.12.11", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", - "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, "requires": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.16.7" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-compilation-targets": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", - "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", "dev": true, "requires": { - "@babel/compat-data": "^7.12.5", - "@babel/helper-validator-option": "^7.12.1", - "browserslist": "^4.14.5", - "semver": "^5.5.0" + "@babel/compat-data": "^7.17.7", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", - "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz", + "integrity": "sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", - "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" } }, - "@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", - "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" } }, - "@babel/helper-explode-assignable-expression": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", - "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.16.7" } }, - "@babel/helper-function-name": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", - "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", + "@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/types": "^7.12.11" + "@babel/types": "^7.16.7" } }, - "@babel/helper-get-function-arity": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", - "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", + "@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dev": true, "requires": { - "@babel/types": "^7.12.10" + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" } }, "@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", - "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", - "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, "requires": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "requires": { - "@babel/types": "^7.12.5" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", - "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "requires": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.16.7" } }, "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", - "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/types": "^7.12.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helper-replace-supers": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", - "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.7", - "@babel/helper-optimise-call-expression": "^7.12.10", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.11" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.17.0" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.16.0" } }, "@babel/helper-split-export-declaration": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", - "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, "requires": { - "@babel/types": "^7.12.11" + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz", - "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", - "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", "dev": true, "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" } }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz", + "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==", "dev": true }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", + "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" + } + }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.12.tgz", - "integrity": "sha512-nrz9y0a4xmUrRq51bYkWJIO5SBZyG2ys2qinHsN0zHDHVsUaModrkpyWWWXfGqYQmOL3x9sQIcTNN/pBGpo09A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", + "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", - "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", + "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.17.6", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", - "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", - "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", - "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", - "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", - "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", - "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", + "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" + "@babel/compat-data": "^7.17.0", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.16.7" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", - "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", - "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", - "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", - "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-async-generators": { @@ -7323,12 +7339,21 @@ } }, "@babel/plugin-syntax-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", - "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-dynamic-import": { @@ -7349,15 +7374,6 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, - "@babel/plugin-syntax-flow": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.1.tgz", - "integrity": "sha512-1lBLLmtxrwpm4VKmtVFselI/P3pX+G63fAtUUt6b2Nzgao77KNDwyuRt90Mj2/9pKobtt68FdvjfqohZjg/FCA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, "@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -7421,416 +7437,444 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, "@babel/plugin-syntax-top-level-await": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", - "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", - "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", - "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", - "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz", - "integrity": "sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-classes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", - "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", - "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-destructuring": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", - "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz", + "integrity": "sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", - "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", - "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", - "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.10.tgz", - "integrity": "sha512-0ti12wLTLeUIzu9U7kjqIn4MyOL7+Wibc7avsHhj4o1l5C0ATs8p2IMHrVYjm9t9wzhfEO6S3kxax0Rpdo8LTg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-flow": "^7.12.1" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-for-of": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", - "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-function-name": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", - "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", - "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", - "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", - "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", - "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz", + "integrity": "sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", - "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz", + "integrity": "sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", - "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", - "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", + "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" } }, "@babel/plugin-transform-new-target": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", - "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-object-super": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", - "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, "@babel/plugin-transform-parameters": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", - "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-property-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", - "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", - "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", + "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", "dev": true, "requires": { - "regenerator-transform": "^0.14.2" + "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", - "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", - "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", - "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", - "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", - "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", - "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-typescript": "^7.16.7" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", - "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", - "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/preset-env": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz", - "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.12.7", - "@babel/helper-compilation-targets": "^7.12.5", - "@babel/helper-module-imports": "^7.12.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-option": "^7.12.11", - "@babel/plugin-proposal-async-generator-functions": "^7.12.1", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-dynamic-import": "^7.12.1", - "@babel/plugin-proposal-export-namespace-from": "^7.12.1", - "@babel/plugin-proposal-json-strings": "^7.12.1", - "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", - "@babel/plugin-proposal-numeric-separator": "^7.12.7", - "@babel/plugin-proposal-object-rest-spread": "^7.12.1", - "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", - "@babel/plugin-proposal-optional-chaining": "^7.12.7", - "@babel/plugin-proposal-private-methods": "^7.12.1", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.12.1", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", + "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.12.1", - "@babel/plugin-transform-arrow-functions": "^7.12.1", - "@babel/plugin-transform-async-to-generator": "^7.12.1", - "@babel/plugin-transform-block-scoped-functions": "^7.12.1", - "@babel/plugin-transform-block-scoping": "^7.12.11", - "@babel/plugin-transform-classes": "^7.12.1", - "@babel/plugin-transform-computed-properties": "^7.12.1", - "@babel/plugin-transform-destructuring": "^7.12.1", - "@babel/plugin-transform-dotall-regex": "^7.12.1", - "@babel/plugin-transform-duplicate-keys": "^7.12.1", - "@babel/plugin-transform-exponentiation-operator": "^7.12.1", - "@babel/plugin-transform-for-of": "^7.12.1", - "@babel/plugin-transform-function-name": "^7.12.1", - "@babel/plugin-transform-literals": "^7.12.1", - "@babel/plugin-transform-member-expression-literals": "^7.12.1", - "@babel/plugin-transform-modules-amd": "^7.12.1", - "@babel/plugin-transform-modules-commonjs": "^7.12.1", - "@babel/plugin-transform-modules-systemjs": "^7.12.1", - "@babel/plugin-transform-modules-umd": "^7.12.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", - "@babel/plugin-transform-new-target": "^7.12.1", - "@babel/plugin-transform-object-super": "^7.12.1", - "@babel/plugin-transform-parameters": "^7.12.1", - "@babel/plugin-transform-property-literals": "^7.12.1", - "@babel/plugin-transform-regenerator": "^7.12.1", - "@babel/plugin-transform-reserved-words": "^7.12.1", - "@babel/plugin-transform-shorthand-properties": "^7.12.1", - "@babel/plugin-transform-spread": "^7.12.1", - "@babel/plugin-transform-sticky-regex": "^7.12.7", - "@babel/plugin-transform-template-literals": "^7.12.1", - "@babel/plugin-transform-typeof-symbol": "^7.12.10", - "@babel/plugin-transform-unicode-escapes": "^7.12.1", - "@babel/plugin-transform-unicode-regex": "^7.12.1", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.12.11", - "core-js-compat": "^3.8.0", - "semver": "^5.5.0" + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.16.8", + "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.16.8", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.20.2", + "semver": "^6.3.0" } }, "@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -7841,422 +7885,523 @@ } }, "@babel/register": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.12.10.tgz", - "integrity": "sha512-EvX/BvMMJRAA3jZgILWgbsrHwBQvllC5T8B29McyME8DvkdOxk4ujESfrMvME8IHSDvWXrmMXxPvA/lx2gqPLQ==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.17.7.tgz", + "integrity": "sha512-fg56SwvXRifootQEDQAu1mKdjh5uthPzdO0N6t358FktfL4XjAVXuH58ULoiW8mesxiOgNIrxiImqEwv0+hRRA==", "dev": true, "requires": { + "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", - "lodash": "^4.17.19", "make-dir": "^2.1.0", - "pirates": "^4.0.0", + "pirates": "^4.0.5", "source-map-support": "^0.5.16" } }, "@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", - "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/traverse": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", - "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.11", - "@babel/generator": "^7.12.11", - "@babel/helper-function-name": "^7.12.11", - "@babel/helper-split-export-declaration": "^7.12.11", - "@babel/parser": "^7.12.11", - "@babel/types": "^7.12.12", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz", + "integrity": "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.9", + "@babel/types": "^7.17.0", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", - "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "@cspell/cspell-bundled-dicts": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.1.0.tgz", - "integrity": "sha512-R7ZzZ4vy6rNIo85Ho5SYATLOcaiDkICCrBYu92Gq/7L4GsVdFkEZis9Rx9DEcPLNn+9DBXcsD8XO7eiOxwqZww==", - "dev": true, - "requires": { - "@cspell/dict-aws": "^1.0.13", - "@cspell/dict-bash": "^1.0.11", - "@cspell/dict-companies": "^1.0.35", - "@cspell/dict-cpp": "^1.1.37", - "@cspell/dict-cryptocurrencies": "^1.0.10", - "@cspell/dict-csharp": "^1.0.10", - "@cspell/dict-css": "^1.0.10", - "@cspell/dict-django": "^1.0.25", - "@cspell/dict-dotnet": "^1.0.24", - "@cspell/dict-elixir": "^1.0.23", - "@cspell/dict-en_us": "^1.2.38", - "@cspell/dict-en-gb": "^1.1.27", - "@cspell/dict-filetypes": "^1.1.5", - "@cspell/dict-fonts": "^1.0.13", - "@cspell/dict-fullstack": "^1.0.36", - "@cspell/dict-golang": "^1.1.24", - "@cspell/dict-haskell": "^1.0.12", - "@cspell/dict-html": "^1.1.5", - "@cspell/dict-html-symbol-entities": "^1.0.23", - "@cspell/dict-java": "^1.0.22", - "@cspell/dict-latex": "^1.0.23", - "@cspell/dict-lorem-ipsum": "^1.0.22", - "@cspell/dict-lua": "^1.0.16", - "@cspell/dict-node": "^1.0.9", - "@cspell/dict-npm": "^1.0.10", - "@cspell/dict-php": "^1.0.23", - "@cspell/dict-powershell": "^1.0.14", - "@cspell/dict-python": "^1.0.32", - "@cspell/dict-ruby": "^1.0.12", - "@cspell/dict-rust": "^1.0.22", - "@cspell/dict-scala": "^1.0.21", - "@cspell/dict-software-terms": "^1.0.23", - "@cspell/dict-typescript": "^1.0.16" - } + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.19.7.tgz", + "integrity": "sha512-9h2KdI3yKODc8rAxkgB5UZb6RLwwEO25Fo91vnOtM1xfwLhX/scMACU1DoqtnTVaE73HoQ46DYAZAAq/OloRFQ==", + "dev": true, + "requires": { + "@cspell/dict-ada": "^2.0.0", + "@cspell/dict-aws": "^2.0.0", + "@cspell/dict-bash": "^2.0.2", + "@cspell/dict-companies": "^2.0.3", + "@cspell/dict-cpp": "^2.0.2", + "@cspell/dict-cryptocurrencies": "^2.0.0", + "@cspell/dict-csharp": "^2.0.1", + "@cspell/dict-css": "^2.0.0", + "@cspell/dict-dart": "^1.1.0", + "@cspell/dict-django": "^2.0.0", + "@cspell/dict-dotnet": "^2.0.1", + "@cspell/dict-elixir": "^2.0.1", + "@cspell/dict-en_us": "^2.2.0", + "@cspell/dict-en-gb": "^1.1.33", + "@cspell/dict-filetypes": "^2.0.1", + "@cspell/dict-fonts": "^2.0.0", + "@cspell/dict-fullstack": "^2.0.4", + "@cspell/dict-git": "^1.0.1", + "@cspell/dict-golang": "^2.0.0", + "@cspell/dict-haskell": "^2.0.0", + "@cspell/dict-html": "^3.0.1", + "@cspell/dict-html-symbol-entities": "^2.0.0", + "@cspell/dict-java": "^2.0.0", + "@cspell/dict-latex": "^2.0.0", + "@cspell/dict-lorem-ipsum": "^2.0.0", + "@cspell/dict-lua": "^2.0.0", + "@cspell/dict-node": "^2.0.0", + "@cspell/dict-npm": "^2.0.2", + "@cspell/dict-php": "^2.0.0", + "@cspell/dict-powershell": "^2.0.0", + "@cspell/dict-public-licenses": "^1.0.4", + "@cspell/dict-python": "^2.0.6", + "@cspell/dict-r": "^1.0.2", + "@cspell/dict-ruby": "^2.0.1", + "@cspell/dict-rust": "^2.0.0", + "@cspell/dict-scala": "^2.0.0", + "@cspell/dict-software-terms": "^2.1.4", + "@cspell/dict-swift": "^1.0.2", + "@cspell/dict-typescript": "^2.0.0", + "@cspell/dict-vue": "^2.0.2" + } + }, + "@cspell/cspell-pipe": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-5.19.7.tgz", + "integrity": "sha512-C2+qovrXyZtoM+IcyMuwwYieoGBwwnWORat+j7bkIkVHf6Pa9spxY3D1IdLt04PqWBKWKHb1g9KzJzw5grBqZw==", + "dev": true + }, + "@cspell/cspell-types": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-5.19.7.tgz", + "integrity": "sha512-xL9a0oE8kPQ/GCkE/bxE5DTCMTctCpk7tdrhYG26wVbMK1VRGo8fv9w+vRVzXgTfF5jTxolEA1LTtfVBuik1MA==", + "dev": true + }, + "@cspell/dict-ada": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-2.0.0.tgz", + "integrity": "sha512-4gfJEYXVwz6IN2LBaT6QoUV4pqaR35i0z0u9O684vLuVczvNJIHa4vNaSEFBr9d6xxncUyqstgP9P73ajJjh9A==", + "dev": true }, "@cspell/dict-aws": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-1.0.13.tgz", - "integrity": "sha512-9rq8BS5p418THq12PIkLQmGhg4kQ8tMH8vyB7gTF2lOrA+xMwV5HjZAepoYiJCxDQI5GAQJZlAaBi5DRG3AN2A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-2.0.0.tgz", + "integrity": "sha512-NKz7pDZ7pwj/b33i3f4WLpC1rOOUMmENwYgftxU+giU2YBeKM2wZbMTSEIzsrel56r0UlQYmdIVlP/B4nnVaoQ==", "dev": true }, "@cspell/dict-bash": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-1.0.11.tgz", - "integrity": "sha512-DTOugbPacEFIav5s+VniByouu4apD1SKS5inwiBndw0TH3Pkm4MFTPUwfT1y7Ki4HEIyfRI2ughig2045SBqRw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-2.0.2.tgz", + "integrity": "sha512-ASIgI/LmV2TYrD4mtk+gm4XmUSTRomOyRt7NDWyBpEww/AeawC2O2NH6FosyUT6dUU3GaXt2wgJRN7R78n1SGg==", "dev": true }, "@cspell/dict-companies": { - "version": "1.0.35", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-1.0.35.tgz", - "integrity": "sha512-lFoXFqXgAUjj14t7VJm+D/j9jU9kn4Eud+Q2gVQTKs6+oMivJ0hROpqZv/CEYHlm/4MpP5Livp0z0E6ARCE0kQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-2.0.3.tgz", + "integrity": "sha512-O622rMAaHm85AmqNyMki5je8HB/1XlTKbGOXh2UUhooI5qdgdfrjTQ6VBuHwHrfEfuODBHYTNYXVB2m23XqHCg==", "dev": true }, "@cspell/dict-cpp": { - "version": "1.1.37", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-1.1.37.tgz", - "integrity": "sha512-1X48pxiOdAw5Q7zj0k8/L5B1YY2W0k4go4CB5rcsuGRzsWXsdnKXHQTeMTAw7epIe4lj+Ef9oWaU+ODQpDZOCQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-2.0.3.tgz", + "integrity": "sha512-aWRvI3CQW2M3XeJpDVffItw/9n4hxsN5EPwyBa6Po6EnCxZZZLOqpieZk4JNz4pH0/xbnOX+sMMuSeKWr71r/w==", "dev": true }, "@cspell/dict-cryptocurrencies": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-1.0.10.tgz", - "integrity": "sha512-47ABvDJOkaST/rXipNMfNvneHUzASvmL6K/CbOFpYKfsd0x23Jc9k1yaOC7JAm82XSC/8a7+3Yu+Fk2jVJNnsA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-2.0.0.tgz", + "integrity": "sha512-nREysmmfOp7L2YCRAUufQahwD5/Punzb5AZ6eyg4zUamdRWHgBFphb5/9h2flt1vgdUfhc6hZcML21Ci7iXjaA==", "dev": true }, "@cspell/dict-csharp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-1.0.10.tgz", - "integrity": "sha512-jAl4HeRTwbN2+tEqL8cjM7GLXSJr9Jde3k8CqfxKME7qwVRCoBW6RkhyDHfEyaQ1LomDhnr35uiHEVrw7xCHMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-2.0.1.tgz", + "integrity": "sha512-ZzAr+WRP2FUtXHZtfhe8f3j9vPjH+5i44Hcr5JqbWxmqciGoTbWBPQXwu9y+J4mbdC69HSWRrVGkNJ8rQk8pSw==", "dev": true }, "@cspell/dict-css": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-1.0.10.tgz", - "integrity": "sha512-QQbh+GBAyTVU8Wlf1xZPxZQQ3uRzb1lYE5RjE7hnRTSc4HtWYcb2+6XpO51QDl/dRhCmP3vEHzFF/swzHRa5hw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-2.0.0.tgz", + "integrity": "sha512-MrFyswFHnPh4H0u6IlV4eHy+ZCUrrHzeL161LyTOqCvaKpbZavMgNYXzZqTF9xafO0iLgwKrl+Gkclu1KVBg0Q==", + "dev": true + }, + "@cspell/dict-dart": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-1.1.0.tgz", + "integrity": "sha512-bBqZINm+RVjMgUrAhRzv/xx3jc3dkIqO0higPbsK+63IAtMNY3EiQnEO4eapbU+qAhyvICY9hZQZXy5Ux4p+Pw==", "dev": true }, "@cspell/dict-django": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-1.0.25.tgz", - "integrity": "sha512-kQfZhvjAodb5CNgryYoEKlUaHA+IVGhZIpON5ZJBuxrPUZ4SyklACPXKxDyXnKAibrERoi4zNL6pBbsljEL03w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-2.0.0.tgz", + "integrity": "sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw==", "dev": true }, "@cspell/dict-dotnet": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-1.0.24.tgz", - "integrity": "sha512-TxmMSh2T7C+DzF0rGTwVWFGCwqiwqLpyKar37kJt62bhadbxFKv+XxkLjOLVmgoqhA17BXM813hIjjZrICj4jg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz", + "integrity": "sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ==", "dev": true }, "@cspell/dict-elixir": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-1.0.23.tgz", - "integrity": "sha512-UKDgNSZ36o31IX4NjCF/lCuOAoLEEsjSB2KwMD2ucT66MSFEPLk1womGY+iWblISeeBmB9EehfL1hjgoRwGlUw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz", + "integrity": "sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow==", "dev": true }, "@cspell/dict-en_us": { - "version": "1.2.39", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-1.2.39.tgz", - "integrity": "sha512-rMn5pIm3bl+t3Qxdf3WMkLZ2kzs/FDHSCDR9ha+JOtCJ1yrJTLdlZvokGDLwMScztbgooEvabsN8AUqPutOSog==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.2.0.tgz", + "integrity": "sha512-IJWu8MI2NdLyPzekrMi9K+v71b0qjDE+z/BccoMA/APnphqgSNM8BDUAzhio6mPKi1AvPRCNUjk79oiUfp+1Gw==", "dev": true }, "@cspell/dict-en-gb": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.27.tgz", - "integrity": "sha512-0tY939q0vzmsUotKQe/i8mDGqiiw4V3Kv/nkTvxFfVQAd6JRfpWBKlMbVV5Oy37nQkQiwkDLY4v90AbyqOvG8Q==", + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", + "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", "dev": true }, "@cspell/dict-filetypes": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-1.1.5.tgz", - "integrity": "sha512-yfkB37J+hL6W8qa4AknFp7u6CGECrw2ql2/y0lUKruLQYid0ApK+bH+ll+Sqgl2YS5QAOhclskc72aQHAcRJIQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-2.0.1.tgz", + "integrity": "sha512-bQ7K3U/3hKO2lpQjObf0veNP/n50qk5CVezSwApMBckf/sAVvDTR1RGAvYdr+vdQnkdQrk6wYmhbshXi0sLDVg==", "dev": true }, "@cspell/dict-fonts": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-1.0.13.tgz", - "integrity": "sha512-oCwcJhwWqAu4dijGkTjOgGCQftZGfKkf+oBXjFIySdkAKGtddV6eW6VFLLtimNUf53e9Cb5wils+1Gl4NqWx1w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-2.0.0.tgz", + "integrity": "sha512-AgkTalphfDPtKFPYmEExDcj8rRCh86xlOSXco8tehOEkYVYbksOk9XH0YVH34RFpy93YBd2nnVGLgyGVwagcPw==", "dev": true }, "@cspell/dict-fullstack": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-1.0.36.tgz", - "integrity": "sha512-npScBMAoZsjVE5uC1I72vmM1FCYnqzHH1ujgiBkbKd6Dp73VZ1f6OtpSQgqq9/onb0mSmMVF2kw4gPj8BlwGHg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-2.0.4.tgz", + "integrity": "sha512-+JtYO58QAXnetRN+MGVzI8YbkbFTLpYfl/Cw/tmNqy7U1IDVC4sTXQ2pZvbbeKQWFHBqYvBs0YASV+mTouXYBw==", + "dev": true + }, + "@cspell/dict-git": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-1.0.1.tgz", + "integrity": "sha512-Rk+eTof/9inF11lvxmkCRK+gODatA3qai8kSASv6OG/JfPvpj7fTHErx/rdgPw/LOTDUafnoTjTYmj7B2MOQXg==", "dev": true }, "@cspell/dict-golang": { - "version": "1.1.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-1.1.24.tgz", - "integrity": "sha512-qq3Cjnx2U1jpeWAGJL1GL0ylEhUMqyaR36Xij6Y6Aq4bViCRp+HRRqk0x5/IHHbOrti45h3yy7ii1itRFo+Xkg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-2.0.0.tgz", + "integrity": "sha512-rUeZJR/S/ZjAsOURtxsAO6xDQhL0IzF458ScahaeOqe0zVL3tx7tCLikCgT92NWPs3BNqmsZGqYSDbn/1KsSIA==", "dev": true }, "@cspell/dict-haskell": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-1.0.12.tgz", - "integrity": "sha512-JrSSuV2oY8Z1/qYi8j1w5M3eokiFkcpRtCrxpKlHYFXFEvmqTH9D8qvzVbAkrQpefMppy8uIUzknSzhwAc/MQA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-2.0.0.tgz", + "integrity": "sha512-cjX1Br+gSWqtcmJD/IMHz1UoP3pUaKIIKy/JfhEs7ANtRt6hhfEKe9dl2kQzDkkKt4pXol+YgdYxL/sVc/nLgQ==", "dev": true }, "@cspell/dict-html": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-1.1.5.tgz", - "integrity": "sha512-ecwFDcponQgLpC9VJK7SRAbLu3CAlw6KUSlLtVOiN3zxlh27MDCCMp9jCD4UImZGACe0YQ1Zj0DW7PjXkHuKHg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-3.0.1.tgz", + "integrity": "sha512-sbuFd+nSjgbrGf5eYwSddFhm1eLLePKWyH6Zn8Zb0OODrBK5e4vGn1/scI/MOH5a2IvNs8W9wp84uMBFJcQZtw==", "dev": true }, "@cspell/dict-html-symbol-entities": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-1.0.23.tgz", - "integrity": "sha512-PV0UBgcBFbBLf/m1wfkVMM8w96kvfHoiCGLWO6BR3Q9v70IXoE4ae0+T+f0CkxcEkacMqEQk/I7vuE9MzrjaNw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-2.0.0.tgz", + "integrity": "sha512-71S5wGCe7dq6C+zGDwsEAe5msub/irrLi6SExeG11a/EkpA3RKAEheDGPk0hOY4+vOcIFHaApxOjLTtgQfYWfA==", "dev": true }, "@cspell/dict-java": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-1.0.22.tgz", - "integrity": "sha512-CVAJ29dx1XwwutgsMgaj5eCl1Nc7X7qFhWL2KkAdu78A/NUIaS+1I9KS0hHhdZx/wLke9dH8TR7NyPQGpGxeAw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-2.0.0.tgz", + "integrity": "sha512-9f5LDATlAiXRGqxLxgqbOLlQxuMW2zcN7tBgxwtN+4u90vM03ZUOR/gKIuDV/y0ZuAiWBIjA73cjk8DJ13Q1eA==", "dev": true }, "@cspell/dict-latex": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-1.0.23.tgz", - "integrity": "sha512-xn9VvX5+q9xxELiOl5o8W/0nKympOc9i6Bq6PqX3fxhVWV4xURT18sp14OI9dNXxOSm5TRzL96vgLYvK/FYQVw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-2.0.0.tgz", + "integrity": "sha512-H6RRwbHhQ9ARoO1R57SDqB+q/J5jUDdVnkdfukJkA+HNlJBhCcDuzGOIJqr+GBkJYDkF3obZ3LEOk2lUfT+Eyg==", "dev": true }, "@cspell/dict-lorem-ipsum": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-1.0.22.tgz", - "integrity": "sha512-yqzspR+2ADeAGUxLTfZ4pXvPl7FmkENMRcGDECmddkOiuEwBCWMZdMP5fng9B0Q6j91hQ8w9CLvJKBz10TqNYg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-2.0.0.tgz", + "integrity": "sha512-jKogAKtqvgPMleL6usyj3rZ0m8sVUR6drrD+wMnWSfdx1BmUyTsYiuh/mPEfLAebaYHELWSLQG3rDZRvV9Riqg==", "dev": true }, "@cspell/dict-lua": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-1.0.16.tgz", - "integrity": "sha512-YiHDt8kmHJ8nSBy0tHzaxiuitYp+oJ66ffCYuFWTNB3//Y0SI4OGHU3omLsQVeXIfCeVrO4DrVvRDoCls9B5zQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-2.0.0.tgz", + "integrity": "sha512-7WUEBEspSKtsq104WdIys1+DLqAxpJPzw74Py1TuE3fI5GvlzeSZkRFP2ya54GB2lCO4C3mq4M8EnitpibVDfw==", "dev": true }, "@cspell/dict-node": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-1.0.10.tgz", - "integrity": "sha512-MnLy0pOcd+Zo8+M8VmumrIQN5SuAduZZrYKHhvXfxdVfX5vl5BfD6Gl25hzH0DrlAVlJOWAnkMZZFMYh4nGWRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-2.0.0.tgz", + "integrity": "sha512-tPPl3liJORa/l6AoYqh/7rjoM7bdtaIXnIN6ox7CE0flZcBS5rWOB6mzEY3rpu/XJX0pjbBiIoqrolDkVl1RTQ==", "dev": true }, "@cspell/dict-npm": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-1.0.10.tgz", - "integrity": "sha512-LxLjMOyELWtVBHpive60G3MJseid30M9GR5Vodo9cT6lqT1CkbdsNP9j3oTwVXHTMKB3I+IOHNapuFG1ILcEew==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-2.0.2.tgz", + "integrity": "sha512-Q5ua0aeKTxW4WxvtU+UMdct46hCStOTeEiiG8iinTh/mH5brmdtMEj4olO8+mmkAKPpIC4TI3TmaaN6RN+Vpgw==", "dev": true }, "@cspell/dict-php": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-1.0.23.tgz", - "integrity": "sha512-rRLf/09rXDrzs0DJuNXNmFVTw2b2zLmZKNF4LIPrFHYHvdfsMvwVqxkr/SAyhF8C6zi5sW0XYC/J0S/3IE927w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-2.0.0.tgz", + "integrity": "sha512-29WgU77eTO985LvMHwPi1pcpfopfCWfTdffDyqya0JIfOSaFUrlYKzGPkE4mRxcz2G3hXsaM0SRvBNdIRwEdUg==", "dev": true }, "@cspell/dict-powershell": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-1.0.14.tgz", - "integrity": "sha512-hisOXXi5PBXB5YKtrJQIis2FIRHgSW1U0/sd4yI36lzb3ZMEvGJwdAdyhXN3IGiqRUNxMzJiXAeXfhnia4xPtQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-2.0.0.tgz", + "integrity": "sha512-6uvEhLiGmG3u9TFkM1TYcky6aL9Yk7Sk3KJwoTYBaQJY2KqrprgyQtW6yxIw9oU52VRHlq3KKvSAA9Q26+SIkQ==", + "dev": true + }, + "@cspell/dict-public-licenses": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.4.tgz", + "integrity": "sha512-h4xULfVEDUeWyvp1OO19pcGDqWcBEQ7WGMp3QBHyYpjsamlzsyYYjCRSY2ZvpM7wruDmywSRFmRHJ/+uNFT7nA==", "dev": true }, "@cspell/dict-python": { - "version": "1.0.33", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-1.0.33.tgz", - "integrity": "sha512-tRmE4TzHDFPs7sJ1a3XbfyFrvRHwefVz+z1wkm6tkXK9TPrCbIS+rV/T8xhj205q4lpZQ/TkNB3lT40eLB9O8A==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-2.0.6.tgz", + "integrity": "sha512-54ICgMRiGwavorg8UJC38Fwx8tW8WKj8pimJmFUd0F/ImQ8wmeg4VrmyMach5MZVUaw1qUe2aP5uSyqA15Q0mg==", + "dev": true + }, + "@cspell/dict-r": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-1.0.2.tgz", + "integrity": "sha512-Rp3d4sgD6izW9TW5yVI3D//3HTl9oOGBuzTvXRdoHksVPRvzIu2liVhj8MnQ3XIRe5Kc6IhLBAm6izuV2BpGwQ==", "dev": true }, "@cspell/dict-ruby": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-1.0.12.tgz", - "integrity": "sha512-1qGZpVbfWfGLujKFyt2Nd9bc7rNXdkjYIRfpGmn/fwVDhWz/D4Q8GLMQPB2ixocSuF3pjfsRTh1D+rKK17WFjg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-2.0.1.tgz", + "integrity": "sha512-qGqhYfFeoBOashv/l0Kj5o4ilyvfq0s+t+r32juPOkOnbHz+hzxnJo2tMMg/L/UdjVV7Y8ovg4LDBC/seVrMYQ==", "dev": true }, "@cspell/dict-rust": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-1.0.22.tgz", - "integrity": "sha512-7WOIzv0BPiU+MssZbbMk8K+HR/g9Bcvd0+jXJC3/AKT8L6l0Mx0Tr/oF7cJ4xvCYgA84nBz3PhMZkabGSz/Nkg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-2.0.0.tgz", + "integrity": "sha512-EWlQivTKXMU3TTcq/Pi6KPKTQADknasQ700UrxRPzxhwQ4sKVZ88GDu6VZJlsbFUz8Vko289KS6wjiox/7WpmQ==", "dev": true }, "@cspell/dict-scala": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-1.0.21.tgz", - "integrity": "sha512-5V/R7PRbbminTpPS3ywgdAalI9BHzcEjEj9ug4kWYvBIGwSnS7T6QCFCiu+e9LvEGUqQC+NHgLY4zs1NaBj2vA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-2.0.0.tgz", + "integrity": "sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g==", "dev": true }, "@cspell/dict-software-terms": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-1.0.24.tgz", - "integrity": "sha512-617u+fn0T/9vx1UBK4qMghhyVNe90iG9BzpeRrtARLVkz2bOADwAp+VwTYwOgDlbvim6dcfWEQgVfVu4Ape0kg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-2.1.4.tgz", + "integrity": "sha512-MB2eT9qhbnIEJajGv+ndzzi6S8NCJ9cMyeGJYMoRAiJobTKP6xPrT37VjPzhckRtrHJGG//UgtQ4NsiK5aBITw==", + "dev": true + }, + "@cspell/dict-swift": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-1.0.2.tgz", + "integrity": "sha512-IrMcRO7AYB2qU5cj4ttZyEbd04DRNOG6Iha106qGGmn4P096m+Y7lOnSLJx/rZbD/cAT3Z/7i465Lr1J93j7yg==", "dev": true }, "@cspell/dict-typescript": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-1.0.16.tgz", - "integrity": "sha512-DEKi6vD605ebDhCC4Hrtz29k59TcijPVsmVKheTpMrL1MD/S96Ftb19gW0pEIVK9vwYZIljmGwgz4qYyuM5Liw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-2.0.0.tgz", + "integrity": "sha512-WFBahxsnD2y4Os14tE5Zxh31Ggn4DzGOAu3UoxYl1lLLxaszx4RH7LmAeFuznySboiaBeRBbpfJOjQA796O6VQ==", + "dev": true + }, + "@cspell/dict-vue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-2.0.2.tgz", + "integrity": "sha512-/MB0RS0Gn01s4pgmjy0FvsLfr3RRMrRphEuvTRserNcM8XVtoIVAtrjig/Gg0DPwDrN8Clm0L1j7iQay6S8D0g==", "dev": true }, "@eslint/eslintrc": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", - "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.20", + "js-yaml": "^4.1.0", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true } } }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@microsoft/tsdoc": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", + "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "dev": true + }, + "@microsoft/tsdoc-config": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz", + "integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.14.1", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" }, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", "dev": true, "requires": { - "p-limit": "^2.2.0" + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" } } } }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true - }, "@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, + "@types/chai": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz", + "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/json5": { @@ -8265,26 +8410,45 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/mocha": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", + "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "dev": true + }, + "@types/node": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.24.tgz", + "integrity": "sha512-aveCYRQbgTH9Pssp1voEP7HiuWlD2jW2BO56w+bVrJn04i61yh6mRfoKO6hEYQD9vF+W8Chkwc6j1M36uPkx4g==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.0.tgz", - "integrity": "sha512-IJ5e2W7uFNfg4qh9eHkHRUCbgZ8VKtGwD07kannJvM5t/GU8P8+24NX8gi3Hf5jST5oWPY8kyV1s/WtfiZ4+Ww==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.19.0.tgz", + "integrity": "sha512-w59GpFqDYGnWFim9p6TGJz7a3qWeENJuAKCqjGSx+Hq/bwq3RZwXYqy98KIfN85yDqz9mq6QXiY5h0FjGQLyEg==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.14.0", - "@typescript-eslint/scope-manager": "4.14.0", - "debug": "^4.1.1", + "@typescript-eslint/scope-manager": "5.19.0", + "@typescript-eslint/type-utils": "5.19.0", + "@typescript-eslint/utils": "5.19.0", + "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" }, "dependencies": { "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -8292,68 +8456,64 @@ } } }, - "@typescript-eslint/experimental-utils": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.0.tgz", - "integrity": "sha512-6i6eAoiPlXMKRbXzvoQD5Yn9L7k9ezzGRvzC/x1V3650rUk3c3AOjQyGYyF9BDxQQDK2ElmKOZRD0CbtdkMzQQ==", + "@typescript-eslint/parser": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.19.0.tgz", + "integrity": "sha512-yhktJjMCJX8BSBczh1F/uY8wGRYrBeyn84kH6oyqdIJwTGKmzX5Qiq49LRQ0Jh0LXnWijEziSo6BRqny8nqLVQ==", "dev": true, "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.14.0", - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/typescript-estree": "4.14.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "@typescript-eslint/scope-manager": "5.19.0", + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/typescript-estree": "5.19.0", + "debug": "^4.3.2" } }, - "@typescript-eslint/parser": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.14.0.tgz", - "integrity": "sha512-sUDeuCjBU+ZF3Lzw0hphTyScmDDJ5QVkyE21pRoBo8iDl7WBtVFS+WDN3blY1CH3SBt7EmYCw6wfmJjF0l/uYg==", + "@typescript-eslint/scope-manager": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.19.0.tgz", + "integrity": "sha512-Fz+VrjLmwq5fbQn5W7cIJZ066HxLMKvDEmf4eu1tZ8O956aoX45jAuBB76miAECMTODyUxH61AQM7q4/GOMQ5g==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.14.0", - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/typescript-estree": "4.14.0", - "debug": "^4.1.1" + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/visitor-keys": "5.19.0" } }, - "@typescript-eslint/scope-manager": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.14.0.tgz", - "integrity": "sha512-/J+LlRMdbPh4RdL4hfP1eCwHN5bAhFAGOTsvE6SxsrM/47XQiPSgF5MDgLyp/i9kbZV9Lx80DW0OpPkzL+uf8Q==", + "@typescript-eslint/type-utils": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.19.0.tgz", + "integrity": "sha512-O6XQ4RI4rQcBGshTQAYBUIGsKqrKeuIOz9v8bckXZnSeXjn/1+BDZndHLe10UplQeJLXDNbaZYrAytKNQO2T4Q==", "dev": true, "requires": { - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/visitor-keys": "4.14.0" + "@typescript-eslint/utils": "5.19.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.14.0.tgz", - "integrity": "sha512-VsQE4VvpldHrTFuVPY1ZnHn/Txw6cZGjL48e+iBxTi2ksa9DmebKjAeFmTVAYoSkTk7gjA7UqJ7pIsyifTsI4A==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.19.0.tgz", + "integrity": "sha512-zR1ithF4Iyq1wLwkDcT+qFnhs8L5VUtjgac212ftiOP/ZZUOCuuF2DeGiZZGQXGoHA50OreZqLH5NjDcDqn34w==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.0.tgz", - "integrity": "sha512-wRjZ5qLao+bvS2F7pX4qi2oLcOONIB+ru8RGBieDptq/SudYwshveORwCVU4/yMAd4GK7Fsf8Uq1tjV838erag==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.19.0.tgz", + "integrity": "sha512-dRPuD4ocXdaE1BM/dNR21elSEUPKaWgowCA0bqJ6YbYkvtrPVEvZ+zqcX5a8ECYn3q5iBSSUcBBD42ubaOp0Hw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.14.0", - "@typescript-eslint/visitor-keys": "4.14.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/visitor-keys": "5.19.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" }, "dependencies": { "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -8361,14 +8521,28 @@ } } }, + "@typescript-eslint/utils": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.19.0.tgz", + "integrity": "sha512-ZuEckdupXpXamKvFz/Ql8YnePh2ZWcwz7APICzJL985Rp5C2AYcHO62oJzIqNhAMtMK6XvrlBTZeNG8n7gS3lQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.19.0", + "@typescript-eslint/types": "5.19.0", + "@typescript-eslint/typescript-estree": "5.19.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, "@typescript-eslint/visitor-keys": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.0.tgz", - "integrity": "sha512-MeHHzUyRI50DuiPgV9+LxcM52FCJFYjJiWHtXlbyC27b80mfOwKeiKI+MHOTEpcpfmoPFm/vvQS88bYIx6PZTA==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.19.0.tgz", + "integrity": "sha512-Ym7zZoMDZcAKWsULi2s7UMLREdVQdScPQ/fKWMYefarCztWlHPFVJo8racf8R0Gc8FAEJ2eD4of8As1oFtnQlQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.14.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.19.0", + "eslint-visitor-keys": "^3.0.0" } }, "@ungap/promise-all-settled": { @@ -8378,28 +8552,18 @@ "dev": true }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true }, "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "requires": {} }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -8419,9 +8583,9 @@ "dev": true }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { @@ -8434,50 +8598,32 @@ } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "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 }, "array-includes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", - "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "get-intrinsic": "^1.0.1", - "is-string": "^1.0.5" + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" } }, "array-timsort": { @@ -8493,14 +8639,27 @@ "dev": true }, "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, "assertion-error": { @@ -8509,53 +8668,49 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true + "babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + } }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "dev": true, "requires": { - "object.assign": "^4.1.0" + "@babel/helper-define-polyfill-provider": "^0.3.1" } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "binary-extensions": { @@ -8590,51 +8745,42 @@ "dev": true }, "browserslist": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", - "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001173", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.634", + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", "escalade": "^3.1.1", - "node-releases": "^1.1.69" + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" } }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "c8": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", + "integrity": "sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw==", "dev": true, "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.2", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.0.1", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.0.2", + "rimraf": "^3.0.0", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^8.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.7" } }, "call-bind": { @@ -8654,28 +8800,29 @@ "dev": true }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, "caniuse-lite": { - "version": "1.0.30001179", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz", - "integrity": "sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA==", + "version": "1.0.30001332", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", + "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==", "dev": true }, "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", "deep-eql": "^3.0.1", "get-func-name": "^2.0.0", - "pathval": "^1.1.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", "type-detect": "^4.0.5" } }, @@ -8697,78 +8844,107 @@ "dev": true }, "chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" } }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true + "clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", + "dev": true, + "requires": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + } }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "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 }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "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, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "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, "requires": { - "ansi-regex": "^4.1.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -8784,26 +8960,14 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", - "dev": true - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, "comment-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.1.0.tgz", - "integrity": "sha512-WEghmVYaNq9NlWbrkzQTSsya9ycLyxJxpTQfZEan6a5Jomnjw18zS3Podf8q1Zf9BvonvQd/+Z7Z39L7KKzzdQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.2.tgz", + "integrity": "sha512-H8T+kl3nZesZu41zO2oNXIJWojNeK3mHxCLrsBNu6feksBXsgb+PtYz5daP5P86A0F3sz3840KVYehr04enISQ==", "dev": true, "requires": { "array-timsort": "^1.0.3", - "core-util-is": "^1.0.2", + "core-util-is": "^1.0.3", "esprima": "^4.0.1", "has-own-prop": "^2.0.0", "repeat-string": "^1.6.1" @@ -8843,37 +9007,25 @@ "requires": { "semver": "^6.0.0" } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true } } }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" } }, "core-js-compat": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz", - "integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==", + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", + "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", "dev": true, "requires": { - "browserslist": "^4.16.1", + "browserslist": "^4.19.1", "semver": "7.0.0" }, "dependencies": { @@ -8886,11 +9038,24 @@ } }, "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -8909,21 +9074,26 @@ "dev": true }, "cspell": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.1.3.tgz", - "integrity": "sha512-pZ5EecESCQUmV1pD6/ehBjS+iNUfoJDjH22TCVF1P+ClHvtkiStSxIAtBPdzrVuFyUtYxTB5m6DnHInoVhx7eQ==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "commander": "^6.2.1", - "comment-json": "^4.1.0", - "cspell-glob": "^5.1.3", - "cspell-lib": "^5.1.3", - "fs-extra": "^9.0.1", + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.19.7.tgz", + "integrity": "sha512-7/y+k708tv68+5lpN23Ew1/djx/EnG838zZ8W2ZDWCc6uRHutqRhpxsjMZr/MT3RHN44iKUj2MgT5+sfnhr4eg==", + "dev": true, + "requires": { + "@cspell/cspell-pipe": "^5.19.7", + "chalk": "^4.1.2", + "commander": "^9.1.0", + "cspell-gitignore": "^5.19.7", + "cspell-glob": "^5.19.7", + "cspell-lib": "^5.19.7", + "fast-json-stable-stringify": "^2.1.0", + "file-entry-cache": "^6.0.1", + "fs-extra": "^10.0.1", "get-stdin": "^8.0.0", - "glob": "^7.1.6", - "minimatch": "^3.0.4", - "strip-ansi": "^6.0.0" + "glob": "^7.2.0", + "imurmurhash": "^0.1.4", + "semver": "^7.3.6", + "strip-ansi": "^6.0.1", + "vscode-uri": "^3.0.3" }, "dependencies": { "ansi-styles": { @@ -8936,9 +9106,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8960,12 +9130,27 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "commander": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.1.0.tgz", + "integrity": "sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8977,74 +9162,82 @@ } } }, - "cspell-glob": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-5.1.3.tgz", - "integrity": "sha512-l9N6nb2yU+rhU+IAPmFdxDvblYbZCc1LAyk3MxmvoY7N+eKgrF7ZG8G85029qmVI8eepEMP0UxBHLeV9GDC2TA==", + "cspell-gitignore": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.19.7.tgz", + "integrity": "sha512-rEqlN6wigNj4P/4Z3QCI1P56KhKkPtXNBpGMXC5CbxIK/NTtn3cLaqHKIZp92pypEnU077lxSCSqRRYCPbg/6A==", "dev": true, "requires": { - "micromatch": "^4.0.2" + "cspell-glob": "^5.19.7", + "find-up": "^5.0.0" } }, - "cspell-io": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-5.1.3.tgz", - "integrity": "sha512-B62hnk5O1p54MW9Gm72ulivjyEKKxpO6mnv01Q8Im+vsdJdJHyBoIBDaT1Y/qGh3Nd4CgbhvcXvWIT2vzbx/ag==", + "cspell-glob": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-5.19.7.tgz", + "integrity": "sha512-fqlF7oqYTT2A3SRfQr7gzN21fwPoRO9IGKec1L3QeGkni5UPDxGrM2a5z+oLaYs2GN5pEf29BXVlN7dq0jVxIg==", "dev": true, "requires": { - "iconv-lite": "^0.6.2", - "iterable-to-stream": "^1.0.1" + "micromatch": "^4.0.5" } }, + "cspell-io": { + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-5.19.7.tgz", + "integrity": "sha512-SEy8XkuOhvwleGjh336EBYj5HlH1J5FrCI5GxxGiU2g8zvWlBPQmaCfQPPO4tnDrrXtK76rZvolBu1jfCmWwQA==", + "dev": true + }, "cspell-lib": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.1.3.tgz", - "integrity": "sha512-/jXWiZHMzRWcLT3ErxVOpRETUnwXqYMD5vkKiUYiQOsDz54p9odR1r+Y4hMUsQLK29506UDiKBVkYrhCNyPuWA==", + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.19.7.tgz", + "integrity": "sha512-d4ewH1RBgcBE9NqAh0FexmVQ6YvkDQv9XOysskeDH+G9wm975owENUU/mBd8AyBt2b4YXL/FoLtaKd/7MRoNDA==", "dev": true, "requires": { - "@cspell/cspell-bundled-dicts": "^5.1.0", - "comment-json": "^4.1.0", + "@cspell/cspell-bundled-dicts": "^5.19.7", + "@cspell/cspell-pipe": "^5.19.7", + "@cspell/cspell-types": "^5.19.7", + "clear-module": "^4.1.2", + "comment-json": "^4.2.2", "configstore": "^5.0.1", - "cspell-io": "^5.1.3", - "cspell-trie-lib": "^5.1.3", - "cspell-util-bundle": "^5.1.3", - "fs-extra": "^9.0.1", + "cosmiconfig": "^7.0.1", + "cspell-glob": "^5.19.7", + "cspell-io": "^5.19.7", + "cspell-trie-lib": "^5.19.7", + "fast-equals": "^3.0.1", + "find-up": "^5.0.0", + "fs-extra": "^10.0.1", "gensequence": "^3.1.1", - "minimatch": "^3.0.4", + "import-fresh": "^3.3.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", - "vscode-uri": "^3.0.2" + "vscode-languageserver-textdocument": "^1.0.4", + "vscode-uri": "^3.0.3" } }, "cspell-trie-lib": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.1.3.tgz", - "integrity": "sha512-rNfPZpBwCDsZuK2CJFxjFTk2WnbFfscWyAWN3djyKPbt1TZen0dd/kIPOIzAZxhealx+xfvJwt0kk2nZq5g8Lg==", + "version": "5.19.7", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.19.7.tgz", + "integrity": "sha512-qr0HS2hGuyIQhDGG5li0nqIjVi039iPRHR8wpeDoSO0YIBCll22i/VlvW3CSmqXLaP5RRoAc9txiZkIGob6DkQ==", "dev": true, "requires": { - "fs-extra": "^9.0.1", + "@cspell/cspell-pipe": "^5.19.7", + "fs-extra": "^10.0.1", "gensequence": "^3.1.1" } }, - "cspell-util-bundle": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/cspell-util-bundle/-/cspell-util-bundle-5.1.3.tgz", - "integrity": "sha512-FDxs0sw4gYMKKHdSobypvLQTRsZB96n9QNewRuyMv6nVwOcD1JsboClMpYigeE3rxBvyiGbj0V+Vf94+RTWWWA==", - "dev": true - }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" } }, "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, "deep-eql": { @@ -9057,20 +9250,11 @@ } }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" - } - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -9081,9 +9265,9 @@ } }, "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, "dir-glob": { @@ -9114,26 +9298,11 @@ } }, "electron-to-chromium": { - "version": "1.3.643", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.643.tgz", - "integrity": "sha512-TGomM4gj8adt/uqRgPbu9F0yhUVAR1deww5X0fvbQgpGr9suSMjLgc4IwQ9YKGkp1t03cDbZum20OfAkiTYjAg==", - "dev": true - }, - "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==", + "version": "1.4.107", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.107.tgz", + "integrity": "sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg==", "dev": true }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -9144,25 +9313,40 @@ } }, "es-abstract": { - "version": "1.18.0-next.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", - "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.1", - "object-inspect": "^1.9.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.3", - "string.prototype.trimstart": "^1.0.3" + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" } }, "es-to-primitive": { @@ -9176,12 +9360,6 @@ "is-symbol": "^1.0.2" } }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -9195,46 +9373,44 @@ "dev": true }, "eslint": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", - "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.13.0.tgz", + "integrity": "sha512-D+Xei61eInqauAyTJ6C0q6x9mx7kTUC1KZ0m0LSEexR0V+e94K12LmWX076ZIsldwfQ2RONdaJe0re0TRGQbRQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.3.0", + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.2.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^6.0.0", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.20", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -9249,9 +9425,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -9273,13 +9449,38 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "has-flag": { @@ -9288,15 +9489,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9305,59 +9497,102 @@ "requires": { "has-flag": "^4.0.0" } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true } } }, "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "debug": "^3.2.7", + "resolve": "^1.20.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "dev": true, "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" + "debug": "^3.2.7", + "find-up": "^2.1.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "ms": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true } } @@ -9370,37 +9605,44 @@ "requires": { "eslint-utils": "^2.0.0", "regexpp": "^3.0.0" - } - }, - "eslint-plugin-flowtype": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.2.0.tgz", - "integrity": "sha512-z7ULdTxuhlRJcEe1MVljePXricuPOrsWfScRXFhNzVD5dmTHWjIF57AxD0e7AbEoLSbjSsaA5S+hCg43WvpXJQ==", - "dev": true, - "requires": { - "lodash": "^4.17.15", - "string-natural-compare": "^3.0.1" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "eslint-plugin-import": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", - "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.0", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "dependencies": { "debug": { @@ -9413,13 +9655,12 @@ } }, "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "^2.0.2" } }, "ms": { @@ -9433,39 +9674,102 @@ "eslint-plugin-internal-rules": { "version": "file:resources/eslint-internal-rules" }, - "eslint-plugin-istanbul": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-istanbul/-/eslint-plugin-istanbul-0.1.2.tgz", - "integrity": "sha512-lkH0DnPxdPUZ9HMG8wpcJcl481IXRHJX1Jj1SqTWtiNgeuz/s2OOJLbCEyrIoz4HJxC4OOS4tbbGOlqeovqHaw==", + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-plugin-react": { + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz", + "integrity": "sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.4.0.tgz", + "integrity": "sha512-U3RVIfdzJaeKDQKEJbz5p3NW8/L80PCATJAfuojwbaEL+gBjfGdhUcGde+WGUW46Q5sr/NgxevsIiDtNXrvZaQ==", + "dev": true, + "requires": {} + }, + "eslint-plugin-simple-import-sort": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz", + "integrity": "sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==", "dev": true, "requires": {} }, - "eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "eslint-plugin-tsdoc": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.16.tgz", + "integrity": "sha512-F/RWMnyDQuGlg82vQEFHQtGyWi7++XJKdYNn0ulIbyMOFqYIjoJOUdE6olORxgwgLkpJxsCJpJbTHgxJ/ggfXw==", "dev": true, "requires": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "@microsoft/tsdoc": "0.14.1", + "@microsoft/tsdoc-config": "0.16.1" } }, "eslint-scope": { @@ -9476,48 +9780,48 @@ "requires": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } }, "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "requires": { - "acorn": "^7.4.0", + "acorn": "^8.7.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "eslint-visitor-keys": "^3.3.0" } }, "esprima": { @@ -9527,20 +9831,12 @@ "dev": true }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "esrecurse": { @@ -9550,20 +9846,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -9578,18 +9866,23 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-equals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-3.0.1.tgz", + "integrity": "sha512-J9FxqqC9E/ja0C+SYhoG3Jl6pQuhP92HNcVC75xDEhB+GUzPnjEp3vMfPIxPprYZFfXS5hpVvvPCWUMiDSMS8Q==", + "dev": true + }, "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" } }, "fast-json-stable-stringify": { @@ -9605,18 +9898,18 @@ "dev": true }, "fastq": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", - "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" } }, "file-entry-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", - "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { "flat-cache": "^3.0.4" @@ -9640,60 +9933,6 @@ "commondir": "^1.0.1", "make-dir": "^2.0.0", "pkg-dir": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - } } }, "find-up": { @@ -9723,15 +9962,9 @@ } }, "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "flow-bin": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.142.0.tgz", - "integrity": "sha512-YgiapK/wrJjcgSgOWfoncbZ4vZrZWdHs+p7V9duI9zo4ehW2nM/VRrpSaWoZ+CWu3t+duGyAvupJvC6MM2l07w==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "foreground-child": { @@ -9744,19 +9977,12 @@ "signal-exit": "^3.0.2" } }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true - }, "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", "dev": true, "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" @@ -9769,9 +9995,9 @@ "dev": true }, "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, @@ -9812,9 +10038,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", - "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -9822,22 +10048,26 @@ "has-symbols": "^1.0.1" } }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, "get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -9849,9 +10079,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -9873,31 +10103,23 @@ "dev": true }, "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "growl": { @@ -9915,6 +10137,12 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -9928,19 +10156,18 @@ "dev": true }, "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, - "hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "requires": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" + "has-symbols": "^1.0.2" } }, "he": { @@ -9949,31 +10176,16 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, "import-fresh": { @@ -9986,6 +10198,15 @@ "resolve-from": "^4.0.0" }, "dependencies": { + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -10000,12 +10221,6 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -10028,12 +10243,32 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -10043,26 +10278,39 @@ "binary-extensions": "^2.0.0" } }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, "requires": { "has": "^1.0.3" } }, "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-extglob": { "version": "2.1.1", @@ -10077,18 +10325,18 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true }, "is-number": { @@ -10097,6 +10345,15 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -10109,34 +10366,50 @@ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } }, "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.2" } }, "is-typedarray": { @@ -10145,91 +10418,39 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true }, - "istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "requires": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "call-bind": "^1.0.2" } }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, "istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", @@ -10256,12 +10477,6 @@ "semver": "^6.0.0" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10273,39 +10488,20 @@ } } }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, "requires": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, - "iterable-to-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/iterable-to-stream/-/iterable-to-stream-1.0.1.tgz", - "integrity": "sha512-O62gD5ADMUGtJoOoM9U6LQ7i4byPXUNoHJ6mqsmkQJcom331ZJGDApWgDESWyBMEHEJRjtHozgIiTzYo9RU4UA==", + "jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", "dev": true }, "js-tokens": { @@ -10315,13 +10511,12 @@ "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "jsesc": { @@ -10330,6 +10525,12 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -10343,13 +10544,10 @@ "dev": true }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true }, "jsonfile": { "version": "6.1.0", @@ -10361,6 +10559,22 @@ "universalify": "^2.0.0" } }, + "jsx-ast-utils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.2.tgz", + "integrity": "sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "object.assign": "^4.1.2" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -10371,31 +10585,11 @@ "type-check": "~0.4.0" } }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true }, "locate-path": { "version": "6.0.0", @@ -10406,25 +10600,26 @@ "p-locate": "^5.0.0" } }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "requires": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "dependencies": { "ansi-styles": { @@ -10437,9 +10632,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -10478,6 +10673,24 @@ } } }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -10495,6 +10708,14 @@ "requires": { "pify": "^4.0.1", "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "merge2": { @@ -10504,70 +10725,77 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "mocha": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", - "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "requires": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.1.6", + "glob": "7.2.0", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", + "supports-color": "8.1.1", "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "dependencies": { "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, "escape-string-regexp": { @@ -10582,24 +10810,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true } } }, @@ -10610,9 +10849,9 @@ "dev": true }, "nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true }, "natural-compare": { @@ -10621,233 +10860,28 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, "node-releases": { - "version": "1.1.70", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz", - "integrity": "sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", + "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==", "dev": true }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "requires": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "dev": true }, "object-keys": { @@ -10862,22 +10896,53 @@ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "requires": { "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" + "es-abstract": "^1.19.1" } }, "object.values": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", - "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "es-abstract": "^1.19.1" } }, "once": { @@ -10921,49 +10986,31 @@ "p-limit": "^3.0.2" } }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", "dev": true, "requires": { - "callsites": "^3.0.0" + "callsites": "^3.1.0" } }, "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { - "error-ex": "^1.2.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, "path-exists": { @@ -10985,9 +11032,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { @@ -10997,15 +11044,21 @@ "dev": true }, "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pify": { @@ -11015,66 +11068,57 @@ "dev": true }, "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true }, "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { - "find-up": "^2.1.0" + "find-up": "^3.0.0" }, "dependencies": { "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "^3.0.0" } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -11090,30 +11134,26 @@ "dev": true }, "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "dev": true }, - "process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, "requires": { - "fromentries": "^1.2.0" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, "randombytes": { @@ -11125,99 +11165,16 @@ "safe-buffer": "^5.1.0" } }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "dependencies": { - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "requires": { "picomatch": "^2.2.1" @@ -11230,59 +11187,69 @@ "dev": true }, "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dev": true, "requires": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "dev": true }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dev": true, "requires": { "@babel/runtime": "^7.8.4" } }, + "regexp.prototype.flags": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.2.tgz", + "integrity": "sha512-Ynz8fTQW5/1elh+jWU2EDDzeoNbD0OQ0R+D1VJU5ATOkUaro4A9YEkdN2ODQl/8UQFPPpZNw91fOcLFamM7Pww==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", "dev": true }, "regjsparser": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.6.tgz", - "integrity": "sha512-jjyuCp+IEMIm3N1H1LLTJW1EISEJV9+5oHdEyrt43Pg9cDSb6rrLZei2cVWpl0xTjmmlpec/lEQGYgM7xfpGCQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -11296,15 +11263,6 @@ } } }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -11317,26 +11275,15 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-from": { @@ -11370,10 +11317,13 @@ } }, "run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, "safe-buffer": { "version": "5.1.2", @@ -11381,32 +11331,29 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { "randombytes": "^2.1.0" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } }, "shebang-command": { "version": "2.0.0", @@ -11423,55 +11370,29 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -11479,9 +11400,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -11496,125 +11417,55 @@ } } }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "requires": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" } }, "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "strip-json-comments": { @@ -11632,37 +11483,11 @@ "has-flag": "^3.0.0" } }, - "table": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", - "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", - "dev": true, - "requires": { - "ajv": "^7.0.2", - "lodash": "^4.17.20", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ajv": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz", - "integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true }, "test-exclude": { "version": "6.0.0", @@ -11697,14 +11522,14 @@ } }, "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { @@ -11716,28 +11541,24 @@ "requires": { "minimist": "^1.2.0" } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true } } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "tsutils": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.19.1.tgz", - "integrity": "sha512-GEdoBf5XI324lu7ycad7s6laADfnAqCw6wLGI+knxvw9vsIYBaJfYdmeCEG3FMMUiSm3OGgNb+m6utsWf5h9Vw==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "type-check": { @@ -11755,12 +11576,6 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -11771,37 +11586,49 @@ } }, "typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true }, "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" } }, "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true }, "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, "unique-string": { @@ -11826,34 +11653,51 @@ "dev": true, "requires": { "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } } }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, "v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } } }, + "vscode-languageserver-textdocument": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz", + "integrity": "sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ==", + "dev": true + }, "vscode-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz", - "integrity": "sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.3.tgz", + "integrity": "sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA==", "dev": true }, "which": { @@ -11865,52 +11709,17 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "requires": { - "string-width": "^1.0.2 || 2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" } }, "word-wrap": { @@ -11920,62 +11729,11 @@ "dev": true }, "workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", "dev": true }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -12001,9 +11759,9 @@ "dev": true }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { @@ -12012,116 +11770,51 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "dependencies": { "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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 }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "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, "requires": { - "ansi-regex": "^4.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } } } }, "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true }, "yargs-unparser": { "version": "2.0.0", @@ -12133,20 +11826,6 @@ "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" - }, - "dependencies": { - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - } } }, "yocto-queue": { diff --git a/package.json b/package.json index 69f4d05f5e..670a0698f3 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,18 @@ { "name": "graphql", - "version": "15.4.0", + "version": "16.10.0", "description": "A Query Language and Runtime which can target any service.", "license": "MIT", "private": true, "main": "index", "module": "index.mjs", - "types": "index.d.ts", + "typesVersions": { + ">=4.1.0": { + "*": [ + "*" + ] + } + }, "sideEffects": false, "homepage": "https://github.com/graphql/graphql-js", "bugs": { @@ -21,51 +27,55 @@ "graphql-js" ], "engines": { - "node": ">= 14.2" - }, - "engines_on_npm": { - "node": ">= 10.x" + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" }, "scripts": { - "preversion": ". ./resources/checkgit.sh && npm ci", - "version": "node resources/gen-version.js && npm test && git add src/version.js", - "fuzzonly": "mocha --full-trace src/**/__tests__/**/*-fuzz.js", + "preversion": "bash -c '. ./resources/checkgit.sh && npm ci --ignore-scripts'", + "version": "node resources/gen-version.js && npm test && git add src/version.ts", + "fuzzonly": "mocha --full-trace src/**/__tests__/**/*-fuzz.ts", "changelog": "node resources/gen-changelog.js", "benchmark": "node benchmark/benchmark.js", - "test": "npm run lint && npm run check && npm run testonly && npm run prettier:check && npm run check:spelling && npm run build:npm && npm run build:deno && npm run check:integrations", - "lint": "eslint --cache .", - "check": "flow check", - "testonly": "mocha --full-trace src/**/__tests__/**/*-test.js", - "testonly:cover": "nyc npm run testonly", + "test": "npm run lint && npm run check && npm run testonly && npm run prettier:check && npm run check:spelling && npm run check:integrations", + "lint": "eslint --cache --max-warnings 0 .", + "check": "tsc --pretty", + "testonly": "mocha --full-trace src/**/__tests__/**/*-test.ts", + "testonly:cover": "c8 npm run testonly", "prettier": "prettier --write --list-different .", "prettier:check": "prettier --check .", - "check:spelling": "cspell '**/*'", - "check:integrations": "mocha --full-trace integrationTests/*-test.js", + "check:spelling": "cspell --cache --no-progress '**/*'", + "check:integrations": "npm run build:npm && npm run build:deno && mocha --full-trace integrationTests/*-test.js", "build:npm": "node resources/build-npm.js", "build:deno": "node resources/build-deno.js", "gitpublish:npm": "bash ./resources/gitpublish.sh npm npmDist", "gitpublish:deno": "bash ./resources/gitpublish.sh deno denoDist" }, "devDependencies": { - "@babel/core": "7.12.10", - "@babel/plugin-transform-flow-strip-types": "7.12.10", - "@babel/preset-env": "7.12.11", - "@babel/register": "7.12.10", - "@typescript-eslint/eslint-plugin": "4.14.0", - "@typescript-eslint/parser": "4.14.0", - "babel-eslint": "10.1.0", - "chai": "4.2.0", - "cspell": "5.1.3", - "eslint": "7.18.0", - "eslint-plugin-flowtype": "5.2.0", - "eslint-plugin-import": "2.22.1", + "@babel/core": "7.17.9", + "@babel/plugin-syntax-typescript": "7.16.7", + "@babel/plugin-transform-typescript": "7.16.8", + "@babel/preset-env": "7.16.11", + "@babel/register": "7.17.7", + "@types/chai": "4.3.1", + "@types/mocha": "9.1.0", + "@types/node": "17.0.24", + "@typescript-eslint/eslint-plugin": "5.19.0", + "@typescript-eslint/parser": "5.19.0", + "c8": "7.11.0", + "chai": "4.3.6", + "cspell": "5.19.7", + "eslint": "8.13.0", + "eslint-plugin-import": "2.26.0", "eslint-plugin-internal-rules": "file:./resources/eslint-internal-rules", - "eslint-plugin-istanbul": "0.1.2", "eslint-plugin-node": "11.1.0", - "flow-bin": "0.142.0", - "mocha": "8.2.1", - "nyc": "15.1.0", - "prettier": "2.2.1", - "typescript": "4.1.3" + "eslint-plugin-react": "7.29.4", + "eslint-plugin-react-hooks": "4.4.0", + "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-tsdoc": "0.2.16", + "mocha": "9.2.2", + "prettier": "2.6.2", + "typescript": "4.6.3" + }, + "publishConfig": { + "tag": "latest" } } diff --git a/resources/build-deno.js b/resources/build-deno.js index 1b1685a21a..f0479a858a 100644 --- a/resources/build-deno.js +++ b/resources/build-deno.js @@ -5,10 +5,14 @@ const path = require('path'); const babel = require('@babel/core'); -const { readdirRecursive, showDirStats } = require('./utils'); +const { + writeGeneratedFile, + readdirRecursive, + showDirStats, +} = require('./utils.js'); if (require.main === module) { - fs.rmdirSync('./denoDist', { recursive: true, force: true }); + fs.rmSync('./denoDist', { recursive: true, force: true }); fs.mkdirSync('./denoDist'); const srcFiles = readdirRecursive('./src', { ignoreDir: /^__.*__$/ }); @@ -17,12 +21,10 @@ if (require.main === module) { const destPath = path.join('./denoDist', filepath); fs.mkdirSync(path.dirname(destPath), { recursive: true }); - if (filepath.endsWith('.js')) { + if (filepath.endsWith('.ts')) { const options = { babelrc: false, configFile: './.babelrc-deno.json' }; const output = babel.transformFileSync(srcPath, options).code + '\n'; - fs.writeFileSync(destPath, output); - } else if (filepath.endsWith('.d.ts')) { - fs.copyFileSync(srcPath, destPath); + writeGeneratedFile(destPath, output); } } diff --git a/resources/build-npm.js b/resources/build-npm.js index e39a2c63df..7ff0cf079c 100644 --- a/resources/build-npm.js +++ b/resources/build-npm.js @@ -4,59 +4,112 @@ const fs = require('fs'); const path = require('path'); const assert = require('assert'); +const ts = require('typescript'); const babel = require('@babel/core'); -const { readdirRecursive, showDirStats } = require('./utils'); +const { + writeGeneratedFile, + readdirRecursive, + showDirStats, +} = require('./utils.js'); if (require.main === module) { - fs.rmdirSync('./npmDist', { recursive: true, force: true }); + fs.rmSync('./npmDist', { recursive: true, force: true }); fs.mkdirSync('./npmDist'); + const packageJSON = buildPackageJSON(); + const srcFiles = readdirRecursive('./src', { ignoreDir: /^__.*__$/ }); for (const filepath of srcFiles) { const srcPath = path.join('./src', filepath); const destPath = path.join('./npmDist', filepath); fs.mkdirSync(path.dirname(destPath), { recursive: true }); - if (filepath.endsWith('.js')) { - const flowBody = '// @flow strict\n' + fs.readFileSync(srcPath, 'utf-8'); - fs.writeFileSync(destPath + '.flow', flowBody); - + if (filepath.endsWith('.ts')) { const cjs = babelBuild(srcPath, { envName: 'cjs' }); - fs.writeFileSync(destPath, cjs); + writeGeneratedFile(destPath.replace(/\.ts$/, '.js'), cjs); const mjs = babelBuild(srcPath, { envName: 'mjs' }); - fs.writeFileSync(destPath.replace(/\.js$/, '.mjs'), mjs); - } else if (filepath.endsWith('.d.ts')) { - fs.copyFileSync(srcPath, destPath); + writeGeneratedFile(destPath.replace(/\.ts$/, '.mjs'), mjs); } } + // Based on https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#getting-the-dts-from-a-javascript-file + const tsConfig = JSON.parse( + fs.readFileSync(require.resolve('../tsconfig.json'), 'utf-8'), + ); + assert( + tsConfig.compilerOptions, + '"tsconfig.json" should have `compilerOptions`', + ); + const tsOptions = { + ...tsConfig.compilerOptions, + noEmit: false, + declaration: true, + declarationDir: './npmDist', + emitDeclarationOnly: true, + }; + + const tsHost = ts.createCompilerHost(tsOptions); + tsHost.writeFile = (filepath, body) => { + writeGeneratedFile(filepath, body); + }; + + const tsProgram = ts.createProgram(['src/index.ts'], tsOptions, tsHost); + const tsResult = tsProgram.emit(); + assert( + !tsResult.emitSkipped, + 'Fail to generate `*.d.ts` files, please run `npm run check`', + ); + + assert(packageJSON.types === undefined, 'Unexpected "types" in package.json'); + const supportedTSVersions = Object.keys(packageJSON.typesVersions); + assert( + supportedTSVersions.length === 1, + 'Property "typesVersions" should have exactly one key.', + ); + // TODO: revisit once TS implements https://github.com/microsoft/TypeScript/issues/32166 + const notSupportedTSVersionFile = 'NotSupportedTSVersion.d.ts'; + fs.writeFileSync( + path.join('./npmDist', notSupportedTSVersionFile), + // Provoke syntax error to show this message + `"Package 'graphql' support only TS versions that are ${supportedTSVersions[0]}".`, + ); + packageJSON.typesVersions = { + ...packageJSON.typesVersions, + '*': { '*': [notSupportedTSVersionFile] }, + }; + fs.copyFileSync('./LICENSE', './npmDist/LICENSE'); fs.copyFileSync('./README.md', './npmDist/README.md'); // Should be done as the last step so only valid packages can be published - const packageJSON = buildPackageJSON(); - fs.writeFileSync( - './npmDist/package.json', - JSON.stringify(packageJSON, null, 2), - ); + writeGeneratedFile('./npmDist/package.json', JSON.stringify(packageJSON)); showDirStats('./npmDist'); } function babelBuild(srcPath, options) { - return babel.transformFileSync(srcPath, options).code + '\n'; + const { code } = babel.transformFileSync(srcPath, { + babelrc: false, + configFile: './.babelrc-npm.json', + ...options, + }); + return code + '\n'; } function buildPackageJSON() { - const packageJSON = require('../package.json'); + const packageJSON = JSON.parse( + fs.readFileSync(require.resolve('../package.json'), 'utf-8'), + ); + delete packageJSON.private; delete packageJSON.scripts; delete packageJSON.devDependencies; - packageJSON.engines = packageJSON.engines_on_npm; - delete packageJSON.engines_on_npm; + // TODO: move to integration tests + const publishTag = packageJSON.publishConfig?.tag; + assert(publishTag != null, 'Should have packageJSON.publishConfig defined!'); const { version } = packageJSON; const versionMatch = /^\d+\.\d+\.\d+-?(?.*)?$/.exec(version); @@ -67,14 +120,19 @@ function buildPackageJSON() { const { preReleaseTag } = versionMatch.groups; if (preReleaseTag != null) { - const [tag] = preReleaseTag.split('.'); + const splittedTag = preReleaseTag.split('.'); + // Note: `experimental-*` take precedence over `alpha`, `beta` or `rc`. + const versionTag = splittedTag[2] ?? splittedTag[0]; assert( - tag.startsWith('experimental-') || ['alpha', 'beta', 'rc'].includes(tag), - `"${tag}" tag is supported.`, + ['alpha', 'beta', 'rc'].includes(versionTag) || + versionTag.startsWith('experimental-'), + `"${versionTag}" tag is not supported.`, + ); + assert.equal( + versionTag, + publishTag, + 'Publish tag and version tag should match!', ); - - assert(!packageJSON.publishConfig, 'Can not override "publishConfig".'); - packageJSON.publishConfig = { tag: tag || 'latest' }; } return packageJSON; diff --git a/resources/check-cycles.js b/resources/check-cycles.js deleted file mode 100644 index e5f0385d5f..0000000000 --- a/resources/check-cycles.js +++ /dev/null @@ -1,61 +0,0 @@ -'use strict'; - -const os = require('os'); -const fs = require('fs'); -const path = require('path'); -const assert = require('assert'); - -const { exec } = require('./utils'); - -const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'flow-dep-graph')); -const tmpFile = path.join(tmpDir, 'out.dot'); - -exec(`npx flow graph dep-graph --quiet --strip-root --out ${tmpFile}`); -const dot = fs.readFileSync(tmpFile, 'utf-8'); -assert(dot.startsWith('digraph {\n') && dot.endsWith('\n}')); -const dotLines = dot.split('\n').slice(1, -1); - -let depGraph = []; -for (const line of dotLines) { - const [, from, to] = line.trim().match(/^"(.*?)" -> "(.*?)"$/); - assert(from && to); - depGraph.push([from, to]); -} - -for (const [from, to] of depGraph) { - if ( - path.basename(to) === 'index.js' && - !path.dirname(to).endsWith('__fixtures__') && - path.basename(from) !== 'index.js' - ) { - console.log(from); - } -} - -let removedEdges; -do { - removedEdges = 0; - const fromFiles = new Set(); - const toFiles = new Set(); - - for (const [from, to] of depGraph) { - fromFiles.add(from); - toFiles.add(to); - } - - console.log(depGraph.length); - // eslint-disable-next-line no-loop-func - depGraph = depGraph.filter(([from, to]) => { - if (!toFiles.has(from) || !fromFiles.has(to)) { - ++removedEdges; - return false; - } - return true; - }); -} while (removedEdges > 0); - -console.log('digraph {'); -for (const [from, to] of depGraph) { - console.log(` "${from}" -> "${to}"`); -} -console.log('}'); diff --git a/resources/checkgit.sh b/resources/checkgit.sh index ef853bb6dd..e5e4c67cf2 100644 --- a/resources/checkgit.sh +++ b/resources/checkgit.sh @@ -1,4 +1,5 @@ # Exit immediately if any subcommand terminated +set -e trap "exit 1" ERR # @@ -8,6 +9,14 @@ trap "exit 1" ERR # and including any changes on main. # +# Check that local copy has no modifications +GIT_MODIFIED_FILES=$(git ls-files -dm 2> /dev/null); +GIT_STAGED_FILES=$(git diff --cached --name-only 2> /dev/null); +if [ "$GIT_MODIFIED_FILES" != "" -o "$GIT_STAGED_FILES" != "" ]; then + read -p "Git has local modifications. Continue? (y|N) " yn; + if [ "$yn" != "y" ]; then exit 1; fi; +fi; + # First fetch to ensure git is up to date. Fail-fast if this fails. git fetch; if [[ $? -ne 0 ]]; then exit 1; fi; diff --git a/resources/diff-npm-package.js b/resources/diff-npm-package.js new file mode 100644 index 0000000000..c0d8d8c991 --- /dev/null +++ b/resources/diff-npm-package.js @@ -0,0 +1,104 @@ +'use strict'; + +const os = require('os'); +const fs = require('fs'); +const path = require('path'); +const cp = require('child_process'); + +const LOCAL = 'local'; +const localRepoDir = path.join(__dirname, '..'); +const tmpDir = path.join(os.tmpdir(), 'graphql-js-npm-diff'); +fs.rmSync(tmpDir, { recursive: true, force: true }); +fs.mkdirSync(tmpDir); + +const args = process.argv.slice(2); +let [fromRevision, toRevision] = args; +if (args.length < 2) { + fromRevision = fromRevision ?? 'HEAD'; + toRevision = toRevision ?? LOCAL; + console.warn( + `Assuming you meant: diff-npm-package ${fromRevision} ${toRevision}`, + ); +} + +console.log(`📦 Building NPM package for ${fromRevision}...`); +const fromPackage = prepareNPMPackage(fromRevision); + +console.log(`📦 Building NPM package for ${toRevision}...`); +const toPackage = prepareNPMPackage(toRevision); + +console.log('➖➕ Generating diff...'); +const diff = exec(`npm diff --diff=${fromPackage} --diff=${toPackage}`); + +if (diff === '') { + console.log('No changes found!'); +} else { + const reportPath = path.join(localRepoDir, 'npm-dist-diff.html'); + fs.writeFileSync(reportPath, generateReport(diff), 'utf-8'); + console.log('Report saved to: ', reportPath); +} + +function generateReport(diffString) { + return ` + + + + + + + + + + + +

+ + + `; +} +function prepareNPMPackage(revision) { + if (revision === LOCAL) { + exec('npm --quiet run build:npm', { cwd: localRepoDir }); + return path.join(localRepoDir, 'npmDist'); + } + + // Returns the complete git hash for a given git revision reference. + const hash = exec(`git rev-parse "${revision}"`); + + const repoDir = path.join(tmpDir, hash); + fs.rmSync(repoDir, { recursive: true, force: true }); + fs.mkdirSync(repoDir); + exec(`git archive "${hash}" | tar -xC "${repoDir}"`); + exec('npm --quiet ci --ignore-scripts', { cwd: repoDir }); + exec('npm --quiet run build:npm', { cwd: repoDir }); + return path.join(repoDir, 'npmDist'); +} + +function exec(command, options = {}) { + const result = cp.execSync(command, { + encoding: 'utf-8', + stdio: ['inherit', 'pipe', 'inherit'], + ...options, + }); + return result?.trimEnd(); +} diff --git a/resources/eslint-internal-rules/index.js b/resources/eslint-internal-rules/index.js index dcb9e34965..4acc530f3a 100644 --- a/resources/eslint-internal-rules/index.js +++ b/resources/eslint-internal-rules/index.js @@ -1,7 +1,13 @@ 'use strict'; +const onlyASCII = require('./only-ascii.js'); +const noDirImport = require('./no-dir-import.js'); +const requireToStringTag = require('./require-to-string-tag.js'); + module.exports = { rules: { - 'no-dir-import': require('./no-dir-import'), + 'only-ascii': onlyASCII, + 'no-dir-import': noDirImport, + 'require-to-string-tag': requireToStringTag, }, }; diff --git a/resources/eslint-internal-rules/no-dir-import.js b/resources/eslint-internal-rules/no-dir-import.js index 156a4e9741..5322039875 100644 --- a/resources/eslint-internal-rules/no-dir-import.js +++ b/resources/eslint-internal-rules/no-dir-import.js @@ -3,7 +3,7 @@ const fs = require('fs'); const path = require('path'); -module.exports = function (context) { +module.exports = function noDirImportRule(context) { return { ImportDeclaration: checkImportPath, ExportNamedDeclaration: checkImportPath, diff --git a/resources/eslint-internal-rules/only-ascii.js b/resources/eslint-internal-rules/only-ascii.js new file mode 100644 index 0000000000..f5ddbe1b68 --- /dev/null +++ b/resources/eslint-internal-rules/only-ascii.js @@ -0,0 +1,39 @@ +'use strict'; + +module.exports = { + meta: { + schema: [ + { + type: 'object', + properties: { + allowEmoji: { + type: 'boolean', + }, + }, + additionalProperties: false, + }, + ], + }, + create: onlyASCII, +}; + +function onlyASCII(context) { + const regExp = + context.options[0]?.allowEmoji === true + ? /[^\p{ASCII}\p{Emoji}]+/gu + : /\P{ASCII}+/gu; + + return { + Program() { + const sourceCode = context.getSourceCode(); + const text = sourceCode.getText(); + + for (const match of text.matchAll(regExp)) { + context.report({ + loc: sourceCode.getLocFromIndex(match.index), + message: `Non-ASCII character "${match[0]}" found.`, + }); + } + }, + }; +} diff --git a/resources/eslint-internal-rules/package.json b/resources/eslint-internal-rules/package.json index 60cbef8ee9..5912b1453e 100644 --- a/resources/eslint-internal-rules/package.json +++ b/resources/eslint-internal-rules/package.json @@ -1,4 +1,8 @@ { "name": "eslint-plugin-graphql-internal", - "version": "0.0.0" + "version": "0.0.0", + "private": true, + "engines": { + "node": ">= 14.0.0" + } } diff --git a/resources/eslint-internal-rules/require-to-string-tag.js b/resources/eslint-internal-rules/require-to-string-tag.js new file mode 100644 index 0000000000..517fd07eb3 --- /dev/null +++ b/resources/eslint-internal-rules/require-to-string-tag.js @@ -0,0 +1,37 @@ +'use strict'; + +module.exports = function requireToStringTag(context) { + const sourceCode = context.getSourceCode(); + + return { + 'ExportNamedDeclaration > ClassDeclaration': (classNode) => { + const properties = classNode.body.body; + if (properties.some(isToStringTagProperty)) { + return; + } + + const jsDoc = context.getJSDocComment(classNode)?.value; + // FIXME: use proper TSDoc parser instead of includes once we fix TSDoc comments + if (jsDoc?.includes('@internal') === true) { + return; + } + + context.report({ + node: classNode, + message: + 'All classes in public API required to have [Symbol.toStringTag] method', + }); + }, + }; + + function isToStringTagProperty(propertyNode) { + if ( + propertyNode.type !== 'MethodDefinition' || + propertyNode.kind !== 'get' + ) { + return false; + } + const keyText = sourceCode.getText(propertyNode.key); + return keyText === 'Symbol.toStringTag'; + } +}; diff --git a/resources/gen-changelog.js b/resources/gen-changelog.js index 48a3cf366a..02bb634050 100644 --- a/resources/gen-changelog.js +++ b/resources/gen-changelog.js @@ -5,13 +5,16 @@ const https = require('https'); const packageJSON = require('../package.json'); -const { exec } = require('./utils'); +const { exec } = require('./utils.js'); const graphqlRequest = util.promisify(graphqlRequestImpl); const labelsConfig = { 'PR: breaking change 💥': { section: 'Breaking Change 💥', }, + 'PR: deprecation ⚠': { + section: 'Deprecation ⚠', + }, 'PR: feature 🚀': { section: 'New Feature 🚀', }, @@ -47,9 +50,10 @@ if (!packageJSON.repository || typeof packageJSON.repository.url !== 'string') { process.exit(1); } -const repoURLMatch = /https:\/\/github.com\/(?[^/]+)\/(?[^/]+).git/.exec( - packageJSON.repository.url, -); +const repoURLMatch = + /https:\/\/github.com\/(?[^/]+)\/(?[^/]+).git/.exec( + packageJSON.repository.url, + ); if (repoURLMatch == null) { console.error('Cannot extract organization and repo name from repo URL!'); process.exit(1); diff --git a/resources/gen-version.js b/resources/gen-version.js index 0141ff3597..b73621bce7 100644 --- a/resources/gen-version.js +++ b/resources/gen-version.js @@ -1,9 +1,9 @@ 'use strict'; -const fs = require('fs'); - const { version } = require('../package.json'); +const { writeGeneratedFile } = require('./utils.js'); + const versionMatch = /^(\d+)\.(\d+)\.(\d+)-?(.*)?$/.exec(version); if (!versionMatch) { throw new Error('Version does not match semver spec: ' + version); @@ -11,27 +11,28 @@ if (!versionMatch) { const [, major, minor, patch, preReleaseTag] = versionMatch; -const body = `/** - * Note: This file is autogenerated using "resources/gen-version.js" script and - * automatically updated by "npm version" command. - */ +const body = ` +// Note: This file is autogenerated using "resources/gen-version.js" script and +// automatically updated by "npm version" command. /** * A string containing the version of the GraphQL.js library */ -export const version = '${version}'; +export const version = '${version}' as string; /** * An object containing the components of the GraphQL.js version string */ export const versionInfo = Object.freeze({ - major: ${major}, - minor: ${minor}, - patch: ${patch}, - preReleaseTag: ${preReleaseTag ? `'${preReleaseTag}'` : 'null'}, + major: ${major} as number, + minor: ${minor} as number, + patch: ${patch} as number, + preReleaseTag: ${ + preReleaseTag ? `'${preReleaseTag}'` : 'null' + } as string | null, }); `; if (require.main === module) { - fs.writeFileSync('./src/version.js', body); + writeGeneratedFile('./src/version.ts', body); } diff --git a/resources/gitpublish.sh b/resources/gitpublish.sh deleted file mode 100755 index c88597fc86..0000000000 --- a/resources/gitpublish.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# This script maintains a git branch which mirrors main but in a form that -# what will eventually be deployed to npm, allowing npm dependencies to use: -# -# "graphql": "git://github.com/graphql/graphql-js.git#npm" -# -# Additionally it use use to push Deno build to `deno` branch. - -BRANCH=$1 -DIST_DIR=$2 - -# Exit immediately if any subcommand terminated -set -e - -if [ -z "${BRANCH}" ]; then - echo 'Must provide BRANCH as first argument!' - exit 1; -fi; - -if [ -z "${DIST_DIR}" ]; then - echo 'Must provide DIST_DIR as second argument!' - exit 1; -fi; - -if [ -z "${GH_TOKEN}" ]; then - echo 'Must provide GH_TOKEN as environment variable!' - exit 1; -fi; - -if [ ! -d $DIST_DIR ]; then - echo "Directory '${DIST_DIR}' does not exist!" - exit 1; -fi; - -# Create empty directory -rm -rf $BRANCH -git clone -b $BRANCH -- "https://${GH_TOKEN}@github.com/graphql/graphql-js.git" $BRANCH - -# Remove existing files first -rm -rf $BRANCH/**/* -rm -rf $BRANCH/* - -# Copy over necessary files -cp -r $DIST_DIR/* $BRANCH/ - -# Reference current commit -HEAD_REV=`git rev-parse HEAD` -echo $HEAD_REV - -# Deploy -cd $BRANCH -git config user.name "GitHub Action Script" -git config user.email "please@open.issue" -git add -A . -if git diff --staged --quiet; then - echo "Nothing to publish" -else - git commit -a -m "Deploy $HEAD_REV to '$BRANCH' branch" - git push > /dev/null 2>&1 - echo "Pushed" -fi diff --git a/resources/inline-invariant.js b/resources/inline-invariant.js index c17367c8e0..d3f5a1b6f0 100644 --- a/resources/inline-invariant.js +++ b/resources/inline-invariant.js @@ -9,14 +9,14 @@ * * to: * - * ! ? invariant(0, ...) : undefined; + * () || invariant(false ...) */ module.exports = function inlineInvariant(context) { const invariantTemplate = context.template(` - (%%cond%%) || invariant(0, %%args%%) + (%%cond%%) || invariant(false, %%args%%) `); const assertTemplate = context.template(` - (%%cond%%) || devAssert(0, %%args%%) + (%%cond%%) || devAssert(false, %%args%%) `); return { diff --git a/resources/ts-register.js b/resources/ts-register.js new file mode 100644 index 0000000000..649eb5fdd2 --- /dev/null +++ b/resources/ts-register.js @@ -0,0 +1,3 @@ +'use strict'; + +require('@babel/register')({ extensions: ['.ts'] }); diff --git a/resources/utils.js b/resources/utils.js index 6ab659dc3b..37cd83e801 100644 --- a/resources/utils.js +++ b/resources/utils.js @@ -1,35 +1,18 @@ 'use strict'; const fs = require('fs'); -const util = require('util'); const path = require('path'); const childProcess = require('child_process'); +const prettier = require('prettier'); + function exec(command, options) { const output = childProcess.execSync(command, { maxBuffer: 10 * 1024 * 1024, // 10MB encoding: 'utf-8', ...options, }); - return removeTrailingNewLine(output); -} - -const childProcessExec = util.promisify(childProcess.exec); -async function execAsync(command, options) { - const output = await childProcessExec(command, { - maxBuffer: 10 * 1024 * 1024, // 10MB - encoding: 'utf-8', - ...options, - }); - return removeTrailingNewLine(output.stdout); -} - -function removeTrailingNewLine(str) { - if (str == null) { - return str; - } - - return str.split('\n').slice(0, -1).join('\n'); + return output && output.trimEnd(); } function readdirRecursive(dirPath, opts = {}) { @@ -99,9 +82,18 @@ function showDirStats(dirPath) { ); } +const prettierConfig = JSON.parse( + fs.readFileSync(require.resolve('../.prettierrc'), 'utf-8'), +); + +function writeGeneratedFile(filepath, body) { + const formatted = prettier.format(body, { filepath, ...prettierConfig }); + fs.writeFileSync(filepath, formatted); +} + module.exports = { exec, - execAsync, readdirRecursive, showDirStats, + writeGeneratedFile, }; diff --git a/src/__testUtils__/__tests__/dedent-test.js b/src/__testUtils__/__tests__/dedent-test.ts similarity index 64% rename from src/__testUtils__/__tests__/dedent-test.js rename to src/__testUtils__/__tests__/dedent-test.ts index 9ee2440bce..dfaf28e979 100644 --- a/src/__testUtils__/__tests__/dedent-test.js +++ b/src/__testUtils__/__tests__/dedent-test.ts @@ -1,11 +1,11 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../dedent'; +import { dedent, dedentString } from '../dedent'; -describe('dedent', () => { +describe('dedentString', () => { it('removes indentation in typical usage', () => { - const output = dedent` + const output = dedentString(` type Query { me: User } @@ -14,7 +14,7 @@ describe('dedent', () => { id: ID name: String } - `; + `); expect(output).to.equal( [ 'type Query {', @@ -25,94 +25,95 @@ describe('dedent', () => { ' id: ID', ' name: String', '}', - '', ].join('\n'), ); }); it('removes only the first level of indentation', () => { - const output = dedent` + const output = dedentString(` first second third fourth - `; + `); expect(output).to.equal( - ['first', ' second', ' third', ' fourth', ''].join('\n'), + ['first', ' second', ' third', ' fourth'].join('\n'), ); }); it('does not escape special characters', () => { - const output = dedent` + const output = dedentString(` type Root { field(arg: String = "wi\th de\fault"): String } - `; + `); expect(output).to.equal( [ 'type Root {', ' field(arg: String = "wi\th de\fault"): String', '}', - '', ].join('\n'), ); }); it('also removes indentation using tabs', () => { - const output = dedent` + const output = dedentString(` \t\t type Query { \t\t me: User \t\t } - `; - expect(output).to.equal(['type Query {', ' me: User', '}', ''].join('\n')); + `); + expect(output).to.equal(['type Query {', ' me: User', '}'].join('\n')); }); - it('removes leading newlines', () => { - const output = dedent` + it('removes leading and trailing newlines', () => { + const output = dedentString(` type Query { me: User - }`; + } + + + `); expect(output).to.equal(['type Query {', ' me: User', '}'].join('\n')); }); - it('does not remove trailing newlines', () => { - const output = dedent` + it('removes all trailing spaces and tabs', () => { + const output = dedentString(` type Query { me: User } - - `; - expect(output).to.equal( - ['type Query {', ' me: User', '}', '', ''].join('\n'), - ); + \t\t \t `); + expect(output).to.equal(['type Query {', ' me: User', '}'].join('\n')); }); - it('removes all trailing spaces and tabs', () => { - const output = dedent` - type Query { + it('works on text without leading newline', () => { + const output = dedentString(` type Query { me: User } - \t\t \t `; - expect(output).to.equal(['type Query {', ' me: User', '}', ''].join('\n')); + `); + expect(output).to.equal(['type Query {', ' me: User', '}'].join('\n')); }); +}); - it('works on text without leading newline', () => { - const output = dedent` type Query { +describe('dedent', () => { + it('removes indentation in typical usage', () => { + const output = dedent` + type Query { me: User - }`; + } + `; expect(output).to.equal(['type Query {', ' me: User', '}'].join('\n')); }); it('supports expression interpolation', () => { - const name = 'Luke Skywalker'; - const age = 42; + const name = 'John'; + const surname = 'Doe'; const output = dedent` { "me": { - "name": "${name}" - "age": ${String(age)} + "name": "${name}", + "surname": "${surname}" } } `; @@ -120,11 +121,10 @@ describe('dedent', () => { [ '{', ' "me": {', - ' "name": "Luke Skywalker"', - ' "age": 42', + ' "name": "John",', + ' "surname": "Doe"', ' }', '}', - '', ].join('\n'), ); }); diff --git a/src/__testUtils__/__tests__/genFuzzStrings-test.js b/src/__testUtils__/__tests__/genFuzzStrings-test.ts similarity index 88% rename from src/__testUtils__/__tests__/genFuzzStrings-test.js rename to src/__testUtils__/__tests__/genFuzzStrings-test.ts index 75da1b63cc..516ed00fe7 100644 --- a/src/__testUtils__/__tests__/genFuzzStrings-test.js +++ b/src/__testUtils__/__tests__/genFuzzStrings-test.ts @@ -1,13 +1,13 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import genFuzzStrings from '../genFuzzStrings'; +import { genFuzzStrings } from '../genFuzzStrings'; -function expectFuzzStrings(options: {| - allowedChars: Array, - maxLength: number, -|}) { - return expect(Array.from(genFuzzStrings(options))); +function expectFuzzStrings(options: { + allowedChars: ReadonlyArray; + maxLength: number; +}) { + return expect([...genFuzzStrings(options)]); } describe('genFuzzStrings', () => { diff --git a/src/__testUtils__/__tests__/inspectStr-test.js b/src/__testUtils__/__tests__/inspectStr-test.ts similarity index 92% rename from src/__testUtils__/__tests__/inspectStr-test.js rename to src/__testUtils__/__tests__/inspectStr-test.ts index b31e59b159..9c3eba3a95 100644 --- a/src/__testUtils__/__tests__/inspectStr-test.js +++ b/src/__testUtils__/__tests__/inspectStr-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import inspectStr from '../inspectStr'; +import { inspectStr } from '../inspectStr'; describe('inspectStr', () => { it('handles null and undefined values', () => { diff --git a/src/__testUtils__/__tests__/resolveOnNextTick-test.js b/src/__testUtils__/__tests__/resolveOnNextTick-test.ts similarity index 89% rename from src/__testUtils__/__tests__/resolveOnNextTick-test.js rename to src/__testUtils__/__tests__/resolveOnNextTick-test.ts index 5d51eb8aa8..0916b44a0c 100644 --- a/src/__testUtils__/__tests__/resolveOnNextTick-test.js +++ b/src/__testUtils__/__tests__/resolveOnNextTick-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import resolveOnNextTick from '../resolveOnNextTick'; +import { resolveOnNextTick } from '../resolveOnNextTick'; describe('resolveOnNextTick', () => { it('resolves promise on the next tick', async () => { diff --git a/src/__testUtils__/dedent.js b/src/__testUtils__/dedent.js deleted file mode 100644 index c4b8e8da7b..0000000000 --- a/src/__testUtils__/dedent.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * An ES6 string tag that fixes indentation. Also removes leading newlines - * and trailing spaces and tabs, but keeps trailing newlines. - * - * Example usage: - * const str = dedent` - * { - * test - * } - * `; - * str === "{\n test\n}\n"; - */ -export default function dedent( - strings: $ReadOnlyArray, - ...values: $ReadOnlyArray -): string { - let str = ''; - - for (let i = 0; i < strings.length; ++i) { - str += strings[i]; - if (i < values.length) { - // istanbul ignore next (Ignore else inside Babel generated code) - const value = values[i]; - - str += value; // interpolation - } - } - - const trimmedStr = str - .replace(/^\n*/m, '') // remove leading newline - .replace(/[ \t]*$/, ''); // remove trailing spaces and tabs - - // fixes indentation by removing leading spaces and tabs from each line - let indent = ''; - for (const char of trimmedStr) { - if (char !== ' ' && char !== '\t') { - break; - } - indent += char; - } - return trimmedStr.replace(RegExp('^' + indent, 'mg'), ''); // remove indent -} diff --git a/src/__testUtils__/dedent.ts b/src/__testUtils__/dedent.ts new file mode 100644 index 0000000000..7fc6b46345 --- /dev/null +++ b/src/__testUtils__/dedent.ts @@ -0,0 +1,41 @@ +export function dedentString(string: string): string { + const trimmedStr = string + .replace(/^\n*/m, '') // remove leading newline + .replace(/[ \t\n]*$/, ''); // remove trailing spaces and tabs + + // fixes indentation by removing leading spaces and tabs from each line + let indent = ''; + for (const char of trimmedStr) { + if (char !== ' ' && char !== '\t') { + break; + } + indent += char; + } + + return trimmedStr.replace(RegExp('^' + indent, 'mg'), ''); // remove indent +} + +/** + * An ES6 string tag that fixes indentation and also trims string. + * + * Example usage: + * ```ts + * const str = dedent` + * { + * test + * } + * `; + * str === "{\n test\n}"; + * ``` + */ +export function dedent( + strings: ReadonlyArray, + ...values: ReadonlyArray +): string { + let str = strings[0]; + + for (let i = 1; i < strings.length; ++i) { + str += values[i - 1] + strings[i]; // interpolation + } + return dedentString(str); +} diff --git a/src/__testUtils__/expectJSON.ts b/src/__testUtils__/expectJSON.ts new file mode 100644 index 0000000000..64e2ba5dea --- /dev/null +++ b/src/__testUtils__/expectJSON.ts @@ -0,0 +1,51 @@ +import { expect } from 'chai'; + +import { isObjectLike } from '../jsutils/isObjectLike'; +import { mapValue } from '../jsutils/mapValue'; + +/** + * Deeply transforms an arbitrary value to a JSON-safe value by calling toJSON + * on any nested value which defines it. + */ +function toJSONDeep(value: unknown): unknown { + if (!isObjectLike(value)) { + return value; + } + + if (typeof value.toJSON === 'function') { + return value.toJSON(); + } + + if (Array.isArray(value)) { + return value.map(toJSONDeep); + } + + return mapValue(value, toJSONDeep); +} + +export function expectJSON(actual: unknown) { + const actualJSON = toJSONDeep(actual); + + return { + toDeepEqual(expected: unknown) { + const expectedJSON = toJSONDeep(expected); + expect(actualJSON).to.deep.equal(expectedJSON); + }, + toDeepNestedProperty(path: string, expected: unknown) { + const expectedJSON = toJSONDeep(expected); + expect(actualJSON).to.deep.nested.property(path, expectedJSON); + }, + }; +} + +export function expectToThrowJSON(fn: () => unknown) { + function mapException(): unknown { + try { + return fn(); + } catch (error) { + throw toJSONDeep(error); + } + } + + return expect(mapException).to.throw(); +} diff --git a/src/__testUtils__/genFuzzStrings.js b/src/__testUtils__/genFuzzStrings.ts similarity index 83% rename from src/__testUtils__/genFuzzStrings.js rename to src/__testUtils__/genFuzzStrings.ts index 4ead99080c..f29e1bb860 100644 --- a/src/__testUtils__/genFuzzStrings.js +++ b/src/__testUtils__/genFuzzStrings.ts @@ -1,10 +1,10 @@ /** * Generator that produces all possible combinations of allowed characters. */ -export default function* genFuzzStrings(options: {| - allowedChars: Array, - maxLength: number, -|}): Generator { +export function* genFuzzStrings(options: { + allowedChars: ReadonlyArray; + maxLength: number; +}): Generator { const { allowedChars, maxLength } = options; const numAllowedChars = allowedChars.length; diff --git a/src/__testUtils__/inspectStr.js b/src/__testUtils__/inspectStr.ts similarity index 70% rename from src/__testUtils__/inspectStr.js rename to src/__testUtils__/inspectStr.ts index a99a28150a..721d6e673a 100644 --- a/src/__testUtils__/inspectStr.js +++ b/src/__testUtils__/inspectStr.ts @@ -1,7 +1,9 @@ +import type { Maybe } from '../jsutils/Maybe'; + /** * Special inspect function to produce readable string literal for error messages in tests */ -export default function inspectStr(str: ?string): string { +export function inspectStr(str: Maybe): string { if (str == null) { return 'null'; } diff --git a/src/__testUtils__/kitchenSinkQuery.js b/src/__testUtils__/kitchenSinkQuery.ts similarity index 83% rename from src/__testUtils__/kitchenSinkQuery.js rename to src/__testUtils__/kitchenSinkQuery.ts index 2ccdc9dc92..9ed9a7e983 100644 --- a/src/__testUtils__/kitchenSinkQuery.js +++ b/src/__testUtils__/kitchenSinkQuery.ts @@ -1,5 +1,4 @@ -// $FlowFixMe[incompatible-call] -const kitchenSinkQuery: string = String.raw` +export const kitchenSinkQuery: string = String.raw` query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { whoever123is: node(id: [123, 456]) { id @@ -29,7 +28,9 @@ mutation likeStory @onMutation { } } -subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) +subscription StoryLikeSubscription( + $input: StoryLikeSubscribeInput @onVariableDefinition +) @onSubscription { storyLikeSubscribe(input: $input) { story { @@ -65,5 +66,3 @@ query { __typename } `; - -export default kitchenSinkQuery; diff --git a/src/__testUtils__/kitchenSinkSDL.js b/src/__testUtils__/kitchenSinkSDL.ts similarity index 95% rename from src/__testUtils__/kitchenSinkSDL.js rename to src/__testUtils__/kitchenSinkSDL.ts index 7b171ac027..7b7a537783 100644 --- a/src/__testUtils__/kitchenSinkSDL.js +++ b/src/__testUtils__/kitchenSinkSDL.ts @@ -1,4 +1,4 @@ -const kitchenSinkSDL: string = ` +export const kitchenSinkSDL = ` """This is a description of the schema as a whole.""" schema { query: QueryType @@ -27,6 +27,7 @@ type Foo implements Bar & Baz & Two { five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type seven(argument: Int = null): Type + eight(argument: OneOfInputType): Type } type AnnotatedObject @onObject(arg: "value") { @@ -116,6 +117,11 @@ input InputType { answer: Int = 42 } +input OneOfInputType @oneOf { + string: String + int: Int +} + input AnnotatedInput @onInputObject { annotatedField: Type @onInputFieldDefinition } @@ -156,5 +162,3 @@ extend schema @onSchema { subscription: SubscriptionType } `; - -export default kitchenSinkSDL; diff --git a/src/__testUtils__/resolveOnNextTick.js b/src/__testUtils__/resolveOnNextTick.js deleted file mode 100644 index b27ba839b2..0000000000 --- a/src/__testUtils__/resolveOnNextTick.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function resolveOnNextTick(): Promise { - return Promise.resolve(undefined); -} diff --git a/src/__testUtils__/resolveOnNextTick.ts b/src/__testUtils__/resolveOnNextTick.ts new file mode 100644 index 0000000000..6dd50b3982 --- /dev/null +++ b/src/__testUtils__/resolveOnNextTick.ts @@ -0,0 +1,3 @@ +export function resolveOnNextTick(): Promise { + return Promise.resolve(undefined); +} diff --git a/src/__tests__/starWarsData.js b/src/__tests__/starWarsData.ts similarity index 83% rename from src/__tests__/starWarsData.js rename to src/__tests__/starWarsData.ts index 7e1917b8bd..60c4331bb6 100644 --- a/src/__tests__/starWarsData.js +++ b/src/__tests__/starWarsData.ts @@ -2,31 +2,30 @@ * These are types which correspond to the schema. * They represent the shape of the data visited during field resolution. */ -export type Character = { - id: string, - name: string, - friends: Array, - appearsIn: Array, - ... -}; +export interface Character { + id: string; + name: string; + friends: ReadonlyArray; + appearsIn: ReadonlyArray; +} -export type Human = {| - type: 'Human', - id: string, - name: string, - friends: Array, - appearsIn: Array, - homePlanet?: string, -|}; - -export type Droid = {| - type: 'Droid', - id: string, - name: string, - friends: Array, - appearsIn: Array, - primaryFunction: string, -|}; +export interface Human { + type: 'Human'; + id: string; + name: string; + friends: ReadonlyArray; + appearsIn: ReadonlyArray; + homePlanet?: string; +} + +export interface Droid { + type: 'Droid'; + id: string; + name: string; + friends: ReadonlyArray; + appearsIn: ReadonlyArray; + primaryFunction: string; +} /** * This defines a basic set of data for our Star Wars Schema. @@ -79,7 +78,7 @@ const tarkin: Human = { appearsIn: [4], }; -const humanData: {| [id: string]: Human |} = { +const humanData: { [id: string]: Human } = { [luke.id]: luke, [vader.id]: vader, [han.id]: han, @@ -105,7 +104,7 @@ const artoo: Droid = { primaryFunction: 'Astromech', }; -const droidData: {| [id: string]: Droid |} = { +const droidData: { [id: string]: Droid } = { [threepio.id]: threepio, [artoo.id]: artoo, }; diff --git a/src/__tests__/starWarsIntrospection-test.js b/src/__tests__/starWarsIntrospection-test.ts similarity index 100% rename from src/__tests__/starWarsIntrospection-test.js rename to src/__tests__/starWarsIntrospection-test.ts diff --git a/src/__tests__/starWarsQuery-test.js b/src/__tests__/starWarsQuery-test.ts similarity index 94% rename from src/__tests__/starWarsQuery-test.js rename to src/__tests__/starWarsQuery-test.ts index 8b8ef8a56e..2662079d01 100644 --- a/src/__tests__/starWarsQuery-test.js +++ b/src/__tests__/starWarsQuery-test.ts @@ -1,7 +1,9 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { graphql, graphqlSync } from '../graphql'; +import { expectJSON } from '../__testUtils__/expectJSON'; + +import { graphql } from '../graphql'; import { StarWarsSchema as schema } from './starWarsSchema'; @@ -26,28 +28,6 @@ describe('Star Wars Query Tests', () => { }); }); - it('Accepts positional arguments to graphql()', async () => { - const source = ` - query HeroNameQuery { - hero { - name - } - } - `; - - const result = await graphql(schema, source); - expect(result).to.deep.equal({ - data: { - hero: { - name: 'R2-D2', - }, - }, - }); - - const syncResult = graphqlSync(schema, source); - expect(syncResult).to.deep.equal(result); - }); - it('Allows us to query for the ID and friends of R2-D2', async () => { const source = ` query HeroNameAndFriendsQuery { @@ -415,7 +395,7 @@ describe('Star Wars Query Tests', () => { `; const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { hero: { name: 'R2-D2', @@ -446,7 +426,7 @@ describe('Star Wars Query Tests', () => { `; const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { hero: { name: 'R2-D2', @@ -497,7 +477,7 @@ describe('Star Wars Query Tests', () => { `; const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { mainHero: { name: 'R2-D2', diff --git a/src/__tests__/starWarsSchema.js b/src/__tests__/starWarsSchema.ts similarity index 87% rename from src/__tests__/starWarsSchema.js rename to src/__tests__/starWarsSchema.ts index e06c2cef71..c646c8aea3 100644 --- a/src/__tests__/starWarsSchema.js +++ b/src/__tests__/starWarsSchema.ts @@ -1,16 +1,14 @@ -import invariant from '../jsutils/invariant'; - -import { GraphQLSchema } from '../type/schema'; -import { GraphQLString } from '../type/scalars'; import { - GraphQLList, - GraphQLNonNull, GraphQLEnumType, GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, GraphQLObjectType, } from '../type/definition'; +import { GraphQLString } from '../type/scalars'; +import { GraphQLSchema } from '../type/schema'; -import { getFriends, getHero, getHuman, getDroid } from './starWarsData'; +import { getDroid, getFriends, getHero, getHuman } from './starWarsData'; /** * This is designed to be an end-to-end test, demonstrating @@ -27,6 +25,7 @@ import { getFriends, getHero, getHuman, getDroid } from './starWarsData'; * Using our shorthand to describe type systems, the type system for our * Star Wars example is: * + * ```graphql * enum Episode { NEW_HOPE, EMPIRE, JEDI } * * interface Character { @@ -57,6 +56,7 @@ import { getFriends, getHero, getHuman, getDroid } from './starWarsData'; * human(id: String!): Human * droid(id: String!): Droid * } + * ``` * * We begin by setting up our schema. */ @@ -65,7 +65,9 @@ import { getFriends, getHero, getHuman, getDroid } from './starWarsData'; * The original trilogy consists of three movies. * * This implements the following type system shorthand: - * enum Episode { NEW_HOPE, EMPIRE, JEDI } + * ```graphql + * enum Episode { NEW_HOPE, EMPIRE, JEDI } + * ``` */ const episodeEnum = new GraphQLEnumType({ name: 'Episode', @@ -90,15 +92,17 @@ const episodeEnum = new GraphQLEnumType({ * Characters in the Star Wars trilogy are either humans or droids. * * This implements the following type system shorthand: - * interface Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } + * ```graphql + * interface Character { + * id: String! + * name: String + * friends: [Character] + * appearsIn: [Episode] + * secretBackstory: String + * } + * ``` */ -const characterInterface = new GraphQLInterfaceType({ +const characterInterface: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'Character', description: 'A character in the Star Wars Trilogy', fields: () => ({ @@ -131,9 +135,6 @@ const characterInterface = new GraphQLInterfaceType({ case 'Droid': return droidType.name; } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false); }, }); @@ -141,13 +142,15 @@ const characterInterface = new GraphQLInterfaceType({ * We define our human type, which implements the character interface. * * This implements the following type system shorthand: - * type Human : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } + * ```graphql + * type Human : Character { + * id: String! + * name: String + * friends: [Character] + * appearsIn: [Episode] + * secretBackstory: String + * } + * ``` */ const humanType = new GraphQLObjectType({ name: 'Human', @@ -190,14 +193,16 @@ const humanType = new GraphQLObjectType({ * The other type of character in Star Wars is a droid. * * This implements the following type system shorthand: - * type Droid : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * primaryFunction: String - * } + * ```graphql + * type Droid : Character { + * id: String! + * name: String + * friends: [Character] + * appearsIn: [Episode] + * secretBackstory: String + * primaryFunction: String + * } + * ``` */ const droidType = new GraphQLObjectType({ name: 'Droid', @@ -243,12 +248,13 @@ const droidType = new GraphQLObjectType({ * of the Star Wars trilogy, R2-D2, directly. * * This implements the following type system shorthand: - * type Query { - * hero(episode: Episode): Character - * human(id: String!): Human - * droid(id: String!): Droid - * } - * + * ```graphql + * type Query { + * hero(episode: Episode): Character + * human(id: String!): Human + * droid(id: String!): Droid + * } + * ``` */ const queryType = new GraphQLObjectType({ name: 'Query', diff --git a/src/__tests__/starWarsValidation-test.js b/src/__tests__/starWarsValidation-test.ts similarity index 100% rename from src/__tests__/starWarsValidation-test.js rename to src/__tests__/starWarsValidation-test.ts diff --git a/src/__tests__/version-test.js b/src/__tests__/version-test.js deleted file mode 100644 index ffa8d981e6..0000000000 --- a/src/__tests__/version-test.js +++ /dev/null @@ -1,40 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { version, versionInfo } from '../version'; - -describe('Version', () => { - it('version', () => { - expect(version).to.be.a('string'); - expect(version).to.match( - /^\d+\.\d+\.\d(-(alpha|beta|rc|(experimental-[\w-]+))\.\d+)?$/, - ); - }); - - it('versionInfo', () => { - expect(versionInfo).to.be.an('object'); - expect(versionInfo).to.have.all.keys( - 'major', - 'minor', - 'patch', - 'preReleaseTag', - ); - - const { major, minor, patch, preReleaseTag } = versionInfo; - - expect(major).to.be.a('number'); - expect(minor).to.be.a('number'); - expect(patch).to.be.a('number'); - - // istanbul ignore next (Can't be verified on all versions) - if (preReleaseTag !== null) { - expect(preReleaseTag).to.be.a('string'); - } - - expect( - `${major}.${minor}.${patch}` + - // istanbul ignore next (Can't be verified on all versions) - (preReleaseTag !== null ? '-' + preReleaseTag : ''), - ).to.equal(version); - }); -}); diff --git a/src/__tests__/version-test.ts b/src/__tests__/version-test.ts new file mode 100644 index 0000000000..3680512de8 --- /dev/null +++ b/src/__tests__/version-test.ts @@ -0,0 +1,54 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { version, versionInfo } from '../version'; + +describe('Version', () => { + it('versionInfo', () => { + expect(versionInfo).to.be.an('object'); + expect(versionInfo).to.have.all.keys( + 'major', + 'minor', + 'patch', + 'preReleaseTag', + ); + + const { major, minor, patch, preReleaseTag } = versionInfo; + expect(major).to.be.a('number').at.least(0); + expect(minor).to.be.a('number').at.least(0); + expect(patch).to.be.a('number').at.least(0); + + // Can't be verified on all versions + /* c8 ignore start */ + switch (preReleaseTag?.split('.').length) { + case undefined: + break; + case 2: + expect(preReleaseTag).to.match( + /^(alpha|beta|rc|experimental-[\w-]+)\.\d+/, + ); + break; + case 4: + expect(preReleaseTag).to.match( + /^(alpha|beta|rc)\.\d+.experimental-[\w-]+\.\d+/, + ); + break; + default: + expect.fail('Invalid pre-release tag: ' + preReleaseTag); + } + /* c8 ignore stop */ + }); + + it('version', () => { + expect(version).to.be.a('string'); + + const { major, minor, patch, preReleaseTag } = versionInfo; + expect(version).to.equal( + // Can't be verified on all versions + /* c8 ignore next 3 */ + preReleaseTag === null + ? `${major}.${minor}.${patch}` + : `${major}.${minor}.${patch}-${preReleaseTag}`, + ); + }); +}); diff --git a/src/error/GraphQLError.d.ts b/src/error/GraphQLError.d.ts deleted file mode 100644 index 99001fd26f..0000000000 --- a/src/error/GraphQLError.d.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { ASTNode } from '../language/ast'; -import { Source } from '../language/source'; -import { SourceLocation } from '../language/location'; - -/** - * A GraphQLError describes an Error found during the parse, validate, or - * execute phases of performing a GraphQL operation. In addition to a message - * and stack trace, it also includes information about the locations in a - * GraphQL document and/or execution result that correspond to the Error. - */ -export class GraphQLError extends Error { - constructor( - message: string, - nodes?: Maybe | ASTNode>, - source?: Maybe, - positions?: Maybe>, - path?: Maybe>, - originalError?: Maybe, - extensions?: Maybe<{ [key: string]: any }>, - ); - - /** - * A message describing the Error for debugging purposes. - * - * Enumerable, and appears in the result of JSON.stringify(). - * - * Note: should be treated as readonly, despite invariant usage. - */ - message: string; - - /** - * An array of { line, column } locations within the source GraphQL document - * which correspond to this error. - * - * Errors during validation often contain multiple locations, for example to - * point out two things with the same name. Errors during execution include a - * single location, the field which produced the error. - * - * Enumerable, and appears in the result of JSON.stringify(). - */ - readonly locations: ReadonlyArray | undefined; - - /** - * An array describing the JSON-path into the execution response which - * corresponds to this error. Only included for errors during execution. - * - * Enumerable, and appears in the result of JSON.stringify(). - */ - readonly path: ReadonlyArray | undefined; - - /** - * An array of GraphQL AST Nodes corresponding to this error. - */ - readonly nodes: ReadonlyArray | undefined; - - /** - * The source GraphQL document corresponding to this error. - * - * Note that if this Error represents more than one node, the source may not - * represent nodes after the first node. - */ - readonly source: Source | undefined; - - /** - * An array of character offsets within the source GraphQL document - * which correspond to this error. - */ - readonly positions: ReadonlyArray | undefined; - - /** - * The original error thrown from a field resolver during execution. - */ - readonly originalError: Maybe; - - /** - * Extension fields to add to the formatted error. - */ - readonly extensions: { [key: string]: any } | undefined; -} - -/** - * Prints a GraphQLError to a string, representing useful location information - * about the error's position in the source. - */ -export function printError(error: GraphQLError): string; diff --git a/src/error/GraphQLError.js b/src/error/GraphQLError.js deleted file mode 100644 index 3040787939..0000000000 --- a/src/error/GraphQLError.js +++ /dev/null @@ -1,241 +0,0 @@ -// FIXME: -// flowlint uninitialized-instance-property:off - -import isObjectLike from '../jsutils/isObjectLike'; -import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols'; - -import type { ASTNode } from '../language/ast'; -import type { Source } from '../language/source'; -import type { SourceLocation } from '../language/location'; -import { getLocation } from '../language/location'; -import { printLocation, printSourceLocation } from '../language/printLocation'; - -/** - * A GraphQLError describes an Error found during the parse, validate, or - * execute phases of performing a GraphQL operation. In addition to a message - * and stack trace, it also includes information about the locations in a - * GraphQL document and/or execution result that correspond to the Error. - */ -export class GraphQLError extends Error { - /** - * A message describing the Error for debugging purposes. - * - * Enumerable, and appears in the result of JSON.stringify(). - * - * Note: should be treated as readonly, despite invariant usage. - */ - message: string; - - /** - * An array of { line, column } locations within the source GraphQL document - * which correspond to this error. - * - * Errors during validation often contain multiple locations, for example to - * point out two things with the same name. Errors during execution include a - * single location, the field which produced the error. - * - * Enumerable, and appears in the result of JSON.stringify(). - */ - +locations: $ReadOnlyArray | void; - - /** - * An array describing the JSON-path into the execution response which - * corresponds to this error. Only included for errors during execution. - * - * Enumerable, and appears in the result of JSON.stringify(). - */ - +path: $ReadOnlyArray | void; - - /** - * An array of GraphQL AST Nodes corresponding to this error. - */ - +nodes: $ReadOnlyArray | void; - - /** - * The source GraphQL document for the first location of this error. - * - * Note that if this Error represents more than one node, the source may not - * represent nodes after the first node. - */ - +source: Source | void; - - /** - * An array of character offsets within the source GraphQL document - * which correspond to this error. - */ - +positions: $ReadOnlyArray | void; - - /** - * The original error thrown from a field resolver during execution. - */ - +originalError: ?Error; - - /** - * Extension fields to add to the formatted error. - */ - +extensions: { [key: string]: mixed, ... } | void; - - constructor( - message: string, - nodes?: $ReadOnlyArray | ASTNode | void | null, - source?: ?Source, - positions?: ?$ReadOnlyArray, - path?: ?$ReadOnlyArray, - originalError?: ?(Error & { +extensions?: mixed, ... }), - extensions?: ?{ [key: string]: mixed, ... }, - ) { - super(message); - - // Compute list of blame nodes. - const _nodes = Array.isArray(nodes) - ? nodes.length !== 0 - ? nodes - : undefined - : nodes - ? [nodes] - : undefined; - - // Compute locations in the source for the given nodes/positions. - let _source = source; - if (!_source && _nodes) { - _source = _nodes[0].loc?.source; - } - - let _positions = positions; - if (!_positions && _nodes) { - _positions = _nodes.reduce((list, node) => { - if (node.loc) { - list.push(node.loc.start); - } - return list; - }, []); - } - if (_positions && _positions.length === 0) { - _positions = undefined; - } - - let _locations; - if (positions && source) { - _locations = positions.map((pos) => getLocation(source, pos)); - } else if (_nodes) { - _locations = _nodes.reduce((list, node) => { - if (node.loc) { - list.push(getLocation(node.loc.source, node.loc.start)); - } - return list; - }, []); - } - - let _extensions = extensions; - if (_extensions == null && originalError != null) { - const originalExtensions = originalError.extensions; - if (isObjectLike(originalExtensions)) { - _extensions = originalExtensions; - } - } - - Object.defineProperties((this: any), { - name: { value: 'GraphQLError' }, - message: { - value: message, - // By being enumerable, JSON.stringify will include `message` in the - // resulting output. This ensures that the simplest possible GraphQL - // service adheres to the spec. - enumerable: true, - writable: true, - }, - locations: { - // Coercing falsy values to undefined ensures they will not be included - // in JSON.stringify() when not provided. - value: _locations ?? undefined, - // By being enumerable, JSON.stringify will include `locations` in the - // resulting output. This ensures that the simplest possible GraphQL - // service adheres to the spec. - enumerable: _locations != null, - }, - path: { - // Coercing falsy values to undefined ensures they will not be included - // in JSON.stringify() when not provided. - value: path ?? undefined, - // By being enumerable, JSON.stringify will include `path` in the - // resulting output. This ensures that the simplest possible GraphQL - // service adheres to the spec. - enumerable: path != null, - }, - nodes: { - value: _nodes ?? undefined, - }, - source: { - value: _source ?? undefined, - }, - positions: { - value: _positions ?? undefined, - }, - originalError: { - value: originalError, - }, - extensions: { - // Coercing falsy values to undefined ensures they will not be included - // in JSON.stringify() when not provided. - value: _extensions ?? undefined, - // By being enumerable, JSON.stringify will include `path` in the - // resulting output. This ensures that the simplest possible GraphQL - // service adheres to the spec. - enumerable: _extensions != null, - }, - }); - - // Include (non-enumerable) stack trace. - if (originalError?.stack) { - Object.defineProperty(this, 'stack', { - value: originalError.stack, - writable: true, - configurable: true, - }); - return; - } - - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') - if (Error.captureStackTrace) { - Error.captureStackTrace(this, GraphQLError); - } else { - Object.defineProperty(this, 'stack', { - value: Error().stack, - writable: true, - configurable: true, - }); - } - } - - toString(): string { - return printError(this); - } - - // FIXME: workaround to not break chai comparisons, should be remove in v16 - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG](): string { - return 'Object'; - } -} - -/** - * Prints a GraphQLError to a string, representing useful location information - * about the error's position in the source. - */ -export function printError(error: GraphQLError): string { - let output = error.message; - - if (error.nodes) { - for (const node of error.nodes) { - if (node.loc) { - output += '\n\n' + printLocation(node.loc); - } - } - } else if (error.source && error.locations) { - for (const location of error.locations) { - output += '\n\n' + printSourceLocation(error.source, location); - } - } - - return output; -} diff --git a/src/error/GraphQLError.ts b/src/error/GraphQLError.ts new file mode 100644 index 0000000000..77a5e78779 --- /dev/null +++ b/src/error/GraphQLError.ts @@ -0,0 +1,312 @@ +import { isObjectLike } from '../jsutils/isObjectLike'; +import type { Maybe } from '../jsutils/Maybe'; + +import type { ASTNode, Location } from '../language/ast'; +import type { SourceLocation } from '../language/location'; +import { getLocation } from '../language/location'; +import { printLocation, printSourceLocation } from '../language/printLocation'; +import type { Source } from '../language/source'; + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLErrorExtensions { + [attributeName: string]: unknown; +} + +/** + * Custom formatted extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLFormattedErrorExtensions { + [attributeName: string]: unknown; +} + +export interface GraphQLErrorOptions { + nodes?: ReadonlyArray | ASTNode | null; + source?: Maybe; + positions?: Maybe>; + path?: Maybe>; + originalError?: Maybe; + extensions?: Maybe; +} + +type BackwardsCompatibleArgs = + | [options?: GraphQLErrorOptions] + | [ + nodes?: GraphQLErrorOptions['nodes'], + source?: GraphQLErrorOptions['source'], + positions?: GraphQLErrorOptions['positions'], + path?: GraphQLErrorOptions['path'], + originalError?: GraphQLErrorOptions['originalError'], + extensions?: GraphQLErrorOptions['extensions'], + ]; + +function toNormalizedOptions( + args: BackwardsCompatibleArgs, +): GraphQLErrorOptions { + const firstArg = args[0]; + if (firstArg == null || 'kind' in firstArg || 'length' in firstArg) { + return { + nodes: firstArg, + source: args[1], + positions: args[2], + path: args[3], + originalError: args[4], + extensions: args[5], + }; + } + return firstArg; +} + +/** + * A GraphQLError describes an Error found during the parse, validate, or + * execute phases of performing a GraphQL operation. In addition to a message + * and stack trace, it also includes information about the locations in a + * GraphQL document and/or execution result that correspond to the Error. + */ +export class GraphQLError extends Error { + /** + * An array of `{ line, column }` locations within the source GraphQL document + * which correspond to this error. + * + * Errors during validation often contain multiple locations, for example to + * point out two things with the same name. Errors during execution include a + * single location, the field which produced the error. + * + * Enumerable, and appears in the result of JSON.stringify(). + */ + readonly locations: ReadonlyArray | undefined; + + /** + * An array describing the JSON-path into the execution response which + * corresponds to this error. Only included for errors during execution. + * + * Enumerable, and appears in the result of JSON.stringify(). + */ + readonly path: ReadonlyArray | undefined; + + /** + * An array of GraphQL AST Nodes corresponding to this error. + */ + readonly nodes: ReadonlyArray | undefined; + + /** + * The source GraphQL document for the first location of this error. + * + * Note that if this Error represents more than one node, the source may not + * represent nodes after the first node. + */ + readonly source: Source | undefined; + + /** + * An array of character offsets within the source GraphQL document + * which correspond to this error. + */ + readonly positions: ReadonlyArray | undefined; + + /** + * The original error thrown from a field resolver during execution. + */ + readonly originalError: Error | undefined; + + /** + * Extension fields to add to the formatted error. + */ + readonly extensions: GraphQLErrorExtensions; + + constructor(message: string, options?: GraphQLErrorOptions); + /** + * @deprecated Please use the `GraphQLErrorOptions` constructor overload instead. + */ + constructor( + message: string, + nodes?: ReadonlyArray | ASTNode | null, + source?: Maybe, + positions?: Maybe>, + path?: Maybe>, + originalError?: Maybe, + extensions?: Maybe, + ); + constructor(message: string, ...rawArgs: BackwardsCompatibleArgs) { + const { nodes, source, positions, path, originalError, extensions } = + toNormalizedOptions(rawArgs); + super(message); + + this.name = 'GraphQLError'; + this.path = path ?? undefined; + this.originalError = originalError ?? undefined; + + // Compute list of blame nodes. + this.nodes = undefinedIfEmpty( + Array.isArray(nodes) ? nodes : nodes ? [nodes] : undefined, + ); + + const nodeLocations = undefinedIfEmpty( + this.nodes + ?.map((node) => node.loc) + .filter((loc): loc is Location => loc != null), + ); + + // Compute locations in the source for the given nodes/positions. + this.source = source ?? nodeLocations?.[0]?.source; + + this.positions = positions ?? nodeLocations?.map((loc) => loc.start); + + this.locations = + positions && source + ? positions.map((pos) => getLocation(source, pos)) + : nodeLocations?.map((loc) => getLocation(loc.source, loc.start)); + + const originalExtensions = isObjectLike(originalError?.extensions) + ? originalError?.extensions + : undefined; + this.extensions = extensions ?? originalExtensions ?? Object.create(null); + + // Only properties prescribed by the spec should be enumerable. + // Keep the rest as non-enumerable. + Object.defineProperties(this, { + message: { + writable: true, + enumerable: true, + }, + name: { enumerable: false }, + nodes: { enumerable: false }, + source: { enumerable: false }, + positions: { enumerable: false }, + originalError: { enumerable: false }, + }); + + // Include (non-enumerable) stack trace. + /* c8 ignore start */ + // FIXME: https://github.com/graphql/graphql-js/issues/2317 + if (originalError?.stack) { + Object.defineProperty(this, 'stack', { + value: originalError.stack, + writable: true, + configurable: true, + }); + } else if (Error.captureStackTrace) { + Error.captureStackTrace(this, GraphQLError); + } else { + Object.defineProperty(this, 'stack', { + value: Error().stack, + writable: true, + configurable: true, + }); + } + /* c8 ignore stop */ + } + + get [Symbol.toStringTag](): string { + return 'GraphQLError'; + } + + toString(): string { + let output = this.message; + + if (this.nodes) { + for (const node of this.nodes) { + if (node.loc) { + output += '\n\n' + printLocation(node.loc); + } + } + } else if (this.source && this.locations) { + for (const location of this.locations) { + output += '\n\n' + printSourceLocation(this.source, location); + } + } + + return output; + } + + toJSON(): GraphQLFormattedError { + type WritableFormattedError = { + -readonly [P in keyof GraphQLFormattedError]: GraphQLFormattedError[P]; + }; + + const formattedError: WritableFormattedError = { + message: this.message, + }; + + if (this.locations != null) { + formattedError.locations = this.locations; + } + + if (this.path != null) { + formattedError.path = this.path; + } + + if (this.extensions != null && Object.keys(this.extensions).length > 0) { + formattedError.extensions = this.extensions; + } + + return formattedError; + } +} + +function undefinedIfEmpty( + array: Array | undefined, +): Array | undefined { + return array === undefined || array.length === 0 ? undefined : array; +} + +/** + * See: https://spec.graphql.org/draft/#sec-Errors + */ +export interface GraphQLFormattedError { + /** + * A short, human-readable summary of the problem that **SHOULD NOT** change + * from occurrence to occurrence of the problem, except for purposes of + * localization. + */ + readonly message: string; + /** + * If an error can be associated to a particular point in the requested + * GraphQL document, it should contain a list of locations. + */ + readonly locations?: ReadonlyArray; + /** + * If an error can be associated to a particular field in the GraphQL result, + * it _must_ contain an entry with the key `path` that details the path of + * the response field which experienced the error. This allows clients to + * identify whether a null result is intentional or caused by a runtime error. + */ + readonly path?: ReadonlyArray; + /** + * Reserved for implementors to extend the protocol however they see fit, + * and hence there are no additional restrictions on its contents. + */ + readonly extensions?: GraphQLFormattedErrorExtensions; +} + +/** + * Prints a GraphQLError to a string, representing useful location information + * about the error's position in the source. + * + * @deprecated Please use `error.toString` instead. Will be removed in v17 + */ +export function printError(error: GraphQLError): string { + return error.toString(); +} + +/** + * Given a GraphQLError, format it according to the rules described by the + * Response Format, Errors section of the GraphQL Specification. + * + * @deprecated Please use `error.toJSON` instead. Will be removed in v17 + */ +export function formatError(error: GraphQLError): GraphQLFormattedError { + return error.toJSON(); +} diff --git a/src/error/__tests__/GraphQLError-test.js b/src/error/__tests__/GraphQLError-test.js deleted file mode 100644 index b72d31b174..0000000000 --- a/src/error/__tests__/GraphQLError-test.js +++ /dev/null @@ -1,201 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import dedent from '../../__testUtils__/dedent'; - -import invariant from '../../jsutils/invariant'; - -import { Kind } from '../../language/kinds'; -import { parse } from '../../language/parser'; -import { Source } from '../../language/source'; - -import { GraphQLError, printError } from '../GraphQLError'; - -const source = new Source(dedent` - { - field - } -`); -const ast = parse(source); -const operationNode = ast.definitions[0]; -invariant(operationNode.kind === Kind.OPERATION_DEFINITION); -const fieldNode = operationNode.selectionSet.selections[0]; -invariant(fieldNode); - -describe('GraphQLError', () => { - it('is a class and is a subclass of Error', () => { - expect(new GraphQLError('str')).to.be.instanceof(Error); - expect(new GraphQLError('str')).to.be.instanceof(GraphQLError); - }); - - it('has a name, message, and stack trace', () => { - const e = new GraphQLError('msg'); - - expect(e).to.include({ name: 'GraphQLError', message: 'msg' }); - expect(e.stack).to.be.a('string'); - }); - - it('uses the stack of an original error', () => { - const original = new Error('original'); - const e = new GraphQLError( - 'msg', - undefined, - undefined, - undefined, - undefined, - original, - ); - - expect(e).to.include({ - name: 'GraphQLError', - message: 'msg', - stack: original.stack, - originalError: original, - }); - }); - - it('creates new stack if original error has no stack', () => { - const original = new Error('original'); - const e = new GraphQLError('msg', null, null, null, null, original); - - expect(e).to.include({ - name: 'GraphQLError', - message: 'msg', - originalError: original, - }); - expect(e.stack).to.be.a('string'); - }); - - it('converts nodes to positions and locations', () => { - const e = new GraphQLError('msg', [fieldNode]); - expect(e).to.have.property('source', source); - expect(e).to.deep.include({ - nodes: [fieldNode], - positions: [4], - locations: [{ line: 2, column: 3 }], - }); - }); - - it('converts single node to positions and locations', () => { - const e = new GraphQLError('msg', fieldNode); // Non-array value. - expect(e).to.have.property('source', source); - expect(e).to.deep.include({ - nodes: [fieldNode], - positions: [4], - locations: [{ line: 2, column: 3 }], - }); - }); - - it('converts node with loc.start === 0 to positions and locations', () => { - const e = new GraphQLError('msg', operationNode); - expect(e).to.have.property('source', source); - expect(e).to.deep.include({ - nodes: [operationNode], - positions: [0], - locations: [{ line: 1, column: 1 }], - }); - }); - - it('converts source and positions to locations', () => { - const e = new GraphQLError('msg', null, source, [6]); - expect(e).to.have.property('source', source); - expect(e).to.deep.include({ - nodes: undefined, - positions: [6], - locations: [{ line: 2, column: 5 }], - }); - }); - - it('serializes to include message', () => { - const e = new GraphQLError('msg'); - expect(JSON.stringify(e)).to.equal('{"message":"msg"}'); - }); - - it('serializes to include message and locations', () => { - const e = new GraphQLError('msg', fieldNode); - expect(JSON.stringify(e)).to.equal( - '{"message":"msg","locations":[{"line":2,"column":3}]}', - ); - }); - - it('serializes to include path', () => { - const e = new GraphQLError('msg', null, null, null, [ - 'path', - 3, - 'to', - 'field', - ]); - expect(e).to.have.deep.property('path', ['path', 3, 'to', 'field']); - expect(JSON.stringify(e)).to.equal( - '{"message":"msg","path":["path",3,"to","field"]}', - ); - }); -}); - -describe('printError', () => { - it('prints an error without location', () => { - const error = new GraphQLError('Error without location'); - expect(printError(error)).to.equal('Error without location'); - }); - - it('prints an error using node without location', () => { - const error = new GraphQLError( - 'Error attached to node without location', - parse('{ foo }', { noLocation: true }), - ); - expect(printError(error)).to.equal( - 'Error attached to node without location', - ); - }); - - it('prints an error with nodes from different sources', () => { - const docA = parse( - new Source( - dedent` - type Foo { - field: String - } - `, - 'SourceA', - ), - ); - const opA = docA.definitions[0]; - invariant(opA.kind === Kind.OBJECT_TYPE_DEFINITION && opA.fields); - const fieldA = opA.fields[0]; - - const docB = parse( - new Source( - dedent` - type Foo { - field: Int - } - `, - 'SourceB', - ), - ); - const opB = docB.definitions[0]; - invariant(opB.kind === Kind.OBJECT_TYPE_DEFINITION && opB.fields); - const fieldB = opB.fields[0]; - - const error = new GraphQLError('Example error with two nodes', [ - fieldA.type, - fieldB.type, - ]); - - expect(printError(error) + '\n').to.equal(dedent` - Example error with two nodes - - SourceA:2:10 - 1 | type Foo { - 2 | field: String - | ^ - 3 | } - - SourceB:2:10 - 1 | type Foo { - 2 | field: Int - | ^ - 3 | } - `); - }); -}); diff --git a/src/error/__tests__/GraphQLError-test.ts b/src/error/__tests__/GraphQLError-test.ts new file mode 100644 index 0000000000..1aa7d92f0c --- /dev/null +++ b/src/error/__tests__/GraphQLError-test.ts @@ -0,0 +1,343 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { dedent } from '../../__testUtils__/dedent'; + +import { invariant } from '../../jsutils/invariant'; + +import { Kind } from '../../language/kinds'; +import { parse } from '../../language/parser'; +import { Source } from '../../language/source'; + +import { formatError, GraphQLError, printError } from '../GraphQLError'; + +const source = new Source(dedent` + { + field + } +`); +const ast = parse(source); +const operationNode = ast.definitions[0]; +invariant(operationNode.kind === Kind.OPERATION_DEFINITION); +const fieldNode = operationNode.selectionSet.selections[0]; +invariant(fieldNode); + +describe('GraphQLError', () => { + it('is a class and is a subclass of Error', () => { + expect(new GraphQLError('str')).to.be.instanceof(Error); + expect(new GraphQLError('str')).to.be.instanceof(GraphQLError); + }); + + it('has a name, message, extensions, and stack trace', () => { + const e = new GraphQLError('msg'); + + expect(e).to.deep.include({ + name: 'GraphQLError', + message: 'msg', + extensions: {}, + }); + expect(e.stack).to.be.a('string'); + }); + + it('enumerate only properties prescribed by the spec', () => { + const e = new GraphQLError('msg' /* message */, { + nodes: [fieldNode], + source, + positions: [1, 2, 3], + path: ['a', 'b', 'c'], + originalError: new Error('test'), + extensions: { foo: 'bar' }, + }); + + expect(Object.keys(e)).to.deep.equal([ + 'message', + 'path', + 'locations', + 'extensions', + ]); + }); + + it('uses the stack of an original error', () => { + const original = new Error('original'); + const e = new GraphQLError('msg', { + originalError: original, + }); + + expect(e).to.include({ + name: 'GraphQLError', + message: 'msg', + stack: original.stack, + originalError: original, + }); + }); + + it('creates new stack if original error has no stack', () => { + const original = new Error('original'); + const e = new GraphQLError('msg', { originalError: original }); + + expect(e).to.include({ + name: 'GraphQLError', + message: 'msg', + originalError: original, + }); + expect(e.stack).to.be.a('string'); + }); + + it('converts nodes to positions and locations', () => { + const e = new GraphQLError('msg', { nodes: [fieldNode] }); + expect(e).to.deep.include({ + source, + nodes: [fieldNode], + positions: [4], + locations: [{ line: 2, column: 3 }], + }); + }); + + it('converts single node to positions and locations', () => { + const e = new GraphQLError('msg', { nodes: fieldNode }); // Non-array value. + expect(e).to.deep.include({ + source, + nodes: [fieldNode], + positions: [4], + locations: [{ line: 2, column: 3 }], + }); + }); + + it('converts node with loc.start === 0 to positions and locations', () => { + const e = new GraphQLError('msg', { nodes: operationNode }); + expect(e).to.deep.include({ + source, + nodes: [operationNode], + positions: [0], + locations: [{ line: 1, column: 1 }], + }); + }); + + it('converts node without location to undefined source, positions and locations', () => { + const fieldNodeNoLocation = { + ...fieldNode, + loc: undefined, + }; + + const e = new GraphQLError('msg', { nodes: fieldNodeNoLocation }); + expect(e).to.deep.include({ + nodes: [fieldNodeNoLocation], + source: undefined, + positions: undefined, + locations: undefined, + }); + }); + + it('converts source and positions to locations', () => { + const e = new GraphQLError('msg', { source, positions: [6] }); + expect(e).to.deep.include({ + source, + nodes: undefined, + positions: [6], + locations: [{ line: 2, column: 5 }], + }); + }); + + it('defaults to original error extension only if extensions argument is not passed', () => { + class ErrorWithExtensions extends Error { + extensions: unknown; + + constructor(message: string) { + super(message); + this.extensions = { original: 'extensions' }; + } + } + + const original = new ErrorWithExtensions('original'); + const inheritedExtensions = new GraphQLError('InheritedExtensions', { + originalError: original, + }); + + expect(inheritedExtensions).to.deep.include({ + message: 'InheritedExtensions', + originalError: original, + extensions: { original: 'extensions' }, + }); + + const ownExtensions = new GraphQLError('OwnExtensions', { + originalError: original, + extensions: { own: 'extensions' }, + }); + + expect(ownExtensions).to.deep.include({ + message: 'OwnExtensions', + originalError: original, + extensions: { own: 'extensions' }, + }); + + const ownEmptyExtensions = new GraphQLError('OwnEmptyExtensions', { + originalError: original, + extensions: {}, + }); + + expect(ownEmptyExtensions).to.deep.include({ + message: 'OwnEmptyExtensions', + originalError: original, + extensions: {}, + }); + }); + + it('serializes to include all standard fields', () => { + const eShort = new GraphQLError('msg'); + expect(JSON.stringify(eShort, null, 2)).to.equal(dedent` + { + "message": "msg" + } + `); + + const path = ['path', 2, 'field']; + const extensions = { foo: 'bar' }; + const eFull = new GraphQLError('msg', { + nodes: fieldNode, + path, + extensions, + }); + + // We should try to keep order of fields stable + // Changing it wouldn't be breaking change but will fail some tests in other libraries. + expect(JSON.stringify(eFull, null, 2)).to.equal(dedent` + { + "message": "msg", + "locations": [ + { + "line": 2, + "column": 3 + } + ], + "path": [ + "path", + 2, + "field" + ], + "extensions": { + "foo": "bar" + } + } + `); + }); +}); + +describe('toString', () => { + it('Deprecated: prints an error using printError', () => { + const error = new GraphQLError('Error'); + expect(printError(error)).to.equal('Error'); + }); + + it('prints an error without location', () => { + const error = new GraphQLError('Error without location'); + expect(error.toString()).to.equal('Error without location'); + }); + + it('prints an error using node without location', () => { + const error = new GraphQLError('Error attached to node without location', { + nodes: parse('{ foo }', { noLocation: true }), + }); + expect(error.toString()).to.equal( + 'Error attached to node without location', + ); + }); + + it('prints an error with nodes from different sources', () => { + const docA = parse( + new Source( + dedent` + type Foo { + field: String + } + `, + 'SourceA', + ), + ); + const opA = docA.definitions[0]; + invariant(opA.kind === Kind.OBJECT_TYPE_DEFINITION && opA.fields); + const fieldA = opA.fields[0]; + + const docB = parse( + new Source( + dedent` + type Foo { + field: Int + } + `, + 'SourceB', + ), + ); + const opB = docB.definitions[0]; + invariant(opB.kind === Kind.OBJECT_TYPE_DEFINITION && opB.fields); + const fieldB = opB.fields[0]; + + const error = new GraphQLError('Example error with two nodes', [ + fieldA.type, + fieldB.type, + ]); + + expect(error.toString()).to.equal(dedent` + Example error with two nodes + + SourceA:2:10 + 1 | type Foo { + 2 | field: String + | ^ + 3 | } + + SourceB:2:10 + 1 | type Foo { + 2 | field: Int + | ^ + 3 | } + `); + }); +}); + +describe('toJSON', () => { + it('Deprecated: format an error using formatError', () => { + const error = new GraphQLError('Example Error'); + expect(formatError(error)).to.deep.equal({ + message: 'Example Error', + }); + }); + + it('includes path', () => { + const error = new GraphQLError('msg', { path: ['path', 3, 'to', 'field'] }); + + expect(error.toJSON()).to.deep.equal({ + message: 'msg', + path: ['path', 3, 'to', 'field'], + }); + }); + + it('includes extension fields', () => { + const error = new GraphQLError('msg', { + extensions: { foo: 'bar' }, + }); + + expect(error.toJSON()).to.deep.equal({ + message: 'msg', + extensions: { foo: 'bar' }, + }); + }); + + it('can be created with the legacy argument list', () => { + const error = new GraphQLError( + 'msg', + [operationNode], + source, + [6], + ['path', 2, 'a'], + new Error('I like turtles'), + { hee: 'I like turtles' }, + ); + + expect(error.toJSON()).to.deep.equal({ + message: 'msg', + locations: [{ column: 5, line: 2 }], + path: ['path', 2, 'a'], + extensions: { hee: 'I like turtles' }, + }); + }); +}); diff --git a/src/error/__tests__/formatError-test.js b/src/error/__tests__/formatError-test.js deleted file mode 100644 index d6c8e17e8d..0000000000 --- a/src/error/__tests__/formatError-test.js +++ /dev/null @@ -1,58 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { formatError } from '../formatError'; -import { GraphQLError } from '../GraphQLError'; - -describe('formatError: default error formatter', () => { - it('uses default message', () => { - // $FlowExpectedError[incompatible-call] - const e = new GraphQLError(); - - expect(formatError(e)).to.deep.equal({ - message: 'An unknown error occurred.', - path: undefined, - locations: undefined, - }); - }); - - it('includes path', () => { - const e = new GraphQLError('msg', null, null, null, [ - 'path', - 3, - 'to', - 'field', - ]); - - expect(formatError(e)).to.deep.equal({ - message: 'msg', - locations: undefined, - path: ['path', 3, 'to', 'field'], - }); - }); - - it('includes extension fields', () => { - const e = new GraphQLError('msg', null, null, null, null, null, { - foo: 'bar', - }); - - expect(formatError(e)).to.deep.equal({ - message: 'msg', - locations: undefined, - path: undefined, - extensions: { foo: 'bar' }, - }); - }); - - it('rejects null and undefined errors', () => { - // $FlowExpectedError[incompatible-call] - expect(() => formatError(undefined)).to.throw( - 'Received null or undefined error.', - ); - - // $FlowExpectedError[incompatible-call] - expect(() => formatError(null)).to.throw( - 'Received null or undefined error.', - ); - }); -}); diff --git a/src/error/__tests__/locatedError-test.js b/src/error/__tests__/locatedError-test.js deleted file mode 100644 index 3de473b4c9..0000000000 --- a/src/error/__tests__/locatedError-test.js +++ /dev/null @@ -1,37 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { GraphQLError } from '../GraphQLError'; -import { locatedError } from '../locatedError'; - -describe('locatedError', () => { - it('passes GraphQLError through', () => { - const e = new GraphQLError('msg', null, null, null, [ - 'path', - 3, - 'to', - 'field', - ]); - - expect(locatedError(e, [], [])).to.deep.equal(e); - }); - - it('passes GraphQLError-ish through', () => { - const e = new Error('I have a different prototype chain'); - (e: any).locations = []; - (e: any).path = []; - (e: any).nodes = []; - (e: any).source = null; - (e: any).positions = []; - (e: any).name = 'GraphQLError'; - - expect(locatedError(e, [], [])).to.deep.equal(e); - }); - - it('does not pass through elasticsearch-like errors', () => { - const e = new Error('I am from elasticsearch'); - (e: any).path = '/something/feed/_search'; - - expect(locatedError(e, [], [])).to.not.deep.equal(e); - }); -}); diff --git a/src/error/__tests__/locatedError-test.ts b/src/error/__tests__/locatedError-test.ts new file mode 100644 index 0000000000..e270d09a6d --- /dev/null +++ b/src/error/__tests__/locatedError-test.ts @@ -0,0 +1,49 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { GraphQLError } from '../GraphQLError'; +import { locatedError } from '../locatedError'; + +describe('locatedError', () => { + it('passes GraphQLError through', () => { + const e = new GraphQLError('msg', { path: ['path', 3, 'to', 'field'] }); + + expect(locatedError(e, [], [])).to.deep.equal(e); + }); + + it('wraps non-errors', () => { + const testObject = Object.freeze({}); + const error = locatedError(testObject, [], []); + + expect(error).to.be.instanceOf(GraphQLError); + expect(error.originalError).to.include({ + name: 'NonErrorThrown', + thrownValue: testObject, + }); + }); + + it('passes GraphQLError-ish through', () => { + const e = new Error(); + // @ts-expect-error + e.locations = []; + // @ts-expect-error + e.path = []; + // @ts-expect-error + e.nodes = []; + // @ts-expect-error + e.source = null; + // @ts-expect-error + e.positions = []; + e.name = 'GraphQLError'; + + expect(locatedError(e, [], [])).to.deep.equal(e); + }); + + it('does not pass through elasticsearch-like errors', () => { + const e = new Error('I am from elasticsearch'); + // @ts-expect-error + e.path = '/something/feed/_search'; + + expect(locatedError(e, [], [])).to.not.deep.equal(e); + }); +}); diff --git a/src/error/formatError.d.ts b/src/error/formatError.d.ts deleted file mode 100644 index fb3451b774..0000000000 --- a/src/error/formatError.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { SourceLocation } from '../language/location'; - -import { GraphQLError } from './GraphQLError'; - -/** - * Given a GraphQLError, format it according to the rules described by the - * Response Format, Errors section of the GraphQL Specification. - */ -export function formatError(error: GraphQLError): GraphQLFormattedError; - -/** - * @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors - */ -export interface GraphQLFormattedError< - TExtensions extends Record = Record -> { - /** - * A short, human-readable summary of the problem that **SHOULD NOT** change - * from occurrence to occurrence of the problem, except for purposes of - * localization. - */ - readonly message: string; - /** - * If an error can be associated to a particular point in the requested - * GraphQL document, it should contain a list of locations. - */ - readonly locations?: ReadonlyArray; - /** - * If an error can be associated to a particular field in the GraphQL result, - * it _must_ contain an entry with the key `path` that details the path of - * the response field which experienced the error. This allows clients to - * identify whether a null result is intentional or caused by a runtime error. - */ - readonly path?: ReadonlyArray; - /** - * Reserved for implementors to extend the protocol however they see fit, - * and hence there are no additional restrictions on its contents. - */ - readonly extensions?: TExtensions; -} diff --git a/src/error/formatError.js b/src/error/formatError.js deleted file mode 100644 index d73cc897b0..0000000000 --- a/src/error/formatError.js +++ /dev/null @@ -1,50 +0,0 @@ -import devAssert from '../jsutils/devAssert'; - -import type { SourceLocation } from '../language/location'; - -import type { GraphQLError } from './GraphQLError'; - -/** - * Given a GraphQLError, format it according to the rules described by the - * Response Format, Errors section of the GraphQL Specification. - */ -export function formatError(error: GraphQLError): GraphQLFormattedError { - devAssert(error, 'Received null or undefined error.'); - const message = error.message ?? 'An unknown error occurred.'; - const locations = error.locations; - const path = error.path; - const extensions = error.extensions; - - return extensions - ? { message, locations, path, extensions } - : { message, locations, path }; -} - -/** - * @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors - */ -export type GraphQLFormattedError = {| - /** - * A short, human-readable summary of the problem that **SHOULD NOT** change - * from occurrence to occurrence of the problem, except for purposes of - * localization. - */ - +message: string, - /** - * If an error can be associated to a particular point in the requested - * GraphQL document, it should contain a list of locations. - */ - +locations: $ReadOnlyArray | void, - /** - * If an error can be associated to a particular field in the GraphQL result, - * it _must_ contain an entry with the key `path` that details the path of - * the response field which experienced the error. This allows clients to - * identify whether a null result is intentional or caused by a runtime error. - */ - +path: $ReadOnlyArray | void, - /** - * Reserved for implementors to extend the protocol however they see fit, - * and hence there are no additional restrictions on its contents. - */ - +extensions?: { [key: string]: mixed, ... }, -|}; diff --git a/src/error/index.d.ts b/src/error/index.d.ts deleted file mode 100644 index 9373b7167d..0000000000 --- a/src/error/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { GraphQLError, printError } from './GraphQLError'; -export { syntaxError } from './syntaxError'; -export { locatedError } from './locatedError'; -export { formatError, GraphQLFormattedError } from './formatError'; diff --git a/src/error/index.js b/src/error/index.js deleted file mode 100644 index 914a6dbe46..0000000000 --- a/src/error/index.js +++ /dev/null @@ -1,8 +0,0 @@ -export { GraphQLError, printError } from './GraphQLError'; - -export { syntaxError } from './syntaxError'; - -export { locatedError } from './locatedError'; - -export { formatError } from './formatError'; -export type { GraphQLFormattedError } from './formatError'; diff --git a/src/error/index.ts b/src/error/index.ts new file mode 100644 index 0000000000..7e5d267f50 --- /dev/null +++ b/src/error/index.ts @@ -0,0 +1,11 @@ +export { GraphQLError, printError, formatError } from './GraphQLError'; +export type { + GraphQLErrorOptions, + GraphQLFormattedError, + GraphQLErrorExtensions, + GraphQLFormattedErrorExtensions, +} from './GraphQLError'; + +export { syntaxError } from './syntaxError'; + +export { locatedError } from './locatedError'; diff --git a/src/error/locatedError.d.ts b/src/error/locatedError.d.ts deleted file mode 100644 index 8693757094..0000000000 --- a/src/error/locatedError.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { ASTNode } from '../language/ast'; - -import { GraphQLError } from './GraphQLError'; - -/** - * Given an arbitrary value, presumably thrown while attempting to execute a - * GraphQL operation, produce a new GraphQLError aware of the location in the - * document responsible for the original Error. - */ -export function locatedError( - rawOriginalError: any, - nodes: ASTNode | ReadonlyArray | undefined, - path?: Maybe>, -): GraphQLError; diff --git a/src/error/locatedError.js b/src/error/locatedError.js deleted file mode 100644 index 1b7c335070..0000000000 --- a/src/error/locatedError.js +++ /dev/null @@ -1,36 +0,0 @@ -import inspect from '../jsutils/inspect'; - -import type { ASTNode } from '../language/ast'; - -import { GraphQLError } from './GraphQLError'; - -/** - * Given an arbitrary value, presumably thrown while attempting to execute a - * GraphQL operation, produce a new GraphQLError aware of the location in the - * document responsible for the original Error. - */ -export function locatedError( - rawOriginalError: mixed, - nodes: ASTNode | $ReadOnlyArray | void | null, - path?: ?$ReadOnlyArray, -): GraphQLError { - // Sometimes a non-error is thrown, wrap it as an Error instance to ensure a consistent Error interface. - const originalError: Error | GraphQLError = - rawOriginalError instanceof Error - ? rawOriginalError - : new Error('Unexpected error value: ' + inspect(rawOriginalError)); - - // Note: this uses a brand-check to support GraphQL errors originating from other contexts. - if (Array.isArray(originalError.path)) { - return (originalError: any); - } - - return new GraphQLError( - originalError.message, - (originalError: any).nodes ?? nodes, - (originalError: any).source, - (originalError: any).positions, - path, - originalError, - ); -} diff --git a/src/error/locatedError.ts b/src/error/locatedError.ts new file mode 100644 index 0000000000..bafb9da9b6 --- /dev/null +++ b/src/error/locatedError.ts @@ -0,0 +1,36 @@ +import type { Maybe } from '../jsutils/Maybe'; +import { toError } from '../jsutils/toError'; + +import type { ASTNode } from '../language/ast'; + +import { GraphQLError } from './GraphQLError'; + +/** + * Given an arbitrary value, presumably thrown while attempting to execute a + * GraphQL operation, produce a new GraphQLError aware of the location in the + * document responsible for the original Error. + */ +export function locatedError( + rawOriginalError: unknown, + nodes: ASTNode | ReadonlyArray | undefined | null, + path?: Maybe>, +): GraphQLError { + const originalError = toError(rawOriginalError); + + // Note: this uses a brand-check to support GraphQL errors originating from other contexts. + if (isLocatedGraphQLError(originalError)) { + return originalError; + } + + return new GraphQLError(originalError.message, { + nodes: (originalError as GraphQLError).nodes ?? nodes, + source: (originalError as GraphQLError).source, + positions: (originalError as GraphQLError).positions, + path, + originalError, + }); +} + +function isLocatedGraphQLError(error: any): error is GraphQLError { + return Array.isArray(error.path); +} diff --git a/src/error/syntaxError.d.ts b/src/error/syntaxError.d.ts deleted file mode 100644 index 1c5413c7e0..0000000000 --- a/src/error/syntaxError.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Source } from '../language/source'; - -import { GraphQLError } from './GraphQLError'; - -/** - * Produces a GraphQLError representing a syntax error, containing useful - * descriptive information about the syntax error's position in the source. - */ -export function syntaxError( - source: Source, - position: number, - description: string, -): GraphQLError; diff --git a/src/error/syntaxError.js b/src/error/syntaxError.ts similarity index 77% rename from src/error/syntaxError.js rename to src/error/syntaxError.ts index 21a2dc18e4..386ece72da 100644 --- a/src/error/syntaxError.js +++ b/src/error/syntaxError.ts @@ -11,7 +11,8 @@ export function syntaxError( position: number, description: string, ): GraphQLError { - return new GraphQLError(`Syntax Error: ${description}`, undefined, source, [ - position, - ]); + return new GraphQLError(`Syntax Error: ${description}`, { + source, + positions: [position], + }); } diff --git a/src/execution/__tests__/abstract-test.js b/src/execution/__tests__/abstract-test.ts similarity index 85% rename from src/execution/__tests__/abstract-test.js rename to src/execution/__tests__/abstract-test.ts index 1d8bbeaab0..5253d0d9e0 100644 --- a/src/execution/__tests__/abstract-test.js +++ b/src/execution/__tests__/abstract-test.ts @@ -1,28 +1,29 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; +import { expectJSON } from '../../__testUtils__/expectJSON'; import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString, GraphQLBoolean } from '../../type/scalars'; import { + assertInterfaceType, + GraphQLInterfaceType, GraphQLList, GraphQLObjectType, - GraphQLInterfaceType, GraphQLUnionType, } from '../../type/definition'; +import { GraphQLBoolean, GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { executeSync, execute } from '../execute'; +import { execute, executeSync } from '../execute'; -async function executeQuery(args: {| - schema: GraphQLSchema, - query: string, - rootValue?: mixed, -|}) { +async function executeQuery(args: { + schema: GraphQLSchema; + query: string; + rootValue?: unknown; +}) { const { schema, query, rootValue } = args; const document = parse(query); const result = executeSync({ @@ -38,7 +39,7 @@ async function executeQuery(args: {| contextValue: { async: true }, }); - expect(result).to.deep.equal(asyncResult); + expectJSON(result).toDeepEqual(asyncResult); return result; } @@ -205,7 +206,7 @@ describe('Execute: Handles execution of abstract types', () => { } `; - expect(await executeQuery({ schema, query })).to.deep.equal({ + expectJSON(await executeQuery({ schema, query })).toDeepEqual({ data: { pets: [null, null], }, @@ -224,102 +225,67 @@ describe('Execute: Handles execution of abstract types', () => { }); }); - it('isTypeOf used to resolve runtime type for Union', async () => { - const DogType = new GraphQLObjectType({ - name: 'Dog', - isTypeOf(obj, context) { - const isDog = obj instanceof Dog; - return context.async ? Promise.resolve(isDog) : isDog; - }, + it('isTypeOf can return false', async () => { + const PetType = new GraphQLInterfaceType({ + name: 'Pet', fields: { name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, }, }); - const CatType = new GraphQLObjectType({ - name: 'Cat', - isTypeOf(obj, context) { - const isCat = obj instanceof Cat; - return context.async ? Promise.resolve(isCat) : isCat; + const DogType = new GraphQLObjectType({ + name: 'Dog', + interfaces: [PetType], + isTypeOf(_source, context) { + return context.async ? Promise.resolve(false) : false; }, fields: { name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, + woofs: { type: GraphQLBoolean }, }, }); - const PetType = new GraphQLUnionType({ - name: 'Pet', - types: [DogType, CatType], - }); - const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { - pets: { - type: new GraphQLList(PetType), - resolve() { - return [new Dog('Odie', true), new Cat('Garfield', false)]; - }, + pet: { + type: PetType, + resolve: () => ({}), }, }, }), + types: [DogType], }); - const query = `{ - pets { - ... on Dog { - name - woofs - } - ... on Cat { + const query = ` + { + pet { name - meows } } - }`; + `; - expect(await executeQuery({ schema, query })).to.deep.equal({ - data: { - pets: [ - { - name: 'Odie', - woofs: true, - }, - { - name: 'Garfield', - meows: false, - }, - ], - }, + expectJSON(await executeQuery({ schema, query })).toDeepEqual({ + data: { pet: null }, + errors: [ + { + message: + 'Abstract type "Pet" must resolve to an Object type at runtime for field "Query.pet". Either the "Pet" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.', + locations: [{ line: 3, column: 9 }], + path: ['pet'], + }, + ], }); }); - it('deprecated(will be removed in v16.0.0): resolveType allows resolving with type object', async () => { - const PetType = new GraphQLInterfaceType({ - name: 'Pet', - resolveType(obj, context) { - if (obj instanceof Dog) { - return context.async ? Promise.resolve(DogType) : DogType; - } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') - if (obj instanceof Cat) { - return context.async ? Promise.resolve(CatType) : CatType; - } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false); - }, - fields: { - name: { type: GraphQLString }, - }, - }); - + it('isTypeOf used to resolve runtime type for Union', async () => { const DogType = new GraphQLObjectType({ name: 'Dog', - interfaces: [PetType], + isTypeOf(obj, context) { + const isDog = obj instanceof Dog; + return context.async ? Promise.resolve(isDog) : isDog; + }, fields: { name: { type: GraphQLString }, woofs: { type: GraphQLBoolean }, @@ -328,13 +294,21 @@ describe('Execute: Handles execution of abstract types', () => { const CatType = new GraphQLObjectType({ name: 'Cat', - interfaces: [PetType], + isTypeOf(obj, context) { + const isCat = obj instanceof Cat; + return context.async ? Promise.resolve(isCat) : isCat; + }, fields: { name: { type: GraphQLString }, meows: { type: GraphQLBoolean }, }, }); + const PetType = new GraphQLUnionType({ + name: 'Pet', + types: [DogType, CatType], + }); + const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', @@ -347,22 +321,20 @@ describe('Execute: Handles execution of abstract types', () => { }, }, }), - types: [CatType, DogType], }); - const query = ` - { - pets { + const query = `{ + pets { + ... on Dog { name - ... on Dog { - woofs - } - ... on Cat { - meows - } + woofs + } + ... on Cat { + name + meows } } - `; + }`; expect(await executeQuery({ schema, query })).to.deep.equal({ data: { @@ -442,7 +414,7 @@ describe('Execute: Handles execution of abstract types', () => { } `; - expect(await executeQuery({ schema, query })).to.deep.equal({ + expectJSON(await executeQuery({ schema, query })).toDeepEqual({ data: { pets: [null, null], }, @@ -618,12 +590,12 @@ describe('Execute: Handles execution of abstract types', () => { } `); - function expectError({ forTypeName }: {| forTypeName: mixed |}) { + function expectError({ forTypeName }: { forTypeName: unknown }) { const rootValue = { pet: { __typename: forTypeName } }; const result = executeSync({ schema, document, rootValue }); return { toEqual(message: string) { - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { pet: null }, errors: [ { @@ -642,11 +614,11 @@ describe('Execute: Handles execution of abstract types', () => { ); expectError({ forTypeName: 'Human' }).toEqual( - 'Abstract type "Pet" was resolve to a type "Human" that does not exist inside schema.', + 'Abstract type "Pet" was resolved to a type "Human" that does not exist inside the schema.', ); expectError({ forTypeName: 'String' }).toEqual( - 'Abstract type "Pet" was resolve to a non-object type "String".', + 'Abstract type "Pet" was resolved to a non-object type "String".', ); expectError({ forTypeName: '__Schema' }).toEqual( @@ -654,9 +626,18 @@ describe('Execute: Handles execution of abstract types', () => { ); // FIXME: workaround since we can't inject resolveType into SDL - (schema.getType('Pet'): any).resolveType = () => []; + // @ts-expect-error + assertInterfaceType(schema.getType('Pet')).resolveType = () => []; expectError({ forTypeName: undefined }).toEqual( 'Abstract type "Pet" must resolve to an Object type at runtime for field "Query.pet" with value { __typename: undefined }, received "[]".', ); + + // FIXME: workaround since we can't inject resolveType into SDL + // @ts-expect-error + assertInterfaceType(schema.getType('Pet')).resolveType = () => + schema.getType('Cat'); + expectError({ forTypeName: undefined }).toEqual( + 'Support for returning GraphQLObjectType from resolveType was removed in graphql-js@16.0.0 please return type name instead.', + ); }); }); diff --git a/src/execution/__tests__/directives-test.js b/src/execution/__tests__/directives-test.ts similarity index 99% rename from src/execution/__tests__/directives-test.js rename to src/execution/__tests__/directives-test.ts index 92c8fb9c5f..d94c0f2b8a 100644 --- a/src/execution/__tests__/directives-test.js +++ b/src/execution/__tests__/directives-test.ts @@ -3,9 +3,9 @@ import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; +import { GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { executeSync } from '../execute'; @@ -174,6 +174,7 @@ describe('Execute: handles directives', () => { data: { a: 'a', b: 'b' }, }); }); + it('unless false includes inline fragment', () => { const result = executeTestQuery(` query { @@ -188,6 +189,7 @@ describe('Execute: handles directives', () => { data: { a: 'a', b: 'b' }, }); }); + it('unless true includes inline fragment', () => { const result = executeTestQuery(` query { @@ -234,6 +236,7 @@ describe('Execute: handles directives', () => { data: { a: 'a', b: 'b' }, }); }); + it('unless false includes anonymous inline fragment', () => { const result = executeTestQuery(` query Q { @@ -248,6 +251,7 @@ describe('Execute: handles directives', () => { data: { a: 'a', b: 'b' }, }); }); + it('unless true includes anonymous inline fragment', () => { const result = executeTestQuery(` query { diff --git a/src/execution/__tests__/executor-test.js b/src/execution/__tests__/executor-test.ts similarity index 89% rename from src/execution/__tests__/executor-test.js rename to src/execution/__tests__/executor-test.ts index aa9427ffc4..c758d3e426 100644 --- a/src/execution/__tests__/executor-test.js +++ b/src/execution/__tests__/executor-test.ts @@ -1,22 +1,25 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import inspect from '../../jsutils/inspect'; -import invariant from '../../jsutils/invariant'; +import { expectJSON } from '../../__testUtils__/expectJSON'; +import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick'; + +import { inspect } from '../../jsutils/inspect'; +import { invariant } from '../../jsutils/invariant'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLInt, GraphQLBoolean, GraphQLString } from '../../type/scalars'; import { + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, - GraphQLScalarType, - GraphQLInterfaceType, GraphQLObjectType, + GraphQLScalarType, GraphQLUnionType, } from '../../type/definition'; +import { GraphQLBoolean, GraphQLInt, GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { execute, executeSync } from '../execute'; @@ -31,14 +34,14 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - // $FlowExpectedError[prop-missing] + // @ts-expect-error expect(() => executeSync({ schema })).to.throw('Must provide document.'); }); it('throws if no schema is provided', () => { const document = parse('{ field }'); - // $FlowExpectedError[prop-missing] + // @ts-expect-error expect(() => executeSync({ document })).to.throw( 'Expected undefined to be a GraphQL schema.', ); @@ -63,36 +66,12 @@ describe('Execute: Handles basic execution tasks', () => { `); const variableValues = '{ "a": 1 }'; - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => executeSync({ schema, document, variableValues })).to.throw( 'Variables must be provided as an Object where each property is a variable value. Perhaps look to see if an unparsed JSON string was provided.', ); }); - it('accepts positional arguments', () => { - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Type', - fields: { - a: { - type: GraphQLString, - resolve(rootValue) { - return rootValue; - }, - }, - }, - }), - }); - - const document = parse('{ a }'); - const rootValue = 'rootValue'; - const result = execute(schema, document, rootValue); - - expect(result).to.deep.equal({ - data: { a: 'rootValue' }, - }); - }); - it('executes arbitrary code', async () => { const data = { a: () => 'Apple', @@ -118,7 +97,7 @@ describe('Execute: Handles basic execution tasks', () => { return Promise.resolve(data); } - const DataType = new GraphQLObjectType({ + const DataType: GraphQLObjectType = new GraphQLObjectType({ name: 'DataType', fields: () => ({ a: { type: GraphQLString }, @@ -209,7 +188,7 @@ describe('Execute: Handles basic execution tasks', () => { }); it('merges parallel fragments', () => { - const Type = new GraphQLObjectType({ + const Type: GraphQLObjectType = new GraphQLObjectType({ name: 'Type', fields: () => ({ a: { type: GraphQLString, resolve: () => 'Apple' }, @@ -467,7 +446,7 @@ describe('Execute: Handles basic execution tasks', () => { throw new Error('Error getting syncError'); }, syncRawError() { - // eslint-disable-next-line no-throw-literal + // eslint-disable-next-line @typescript-eslint/no-throw-literal throw 'Error getting syncRawError'; }, syncReturnError() { @@ -504,7 +483,7 @@ describe('Execute: Handles basic execution tasks', () => { }, asyncRawError() { return new Promise(() => { - // eslint-disable-next-line no-throw-literal + // eslint-disable-next-line @typescript-eslint/no-throw-literal throw 'Error getting asyncRawError'; }); }, @@ -513,14 +492,15 @@ describe('Execute: Handles basic execution tasks', () => { }, asyncReturnErrorWithExtensions() { const error = new Error('Error getting asyncReturnErrorWithExtensions'); - (error: any).extensions = { foo: 'bar' }; + // @ts-expect-error + error.extensions = { foo: 'bar' }; return Promise.resolve(error); }, }; const result = await execute({ schema, document, rootValue }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { sync: 'sync', syncError: null, @@ -634,7 +614,7 @@ describe('Execute: Handles basic execution tasks', () => { const result = await execute({ schema, document }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { foods: null }, errors: [ { @@ -646,8 +626,58 @@ describe('Execute: Handles basic execution tasks', () => { }); }); + it('handles sync errors combined with rejections', async () => { + let isAsyncResolverFinished = false; + + const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + syncNullError: { + type: new GraphQLNonNull(GraphQLString), + resolve: () => null, + }, + asyncNullError: { + type: new GraphQLNonNull(GraphQLString), + async resolve() { + await resolveOnNextTick(); + await resolveOnNextTick(); + await resolveOnNextTick(); + isAsyncResolverFinished = true; + return null; + }, + }, + }, + }), + }); + + // Order is important here, as the promise has to be created before the synchronous error is thrown + const document = parse(` + { + asyncNullError + syncNullError + } + `); + + const result = execute({ schema, document }); + + expect(isAsyncResolverFinished).to.equal(false); + expectJSON(await result).toDeepEqual({ + data: null, + errors: [ + { + message: + 'Cannot return null for non-nullable field Query.syncNullError.', + locations: [{ line: 4, column: 9 }], + path: ['syncNullError'], + }, + ], + }); + expect(isAsyncResolverFinished).to.equal(true); + }); + it('Full response path is included for non-nullable fields', () => { - const A = new GraphQLObjectType({ + const A: GraphQLObjectType = new GraphQLObjectType({ name: 'A', fields: () => ({ nullableA: { @@ -693,7 +723,7 @@ describe('Execute: Handles basic execution tasks', () => { `); const result = executeSync({ schema, document }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { nullableA: { aliasedA: null, @@ -775,7 +805,7 @@ describe('Execute: Handles basic execution tasks', () => { const rootValue = { a: 'b' }; const result = executeSync({ schema, document, rootValue }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [{ message: 'Must provide an operation.' }], }); }); @@ -795,7 +825,7 @@ describe('Execute: Handles basic execution tasks', () => { `); const result = executeSync({ schema, document }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -821,7 +851,7 @@ describe('Execute: Handles basic execution tasks', () => { const operationName = 'UnknownExample'; const result = executeSync({ schema, document, operationName }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [{ message: 'Unknown operation named "UnknownExample".' }], }); }); @@ -839,7 +869,7 @@ describe('Execute: Handles basic execution tasks', () => { const operationName = ''; const result = executeSync({ schema, document, operationName }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [{ message: 'Unknown operation named "".' }], }); }); @@ -929,6 +959,53 @@ describe('Execute: Handles basic execution tasks', () => { expect(result).to.deep.equal({ data: { a: 'b' } }); }); + it('resolves to an error if schema does not support operation', () => { + const schema = new GraphQLSchema({ assumeValid: true }); + + const document = parse(` + query Q { __typename } + mutation M { __typename } + subscription S { __typename } + `); + + expectJSON( + executeSync({ schema, document, operationName: 'Q' }), + ).toDeepEqual({ + data: null, + errors: [ + { + message: 'Schema is not configured to execute query operation.', + locations: [{ line: 2, column: 7 }], + }, + ], + }); + + expectJSON( + executeSync({ schema, document, operationName: 'M' }), + ).toDeepEqual({ + data: null, + errors: [ + { + message: 'Schema is not configured to execute mutation operation.', + locations: [{ line: 3, column: 7 }], + }, + ], + }); + + expectJSON( + executeSync({ schema, document, operationName: 'S' }), + ).toDeepEqual({ + data: null, + errors: [ + { + message: + 'Schema is not configured to execute subscription operation.', + locations: [{ line: 4, column: 7 }], + }, + ], + }); + }); + it('correct field ordering despite execution order', async () => { const schema = new GraphQLSchema({ query: new GraphQLObjectType({ @@ -1097,7 +1174,7 @@ describe('Execute: Handles basic execution tasks', () => { }; const result = executeSync({ schema, document, rootValue }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { specials: [{ value: 'foo' }, null], }, @@ -1141,12 +1218,12 @@ describe('Execute: Handles basic execution tasks', () => { }); const result = executeSync({ schema, document: parse('{ customScalar }') }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { customScalar: null }, errors: [ { message: - 'Expected a value of type "CustomScalar" but received: "CUSTOM_VALUE"', + 'Expected `CustomScalar.serialize("CUSTOM_VALUE")` to return non-nullable value, returned: undefined', locations: [{ line: 1, column: 3 }], path: ['customScalar'], }, diff --git a/src/execution/__tests__/lists-test.js b/src/execution/__tests__/lists-test.ts similarity index 76% rename from src/execution/__tests__/lists-test.js rename to src/execution/__tests__/lists-test.ts index 5654b55ccc..ac6460d547 100644 --- a/src/execution/__tests__/lists-test.js +++ b/src/execution/__tests__/lists-test.ts @@ -1,6 +1,8 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import { expectJSON } from '../../__testUtils__/expectJSON'; + import { parse } from '../../language/parser'; import { buildSchema } from '../../utilities/buildASTSchema'; @@ -8,7 +10,7 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { execute, executeSync } from '../execute'; describe('Execute: Accepts any iterable as list value', () => { - function complete(rootValue: mixed) { + function complete(rootValue: unknown) { return executeSync({ schema: buildSchema('type Query { listField: [String] }'), document: parse('{ listField }'), @@ -37,7 +39,7 @@ describe('Execute: Accepts any iterable as list value', () => { }); it('Accepts function arguments as a List value', () => { - function getArgs(..._args: Array) { + function getArgs(..._args: ReadonlyArray) { return arguments; } const listField = getArgs('one', 'two'); @@ -50,7 +52,7 @@ describe('Execute: Accepts any iterable as list value', () => { it('Does not accept (Iterable) String-literal as a List value', () => { const listField = 'Singular'; - expect(complete({ listField })).to.deep.equal({ + expectJSON(complete({ listField })).toDeepEqual({ data: { listField: null }, errors: [ { @@ -65,31 +67,31 @@ describe('Execute: Accepts any iterable as list value', () => { }); describe('Execute: Handles list nullability', () => { - async function complete(args: {| listField: mixed, as: string |}) { + async function complete(args: { listField: unknown; as: string }) { const { listField, as } = args; const schema = buildSchema(`type Query { listField: ${as} }`); const document = parse('{ listField }'); const result = await executeQuery(listField); // Promise> === Array - expect(await executeQuery(promisify(listField))).to.deep.equal(result); + expectJSON(await executeQuery(promisify(listField))).toDeepEqual(result); if (Array.isArray(listField)) { const listOfPromises = listField.map(promisify); // Array> === Array - expect(await executeQuery(listOfPromises)).to.deep.equal(result); + expectJSON(await executeQuery(listOfPromises)).toDeepEqual(result); // Promise>> === Array - expect(await executeQuery(promisify(listOfPromises))).to.deep.equal( + expectJSON(await executeQuery(promisify(listOfPromises))).toDeepEqual( result, ); } return result; - function executeQuery(listValue: mixed) { + function executeQuery(listValue: unknown) { return execute({ schema, document, rootValue: { listField: listValue } }); } - function promisify(value: mixed): Promise { + function promisify(value: unknown): Promise { return value instanceof Error ? Promise.reject(value) : Promise.resolve(value); @@ -129,11 +131,11 @@ describe('Execute: Handles list nullability', () => { expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ data: { listField: [1, null, 2] }, }); - expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int!]' })).toDeepEqual({ data: { listField: null }, errors, }); - expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int!]!' })).toDeepEqual({ data: null, errors, }); @@ -152,14 +154,14 @@ describe('Execute: Handles list nullability', () => { expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ data: { listField: null }, }); - expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int]!' })).toDeepEqual({ data: null, errors, }); expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ data: { listField: null }, }); - expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int!]!' })).toDeepEqual({ data: null, errors, }); @@ -175,19 +177,19 @@ describe('Execute: Handles list nullability', () => { }, ]; - expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int]' })).toDeepEqual({ data: { listField: [1, null, 2] }, errors, }); - expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int]!' })).toDeepEqual({ data: { listField: [1, null, 2] }, errors, }); - expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int!]' })).toDeepEqual({ data: { listField: null }, errors, }); - expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int!]!' })).toDeepEqual({ data: null, errors, }); @@ -203,19 +205,19 @@ describe('Execute: Handles list nullability', () => { }, ]; - expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int]' })).toDeepEqual({ data: { listField: null }, errors, }); - expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int]!' })).toDeepEqual({ data: null, errors, }); - expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int!]' })).toDeepEqual({ data: { listField: null }, errors, }); - expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + expectJSON(await complete({ listField, as: '[Int!]!' })).toDeepEqual({ data: null, errors, }); diff --git a/src/subscription/__tests__/mapAsyncIterator-test.js b/src/execution/__tests__/mapAsyncIterator-test.ts similarity index 67% rename from src/subscription/__tests__/mapAsyncIterator-test.js rename to src/execution/__tests__/mapAsyncIterator-test.ts index 4af866f20a..ec01634e6a 100644 --- a/src/subscription/__tests__/mapAsyncIterator-test.js +++ b/src/execution/__tests__/mapAsyncIterator-test.ts @@ -1,8 +1,9 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import mapAsyncIterator from '../mapAsyncIterator'; +import { mapAsyncIterator } from '../mapAsyncIterator'; +/* eslint-disable @typescript-eslint/require-await */ describe('mapAsyncIterator', () => { it('maps over async generator', async () => { async function* source() { @@ -22,22 +23,26 @@ describe('mapAsyncIterator', () => { }); }); - it('maps over async iterator', async () => { + it('maps over async iterable', async () => { const items = [1, 2, 3]; - const iterator: any = { + const iterable = { [Symbol.asyncIterator]() { return this; }, - next() { - return Promise.resolve({ - done: items.length === 0, - value: items.shift(), - }); + + next(): Promise> { + if (items.length > 0) { + const value = items[0]; + items.shift(); + return Promise.resolve({ done: false, value }); + } + + return Promise.resolve({ done: true, value: undefined }); }, }; - const doubles = mapAsyncIterator(iterator, (x) => x + x); + const doubles = mapAsyncIterator(iterable, (x) => x + x); expect(await doubles.next()).to.deep.equal({ value: 2, done: false }); expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); @@ -71,11 +76,7 @@ describe('mapAsyncIterator', () => { yield 3; } - // Flow test: this is *not* AsyncIterator> - const doubles: AsyncIterator = mapAsyncIterator( - source(), - async (x) => (await x) + x, - ); + const doubles = mapAsyncIterator(source(), (x) => Promise.resolve(x + x)); expect(await doubles.next()).to.deep.equal({ value: 2, done: false }); expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); @@ -88,11 +89,15 @@ describe('mapAsyncIterator', () => { it('allows returning early from mapped async generator', async () => { async function* source() { - yield 1; - yield 2; - - // istanbul ignore next (Shouldn't be reached) - yield 3; + try { + yield 1; + /* c8 ignore next 2 */ + yield 2; + yield 3; // Shouldn't be reached. + } finally { + // eslint-disable-next-line no-unsafe-finally + return 'The End'; + } } const doubles = mapAsyncIterator(source(), (x) => x + x); @@ -101,8 +106,8 @@ describe('mapAsyncIterator', () => { expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); // Early return - expect(await doubles.return()).to.deep.equal({ - value: undefined, + expect(await doubles.return('')).to.deep.equal({ + value: 'The End', done: true, }); @@ -117,28 +122,30 @@ describe('mapAsyncIterator', () => { }); }); - it('allows returning early from mapped async iterator', async () => { + it('allows returning early from mapped async iterable', async () => { const items = [1, 2, 3]; - const iterator: any = { + const iterable = { [Symbol.asyncIterator]() { return this; }, next() { + const value = items[0]; + items.shift(); return Promise.resolve({ done: items.length === 0, - value: items.shift(), + value, }); }, }; - const doubles = mapAsyncIterator(iterator, (x) => x + x); + const doubles = mapAsyncIterator(iterable, (x) => x + x); expect(await doubles.next()).to.deep.equal({ value: 2, done: false }); expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); // Early return - expect(await doubles.return()).to.deep.equal({ + expect(await doubles.return(0)).to.deep.equal({ value: undefined, done: true, }); @@ -147,11 +154,10 @@ describe('mapAsyncIterator', () => { it('passes through early return from async values', async () => { async function* source() { try { - yield 1; - yield 2; - - // istanbul ignore next (Shouldn't be reached) - yield 3; + yield 'a'; + /* c8 ignore next 2 */ + yield 'b'; + yield 'c'; // Shouldn't be reached. } finally { yield 'Done'; yield 'Last'; @@ -160,8 +166,8 @@ describe('mapAsyncIterator', () => { const doubles = mapAsyncIterator(source(), (x) => x + x); - expect(await doubles.next()).to.deep.equal({ value: 2, done: false }); - expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); + expect(await doubles.next()).to.deep.equal({ value: 'aa', done: false }); + expect(await doubles.next()).to.deep.equal({ value: 'bb', done: false }); // Early return expect(await doubles.return()).to.deep.equal({ @@ -180,22 +186,24 @@ describe('mapAsyncIterator', () => { }); }); - it('allows throwing errors through async iterators', async () => { + it('allows throwing errors through async iterable', async () => { const items = [1, 2, 3]; - const iterator: any = { + const iterable = { [Symbol.asyncIterator]() { return this; }, next() { + const value = items[0]; + items.shift(); return Promise.resolve({ done: items.length === 0, - value: items.shift(), + value, }); }, }; - const doubles = mapAsyncIterator(iterator, (x) => x + x); + const doubles = mapAsyncIterator(iterable, (x) => x + x); expect(await doubles.next()).to.deep.equal({ value: 2, done: false }); expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); @@ -203,6 +211,7 @@ describe('mapAsyncIterator', () => { // Throw error let caughtError; try { + /* c8 ignore next */ await doubles.throw('ouch'); } catch (e) { caughtError = e; @@ -214,10 +223,9 @@ describe('mapAsyncIterator', () => { async function* source() { try { yield 1; + /* c8 ignore next 2 */ yield 2; - - // istanbul ignore next (Shouldn't be reached) - yield 3; + yield 3; // Shouldn't be reached. } catch (e) { yield e; } @@ -259,6 +267,7 @@ describe('mapAsyncIterator', () => { let caughtError; try { + /* c8 ignore next */ await doubles.next(); } catch (e) { caughtError = e; @@ -269,45 +278,15 @@ describe('mapAsyncIterator', () => { .with.property('message', 'Goodbye'); }); - it('maps over thrown errors if second callback provided', async () => { - async function* source() { - yield 'Hello'; - throw new Error('Goodbye'); - } - - const doubles = mapAsyncIterator( - source(), - (x) => x + x, - (error) => error, - ); - - expect(await doubles.next()).to.deep.equal({ - value: 'HelloHello', - done: false, - }); - - const result = await doubles.next(); - expect(result.value) - .to.be.an.instanceOf(Error) - .with.property('message', 'Goodbye'); - expect(result.done).to.equal(false); - - expect(await doubles.next()).to.deep.equal({ - value: undefined, - done: true, - }); - }); - - async function testClosesSourceWithMapper(mapper: (number) => T) { + async function testClosesSourceWithMapper(mapper: (value: number) => T) { let didVisitFinally = false; async function* source() { try { yield 1; + /* c8 ignore next 2 */ yield 2; - - // istanbul ignore next (Shouldn't be reached) - yield 3; + yield 3; // Shouldn't be reached. } finally { didVisitFinally = true; yield 1000; @@ -320,6 +299,7 @@ describe('mapAsyncIterator', () => { let expectedError; try { + /* c8 ignore next */ await throwOver1.next(); } catch (error) { expectedError = error; @@ -353,43 +333,4 @@ describe('mapAsyncIterator', () => { : Promise.resolve(x), ); }); - - async function testClosesSourceWithRejectMapper(mapper: (Error) => T) { - async function* source() { - yield 1; - throw new Error(2); - } - - const throwOver1 = mapAsyncIterator(source(), (x) => x, mapper); - - expect(await throwOver1.next()).to.deep.equal({ value: 1, done: false }); - - let expectedError; - try { - await throwOver1.next(); - } catch (error) { - expectedError = error; - } - - expect(expectedError) - .to.be.an.instanceOf(Error) - .with.property('message', 'Cannot count to 2'); - - expect(await throwOver1.next()).to.deep.equal({ - value: undefined, - done: true, - }); - } - - it('closes source if mapper throws an error', async () => { - await testClosesSourceWithRejectMapper((error) => { - throw new Error('Cannot count to ' + error.message); - }); - }); - - it('closes source if mapper rejects', async () => { - await testClosesSourceWithRejectMapper((error) => - Promise.reject(new Error('Cannot count to ' + error.message)), - ); - }); }); diff --git a/src/execution/__tests__/mutations-test.js b/src/execution/__tests__/mutations-test.ts similarity index 96% rename from src/execution/__tests__/mutations-test.js rename to src/execution/__tests__/mutations-test.ts index c9c51296bf..0f0ad1cbf8 100644 --- a/src/execution/__tests__/mutations-test.js +++ b/src/execution/__tests__/mutations-test.ts @@ -1,13 +1,14 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import resolveOnNextTick from '../../__testUtils__/resolveOnNextTick'; +import { expectJSON } from '../../__testUtils__/expectJSON'; +import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick'; import { parse } from '../../language/parser'; +import { GraphQLObjectType } from '../../type/definition'; import { GraphQLInt } from '../../type/scalars'; import { GraphQLSchema } from '../../type/schema'; -import { GraphQLObjectType } from '../../type/definition'; import { execute, executeSync } from '../execute'; @@ -167,7 +168,7 @@ describe('Execute: Handles mutation execution ordering', () => { const rootValue = new Root(6); const result = await execute({ schema, document, rootValue }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { first: { theNumber: 1 }, second: { theNumber: 2 }, diff --git a/src/execution/__tests__/nonnull-test.js b/src/execution/__tests__/nonnull-test.ts similarity index 96% rename from src/execution/__tests__/nonnull-test.js rename to src/execution/__tests__/nonnull-test.ts index 4eb38f12b6..427f2a64d6 100644 --- a/src/execution/__tests__/nonnull-test.js +++ b/src/execution/__tests__/nonnull-test.ts @@ -1,11 +1,13 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import { expectJSON } from '../../__testUtils__/expectJSON'; + import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString } from '../../type/scalars'; import { GraphQLNonNull, GraphQLObjectType } from '../../type/definition'; +import { GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; @@ -106,7 +108,7 @@ const schema = buildSchema(` function executeQuery( query: string, - rootValue: mixed, + rootValue: unknown, ): ExecutionResult | Promise { return execute({ schema, document: parse(query), rootValue }); } @@ -122,7 +124,7 @@ function patchData(data: ExecutionResult): ExecutionResult { return JSON.parse(patch(JSON.stringify(data))); } -async function executeSyncAndAsync(query: string, rootValue: mixed) { +async function executeSyncAndAsync(query: string, rootValue: unknown) { const syncResult = executeSync({ schema, document: parse(query), rootValue }); const asyncResult = await execute({ schema, @@ -130,7 +132,7 @@ async function executeSyncAndAsync(query: string, rootValue: mixed) { rootValue, }); - expect(asyncResult).to.deep.equal(patchData(syncResult)); + expectJSON(asyncResult).toDeepEqual(patchData(syncResult)); return syncResult; } @@ -151,7 +153,7 @@ describe('Execute: handles non-nullable types', () => { it('that throws', async () => { const result = await executeSyncAndAsync(query, throwingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { sync: null }, errors: [ { @@ -175,7 +177,7 @@ describe('Execute: handles non-nullable types', () => { it('that returns null', async () => { const result = await executeSyncAndAsync(query, nullingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { syncNest: null }, errors: [ { @@ -190,7 +192,7 @@ describe('Execute: handles non-nullable types', () => { it('that throws', async () => { const result = await executeSyncAndAsync(query, throwingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { syncNest: null }, errors: [ { @@ -242,7 +244,7 @@ describe('Execute: handles non-nullable types', () => { it('that throws', async () => { const result = await executeQuery(query, throwingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data, errors: [ { @@ -368,7 +370,7 @@ describe('Execute: handles non-nullable types', () => { it('that returns null', async () => { const result = await executeQuery(query, nullingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data, errors: [ { @@ -429,7 +431,7 @@ describe('Execute: handles non-nullable types', () => { it('that throws', async () => { const result = await executeQuery(query, throwingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data, errors: [ { @@ -494,7 +496,7 @@ describe('Execute: handles non-nullable types', () => { it('that returns null', async () => { const result = await executeSyncAndAsync(query, nullingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: null, errors: [ { @@ -509,7 +511,7 @@ describe('Execute: handles non-nullable types', () => { it('that throws', async () => { const result = await executeSyncAndAsync(query, throwingData); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: null, errors: [ { @@ -609,7 +611,7 @@ describe('Execute: handles non-nullable types', () => { `), }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { withNonNullArg: null, }, @@ -636,7 +638,7 @@ describe('Execute: handles non-nullable types', () => { `), }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { withNonNullArg: null, }, @@ -666,7 +668,7 @@ describe('Execute: handles non-nullable types', () => { }, }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { withNonNullArg: null, }, @@ -694,7 +696,7 @@ describe('Execute: handles non-nullable types', () => { }, }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { withNonNullArg: null, }, diff --git a/src/execution/__tests__/oneof-test.ts b/src/execution/__tests__/oneof-test.ts new file mode 100644 index 0000000000..82965afc24 --- /dev/null +++ b/src/execution/__tests__/oneof-test.ts @@ -0,0 +1,185 @@ +import { describe, it } from 'mocha'; + +import { expectJSON } from '../../__testUtils__/expectJSON'; + +import { parse } from '../../language/parser'; + +import { buildSchema } from '../../utilities/buildASTSchema'; + +import type { ExecutionResult } from '../execute'; +import { execute } from '../execute'; + +const schema = buildSchema(` + type Query { + test(input: TestInputObject!): TestObject + } + + input TestInputObject @oneOf { + a: String + b: Int + } + + type TestObject { + a: String + b: Int + } +`); + +function executeQuery( + query: string, + rootValue: unknown, + variableValues?: { [variable: string]: unknown }, +): ExecutionResult | Promise { + return execute({ schema, document: parse(query), rootValue, variableValues }); +} + +describe('Execute: Handles OneOf Input Objects', () => { + describe('OneOf Input Objects', () => { + const rootValue = { + test({ input }: { input: { a?: string; b?: number } }) { + return input; + }, + }; + + it('accepts a good default value', () => { + const query = ` + query ($input: TestInputObject! = {a: "abc"}) { + test(input: $input) { + a + b + } + } + `; + const result = executeQuery(query, rootValue); + + expectJSON(result).toDeepEqual({ + data: { + test: { + a: 'abc', + b: null, + }, + }, + }); + }); + + it('rejects a bad default value', () => { + const query = ` + query ($input: TestInputObject! = {a: "abc", b: 123}) { + test(input: $input) { + a + b + } + } + `; + const result = executeQuery(query, rootValue); + + expectJSON(result).toDeepEqual({ + data: { + test: null, + }, + errors: [ + { + locations: [{ column: 23, line: 3 }], + message: + // This type of error would be caught at validation-time + // hence the vague error message here. + 'Argument "input" of non-null type "TestInputObject!" must not be null.', + path: ['test'], + }, + ], + }); + }); + + it('accepts a good variable', () => { + const query = ` + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + `; + const result = executeQuery(query, rootValue, { input: { a: 'abc' } }); + + expectJSON(result).toDeepEqual({ + data: { + test: { + a: 'abc', + b: null, + }, + }, + }); + }); + + it('accepts a good variable with an undefined key', () => { + const query = ` + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + `; + const result = executeQuery(query, rootValue, { + input: { a: 'abc', b: undefined }, + }); + + expectJSON(result).toDeepEqual({ + data: { + test: { + a: 'abc', + b: null, + }, + }, + }); + }); + + it('rejects a variable with multiple non-null keys', () => { + const query = ` + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + `; + const result = executeQuery(query, rootValue, { + input: { a: 'abc', b: 123 }, + }); + + expectJSON(result).toDeepEqual({ + errors: [ + { + locations: [{ column: 16, line: 2 }], + message: + 'Variable "$input" got invalid value { a: "abc", b: 123 }; Exactly one key must be specified for OneOf type "TestInputObject".', + }, + ], + }); + }); + + it('rejects a variable with multiple nullable keys', () => { + const query = ` + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + `; + const result = executeQuery(query, rootValue, { + input: { a: 'abc', b: null }, + }); + + expectJSON(result).toDeepEqual({ + errors: [ + { + locations: [{ column: 16, line: 2 }], + message: + 'Variable "$input" got invalid value { a: "abc", b: null }; Exactly one key must be specified for OneOf type "TestInputObject".', + }, + ], + }); + }); + }); +}); diff --git a/src/execution/__tests__/resolve-test.js b/src/execution/__tests__/resolve-test.ts similarity index 95% rename from src/execution/__tests__/resolve-test.js rename to src/execution/__tests__/resolve-test.ts index afe911e7bc..a34da196c6 100644 --- a/src/execution/__tests__/resolve-test.js +++ b/src/execution/__tests__/resolve-test.ts @@ -4,9 +4,9 @@ import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; import type { GraphQLFieldConfig } from '../../type/definition'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLInt, GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; +import { GraphQLInt, GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { executeSync } from '../execute'; @@ -64,7 +64,7 @@ describe('Execute: resolve function', () => { this._num = num; } - test(args: {| addend1: number |}, context: {| addend2: number |}) { + test(args: { addend1: number }, context: { addend2: number }) { return this._num + args.addend1 + context.addend2; } } @@ -95,7 +95,7 @@ describe('Execute: resolve function', () => { resolve: (source, args) => JSON.stringify([source, args]), }); - function executeQuery(query: string, rootValue?: mixed) { + function executeQuery(query: string, rootValue?: unknown) { const document = parse(query); return executeSync({ schema, document, rootValue }); } diff --git a/src/execution/__tests__/schema-test.js b/src/execution/__tests__/schema-test.ts similarity index 98% rename from src/execution/__tests__/schema-test.js rename to src/execution/__tests__/schema-test.ts index 7da7849c5a..f9b4e47439 100644 --- a/src/execution/__tests__/schema-test.js +++ b/src/execution/__tests__/schema-test.ts @@ -3,18 +3,18 @@ import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; import { GraphQLList, GraphQLNonNull, GraphQLObjectType, } from '../../type/definition'; import { + GraphQLBoolean, GraphQLID, GraphQLInt, GraphQLString, - GraphQLBoolean, } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { executeSync } from '../execute'; @@ -29,7 +29,7 @@ describe('Execute: Handles execution with a complex schema', () => { }, }); - const BlogAuthor = new GraphQLObjectType({ + const BlogAuthor: GraphQLObjectType = new GraphQLObjectType({ name: 'Author', fields: () => ({ id: { type: GraphQLString }, diff --git a/src/subscription/__tests__/simplePubSub-test.js b/src/execution/__tests__/simplePubSub-test.ts similarity index 93% rename from src/subscription/__tests__/simplePubSub-test.js rename to src/execution/__tests__/simplePubSub-test.ts index d92339687b..e919d770e3 100644 --- a/src/subscription/__tests__/simplePubSub-test.js +++ b/src/execution/__tests__/simplePubSub-test.ts @@ -1,12 +1,12 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import SimplePubSub from './simplePubSub'; +import { SimplePubSub } from './simplePubSub'; describe('SimplePubSub', () => { it('subscribe async-iterator mock', async () => { const pubsub = new SimplePubSub(); - const iterator = pubsub.getSubscriber(); + const iterator = pubsub.getSubscriber((x) => x); // Queue up publishes expect(pubsub.emit('Apple')).to.equal(true); diff --git a/src/subscription/__tests__/simplePubSub.js b/src/execution/__tests__/simplePubSub.ts similarity index 62% rename from src/subscription/__tests__/simplePubSub.js rename to src/execution/__tests__/simplePubSub.ts index e12c93d0b9..7efdf40e57 100644 --- a/src/subscription/__tests__/simplePubSub.js +++ b/src/execution/__tests__/simplePubSub.ts @@ -1,9 +1,11 @@ +import { invariant } from '../../jsutils/invariant'; + /** * Create an AsyncIterator from an EventEmitter. Useful for mocking a * PubSub system for tests. */ -export default class SimplePubSub { - _subscribers: Set<(T) => void>; +export class SimplePubSub { + private _subscribers: Set<(value: T) => void>; constructor() { this._subscribers = new Set(); @@ -16,9 +18,9 @@ export default class SimplePubSub { return this._subscribers.size > 0; } - getSubscriber(transform?: (T) => R): AsyncGenerator { - const pullQueue = []; - const pushQueue = []; + getSubscriber(transform: (value: T) => R): AsyncGenerator { + const pullQueue: Array<(result: IteratorResult) => void> = []; + const pushQueue: Array = []; let listening = true; this._subscribers.add(pushValue); @@ -32,36 +34,38 @@ export default class SimplePubSub { pushQueue.length = 0; }; - /* TODO: Flow doesn't support symbols as keys: - https://github.com/facebook/flow/issues/3258 */ - return ({ - next() { + return { + next(): Promise> { if (!listening) { return Promise.resolve({ value: undefined, done: true }); } if (pushQueue.length > 0) { - return Promise.resolve({ value: pushQueue.shift(), done: false }); + const value = pushQueue[0]; + pushQueue.shift(); + return Promise.resolve({ value, done: false }); } return new Promise((resolve) => pullQueue.push(resolve)); }, - return() { + return(): Promise> { emptyQueue(); return Promise.resolve({ value: undefined, done: true }); }, - throw(error: mixed) { + throw(error: unknown) { emptyQueue(); return Promise.reject(error); }, [Symbol.asyncIterator]() { return this; }, - }: any); + }; function pushValue(event: T): void { - const value = transform != null ? transform(event) : event; + const value: R = transform(event); if (pullQueue.length > 0) { - pullQueue.shift()({ value, done: false }); + const receiver = pullQueue.shift(); + invariant(receiver); + receiver({ value, done: false }); } else { pushQueue.push(value); } diff --git a/src/subscription/__tests__/subscribe-test.js b/src/execution/__tests__/subscribe-test.ts similarity index 51% rename from src/subscription/__tests__/subscribe-test.js rename to src/execution/__tests__/subscribe-test.ts index 5df245c3e7..e9ea0d0ace 100644 --- a/src/subscription/__tests__/subscribe-test.js +++ b/src/execution/__tests__/subscribe-test.ts @@ -1,30 +1,28 @@ -import { expect } from 'chai'; +import { assert, expect } from 'chai'; import { describe, it } from 'mocha'; -import resolveOnNextTick from '../../__testUtils__/resolveOnNextTick'; +import { expectJSON } from '../../__testUtils__/expectJSON'; +import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick'; -import invariant from '../../jsutils/invariant'; -import isAsyncIterable from '../../jsutils/isAsyncIterable'; +import { invariant } from '../../jsutils/invariant'; +import { isAsyncIterable } from '../../jsutils/isAsyncIterable'; -import type { DocumentNode } from '../../language/ast'; import { parse } from '../../language/parser'; -import { GraphQLError } from '../../error/GraphQLError'; - -import { GraphQLSchema } from '../../type/schema'; import { GraphQLList, GraphQLObjectType } from '../../type/definition'; -import { GraphQLInt, GraphQLString, GraphQLBoolean } from '../../type/scalars'; +import { GraphQLBoolean, GraphQLInt, GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { createSourceEventStream, subscribe } from '../subscribe'; -import SimplePubSub from './simplePubSub'; +import { SimplePubSub } from './simplePubSub'; -type Email = {| - from: string, - subject: string, - message: string, - unread: boolean, -|}; +interface Email { + from: string; + subject: string; + message: string; + unread: boolean; +} const EmailType = new GraphQLObjectType({ name: 'Email', @@ -45,7 +43,8 @@ const InboxType = new GraphQLObjectType({ }, unread: { type: GraphQLInt, - resolve: (inbox) => inbox.emails.filter((email) => email.unread).length, + resolve: (inbox) => + inbox.emails.filter((email: any) => email.unread).length, }, emails: { type: new GraphQLList(EmailType) }, }, @@ -66,50 +65,37 @@ const EmailEventType = new GraphQLObjectType({ }, }); -const emailSchema = emailSchemaWithResolvers(); - -function emailSchemaWithResolvers( - subscribeFn?: (T) => mixed, - resolveFn?: (T) => mixed, -) { - return new GraphQLSchema({ - query: QueryType, - subscription: new GraphQLObjectType({ - name: 'Subscription', - fields: { - importantEmail: { - type: EmailEventType, - resolve: resolveFn, - subscribe: subscribeFn, - args: { - priority: { type: GraphQLInt }, - }, +const emailSchema = new GraphQLSchema({ + query: QueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + importantEmail: { + type: EmailEventType, + args: { + priority: { type: GraphQLInt }, }, }, - }), - }); -} + }, + }), +}); -const defaultSubscriptionAST = parse(` - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total +function createSubscription(pubsub: SimplePubSub) { + const document = parse(` + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } } } - } -`); + `); -function createSubscription( - pubsub: SimplePubSub, - schema: GraphQLSchema = emailSchema, - document: DocumentNode = defaultSubscriptionAST, -) { const emails = [ { from: 'joe@graphql.org', @@ -119,8 +105,9 @@ function createSubscription( }, ]; - const data = { + const data: any = { inbox: { emails }, + // FIXME: we shouldn't use mapAsyncIterator here since it makes tests way more complex importantEmail: pubsub.getSubscriber((newEmail) => { emails.push(newEmail); @@ -133,83 +120,88 @@ function createSubscription( }), }; - return subscribe({ schema, document, rootValue: data }); + return subscribe({ schema: emailSchema, document, rootValue: data }); } -async function expectPromiseToThrow( - promise: () => Promise, - message: string, -) { +async function expectPromise(promise: Promise) { + let caughtError: Error; + try { - await promise(); - // istanbul ignore next (Shouldn't be reached) + /* c8 ignore next 2 */ + await promise; expect.fail('promise should have thrown but did not'); } catch (error) { - expect(error).to.be.an.instanceOf(Error); - expect(error.message).to.equal(message); + caughtError = error; } + + return { + toReject() { + expect(caughtError).to.be.an.instanceOf(Error); + }, + toRejectWith(message: string) { + expect(caughtError).to.be.an.instanceOf(Error); + expect(caughtError).to.have.property('message', message); + }, + }; } +const DummyQueryType = new GraphQLObjectType({ + name: 'Query', + fields: { + dummy: { type: GraphQLString }, + }, +}); + +/* eslint-disable @typescript-eslint/require-await */ // Check all error cases when initializing the subscription. describe('Subscription Initialization Phase', () => { - it('accepts positional arguments', async () => { - const document = parse(` - subscription { - importantEmail - } - `); - - async function* emptyAsyncIterator() { - // Empty - } - - // $FlowFixMe[incompatible-call] - const ai = await subscribe(emailSchema, document, { - importantEmail: emptyAsyncIterator, - }); - - ai.next(); - ai.return(); - }); - it('accepts multiple subscription fields defined in schema', async () => { - const pubsub = new SimplePubSub(); - const SubscriptionTypeMultiple = new GraphQLObjectType({ - name: 'Subscription', - fields: { - importantEmail: { type: EmailEventType }, - nonImportantEmail: { type: EmailEventType }, - }, + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString }, + bar: { type: GraphQLString }, + }, + }), }); - const testSchema = new GraphQLSchema({ - query: QueryType, - subscription: SubscriptionTypeMultiple, - }); + async function* fooGenerator() { + yield { foo: 'FooValue' }; + } - const subscription = await createSubscription(pubsub, testSchema); + const subscription = await subscribe({ + schema, + document: parse('subscription { foo }'), + rootValue: { foo: fooGenerator }, + }); invariant(isAsyncIterable(subscription)); - pubsub.emit({ - from: 'yuzhi@graphql.org', - subject: 'Alright', - message: 'Tests are good', - unread: true, + expect(await subscription.next()).to.deep.equal({ + done: false, + value: { data: { foo: 'FooValue' } }, }); - await subscription.next(); + expect(await subscription.next()).to.deep.equal({ + done: true, + value: undefined, + }); }); it('accepts type definition with sync subscribe function', async () => { - const pubsub = new SimplePubSub(); + async function* fooGenerator() { + yield { foo: 'FooValue' }; + } + const schema = new GraphQLSchema({ - query: QueryType, + query: DummyQueryType, subscription: new GraphQLObjectType({ name: 'Subscription', fields: { - importantEmail: { + foo: { type: GraphQLString, - subscribe: () => pubsub.getSubscriber(), + subscribe: fooGenerator, }, }, }), @@ -217,31 +209,36 @@ describe('Subscription Initialization Phase', () => { const subscription = await subscribe({ schema, - document: parse(` - subscription { - importantEmail - } - `), + document: parse('subscription { foo }'), }); invariant(isAsyncIterable(subscription)); - pubsub.emit({ importantEmail: {} }); + expect(await subscription.next()).to.deep.equal({ + done: false, + value: { data: { foo: 'FooValue' } }, + }); - await subscription.next(); + expect(await subscription.next()).to.deep.equal({ + done: true, + value: undefined, + }); }); it('accepts type definition with async subscribe function', async () => { - const pubsub = new SimplePubSub(); + async function* fooGenerator() { + yield { foo: 'FooValue' }; + } + const schema = new GraphQLSchema({ - query: QueryType, + query: DummyQueryType, subscription: new GraphQLObjectType({ name: 'Subscription', fields: { - importantEmail: { + foo: { type: GraphQLString, - subscribe: async () => { + async subscribe() { await resolveOnNextTick(); - return pubsub.getSubscriber(); + return fooGenerator(); }, }, }, @@ -250,142 +247,256 @@ describe('Subscription Initialization Phase', () => { const subscription = await subscribe({ schema, - document: parse(` - subscription { - importantEmail - } - `), + document: parse('subscription { foo }'), }); invariant(isAsyncIterable(subscription)); - expect(subscription).to.have.property('next'); + expect(await subscription.next()).to.deep.equal({ + done: false, + value: { data: { foo: 'FooValue' } }, + }); - pubsub.emit({ importantEmail: {} }); - await subscription.next(); + expect(await subscription.next()).to.deep.equal({ + done: true, + value: undefined, + }); + }); + + it('uses a custom default subscribeFieldResolver', async () => { + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString }, + }, + }), + }); + + async function* fooGenerator() { + yield { foo: 'FooValue' }; + } + + const subscription = await subscribe({ + schema, + document: parse('subscription { foo }'), + rootValue: { customFoo: fooGenerator }, + subscribeFieldResolver: (root) => root.customFoo(), + }); + invariant(isAsyncIterable(subscription)); + + expect(await subscription.next()).to.deep.equal({ + done: false, + value: { data: { foo: 'FooValue' } }, + }); + + expect(await subscription.next()).to.deep.equal({ + done: true, + value: undefined, + }); }); it('should only resolve the first field of invalid multi-field', async () => { - let didResolveImportantEmail = false; - let didResolveNonImportantEmail = false; + async function* fooGenerator() { + yield { foo: 'FooValue' }; + } - const SubscriptionTypeMultiple = new GraphQLObjectType({ - name: 'Subscription', - fields: { - importantEmail: { - type: EmailEventType, - subscribe() { - didResolveImportantEmail = true; - return new SimplePubSub().getSubscriber(); + let didResolveFoo = false; + let didResolveBar = false; + + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { + type: GraphQLString, + subscribe() { + didResolveFoo = true; + return fooGenerator(); + }, }, - }, - nonImportantEmail: { - type: EmailEventType, - // istanbul ignore next (Shouldn't be called) - subscribe() { - didResolveNonImportantEmail = true; - return new SimplePubSub().getSubscriber(); + bar: { + type: GraphQLString, + /* c8 ignore next 3 */ + subscribe() { + didResolveBar = true; + }, }, }, - }, - }); - - const schema = new GraphQLSchema({ - query: QueryType, - subscription: SubscriptionTypeMultiple, + }), }); const subscription = await subscribe({ schema, - document: parse(` - subscription { - importantEmail - nonImportantEmail - } - `), + document: parse('subscription { foo bar }'), }); invariant(isAsyncIterable(subscription)); - subscription.next(); // Ask for a result, but ignore it. + expect(didResolveFoo).to.equal(true); + expect(didResolveBar).to.equal(false); - expect(didResolveImportantEmail).to.equal(true); - expect(didResolveNonImportantEmail).to.equal(false); + expect(await subscription.next()).to.have.property('done', false); - // Close subscription - subscription.return(); + expect(await subscription.next()).to.deep.equal({ + done: true, + value: undefined, + }); }); - it('throws an error if schema is missing', async () => { - const document = parse(` - subscription { - importantEmail - } - `); + it('throws an error if some of required arguments are missing', async () => { + const document = parse('subscription { foo }'); + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString }, + }, + }), + }); - await expectPromiseToThrow( - // $FlowExpectedError[incompatible-call] - () => subscribe({ schema: null, document }), + // @ts-expect-error (schema must not be null) + (await expectPromise(subscribe({ schema: null, document }))).toRejectWith( 'Expected null to be a GraphQL schema.', ); - await expectPromiseToThrow( - // $FlowExpectedError[incompatible-call] - () => subscribe({ document }), + // @ts-expect-error + (await expectPromise(subscribe({ document }))).toRejectWith( 'Expected undefined to be a GraphQL schema.', ); + + // @ts-expect-error (document must not be null) + (await expectPromise(subscribe({ schema, document: null }))).toRejectWith( + 'Must provide document.', + ); + + // @ts-expect-error + (await expectPromise(subscribe({ schema }))).toRejectWith( + 'Must provide document.', + ); + }); + + it('Deprecated: allows positional arguments to createSourceEventStream', async () => { + async function* fooGenerator() { + /* c8 ignore next 2 */ + yield { foo: 'FooValue' }; + } + + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString, subscribe: fooGenerator }, + }, + }), + }); + const document = parse('subscription { foo }'); + + const eventStream = await createSourceEventStream(schema, document); + assert(isAsyncIterable(eventStream)); }); - it('throws an error if document is missing', async () => { - await expectPromiseToThrow( - // $FlowExpectedError[incompatible-call] - () => subscribe({ schema: emailSchema, document: null }), + it('Deprecated: throws an error if document is missing when using positional arguments', async () => { + const document = parse('subscription { foo }'); + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString }, + }, + }), + }); + + // @ts-expect-error (schema must not be null) + (await expectPromise(createSourceEventStream(null, document))).toRejectWith( + 'Expected null to be a GraphQL schema.', + ); + + ( + await expectPromise( + createSourceEventStream( + // @ts-expect-error + undefined, + document, + ), + ) + ).toRejectWith('Expected undefined to be a GraphQL schema.'); + + // @ts-expect-error (document must not be null) + (await expectPromise(createSourceEventStream(schema, null))).toRejectWith( 'Must provide document.', ); - await expectPromiseToThrow( - // $FlowExpectedError[incompatible-call] - () => subscribe({ schema: emailSchema }), + // @ts-expect-error + (await expectPromise(createSourceEventStream(schema))).toRejectWith( 'Must provide document.', ); }); - it('resolves to an error for unknown subscription field', async () => { - const ast = parse(` - subscription { - unknownField - } - `); + it('resolves to an error if schema does not support subscriptions', async () => { + const schema = new GraphQLSchema({ query: DummyQueryType }); + const document = parse('subscription { unknownField }'); - const pubsub = new SimplePubSub(); - const subscription = await createSubscription(pubsub, emailSchema, ast); + const result = await subscribe({ schema, document }); + expectJSON(result).toDeepEqual({ + errors: [ + { + message: + 'Schema is not configured to execute subscription operation.', + locations: [{ line: 1, column: 1 }], + }, + ], + }); + }); - expect(subscription).to.deep.equal({ + it('resolves to an error for unknown subscription field', async () => { + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString }, + }, + }), + }); + const document = parse('subscription { unknownField }'); + + const result = await subscribe({ schema, document }); + expectJSON(result).toDeepEqual({ errors: [ { message: 'The subscription field "unknownField" is not defined.', - locations: [{ line: 3, column: 9 }], + locations: [{ line: 1, column: 16 }], }, ], }); }); it('should pass through unexpected errors thrown in subscribe', async () => { - let expectedError; - try { - // $FlowExpectedError[incompatible-call] - await subscribe({ schema: emailSchema, document: {} }); - } catch (error) { - expectedError = error; - } - expect(expectedError).to.be.instanceOf(Error); + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString }, + }, + }), + }); + + // @ts-expect-error + (await expectPromise(subscribe({ schema, document: {} }))).toReject(); }); it('throws an error if subscribe does not return an iterator', async () => { - const invalidEmailSchema = new GraphQLSchema({ - query: QueryType, + const schema = new GraphQLSchema({ + query: DummyQueryType, subscription: new GraphQLObjectType({ name: 'Subscription', fields: { - importantEmail: { + foo: { type: GraphQLString, subscribe: () => 'test', }, @@ -393,140 +504,95 @@ describe('Subscription Initialization Phase', () => { }), }); - const pubsub = new SimplePubSub(); + const document = parse('subscription { foo }'); - await expectPromiseToThrow( - () => createSubscription(pubsub, invalidEmailSchema), + (await expectPromise(subscribe({ schema, document }))).toRejectWith( 'Subscription field must return Async Iterable. Received: "test".', ); }); it('resolves to an error for subscription resolver errors', async () => { - // Returning an error - const subscriptionReturningErrorSchema = emailSchemaWithResolvers( - () => new Error('test error'), - ); - await testReportsError(subscriptionReturningErrorSchema); - - // Throwing an error - const subscriptionThrowingErrorSchema = emailSchemaWithResolvers(() => { - throw new Error('test error'); - }); - await testReportsError(subscriptionThrowingErrorSchema); - - // Resolving to an error - const subscriptionResolvingErrorSchema = emailSchemaWithResolvers(() => - Promise.resolve(new Error('test error')), - ); - await testReportsError(subscriptionResolvingErrorSchema); - - // Rejecting with an error - const subscriptionRejectingErrorSchema = emailSchemaWithResolvers(() => - Promise.reject(new Error('test error')), - ); - await testReportsError(subscriptionRejectingErrorSchema); - - async function testReportsError(schema: GraphQLSchema) { - // Promise | ExecutionResult> - const result = await subscribe({ - schema, - document: parse(` - subscription { - importantEmail - } - `), - }); - - expect(result).to.deep.equal({ - errors: [ - { - message: 'test error', - locations: [{ line: 3, column: 13 }], - path: ['importantEmail'], + async function subscribeWithFn(subscribeFn: () => unknown) { + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { type: GraphQLString, subscribe: subscribeFn }, }, - ], + }), }); + const document = parse('subscription { foo }'); + const result = await subscribe({ schema, document }); + + expectJSON(await createSourceEventStream(schema, document)).toDeepEqual( + result, + ); + return result; } - }); - it('resolves to an error for source event stream resolver errors', async () => { - // Returning an error - const subscriptionReturningErrorSchema = emailSchemaWithResolvers( - () => new Error('test error'), - ); - await testReportsError(subscriptionReturningErrorSchema); + const expectedResult = { + errors: [ + { + message: 'test error', + locations: [{ line: 1, column: 16 }], + path: ['foo'], + }, + ], + }; - // Throwing an error - const subscriptionThrowingErrorSchema = emailSchemaWithResolvers(() => { - throw new Error('test error'); - }); - await testReportsError(subscriptionThrowingErrorSchema); + expectJSON( + // Returning an error + await subscribeWithFn(() => new Error('test error')), + ).toDeepEqual(expectedResult); - // Resolving to an error - const subscriptionResolvingErrorSchema = emailSchemaWithResolvers(() => - Promise.resolve(new Error('test error')), - ); - await testReportsError(subscriptionResolvingErrorSchema); + expectJSON( + // Throwing an error + await subscribeWithFn(() => { + throw new Error('test error'); + }), + ).toDeepEqual(expectedResult); - // Rejecting with an error - const subscriptionRejectingErrorSchema = emailSchemaWithResolvers(() => - Promise.reject(new Error('test error')), - ); - await testReportsError(subscriptionRejectingErrorSchema); - - async function testReportsError(schema: GraphQLSchema) { - // Promise | ExecutionResult> - const result = await createSourceEventStream( - schema, - parse(` - subscription { - importantEmail - } - `), - ); + expectJSON( + // Resolving to an error + await subscribeWithFn(() => Promise.resolve(new Error('test error'))), + ).toDeepEqual(expectedResult); - expect(result).to.deep.equal({ - errors: [ - { - message: 'test error', - locations: [{ line: 3, column: 13 }], - path: ['importantEmail'], - }, - ], - }); - } + expectJSON( + // Rejecting with an error + await subscribeWithFn(() => Promise.reject(new Error('test error'))), + ).toDeepEqual(expectedResult); }); it('resolves to an error if variables were wrong type', async () => { - // If we receive variables that cannot be coerced correctly, subscribe() - // will resolve to an ExecutionResult that contains an informative error - // description. - const ast = parse(` - subscription ($priority: Int) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + foo: { + type: GraphQLString, + args: { arg: { type: GraphQLInt } }, + }, + }, + }), + }); + + const variableValues = { arg: 'meow' }; + const document = parse(` + subscription ($arg: Int) { + foo(arg: $arg) } `); - const result = await subscribe({ - schema: emailSchema, - document: ast, - variableValues: { priority: 'meow' }, - }); - - expect(result).to.deep.equal({ + // If we receive variables that cannot be coerced correctly, subscribe() will + // resolve to an ExecutionResult that contains an informative error description. + const result = await subscribe({ schema, document, variableValues }); + expectJSON(result).toDeepEqual({ errors: [ { message: - 'Variable "$priority" got invalid value "meow"; Int cannot represent non-integer value: "meow"', + 'Variable "$arg" got invalid value "meow"; Int cannot represent non-integer value: "meow"', locations: [{ line: 2, column: 21 }], }, ], @@ -537,7 +603,7 @@ describe('Subscription Initialization Phase', () => { // Once a subscription returns a valid AsyncIterator, it can still yield errors. describe('Subscription Publish Phase', () => { it('produces a payload for multiple subscribe in same subscription', async () => { - const pubsub = new SimplePubSub(); + const pubsub = new SimplePubSub(); const subscription = await createSubscription(pubsub); invariant(isAsyncIterable(subscription)); @@ -580,7 +646,7 @@ describe('Subscription Publish Phase', () => { }); it('produces a payload per subscription event', async () => { - const pubsub = new SimplePubSub(); + const pubsub = new SimplePubSub(); const subscription = await createSubscription(pubsub); invariant(isAsyncIterable(subscription)); @@ -669,7 +735,7 @@ describe('Subscription Publish Phase', () => { }); it('produces a payload when there are multiple events', async () => { - const pubsub = new SimplePubSub(); + const pubsub = new SimplePubSub(); const subscription = await createSubscription(pubsub); invariant(isAsyncIterable(subscription)); @@ -735,7 +801,7 @@ describe('Subscription Publish Phase', () => { }); it('should not trigger when subscription is already done', async () => { - const pubsub = new SimplePubSub(); + const pubsub = new SimplePubSub(); const subscription = await createSubscription(pubsub); invariant(isAsyncIterable(subscription)); @@ -770,7 +836,7 @@ describe('Subscription Publish Phase', () => { }); payload = subscription.next(); - subscription.return(); + await subscription.return(); // A new email arrives! expect( @@ -789,7 +855,7 @@ describe('Subscription Publish Phase', () => { }); it('should not trigger when subscription is thrown', async () => { - const pubsub = new SimplePubSub(); + const pubsub = new SimplePubSub(); const subscription = await createSubscription(pubsub); invariant(isAsyncIterable(subscription)); @@ -828,22 +894,13 @@ describe('Subscription Publish Phase', () => { // Throw error let caughtError; try { + /* c8 ignore next */ await subscription.throw('ouch'); } catch (e) { caughtError = e; } expect(caughtError).to.equal('ouch'); - // A new email arrives! - expect( - pubsub.emit({ - from: 'yuzhi@graphql.org', - subject: 'Alright 2', - message: 'Tests are good 2', - unread: true, - }), - ).to.equal(false); - expect(await payload).to.deep.equal({ done: true, value: undefined, @@ -851,7 +908,7 @@ describe('Subscription Publish Phase', () => { }); it('event order is correct for multiple publishes', async () => { - const pubsub = new SimplePubSub(); + const pubsub = new SimplePubSub(); const subscription = await createSubscription(pubsub); invariant(isAsyncIterable(subscription)); @@ -917,188 +974,106 @@ describe('Subscription Publish Phase', () => { }); it('should handle error during execution of source event', async () => { - const erroringEmailSchema = emailSchemaWithResolvers( - async function* () { - yield { email: { subject: 'Hello' } }; - yield { email: { subject: 'Goodbye' } }; - yield { email: { subject: 'Bonjour' } }; - }, - (event) => { - if (event.email.subject === 'Goodbye') { - throw new Error('Never leave.'); - } - return event; - }, - ); + async function* generateMessages() { + yield 'Hello'; + yield 'Goodbye'; + yield 'Bonjour'; + } - const subscription = await subscribe({ - schema: erroringEmailSchema, - document: parse(` - subscription { - importantEmail { - email { - subject - } - } - } - `), + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + newMessage: { + type: GraphQLString, + subscribe: generateMessages, + resolve(message) { + if (message === 'Goodbye') { + throw new Error('Never leave.'); + } + return message; + }, + }, + }, + }), }); + + const document = parse('subscription { newMessage }'); + const subscription = await subscribe({ schema, document }); invariant(isAsyncIterable(subscription)); - const payload1 = await subscription.next(); - expect(payload1).to.deep.equal({ + expect(await subscription.next()).to.deep.equal({ done: false, value: { - data: { - importantEmail: { - email: { - subject: 'Hello', - }, - }, - }, + data: { newMessage: 'Hello' }, }, }); // An error in execution is presented as such. - const payload2 = await subscription.next(); - expect(payload2).to.deep.equal({ + expectJSON(await subscription.next()).toDeepEqual({ done: false, value: { + data: { newMessage: null }, errors: [ { message: 'Never leave.', - locations: [{ line: 3, column: 11 }], - path: ['importantEmail'], + locations: [{ line: 1, column: 16 }], + path: ['newMessage'], }, ], - data: { - importantEmail: null, - }, }, }); - // However that does not close the response event stream. Subsequent - // events are still executed. - const payload3 = await subscription.next(); - expect(payload3).to.deep.equal({ + // However that does not close the response event stream. + // Subsequent events are still executed. + expectJSON(await subscription.next()).toDeepEqual({ done: false, value: { - data: { - importantEmail: { - email: { - subject: 'Bonjour', - }, - }, - }, + data: { newMessage: 'Bonjour' }, }, }); - }); - - it('should pass through error thrown in source event stream', async () => { - const erroringEmailSchema = emailSchemaWithResolvers( - async function* () { - yield { email: { subject: 'Hello' } }; - throw new Error('test error'); - }, - (email) => email, - ); - const subscription = await subscribe({ - schema: erroringEmailSchema, - document: parse(` - subscription { - importantEmail { - email { - subject - } - } - } - `), - }); - invariant(isAsyncIterable(subscription)); - - const payload1 = await subscription.next(); - expect(payload1).to.deep.equal({ - done: false, - value: { - data: { - importantEmail: { - email: { - subject: 'Hello', - }, - }, - }, - }, - }); - - let expectedError; - try { - await subscription.next(); - } catch (error) { - expectedError = error; - } - - expect(expectedError).to.be.instanceof(Error); - expect(expectedError).to.have.property('message', 'test error'); - - const payload2 = await subscription.next(); - expect(payload2).to.deep.equal({ + expectJSON(await subscription.next()).toDeepEqual({ done: true, value: undefined, }); }); - it('should resolve GraphQL error from source event stream', async () => { - const erroringEmailSchema = emailSchemaWithResolvers( - async function* () { - yield { email: { subject: 'Hello' } }; - throw new GraphQLError('test error'); - }, - (email) => email, - ); - - const subscription = await subscribe({ - schema: erroringEmailSchema, - document: parse(` - subscription { - importantEmail { - email { - subject - } - } - } - `), - }); - invariant(isAsyncIterable(subscription)); + it('should pass through error thrown in source event stream', async () => { + async function* generateMessages() { + yield 'Hello'; + throw new Error('test error'); + } - const payload1 = await subscription.next(); - expect(payload1).to.deep.equal({ - done: false, - value: { - data: { - importantEmail: { - email: { - subject: 'Hello', - }, + const schema = new GraphQLSchema({ + query: DummyQueryType, + subscription: new GraphQLObjectType({ + name: 'Subscription', + fields: { + newMessage: { + type: GraphQLString, + resolve: (message) => message, + subscribe: generateMessages, }, }, - }, + }), }); - const payload2 = await subscription.next(); - expect(payload2).to.deep.equal({ + const document = parse('subscription { newMessage }'); + const subscription = await subscribe({ schema, document }); + invariant(isAsyncIterable(subscription)); + + expect(await subscription.next()).to.deep.equal({ done: false, value: { - errors: [ - { - message: 'test error', - }, - ], + data: { newMessage: 'Hello' }, }, }); - const payload3 = await subscription.next(); - expect(payload3).to.deep.equal({ + (await expectPromise(subscription.next())).toRejectWith('test error'); + + expect(await subscription.next()).to.deep.equal({ done: true, value: undefined, }); diff --git a/src/execution/__tests__/sync-test.js b/src/execution/__tests__/sync-test.ts similarity index 96% rename from src/execution/__tests__/sync-test.js rename to src/execution/__tests__/sync-test.ts index 184a259b69..021f09fa3c 100644 --- a/src/execution/__tests__/sync-test.js +++ b/src/execution/__tests__/sync-test.ts @@ -1,13 +1,15 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { parse } from '../../language/parser'; +import { expectJSON } from '../../__testUtils__/expectJSON'; -import { validate } from '../../validation/validate'; +import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; +import { GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; + +import { validate } from '../../validation/validate'; import { graphqlSync } from '../../graphql'; @@ -52,7 +54,7 @@ describe('Execute: synchronously when possible', () => { document: parse(doc), rootValue: 'rootValue', }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [{ message: 'Must provide an operation.' }], }); }); @@ -120,7 +122,7 @@ describe('Execute: synchronously when possible', () => { schema: badSchema, source: '{ __typename }', }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [{ message: 'Query root type must be provided.' }], }); }); @@ -131,7 +133,7 @@ describe('Execute: synchronously when possible', () => { schema, source: doc, }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: 'Syntax Error: Expected Name, found "{".', diff --git a/src/execution/__tests__/union-interface-test.js b/src/execution/__tests__/union-interface-test.ts similarity index 92% rename from src/execution/__tests__/union-interface-test.js rename to src/execution/__tests__/union-interface-test.ts index 1d750d273d..7ce9f8b3bc 100644 --- a/src/execution/__tests__/union-interface-test.js +++ b/src/execution/__tests__/union-interface-test.ts @@ -1,27 +1,25 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; - import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString, GraphQLBoolean } from '../../type/scalars'; import { + GraphQLInterfaceType, GraphQLList, - GraphQLUnionType, GraphQLObjectType, - GraphQLInterfaceType, + GraphQLUnionType, } from '../../type/definition'; +import { GraphQLBoolean, GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { executeSync } from '../execute'; class Dog { name: string; barks: boolean; - mother: Dog | void; - father: Dog | void; - progeny: Array; + mother?: Dog; + father?: Dog; + progeny: ReadonlyArray; constructor(name: string, barks: boolean) { this.name = name; @@ -33,9 +31,9 @@ class Dog { class Cat { name: string; meows: boolean; - mother: Cat | void; - father: Cat | void; - progeny: Array; + mother?: Cat; + father?: Cat; + progeny: ReadonlyArray; constructor(name: string, meows: boolean) { this.name = name; @@ -46,13 +44,13 @@ class Cat { class Person { name: string; - pets: Array | void; - friends: Array | void; + pets?: ReadonlyArray; + friends?: ReadonlyArray; constructor( name: string, - pets?: Array, - friends?: Array | void, + pets?: ReadonlyArray, + friends?: ReadonlyArray, ) { this.name = name; this.pets = pets; @@ -67,14 +65,14 @@ const NamedType = new GraphQLInterfaceType({ }, }); -const LifeType = new GraphQLInterfaceType({ +const LifeType: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'Life', fields: () => ({ progeny: { type: new GraphQLList(LifeType) }, }), }); -const MammalType = new GraphQLInterfaceType({ +const MammalType: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'Mammal', interfaces: [LifeType], fields: () => ({ @@ -84,7 +82,7 @@ const MammalType = new GraphQLInterfaceType({ }), }); -const DogType = new GraphQLObjectType({ +const DogType: GraphQLObjectType = new GraphQLObjectType({ name: 'Dog', interfaces: [MammalType, LifeType, NamedType], fields: () => ({ @@ -97,7 +95,7 @@ const DogType = new GraphQLObjectType({ isTypeOf: (value) => value instanceof Dog, }); -const CatType = new GraphQLObjectType({ +const CatType: GraphQLObjectType = new GraphQLObjectType({ name: 'Cat', interfaces: [MammalType, LifeType, NamedType], fields: () => ({ @@ -117,17 +115,16 @@ const PetType = new GraphQLUnionType({ if (value instanceof Dog) { return DogType.name; } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (value instanceof Cat) { return CatType.name; } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false); + /* c8 ignore next 3 */ + // Not reachable, all possible types have been considered. + expect.fail('Not reachable'); }, }); -const PersonType = new GraphQLObjectType({ +const PersonType: GraphQLObjectType = new GraphQLObjectType({ name: 'Person', interfaces: [NamedType, MammalType, LifeType], fields: () => ({ @@ -505,7 +502,7 @@ describe('Execute: Union and intersection types', () => { let encounteredSchema; let encounteredRootValue; - const NamedType2 = new GraphQLInterfaceType({ + const NamedType2: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'Named', fields: { name: { type: GraphQLString }, @@ -518,7 +515,7 @@ describe('Execute: Union and intersection types', () => { }, }); - const PersonType2 = new GraphQLObjectType({ + const PersonType2: GraphQLObjectType = new GraphQLObjectType({ name: 'Person', interfaces: [NamedType2], fields: { diff --git a/src/execution/__tests__/variables-test.js b/src/execution/__tests__/variables-test.ts similarity index 90% rename from src/execution/__tests__/variables-test.js rename to src/execution/__tests__/variables-test.ts index 9f637dd7ed..3a859a0bdc 100644 --- a/src/execution/__tests__/variables-test.js +++ b/src/execution/__tests__/variables-test.ts @@ -1,35 +1,61 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import inspect from '../../jsutils/inspect'; -import invariant from '../../jsutils/invariant'; +import { expectJSON } from '../../__testUtils__/expectJSON'; + +import { inspect } from '../../jsutils/inspect'; +import { invariant } from '../../jsutils/invariant'; + +import { GraphQLError } from '../../error/GraphQLError'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; -import type { GraphQLArgumentConfig } from '../../type/definition'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString } from '../../type/scalars'; +import type { + GraphQLArgumentConfig, + GraphQLFieldConfig, +} from '../../type/definition'; import { + GraphQLEnumType, + GraphQLInputObjectType, GraphQLList, GraphQLNonNull, - GraphQLScalarType, GraphQLObjectType, - GraphQLInputObjectType, - GraphQLEnumType, + GraphQLScalarType, } from '../../type/definition'; +import { GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { executeSync } from '../execute'; import { getVariableValues } from '../values'; +const TestFaultyScalarGraphQLError = new GraphQLError( + 'FaultyScalarErrorMessage', + { + extensions: { + code: 'FaultyScalarErrorMessageExtensionCode', + }, + }, +); + +const TestFaultyScalar = new GraphQLScalarType({ + name: 'FaultyScalar', + parseValue() { + throw TestFaultyScalarGraphQLError; + }, + parseLiteral() { + throw TestFaultyScalarGraphQLError; + }, +}); + const TestComplexScalar = new GraphQLScalarType({ name: 'ComplexScalar', parseValue(value) { - invariant(value === 'SerializedValue'); + expect(value).to.equal('SerializedValue'); return 'DeserializedValue'; }, parseLiteral(ast) { - invariant(ast.value === 'SerializedValue'); + expect(ast).to.include({ kind: 'StringValue', value: 'SerializedValue' }); return 'DeserializedValue'; }, }); @@ -41,6 +67,7 @@ const TestInputObject = new GraphQLInputObjectType({ b: { type: new GraphQLList(GraphQLString) }, c: { type: new GraphQLNonNull(GraphQLString) }, d: { type: TestComplexScalar }, + e: { type: TestFaultyScalar }, }, }); @@ -64,7 +91,9 @@ const TestEnum = new GraphQLEnumType({ }, }); -function fieldWithInputArg(inputArg: GraphQLArgumentConfig) { +function fieldWithInputArg( + inputArg: GraphQLArgumentConfig, +): GraphQLFieldConfig { return { type: GraphQLString, args: { input: inputArg }, @@ -119,7 +148,7 @@ const schema = new GraphQLSchema({ query: TestType }); function executeQuery( query: string, - variableValues?: { [variable: string]: mixed, ... }, + variableValues?: { [variable: string]: unknown }, ) { const document = parse(query); return executeSync({ schema, document, variableValues }); @@ -191,7 +220,7 @@ describe('Execute: Handles inputs', () => { } `); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { fieldWithObjectInput: null, }, @@ -221,6 +250,27 @@ describe('Execute: Handles inputs', () => { }); }); + it('errors on faulty scalar type input', () => { + const result = executeQuery(` + { + fieldWithObjectInput(input: {c: "foo", e: "bar"}) + } + `); + + expectJSON(result).toDeepEqual({ + data: { + fieldWithObjectInput: null, + }, + errors: [ + { + message: 'Argument "input" has invalid value {c: "foo", e: "bar"}.', + path: ['fieldWithObjectInput'], + locations: [{ line: 3, column: 39 }], + }, + ], + }); + }); + describe('using variables', () => { const doc = ` query ($input: TestInputObject) { @@ -360,11 +410,27 @@ describe('Execute: Handles inputs', () => { }); }); + it('errors on faulty scalar type input', () => { + const params = { input: { c: 'foo', e: 'SerializedValue' } }; + const result = executeQuery(doc, params); + + expectJSON(result).toDeepEqual({ + errors: [ + { + message: + 'Variable "$input" got invalid value "SerializedValue" at "input.e"; FaultyScalarErrorMessage', + locations: [{ line: 2, column: 16 }], + extensions: { code: 'FaultyScalarErrorMessageExtensionCode' }, + }, + ], + }); + }); + it('errors on null for nested non-null', () => { const params = { input: { a: 'foo', b: 'bar', c: null } }; const result = executeQuery(doc, params); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -378,7 +444,7 @@ describe('Execute: Handles inputs', () => { it('errors on incorrect type', () => { const result = executeQuery(doc, { input: 'foo bar' }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -392,7 +458,7 @@ describe('Execute: Handles inputs', () => { it('errors on omission of nested non-null', () => { const result = executeQuery(doc, { input: { a: 'foo', b: 'bar' } }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -411,7 +477,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(nestedDoc, { input: { na: { a: 'foo' } } }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -433,7 +499,7 @@ describe('Execute: Handles inputs', () => { }; const result = executeQuery(doc, params); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -608,7 +674,7 @@ describe('Execute: Handles inputs', () => { } `); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -627,7 +693,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { value: null }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -670,7 +736,7 @@ describe('Execute: Handles inputs', () => { it('reports error for missing non-nullable inputs', () => { const result = executeQuery('{ fieldWithNonNullableStringInput }'); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { fieldWithNonNullableStringInput: null, }, @@ -693,7 +759,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { value: [1, 2, 3] }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -718,7 +784,7 @@ describe('Execute: Handles inputs', () => { } `); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { fieldWithNonNullableStringInput: null, }, @@ -776,7 +842,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { input: null }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -839,7 +905,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { input: ['A', null, 'B'] }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -858,7 +924,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { input: null }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -888,7 +954,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { input: ['A', null, 'B'] }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -907,7 +973,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { input: { list: ['A', 'B'] } }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -926,7 +992,7 @@ describe('Execute: Handles inputs', () => { `; const result = executeQuery(doc, { input: 'WhoKnows' }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -970,7 +1036,7 @@ describe('Execute: Handles inputs', () => { } `); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { fieldWithDefaultArgumentValue: null, }, @@ -1024,7 +1090,7 @@ describe('Execute: Handles inputs', () => { it('return all errors by default', () => { const result = getVariableValues(schema, variableDefinitions, inputValue); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ invalidValueError(0, 0), invalidValueError(1, 1), @@ -1041,7 +1107,7 @@ describe('Execute: Handles inputs', () => { { maxErrors: 3 }, ); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ invalidValueError(0, 0), invalidValueError(1, 1), @@ -1058,7 +1124,7 @@ describe('Execute: Handles inputs', () => { { maxErrors: 2 }, ); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ invalidValueError(0, 0), invalidValueError(1, 1), diff --git a/src/execution/collectFields.ts b/src/execution/collectFields.ts new file mode 100644 index 0000000000..d0961bfae8 --- /dev/null +++ b/src/execution/collectFields.ts @@ -0,0 +1,212 @@ +import type { ObjMap } from '../jsutils/ObjMap'; + +import type { + FieldNode, + FragmentDefinitionNode, + FragmentSpreadNode, + InlineFragmentNode, + SelectionSetNode, +} from '../language/ast'; +import { Kind } from '../language/kinds'; + +import type { GraphQLObjectType } from '../type/definition'; +import { isAbstractType } from '../type/definition'; +import { + GraphQLIncludeDirective, + GraphQLSkipDirective, +} from '../type/directives'; +import type { GraphQLSchema } from '../type/schema'; + +import { typeFromAST } from '../utilities/typeFromAST'; + +import { getDirectiveValues } from './values'; + +/** + * Given a selectionSet, collects all of the fields and returns them. + * + * CollectFields requires the "runtime type" of an object. For a field that + * returns an Interface or Union type, the "runtime type" will be the actual + * object type returned by that field. + * + * @internal + */ +export function collectFields( + schema: GraphQLSchema, + fragments: ObjMap, + variableValues: { [variable: string]: unknown }, + runtimeType: GraphQLObjectType, + selectionSet: SelectionSetNode, +): Map> { + const fields = new Map(); + collectFieldsImpl( + schema, + fragments, + variableValues, + runtimeType, + selectionSet, + fields, + new Set(), + ); + return fields; +} + +/** + * Given an array of field nodes, collects all of the subfields of the passed + * in fields, and returns them at the end. + * + * CollectSubFields requires the "return type" of an object. For a field that + * returns an Interface or Union type, the "return type" will be the actual + * object type returned by that field. + * + * @internal + */ +export function collectSubfields( + schema: GraphQLSchema, + fragments: ObjMap, + variableValues: { [variable: string]: unknown }, + returnType: GraphQLObjectType, + fieldNodes: ReadonlyArray, +): Map> { + const subFieldNodes = new Map(); + const visitedFragmentNames = new Set(); + for (const node of fieldNodes) { + if (node.selectionSet) { + collectFieldsImpl( + schema, + fragments, + variableValues, + returnType, + node.selectionSet, + subFieldNodes, + visitedFragmentNames, + ); + } + } + return subFieldNodes; +} + +function collectFieldsImpl( + schema: GraphQLSchema, + fragments: ObjMap, + variableValues: { [variable: string]: unknown }, + runtimeType: GraphQLObjectType, + selectionSet: SelectionSetNode, + fields: Map>, + visitedFragmentNames: Set, +): void { + for (const selection of selectionSet.selections) { + switch (selection.kind) { + case Kind.FIELD: { + if (!shouldIncludeNode(variableValues, selection)) { + continue; + } + const name = getFieldEntryKey(selection); + const fieldList = fields.get(name); + if (fieldList !== undefined) { + fieldList.push(selection); + } else { + fields.set(name, [selection]); + } + break; + } + case Kind.INLINE_FRAGMENT: { + if ( + !shouldIncludeNode(variableValues, selection) || + !doesFragmentConditionMatch(schema, selection, runtimeType) + ) { + continue; + } + collectFieldsImpl( + schema, + fragments, + variableValues, + runtimeType, + selection.selectionSet, + fields, + visitedFragmentNames, + ); + break; + } + case Kind.FRAGMENT_SPREAD: { + const fragName = selection.name.value; + if ( + visitedFragmentNames.has(fragName) || + !shouldIncludeNode(variableValues, selection) + ) { + continue; + } + visitedFragmentNames.add(fragName); + const fragment = fragments[fragName]; + if ( + !fragment || + !doesFragmentConditionMatch(schema, fragment, runtimeType) + ) { + continue; + } + collectFieldsImpl( + schema, + fragments, + variableValues, + runtimeType, + fragment.selectionSet, + fields, + visitedFragmentNames, + ); + break; + } + } + } +} + +/** + * Determines if a field should be included based on the `@include` and `@skip` + * directives, where `@skip` has higher precedence than `@include`. + */ +function shouldIncludeNode( + variableValues: { [variable: string]: unknown }, + node: FragmentSpreadNode | FieldNode | InlineFragmentNode, +): boolean { + const skip = getDirectiveValues(GraphQLSkipDirective, node, variableValues); + if (skip?.if === true) { + return false; + } + + const include = getDirectiveValues( + GraphQLIncludeDirective, + node, + variableValues, + ); + if (include?.if === false) { + return false; + } + return true; +} + +/** + * Determines if a fragment is applicable to the given type. + */ +function doesFragmentConditionMatch( + schema: GraphQLSchema, + fragment: FragmentDefinitionNode | InlineFragmentNode, + type: GraphQLObjectType, +): boolean { + const typeConditionNode = fragment.typeCondition; + if (!typeConditionNode) { + return true; + } + const conditionalType = typeFromAST(schema, typeConditionNode); + if (conditionalType === type) { + return true; + } + if (isAbstractType(conditionalType)) { + return schema.isSubType(conditionalType, type); + } + return false; +} + +/** + * Implements the logic to compute the key of a given field's entry + */ +function getFieldEntryKey(node: FieldNode): string { + return node.alias ? node.alias.value : node.name.value; +} diff --git a/src/execution/execute.d.ts b/src/execution/execute.d.ts deleted file mode 100644 index a20db8c224..0000000000 --- a/src/execution/execute.d.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { PromiseOrValue } from '../jsutils/PromiseOrValue'; -import { Path } from '../jsutils/Path'; - -import { GraphQLError } from '../error/GraphQLError'; -import { GraphQLFormattedError } from '../error/formatError'; - -import { - DocumentNode, - OperationDefinitionNode, - SelectionSetNode, - FieldNode, - FragmentDefinitionNode, -} from '../language/ast'; -import { GraphQLSchema } from '../type/schema'; -import { - GraphQLField, - GraphQLFieldResolver, - GraphQLResolveInfo, - GraphQLTypeResolver, - GraphQLObjectType, -} from '../type/definition'; - -/** - * Data that must be available at all points during query execution. - * - * Namely, schema of the type system that is currently executing, - * and the fragments defined in the query document - */ -export interface ExecutionContext { - schema: GraphQLSchema; - fragments: { [key: string]: FragmentDefinitionNode }; - rootValue: any; - contextValue: any; - operation: OperationDefinitionNode; - variableValues: { [key: string]: any }; - fieldResolver: GraphQLFieldResolver; - errors: Array; -} - -/** - * The result of GraphQL execution. - * - * - `errors` is included when any errors occurred as a non-empty array. - * - `data` is the result of a successful execution of the query. - * - `extensions` is reserved for adding non-standard properties. - */ -export interface ExecutionResult< - TData = { [key: string]: any }, - TExtensions = { [key: string]: any } -> { - errors?: ReadonlyArray; - // TS_SPECIFIC: TData. Motivation: https://github.com/graphql/graphql-js/pull/2490#issuecomment-639154229 - data?: TData | null; - extensions?: TExtensions; -} - -export interface FormattedExecutionResult< - TData = { [key: string]: any }, - TExtensions = { [key: string]: any } -> { - errors?: ReadonlyArray; - // TS_SPECIFIC: TData. Motivation: https://github.com/graphql/graphql-js/pull/2490#issuecomment-639154229 - data?: TData | null; - extensions?: TExtensions; -} - -export interface ExecutionArgs { - schema: GraphQLSchema; - document: DocumentNode; - rootValue?: any; - contextValue?: any; - variableValues?: Maybe<{ [key: string]: any }>; - operationName?: Maybe; - fieldResolver?: Maybe>; - typeResolver?: Maybe>; -} - -/** - * Implements the "Evaluating requests" section of the GraphQL specification. - * - * Returns either a synchronous ExecutionResult (if all encountered resolvers - * are synchronous), or a Promise of an ExecutionResult that will eventually be - * resolved and never rejected. - * - * If the arguments to this function do not result in a legal execution context, - * a GraphQLError will be thrown immediately explaining the invalid input. - * - * Accepts either an object with named arguments, or individual arguments. - */ -export function execute(args: ExecutionArgs): PromiseOrValue; -export function execute( - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: any, - contextValue?: any, - variableValues?: Maybe<{ [key: string]: any }>, - operationName?: Maybe, - fieldResolver?: Maybe>, - typeResolver?: Maybe>, -): PromiseOrValue; - -/** - * Also implements the "Evaluating requests" section of the GraphQL specification. - * However, it guarantees to complete synchronously (or throw an error) assuming - * that all field resolvers are also synchronous. - */ -export function executeSync(args: ExecutionArgs): ExecutionResult; - -/** - * Essential assertions before executing to provide developer feedback for - * improper use of the GraphQL library. - */ -export function assertValidExecutionArguments( - schema: GraphQLSchema, - document: DocumentNode, - rawVariableValues: Maybe<{ [key: string]: any }>, -): void; - -/** - * Constructs a ExecutionContext object from the arguments passed to - * execute, which we will pass throughout the other execution methods. - * - * Throws a GraphQLError if a valid execution context cannot be created. - */ -export function buildExecutionContext( - schema: GraphQLSchema, - document: DocumentNode, - rootValue: any, - contextValue: any, - rawVariableValues: Maybe<{ [key: string]: any }>, - operationName: Maybe, - fieldResolver: Maybe>, - typeResolver?: Maybe>, -): ReadonlyArray | ExecutionContext; - -/** - * Given a selectionSet, adds all of the fields in that selection to - * the passed in map of fields, and returns it at the end. - * - * CollectFields requires the "runtime type" of an object. For a field which - * returns an Interface or Union type, the "runtime type" will be the actual - * Object type returned by that field. - */ -export function collectFields( - exeContext: ExecutionContext, - runtimeType: GraphQLObjectType, - selectionSet: SelectionSetNode, - fields: { [key: string]: Array }, - visitedFragmentNames: { [key: string]: boolean }, -): { [key: string]: Array }; - -export function buildResolveInfo( - exeContext: ExecutionContext, - fieldDef: GraphQLField, - fieldNodes: ReadonlyArray, - parentType: GraphQLObjectType, - path: Path, -): GraphQLResolveInfo; - -/** - * If a resolveType function is not given, then a default resolve behavior is - * used which attempts two strategies: - * - * First, See if the provided value has a `__typename` field defined, if so, use - * that value as name of the resolved type. - * - * Otherwise, test each possible type for the abstract type by calling - * isTypeOf for the object being coerced, returning the first type that matches. - */ -export const defaultTypeResolver: GraphQLTypeResolver; - -/** - * If a resolve function is not given, then a default resolve behavior is used - * which takes the property of the source object of the same name as the field - * and returns it as the result, or if it's a function, returns the result - * of calling that function while passing along args and context. - */ -export const defaultFieldResolver: GraphQLFieldResolver; - -/** - * This method looks up the field on the given type definition. - * It has special casing for the two introspection fields, __schema - * and __typename. __typename is special because it can always be - * queried as a field, even in situations where no other fields - * are allowed, like on a Union. __schema could get automatically - * added to the query type, but that would require mutating type - * definitions, which would cause issues. - */ -export function getFieldDef( - schema: GraphQLSchema, - parentType: GraphQLObjectType, - fieldName: string, -): Maybe>; diff --git a/src/execution/execute.js b/src/execution/execute.ts similarity index 60% rename from src/execution/execute.js rename to src/execution/execute.ts index f272b65aef..55c22ea9de 100644 --- a/src/execution/execute.js +++ b/src/execution/execute.ts @@ -1,73 +1,82 @@ -import arrayFrom from '../polyfills/arrayFrom'; - -import type { Path } from '../jsutils/Path'; +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import { isIterableObject } from '../jsutils/isIterableObject'; +import { isObjectLike } from '../jsutils/isObjectLike'; +import { isPromise } from '../jsutils/isPromise'; +import type { Maybe } from '../jsutils/Maybe'; +import { memoize3 } from '../jsutils/memoize3'; import type { ObjMap } from '../jsutils/ObjMap'; -import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; -import inspect from '../jsutils/inspect'; -import memoize3 from '../jsutils/memoize3'; -import invariant from '../jsutils/invariant'; -import devAssert from '../jsutils/devAssert'; -import isPromise from '../jsutils/isPromise'; -import isObjectLike from '../jsutils/isObjectLike'; -import isCollection from '../jsutils/isCollection'; -import promiseReduce from '../jsutils/promiseReduce'; -import promiseForObject from '../jsutils/promiseForObject'; +import type { Path } from '../jsutils/Path'; import { addPath, pathToArray } from '../jsutils/Path'; +import { promiseForObject } from '../jsutils/promiseForObject'; +import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; +import { promiseReduce } from '../jsutils/promiseReduce'; -import type { GraphQLFormattedError } from '../error/formatError'; +import type { GraphQLFormattedError } from '../error/GraphQLError'; import { GraphQLError } from '../error/GraphQLError'; import { locatedError } from '../error/locatedError'; import type { DocumentNode, - OperationDefinitionNode, - SelectionSetNode, FieldNode, - FragmentSpreadNode, - InlineFragmentNode, FragmentDefinitionNode, + OperationDefinitionNode, } from '../language/ast'; +import { OperationTypeNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import type { GraphQLSchema } from '../type/schema'; import type { - GraphQLObjectType, - GraphQLOutputType, - GraphQLLeafType, GraphQLAbstractType, GraphQLField, GraphQLFieldResolver, + GraphQLLeafType, + GraphQLList, + GraphQLObjectType, + GraphQLOutputType, GraphQLResolveInfo, GraphQLTypeResolver, - GraphQLList, } from '../type/definition'; -import { assertValidSchema } from '../type/validate'; -import { - SchemaMetaFieldDef, - TypeMetaFieldDef, - TypeNameMetaFieldDef, -} from '../type/introspection'; -import { - GraphQLIncludeDirective, - GraphQLSkipDirective, -} from '../type/directives'; import { - isNamedType, - isObjectType, isAbstractType, isLeafType, isListType, isNonNullType, + isObjectType, } from '../type/definition'; - -import { typeFromAST } from '../utilities/typeFromAST'; -import { getOperationRootType } from '../utilities/getOperationRootType'; +import { + SchemaMetaFieldDef, + TypeMetaFieldDef, + TypeNameMetaFieldDef, +} from '../type/introspection'; +import type { GraphQLSchema } from '../type/schema'; +import { assertValidSchema } from '../type/validate'; import { - getVariableValues, - getArgumentValues, - getDirectiveValues, -} from './values'; + collectFields, + collectSubfields as _collectSubfields, +} from './collectFields'; +import { getArgumentValues, getVariableValues } from './values'; + +/** + * A memoized collection of relevant subfields with regard to the return + * type. Memoizing ensures the subfields are not repeatedly calculated, which + * saves overhead when resolving lists of values. + */ +const collectSubfields = memoize3( + ( + exeContext: ExecutionContext, + returnType: GraphQLObjectType, + fieldNodes: ReadonlyArray, + ) => + _collectSubfields( + exeContext.schema, + exeContext.fragments, + exeContext.variableValues, + returnType, + fieldNodes, + ), +); /** * Terminology @@ -84,9 +93,9 @@ import { * * "Selections" are the definitions that can appear legally and at * single level of the query. These include: - * 1) field references e.g "a" - * 2) fragment "spreads" e.g. "...c" - * 3) inline fragment "spreads" e.g. "...on Type { a }" + * 1) field references e.g `a` + * 2) fragment "spreads" e.g. `...c` + * 3) inline fragment "spreads" e.g. `...on Type { a }` */ /** @@ -95,17 +104,18 @@ import { * Namely, schema of the type system that is currently executing, * and the fragments defined in the query document */ -export type ExecutionContext = {| - schema: GraphQLSchema, - fragments: ObjMap, - rootValue: mixed, - contextValue: mixed, - operation: OperationDefinitionNode, - variableValues: { [variable: string]: mixed, ... }, - fieldResolver: GraphQLFieldResolver, - typeResolver: GraphQLTypeResolver, - errors: Array, -|}; +export interface ExecutionContext { + schema: GraphQLSchema; + fragments: ObjMap; + rootValue: unknown; + contextValue: unknown; + operation: OperationDefinitionNode; + variableValues: { [variable: string]: unknown }; + fieldResolver: GraphQLFieldResolver; + typeResolver: GraphQLTypeResolver; + subscribeFieldResolver: GraphQLFieldResolver; + errors: Array; +} /** * The result of GraphQL execution. @@ -114,31 +124,38 @@ export type ExecutionContext = {| * - `data` is the result of a successful execution of the query. * - `extensions` is reserved for adding non-standard properties. */ -export type ExecutionResult = {| - errors?: $ReadOnlyArray, - data?: ObjMap | null, - extensions?: ObjMap, -|}; - -export type FormattedExecutionResult = {| - errors?: $ReadOnlyArray, - data?: ObjMap | null, - extensions?: ObjMap, -|}; - -export type ExecutionArgs = {| - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -|}; +export interface ExecutionResult< + TData = ObjMap, + TExtensions = ObjMap, +> { + errors?: ReadonlyArray; + data?: TData | null; + extensions?: TExtensions; +} + +export interface FormattedExecutionResult< + TData = ObjMap, + TExtensions = ObjMap, +> { + errors?: ReadonlyArray; + data?: TData | null; + extensions?: TExtensions; +} + +export interface ExecutionArgs { + schema: GraphQLSchema; + document: DocumentNode; + rootValue?: unknown; + contextValue?: unknown; + variableValues?: Maybe<{ readonly [variable: string]: unknown }>; + operationName?: Maybe; + fieldResolver?: Maybe>; + typeResolver?: Maybe>; + subscribeFieldResolver?: Maybe>; +} /** - * Implements the "Evaluating requests" section of the GraphQL specification. + * Implements the "Executing requests" section of the GraphQL specification. * * Returns either a synchronous ExecutionResult (if all encountered resolvers * are synchronous), or a Promise of an ExecutionResult that will eventually be @@ -146,96 +163,25 @@ export type ExecutionArgs = {| * * If the arguments to this function do not result in a legal execution context, * a GraphQLError will be thrown immediately explaining the invalid input. - * - * Accepts either an object with named arguments, or individual arguments. */ -declare function execute( - ExecutionArgs, - ..._: [] -): PromiseOrValue; -/* eslint-disable no-redeclare */ -declare function execute( - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -): PromiseOrValue; -export function execute( - argsOrSchema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, -) { - /* eslint-enable no-redeclare */ - // Extract arguments from object args if provided. - return arguments.length === 1 - ? executeImpl(argsOrSchema) - : executeImpl({ - schema: argsOrSchema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, - }); -} - -/** - * Also implements the "Evaluating requests" section of the GraphQL specification. - * However, it guarantees to complete synchronously (or throw an error) assuming - * that all field resolvers are also synchronous. - */ -export function executeSync(args: ExecutionArgs): ExecutionResult { - const result = executeImpl(args); - - // Assert that the execution was synchronous. - if (isPromise(result)) { - throw new Error('GraphQL execution failed to complete synchronously.'); - } - - return result; -} +export function execute(args: ExecutionArgs): PromiseOrValue { + // Temporary for v15 to v16 migration. Remove in v17 + devAssert( + arguments.length < 2, + 'graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.', + ); -function executeImpl(args: ExecutionArgs): PromiseOrValue { - const { - schema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, - } = args; + const { schema, document, variableValues, rootValue } = args; // If arguments are missing or incorrect, throw an error. assertValidExecutionArguments(schema, document, variableValues); // If a valid execution context cannot be created due to incorrect arguments, // a "Response" with only errors is returned. - const exeContext = buildExecutionContext( - schema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, - ); + const exeContext = buildExecutionContext(args); // Return early errors if execution context failed. - if (Array.isArray(exeContext)) { + if (!('schema' in exeContext)) { return { errors: exeContext }; } @@ -246,24 +192,54 @@ function executeImpl(args: ExecutionArgs): PromiseOrValue { // field and its descendants will be omitted, and sibling fields will still // be executed. An execution which encounters errors will still result in a // resolved Promise. - const data = executeOperation(exeContext, exeContext.operation, rootValue); - return buildResponse(exeContext, data); + // + // Errors from sub-fields of a NonNull type may propagate to the top level, + // at which point we still log the error and null the parent field, which + // in this case is the entire response. + try { + const { operation } = exeContext; + const result = executeOperation(exeContext, operation, rootValue); + if (isPromise(result)) { + return result.then( + (data) => buildResponse(data, exeContext.errors), + (error) => { + exeContext.errors.push(error); + return buildResponse(null, exeContext.errors); + }, + ); + } + return buildResponse(result, exeContext.errors); + } catch (error) { + exeContext.errors.push(error); + return buildResponse(null, exeContext.errors); + } +} + +/** + * Also implements the "Executing requests" section of the GraphQL specification. + * However, it guarantees to complete synchronously (or throw an error) assuming + * that all field resolvers are also synchronous. + */ +export function executeSync(args: ExecutionArgs): ExecutionResult { + const result = execute(args); + + // Assert that the execution was synchronous. + if (isPromise(result)) { + throw new Error('GraphQL execution failed to complete synchronously.'); + } + + return result; } /** - * Given a completed execution context and data, build the { errors, data } + * Given a completed execution context and data, build the `{ errors, data }` * response defined by the "Response" section of the GraphQL specification. */ function buildResponse( - exeContext: ExecutionContext, - data: PromiseOrValue | null>, -): PromiseOrValue { - if (isPromise(data)) { - return data.then((resolved) => buildResponse(exeContext, resolved)); - } - return exeContext.errors.length === 0 - ? { data } - : { errors: exeContext.errors, data }; + data: ObjMap | null, + errors: ReadonlyArray, +): ExecutionResult { + return errors.length === 0 ? { data } : { errors, data }; } /** @@ -275,7 +251,7 @@ function buildResponse( export function assertValidExecutionArguments( schema: GraphQLSchema, document: DocumentNode, - rawVariableValues: ?{ +[variable: string]: mixed, ... }, + rawVariableValues: Maybe<{ readonly [variable: string]: unknown }>, ): void { devAssert(document, 'Must provide document.'); @@ -298,16 +274,21 @@ export function assertValidExecutionArguments( * @internal */ export function buildExecutionContext( - schema: GraphQLSchema, - document: DocumentNode, - rootValue: mixed, - contextValue: mixed, - rawVariableValues: ?{ +[variable: string]: mixed, ... }, - operationName: ?string, - fieldResolver: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -): $ReadOnlyArray | ExecutionContext { - let operation: OperationDefinitionNode | void; + args: ExecutionArgs, +): ReadonlyArray | ExecutionContext { + const { + schema, + document, + rootValue, + contextValue, + variableValues: rawVariableValues, + operationName, + fieldResolver, + typeResolver, + subscribeFieldResolver, + } = args; + + let operation: OperationDefinitionNode | undefined; const fragments: ObjMap = Object.create(null); for (const definition of document.definitions) { switch (definition.kind) { @@ -328,6 +309,8 @@ export function buildExecutionContext( case Kind.FRAGMENT_DEFINITION: fragments[definition.name.value] = definition; break; + default: + // ignore non-executable definitions } } @@ -338,7 +321,8 @@ export function buildExecutionContext( return [new GraphQLError('Must provide an operation.')]; } - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const variableDefinitions = operation.variableDefinitions ?? []; const coercedVariableValues = getVariableValues( @@ -361,67 +345,70 @@ export function buildExecutionContext( variableValues: coercedVariableValues.coerced, fieldResolver: fieldResolver ?? defaultFieldResolver, typeResolver: typeResolver ?? defaultTypeResolver, + subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver, errors: [], }; } /** - * Implements the "Evaluating operations" section of the spec. + * Implements the "Executing operations" section of the spec. */ function executeOperation( exeContext: ExecutionContext, operation: OperationDefinitionNode, - rootValue: mixed, -): PromiseOrValue | null> { - const type = getOperationRootType(exeContext.schema, operation); - const fields = collectFields( - exeContext, - type, + rootValue: unknown, +): PromiseOrValue | null> { + const rootType = exeContext.schema.getRootType(operation.operation); + if (rootType == null) { + throw new GraphQLError( + `Schema is not configured to execute ${operation.operation} operation.`, + { nodes: operation }, + ); + } + + const rootFields = collectFields( + exeContext.schema, + exeContext.fragments, + exeContext.variableValues, + rootType, operation.selectionSet, - Object.create(null), - Object.create(null), ); - const path = undefined; - // Errors from sub-fields of a NonNull type may propagate to the top level, - // at which point we still log the error and null the parent field, which - // in this case is the entire response. - try { - const result = - operation.operation === 'mutation' - ? executeFieldsSerially(exeContext, type, rootValue, path, fields) - : executeFields(exeContext, type, rootValue, path, fields); - if (isPromise(result)) { - return result.then(undefined, (error) => { - exeContext.errors.push(error); - return Promise.resolve(null); - }); - } - return result; - } catch (error) { - exeContext.errors.push(error); - return null; + switch (operation.operation) { + case OperationTypeNode.QUERY: + return executeFields(exeContext, rootType, rootValue, path, rootFields); + case OperationTypeNode.MUTATION: + return executeFieldsSerially( + exeContext, + rootType, + rootValue, + path, + rootFields, + ); + case OperationTypeNode.SUBSCRIPTION: + // TODO: deprecate `subscribe` and move all logic here + // Temporary solution until we finish merging execute and subscribe together + return executeFields(exeContext, rootType, rootValue, path, rootFields); } } /** - * Implements the "Evaluating selection sets" section of the spec - * for "write" mode. + * Implements the "Executing selection sets" section of the spec + * for fields that must be executed serially. */ function executeFieldsSerially( exeContext: ExecutionContext, parentType: GraphQLObjectType, - sourceValue: mixed, - path: Path | void, - fields: ObjMap>, -): PromiseOrValue> { + sourceValue: unknown, + path: Path | undefined, + fields: Map>, +): PromiseOrValue> { return promiseReduce( - Object.keys(fields), - (results, responseName) => { - const fieldNodes = fields[responseName]; + fields.entries(), + (results, [responseName, fieldNodes]) => { const fieldPath = addPath(path, responseName, parentType.name); - const result = resolveField( + const result = executeField( exeContext, parentType, sourceValue, @@ -445,36 +432,45 @@ function executeFieldsSerially( } /** - * Implements the "Evaluating selection sets" section of the spec - * for "read" mode. + * Implements the "Executing selection sets" section of the spec + * for fields that may be executed in parallel. */ function executeFields( exeContext: ExecutionContext, parentType: GraphQLObjectType, - sourceValue: mixed, - path: Path | void, - fields: ObjMap>, -): PromiseOrValue> { + sourceValue: unknown, + path: Path | undefined, + fields: Map>, +): PromiseOrValue> { const results = Object.create(null); let containsPromise = false; - for (const responseName of Object.keys(fields)) { - const fieldNodes = fields[responseName]; - const fieldPath = addPath(path, responseName, parentType.name); - const result = resolveField( - exeContext, - parentType, - sourceValue, - fieldNodes, - fieldPath, - ); + try { + for (const [responseName, fieldNodes] of fields.entries()) { + const fieldPath = addPath(path, responseName, parentType.name); + const result = executeField( + exeContext, + parentType, + sourceValue, + fieldNodes, + fieldPath, + ); - if (result !== undefined) { - results[responseName] = result; - if (isPromise(result)) { - containsPromise = true; + if (result !== undefined) { + results[responseName] = result; + if (isPromise(result)) { + containsPromise = true; + } } } + } catch (error) { + if (containsPromise) { + // Ensure that any promises returned by other fields are handled, as they may also reject. + return promiseForObject(results).finally(() => { + throw error; + }); + } + throw error; } // If there are no promises, we can just return the object @@ -489,155 +485,19 @@ function executeFields( } /** - * Given a selectionSet, adds all of the fields in that selection to - * the passed in map of fields, and returns it at the end. - * - * CollectFields requires the "runtime type" of an object. For a field which - * returns an Interface or Union type, the "runtime type" will be the actual - * Object type returned by that field. - * - * @internal - */ -export function collectFields( - exeContext: ExecutionContext, - runtimeType: GraphQLObjectType, - selectionSet: SelectionSetNode, - fields: ObjMap>, - visitedFragmentNames: ObjMap, -): ObjMap> { - for (const selection of selectionSet.selections) { - switch (selection.kind) { - case Kind.FIELD: { - if (!shouldIncludeNode(exeContext, selection)) { - continue; - } - const name = getFieldEntryKey(selection); - if (!fields[name]) { - fields[name] = []; - } - fields[name].push(selection); - break; - } - case Kind.INLINE_FRAGMENT: { - if ( - !shouldIncludeNode(exeContext, selection) || - !doesFragmentConditionMatch(exeContext, selection, runtimeType) - ) { - continue; - } - collectFields( - exeContext, - runtimeType, - selection.selectionSet, - fields, - visitedFragmentNames, - ); - break; - } - case Kind.FRAGMENT_SPREAD: { - const fragName = selection.name.value; - if ( - visitedFragmentNames[fragName] || - !shouldIncludeNode(exeContext, selection) - ) { - continue; - } - visitedFragmentNames[fragName] = true; - const fragment = exeContext.fragments[fragName]; - if ( - !fragment || - !doesFragmentConditionMatch(exeContext, fragment, runtimeType) - ) { - continue; - } - collectFields( - exeContext, - runtimeType, - fragment.selectionSet, - fields, - visitedFragmentNames, - ); - break; - } - } - } - return fields; -} - -/** - * Determines if a field should be included based on the @include and @skip - * directives, where @skip has higher precedence than @include. - */ -function shouldIncludeNode( - exeContext: ExecutionContext, - node: FragmentSpreadNode | FieldNode | InlineFragmentNode, -): boolean { - const skip = getDirectiveValues( - GraphQLSkipDirective, - node, - exeContext.variableValues, - ); - if (skip?.if === true) { - return false; - } - - const include = getDirectiveValues( - GraphQLIncludeDirective, - node, - exeContext.variableValues, - ); - if (include?.if === false) { - return false; - } - return true; -} - -/** - * Determines if a fragment is applicable to the given type. - */ -function doesFragmentConditionMatch( - exeContext: ExecutionContext, - fragment: FragmentDefinitionNode | InlineFragmentNode, - type: GraphQLObjectType, -): boolean { - const typeConditionNode = fragment.typeCondition; - if (!typeConditionNode) { - return true; - } - const conditionalType = typeFromAST(exeContext.schema, typeConditionNode); - if (conditionalType === type) { - return true; - } - if (isAbstractType(conditionalType)) { - return exeContext.schema.isSubType(conditionalType, type); - } - return false; -} - -/** - * Implements the logic to compute the key of a given field's entry - */ -function getFieldEntryKey(node: FieldNode): string { - return node.alias ? node.alias.value : node.name.value; -} - -/** - * Resolves the field on the given source object. In particular, this - * figures out the value that the field returns by calling its resolve function, - * then calls completeValue to complete promises, serialize scalars, or execute - * the sub-selection-set for objects. + * Implements the "Executing fields" section of the spec + * In particular, this function figures out the value that the field returns by + * calling its resolve function, then calls completeValue to complete promises, + * serialize scalars, or execute the sub-selection-set for objects. */ -function resolveField( +function executeField( exeContext: ExecutionContext, parentType: GraphQLObjectType, - source: mixed, - fieldNodes: $ReadOnlyArray, + source: unknown, + fieldNodes: ReadonlyArray, path: Path, -): PromiseOrValue { - const fieldNode = fieldNodes[0]; - const fieldName = fieldNode.name.value; - - const fieldDef = getFieldDef(exeContext.schema, parentType, fieldName); +): PromiseOrValue { + const fieldDef = getFieldDef(exeContext.schema, parentType, fieldNodes[0]); if (!fieldDef) { return; } @@ -707,8 +567,8 @@ function resolveField( */ export function buildResolveInfo( exeContext: ExecutionContext, - fieldDef: GraphQLField, - fieldNodes: $ReadOnlyArray, + fieldDef: GraphQLField, + fieldNodes: ReadonlyArray, parentType: GraphQLObjectType, path: Path, ): GraphQLResolveInfo { @@ -747,7 +607,7 @@ function handleFieldError( /** * Implements the instructions for completeValue as defined in the - * "Field entries" section of the spec. + * "Value Completion" section of the spec. * * If the field type is Non-Null, then this recursively completes the value * for the inner type. It throws a field error if that completion returns null, @@ -764,16 +624,16 @@ function handleFieldError( * and then complete based on that type * * Otherwise, the field type expects a sub-selection set, and will complete the - * value by evaluating all sub-selections. + * value by executing all sub-selections. */ function completeValue( exeContext: ExecutionContext, returnType: GraphQLOutputType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue { + result: unknown, +): PromiseOrValue { // If result is an Error, throw a located error. if (result instanceof Error) { throw result; @@ -835,7 +695,6 @@ function completeValue( } // If field type is Object, execute and complete all sub-selections. - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isObjectType(returnType)) { return completeObjectValue( exeContext, @@ -846,12 +705,11 @@ function completeValue( result, ); } - - // istanbul ignore next (Not reachable. All possible output types have been considered) + /* c8 ignore next 6 */ + // Not reachable, all possible output types have been considered. invariant( false, - 'Cannot complete value of unexpected output type: ' + - inspect((returnType: empty)), + 'Cannot complete value of unexpected output type: ' + inspect(returnType), ); } @@ -862,12 +720,12 @@ function completeValue( function completeListValue( exeContext: ExecutionContext, returnType: GraphQLList, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue<$ReadOnlyArray> { - if (!isCollection(result)) { + result: unknown, +): PromiseOrValue> { + if (!isIterableObject(result)) { throw new GraphQLError( `Expected Iterable, but did not find one for field "${info.parentType.name}.${info.fieldName}".`, ); @@ -877,7 +735,7 @@ function completeListValue( // where the list contains no Promises by avoiding creating another Promise. const itemType = returnType.ofType; let containsPromise = false; - const completedResults = arrayFrom(result, (item, index) => { + const completedResults = Array.from(result, (item, index) => { // No need to modify the info object containing the path, // since from here on it is not ever accessed by resolver functions. const itemPath = addPath(path, index, undefined); @@ -932,12 +790,15 @@ function completeListValue( * Complete a Scalar or Enum by serializing to a valid value, returning * null if serialization is not possible. */ -function completeLeafValue(returnType: GraphQLLeafType, result: mixed): mixed { +function completeLeafValue( + returnType: GraphQLLeafType, + result: unknown, +): unknown { const serializedResult = returnType.serialize(result); - if (serializedResult === undefined) { + if (serializedResult == null) { throw new Error( - `Expected a value of type "${inspect(returnType)}" but ` + - `received: ${inspect(result)}`, + `Expected \`${inspect(returnType)}.serialize(${inspect(result)})\` to ` + + `return non-nullable value, returned: ${inspect(serializedResult)}`, ); } return serializedResult; @@ -950,11 +811,11 @@ function completeLeafValue(returnType: GraphQLLeafType, result: mixed): mixed { function completeAbstractValue( exeContext: ExecutionContext, returnType: GraphQLAbstractType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue> { + result: unknown, +): PromiseOrValue> { const resolveTypeFn = returnType.resolveType ?? exeContext.typeResolver; const contextValue = exeContext.contextValue; const runtimeType = resolveTypeFn(result, contextValue, info, returnType); @@ -997,51 +858,54 @@ function completeAbstractValue( } function ensureValidRuntimeType( - runtimeTypeOrName: mixed, + runtimeTypeName: unknown, exeContext: ExecutionContext, returnType: GraphQLAbstractType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, - result: mixed, + result: unknown, ): GraphQLObjectType { - if (runtimeTypeOrName == null) { + if (runtimeTypeName == null) { throw new GraphQLError( `Abstract type "${returnType.name}" must resolve to an Object type at runtime for field "${info.parentType.name}.${info.fieldName}". Either the "${returnType.name}" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.`, fieldNodes, ); } - // FIXME: temporary workaround until support for passing object types would be removed in v16.0.0 - const runtimeTypeName = isNamedType(runtimeTypeOrName) - ? runtimeTypeOrName.name - : runtimeTypeOrName; + // releases before 16.0.0 supported returning `GraphQLObjectType` from `resolveType` + // TODO: remove in 17.0.0 release + if (isObjectType(runtimeTypeName)) { + throw new GraphQLError( + 'Support for returning GraphQLObjectType from resolveType was removed in graphql-js@16.0.0 please return type name instead.', + ); + } if (typeof runtimeTypeName !== 'string') { throw new GraphQLError( `Abstract type "${returnType.name}" must resolve to an Object type at runtime for field "${info.parentType.name}.${info.fieldName}" with ` + - `value ${inspect(result)}, received "${inspect(runtimeTypeOrName)}".`, + `value ${inspect(result)}, received "${inspect(runtimeTypeName)}".`, ); } const runtimeType = exeContext.schema.getType(runtimeTypeName); if (runtimeType == null) { throw new GraphQLError( - `Abstract type "${returnType.name}" was resolve to a type "${runtimeTypeName}" that does not exist inside schema.`, - fieldNodes, + `Abstract type "${returnType.name}" was resolved to a type "${runtimeTypeName}" that does not exist inside the schema.`, + { nodes: fieldNodes }, ); } if (!isObjectType(runtimeType)) { throw new GraphQLError( - `Abstract type "${returnType.name}" was resolve to a non-object type "${runtimeTypeName}".`, - fieldNodes, + `Abstract type "${returnType.name}" was resolved to a non-object type "${runtimeTypeName}".`, + { nodes: fieldNodes }, ); } if (!exeContext.schema.isSubType(returnType, runtimeType)) { throw new GraphQLError( `Runtime Object type "${runtimeType.name}" is not a possible type for "${returnType.name}".`, - fieldNodes, + { nodes: fieldNodes }, ); } @@ -1054,11 +918,14 @@ function ensureValidRuntimeType( function completeObjectValue( exeContext: ExecutionContext, returnType: GraphQLObjectType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue> { + result: unknown, +): PromiseOrValue> { + // Collect sub-fields to execute to complete this value. + const subFieldNodes = collectSubfields(exeContext, returnType, fieldNodes); + // If there is an isTypeOf predicate function, call it with the // current result. If isTypeOf returns false, then raise an error rather // than continuing execution. @@ -1070,12 +937,12 @@ function completeObjectValue( if (!resolvedIsTypeOf) { throw invalidReturnTypeError(returnType, result, fieldNodes); } - return collectAndExecuteSubfields( + return executeFields( exeContext, returnType, - fieldNodes, - path, result, + path, + subFieldNodes, ); }); } @@ -1085,65 +952,20 @@ function completeObjectValue( } } - return collectAndExecuteSubfields( - exeContext, - returnType, - fieldNodes, - path, - result, - ); + return executeFields(exeContext, returnType, result, path, subFieldNodes); } function invalidReturnTypeError( returnType: GraphQLObjectType, - result: mixed, - fieldNodes: $ReadOnlyArray, + result: unknown, + fieldNodes: ReadonlyArray, ): GraphQLError { return new GraphQLError( `Expected value of type "${returnType.name}" but got: ${inspect(result)}.`, - fieldNodes, + { nodes: fieldNodes }, ); } -function collectAndExecuteSubfields( - exeContext: ExecutionContext, - returnType: GraphQLObjectType, - fieldNodes: $ReadOnlyArray, - path: Path, - result: mixed, -): PromiseOrValue> { - // Collect sub-fields to execute to complete this value. - const subFieldNodes = collectSubfields(exeContext, returnType, fieldNodes); - return executeFields(exeContext, returnType, result, path, subFieldNodes); -} - -/** - * A memoized collection of relevant subfields with regard to the return - * type. Memoizing ensures the subfields are not repeatedly calculated, which - * saves overhead when resolving lists of values. - */ -const collectSubfields = memoize3(_collectSubfields); -function _collectSubfields( - exeContext: ExecutionContext, - returnType: GraphQLObjectType, - fieldNodes: $ReadOnlyArray, -): ObjMap> { - let subFieldNodes = Object.create(null); - const visitedFragmentNames = Object.create(null); - for (const node of fieldNodes) { - if (node.selectionSet) { - subFieldNodes = collectFields( - exeContext, - returnType, - node.selectionSet, - subFieldNodes, - visitedFragmentNames, - ); - } - } - return subFieldNodes; -} - /** * If a resolveType function is not given, then a default resolve behavior is * used which attempts two strategies: @@ -1154,45 +976,41 @@ function _collectSubfields( * Otherwise, test each possible type for the abstract type by calling * isTypeOf for the object being coerced, returning the first type that matches. */ -export const defaultTypeResolver: GraphQLTypeResolver = function ( - value, - contextValue, - info, - abstractType, -) { - // First, look for `__typename`. - if (isObjectLike(value) && typeof value.__typename === 'string') { - return value.__typename; - } +export const defaultTypeResolver: GraphQLTypeResolver = + function (value, contextValue, info, abstractType) { + // First, look for `__typename`. + if (isObjectLike(value) && typeof value.__typename === 'string') { + return value.__typename; + } - // Otherwise, test each possible type. - const possibleTypes = info.schema.getPossibleTypes(abstractType); - const promisedIsTypeOfResults = []; + // Otherwise, test each possible type. + const possibleTypes = info.schema.getPossibleTypes(abstractType); + const promisedIsTypeOfResults = []; - for (let i = 0; i < possibleTypes.length; i++) { - const type = possibleTypes[i]; + for (let i = 0; i < possibleTypes.length; i++) { + const type = possibleTypes[i]; - if (type.isTypeOf) { - const isTypeOfResult = type.isTypeOf(value, contextValue, info); + if (type.isTypeOf) { + const isTypeOfResult = type.isTypeOf(value, contextValue, info); - if (isPromise(isTypeOfResult)) { - promisedIsTypeOfResults[i] = isTypeOfResult; - } else if (isTypeOfResult) { - return type.name; + if (isPromise(isTypeOfResult)) { + promisedIsTypeOfResults[i] = isTypeOfResult; + } else if (isTypeOfResult) { + return type.name; + } } } - } - if (promisedIsTypeOfResults.length) { - return Promise.all(promisedIsTypeOfResults).then((isTypeOfResults) => { - for (let i = 0; i < isTypeOfResults.length; i++) { - if (isTypeOfResults[i]) { - return possibleTypes[i].name; + if (promisedIsTypeOfResults.length) { + return Promise.all(promisedIsTypeOfResults).then((isTypeOfResults) => { + for (let i = 0; i < isTypeOfResults.length; i++) { + if (isTypeOfResults[i]) { + return possibleTypes[i].name; + } } - } - }); - } -}; + }); + } + }; /** * If a resolve function is not given, then a default resolve behavior is used @@ -1200,19 +1018,17 @@ export const defaultTypeResolver: GraphQLTypeResolver = function ( * and returns it as the result, or if it's a function, returns the result * of calling that function while passing along args and context value. */ -export const defaultFieldResolver: GraphQLFieldResolver< - mixed, - mixed, -> = function (source: any, args, contextValue, info) { - // ensure source is a value for which property access is acceptable. - if (isObjectLike(source) || typeof source === 'function') { - const property = source[info.fieldName]; - if (typeof property === 'function') { - return source[info.fieldName](args, contextValue, info); +export const defaultFieldResolver: GraphQLFieldResolver = + function (source: any, args, contextValue, info) { + // ensure source is a value for which property access is acceptable. + if (isObjectLike(source) || typeof source === 'function') { + const property = source[info.fieldName]; + if (typeof property === 'function') { + return source[info.fieldName](args, contextValue, info); + } + return property; } - return property; - } -}; + }; /** * This method looks up the field on the given type definition. @@ -1228,8 +1044,10 @@ export const defaultFieldResolver: GraphQLFieldResolver< export function getFieldDef( schema: GraphQLSchema, parentType: GraphQLObjectType, - fieldName: string, -): ?GraphQLField { + fieldNode: FieldNode, +): Maybe> { + const fieldName = fieldNode.name.value; + if ( fieldName === SchemaMetaFieldDef.name && schema.getQueryType() === parentType diff --git a/src/execution/index.d.ts b/src/execution/index.d.ts deleted file mode 100644 index d70ba3aaa5..0000000000 --- a/src/execution/index.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -export { pathToArray as responsePathAsArray } from '../jsutils/Path'; - -export { - execute, - executeSync, - defaultFieldResolver, - defaultTypeResolver, - ExecutionArgs, - ExecutionResult, - FormattedExecutionResult, -} from './execute'; - -export { getDirectiveValues } from './values'; diff --git a/src/execution/index.js b/src/execution/index.ts similarity index 63% rename from src/execution/index.js rename to src/execution/index.ts index 5ae0706ec9..7727e6d57c 100644 --- a/src/execution/index.js +++ b/src/execution/index.ts @@ -13,4 +13,10 @@ export type { FormattedExecutionResult, } from './execute'; -export { getDirectiveValues } from './values'; +export { subscribe, createSourceEventStream } from './subscribe'; + +export { + getArgumentValues, + getVariableValues, + getDirectiveValues, +} from './values'; diff --git a/src/execution/mapAsyncIterator.ts b/src/execution/mapAsyncIterator.ts new file mode 100644 index 0000000000..82e863c6c0 --- /dev/null +++ b/src/execution/mapAsyncIterator.ts @@ -0,0 +1,57 @@ +import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; + +/** + * Given an AsyncIterable and a callback function, return an AsyncIterator + * which produces values mapped via calling the callback function. + */ +export function mapAsyncIterator( + iterable: AsyncGenerator | AsyncIterable, + callback: (value: T) => PromiseOrValue, +): AsyncGenerator { + const iterator = iterable[Symbol.asyncIterator](); + + async function mapResult( + result: IteratorResult, + ): Promise> { + if (result.done) { + return result; + } + + try { + return { value: await callback(result.value), done: false }; + } catch (error) { + /* c8 ignore start */ + // FIXME: add test case + if (typeof iterator.return === 'function') { + try { + await iterator.return(); + } catch (_e) { + /* ignore error */ + } + } + throw error; + /* c8 ignore stop */ + } + } + + return { + async next() { + return mapResult(await iterator.next()); + }, + async return(): Promise> { + // If iterator.return() does not exist, then type R must be undefined. + return typeof iterator.return === 'function' + ? mapResult(await iterator.return()) + : { value: undefined as any, done: true }; + }, + async throw(error?: unknown) { + if (typeof iterator.throw === 'function') { + return mapResult(await iterator.throw(error)); + } + throw error; + }, + [Symbol.asyncIterator]() { + return this; + }, + }; +} diff --git a/src/execution/subscribe.ts b/src/execution/subscribe.ts new file mode 100644 index 0000000000..8b20ec3374 --- /dev/null +++ b/src/execution/subscribe.ts @@ -0,0 +1,262 @@ +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; +import { isAsyncIterable } from '../jsutils/isAsyncIterable'; +import type { Maybe } from '../jsutils/Maybe'; +import { addPath, pathToArray } from '../jsutils/Path'; + +import { GraphQLError } from '../error/GraphQLError'; +import { locatedError } from '../error/locatedError'; + +import type { DocumentNode } from '../language/ast'; + +import type { GraphQLFieldResolver } from '../type/definition'; +import type { GraphQLSchema } from '../type/schema'; + +import { collectFields } from './collectFields'; +import type { + ExecutionArgs, + ExecutionContext, + ExecutionResult, +} from './execute'; +import { + assertValidExecutionArguments, + buildExecutionContext, + buildResolveInfo, + execute, + getFieldDef, +} from './execute'; +import { mapAsyncIterator } from './mapAsyncIterator'; +import { getArgumentValues } from './values'; + +/** + * Implements the "Subscribe" algorithm described in the GraphQL specification. + * + * Returns a Promise which resolves to either an AsyncIterator (if successful) + * or an ExecutionResult (error). The promise will be rejected if the schema or + * other arguments to this function are invalid, or if the resolved event stream + * is not an async iterable. + * + * If the client-provided arguments to this function do not result in a + * compliant subscription, a GraphQL Response (ExecutionResult) with + * descriptive errors and no data will be returned. + * + * If the source stream could not be created due to faulty subscription + * resolver logic or underlying systems, the promise will resolve to a single + * ExecutionResult containing `errors` and no `data`. + * + * If the operation succeeded, the promise resolves to an AsyncIterator, which + * yields a stream of ExecutionResults representing the response stream. + * + * Accepts either an object with named arguments, or individual arguments. + */ +export async function subscribe( + args: ExecutionArgs, +): Promise | ExecutionResult> { + // Temporary for v15 to v16 migration. Remove in v17 + devAssert( + arguments.length < 2, + 'graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.', + ); + + const resultOrStream = await createSourceEventStream(args); + + if (!isAsyncIterable(resultOrStream)) { + return resultOrStream; + } + + // For each payload yielded from a subscription, map it over the normal + // GraphQL `execute` function, with `payload` as the rootValue. + // This implements the "MapSourceToResponseEvent" algorithm described in + // the GraphQL specification. The `execute` function provides the + // "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the + // "ExecuteQuery" algorithm, for which `execute` is also used. + const mapSourceToResponse = (payload: unknown) => + execute({ + ...args, + rootValue: payload, + }); + + // Map every source value to a ExecutionResult value as described above. + return mapAsyncIterator(resultOrStream, mapSourceToResponse); +} + +type BackwardsCompatibleArgs = + | [options: ExecutionArgs] + | [ + schema: ExecutionArgs['schema'], + document: ExecutionArgs['document'], + rootValue?: ExecutionArgs['rootValue'], + contextValue?: ExecutionArgs['contextValue'], + variableValues?: ExecutionArgs['variableValues'], + operationName?: ExecutionArgs['operationName'], + subscribeFieldResolver?: ExecutionArgs['subscribeFieldResolver'], + ]; + +function toNormalizedArgs(args: BackwardsCompatibleArgs): ExecutionArgs { + const firstArg = args[0]; + if (firstArg && 'document' in firstArg) { + return firstArg; + } + + return { + schema: firstArg, + // FIXME: when underlying TS bug fixed, see https://github.com/microsoft/TypeScript/issues/31613 + document: args[1] as DocumentNode, + rootValue: args[2], + contextValue: args[3], + variableValues: args[4], + operationName: args[5], + subscribeFieldResolver: args[6], + }; +} + +/** + * Implements the "CreateSourceEventStream" algorithm described in the + * GraphQL specification, resolving the subscription source event stream. + * + * Returns a Promise which resolves to either an AsyncIterable (if successful) + * or an ExecutionResult (error). The promise will be rejected if the schema or + * other arguments to this function are invalid, or if the resolved event stream + * is not an async iterable. + * + * If the client-provided arguments to this function do not result in a + * compliant subscription, a GraphQL Response (ExecutionResult) with + * descriptive errors and no data will be returned. + * + * If the the source stream could not be created due to faulty subscription + * resolver logic or underlying systems, the promise will resolve to a single + * ExecutionResult containing `errors` and no `data`. + * + * If the operation succeeded, the promise resolves to the AsyncIterable for the + * event stream returned by the resolver. + * + * A Source Event Stream represents a sequence of events, each of which triggers + * a GraphQL execution for that event. + * + * This may be useful when hosting the stateful subscription service in a + * different process or machine than the stateless GraphQL execution engine, + * or otherwise separating these two steps. For more on this, see the + * "Supporting Subscriptions at Scale" information in the GraphQL specification. + */ +export async function createSourceEventStream( + args: ExecutionArgs, +): Promise | ExecutionResult>; +/** @deprecated will be removed in next major version in favor of named arguments */ +export async function createSourceEventStream( + schema: GraphQLSchema, + document: DocumentNode, + rootValue?: unknown, + contextValue?: unknown, + variableValues?: Maybe<{ readonly [variable: string]: unknown }>, + operationName?: Maybe, + subscribeFieldResolver?: Maybe>, +): Promise | ExecutionResult>; +export async function createSourceEventStream( + ...rawArgs: BackwardsCompatibleArgs +) { + const args = toNormalizedArgs(rawArgs); + + const { schema, document, variableValues } = args; + + // If arguments are missing or incorrectly typed, this is an internal + // developer mistake which should throw an early error. + assertValidExecutionArguments(schema, document, variableValues); + + // If a valid execution context cannot be created due to incorrect arguments, + // a "Response" with only errors is returned. + const exeContext = buildExecutionContext(args); + + // Return early errors if execution context failed. + if (!('schema' in exeContext)) { + return { errors: exeContext }; + } + + try { + const eventStream = await executeSubscription(exeContext); + + // Assert field returned an event stream, otherwise yield an error. + if (!isAsyncIterable(eventStream)) { + throw new Error( + 'Subscription field must return Async Iterable. ' + + `Received: ${inspect(eventStream)}.`, + ); + } + + return eventStream; + } catch (error) { + // If it GraphQLError, report it as an ExecutionResult, containing only errors and no data. + // Otherwise treat the error as a system-class error and re-throw it. + if (error instanceof GraphQLError) { + return { errors: [error] }; + } + throw error; + } +} + +async function executeSubscription( + exeContext: ExecutionContext, +): Promise { + const { schema, fragments, operation, variableValues, rootValue } = + exeContext; + + const rootType = schema.getSubscriptionType(); + if (rootType == null) { + throw new GraphQLError( + 'Schema is not configured to execute subscription operation.', + { nodes: operation }, + ); + } + + const rootFields = collectFields( + schema, + fragments, + variableValues, + rootType, + operation.selectionSet, + ); + const [responseName, fieldNodes] = [...rootFields.entries()][0]; + const fieldDef = getFieldDef(schema, rootType, fieldNodes[0]); + + if (!fieldDef) { + const fieldName = fieldNodes[0].name.value; + throw new GraphQLError( + `The subscription field "${fieldName}" is not defined.`, + { nodes: fieldNodes }, + ); + } + + const path = addPath(undefined, responseName, rootType.name); + const info = buildResolveInfo( + exeContext, + fieldDef, + fieldNodes, + rootType, + path, + ); + + try { + // Implements the "ResolveFieldEventStream" algorithm from GraphQL specification. + // It differs from "ResolveFieldValue" due to providing a different `resolveFn`. + + // Build a JS object of arguments from the field.arguments AST, using the + // variables scope to fulfill any variable references. + const args = getArgumentValues(fieldDef, fieldNodes[0], variableValues); + + // The resolve function's optional third argument is a context value that + // is provided to every resolve function within an execution. It is commonly + // used to represent an authenticated user, or request-specific caches. + const contextValue = exeContext.contextValue; + + // Call the `subscribe()` resolver or the default resolver to produce an + // AsyncIterable yielding raw payloads. + const resolveFn = fieldDef.subscribe ?? exeContext.subscribeFieldResolver; + const eventStream = await resolveFn(rootValue, args, contextValue, info); + + if (eventStream instanceof Error) { + throw eventStream; + } + return eventStream; + } catch (error) { + throw locatedError(error, fieldNodes, pathToArray(path)); + } +} diff --git a/src/execution/values.d.ts b/src/execution/values.d.ts deleted file mode 100644 index 8b17b5487a..0000000000 --- a/src/execution/values.d.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { GraphQLError } from '../error/GraphQLError'; -import { - FieldNode, - DirectiveNode, - VariableDefinitionNode, -} from '../language/ast'; - -import { GraphQLDirective } from '../type/directives'; -import { GraphQLSchema } from '../type/schema'; -import { GraphQLField } from '../type/definition'; - -type CoercedVariableValues = - | { errors: ReadonlyArray; coerced?: never } - | { errors?: never; coerced: { [key: string]: any } }; - -/** - * Prepares an object map of variableValues of the correct type based on the - * provided variable definitions and arbitrary input. If the input cannot be - * parsed to match the variable definitions, a GraphQLError will be thrown. - * - * Note: The returned value is a plain Object with a prototype, since it is - * exposed to user code. Care should be taken to not pull values from the - * Object prototype. - */ -export function getVariableValues( - schema: GraphQLSchema, - varDefNodes: ReadonlyArray, - inputs: { [key: string]: any }, - options?: { maxErrors?: number }, -): CoercedVariableValues; - -/** - * Prepares an object map of argument values given a list of argument - * definitions and list of argument AST nodes. - * - * Note: The returned value is a plain Object with a prototype, since it is - * exposed to user code. Care should be taken to not pull values from the - * Object prototype. - */ -export function getArgumentValues( - def: GraphQLField | GraphQLDirective, - node: FieldNode | DirectiveNode, - variableValues?: Maybe<{ [key: string]: any }>, -): { [key: string]: any }; - -/** - * Prepares an object map of argument values given a directive definition - * and a AST node which may contain directives. Optionally also accepts a map - * of variable values. - * - * If the directive does not exist on the node, returns undefined. - * - * Note: The returned value is a plain Object with a prototype, since it is - * exposed to user code. Care should be taken to not pull values from the - * Object prototype. - */ -export function getDirectiveValues( - directiveDef: GraphQLDirective, - node: { - readonly directives?: ReadonlyArray; - }, - variableValues?: Maybe<{ [key: string]: any }>, -): undefined | { [key: string]: any }; diff --git a/src/execution/values.js b/src/execution/values.ts similarity index 79% rename from src/execution/values.js rename to src/execution/values.ts index cfe9a4e0d7..d65ea9cf20 100644 --- a/src/execution/values.js +++ b/src/execution/values.ts @@ -1,32 +1,31 @@ -import find from '../polyfills/find'; - +import { inspect } from '../jsutils/inspect'; +import { keyMap } from '../jsutils/keyMap'; +import type { Maybe } from '../jsutils/Maybe'; import type { ObjMap } from '../jsutils/ObjMap'; -import keyMap from '../jsutils/keyMap'; -import inspect from '../jsutils/inspect'; -import printPathArray from '../jsutils/printPathArray'; +import { printPathArray } from '../jsutils/printPathArray'; import { GraphQLError } from '../error/GraphQLError'; import type { - FieldNode, DirectiveNode, + FieldNode, VariableDefinitionNode, } from '../language/ast'; import { Kind } from '../language/kinds'; import { print } from '../language/printer'; -import type { GraphQLSchema } from '../type/schema'; import type { GraphQLField } from '../type/definition'; -import type { GraphQLDirective } from '../type/directives'; import { isInputType, isNonNullType } from '../type/definition'; +import type { GraphQLDirective } from '../type/directives'; +import type { GraphQLSchema } from '../type/schema'; +import { coerceInputValue } from '../utilities/coerceInputValue'; import { typeFromAST } from '../utilities/typeFromAST'; import { valueFromAST } from '../utilities/valueFromAST'; -import { coerceInputValue } from '../utilities/coerceInputValue'; type CoercedVariableValues = - | {| errors: $ReadOnlyArray |} - | {| coerced: { [variable: string]: mixed, ... } |}; + | { errors: ReadonlyArray; coerced?: never } + | { coerced: { [variable: string]: unknown }; errors?: never }; /** * Prepares an object map of variableValues of the correct type based on the @@ -36,14 +35,12 @@ type CoercedVariableValues = * Note: The returned value is a plain Object with a prototype, since it is * exposed to user code. Care should be taken to not pull values from the * Object prototype. - * - * @internal */ export function getVariableValues( schema: GraphQLSchema, - varDefNodes: $ReadOnlyArray, - inputs: { +[variable: string]: mixed, ... }, - options?: {| maxErrors?: number |}, + varDefNodes: ReadonlyArray, + inputs: { readonly [variable: string]: unknown }, + options?: { maxErrors?: number }, ): CoercedVariableValues { const errors = []; const maxErrors = options?.maxErrors; @@ -74,11 +71,11 @@ export function getVariableValues( function coerceVariableValues( schema: GraphQLSchema, - varDefNodes: $ReadOnlyArray, - inputs: { +[variable: string]: mixed, ... }, - onError: (GraphQLError) => void, -): { [variable: string]: mixed, ... } { - const coercedValues = {}; + varDefNodes: ReadonlyArray, + inputs: { readonly [variable: string]: unknown }, + onError: (error: GraphQLError) => void, +): { [variable: string]: unknown } { + const coercedValues: { [variable: string]: unknown } = {}; for (const varDefNode of varDefNodes) { const varName = varDefNode.variable.name.value; const varType = typeFromAST(schema, varDefNode.type); @@ -89,7 +86,7 @@ function coerceVariableValues( onError( new GraphQLError( `Variable "$${varName}" expected value of type "${varTypeStr}" which cannot be used as an input type.`, - varDefNode.type, + { nodes: varDefNode.type }, ), ); continue; @@ -103,7 +100,7 @@ function coerceVariableValues( onError( new GraphQLError( `Variable "$${varName}" of required type "${varTypeStr}" was not provided.`, - varDefNode, + { nodes: varDefNode }, ), ); } @@ -116,7 +113,7 @@ function coerceVariableValues( onError( new GraphQLError( `Variable "$${varName}" of non-null type "${varTypeStr}" must not be null.`, - varDefNode, + { nodes: varDefNode }, ), ); continue; @@ -132,14 +129,10 @@ function coerceVariableValues( prefix += ` at "${varName}${printPathArray(path)}"`; } onError( - new GraphQLError( - prefix + '; ' + error.message, - varDefNode, - undefined, - undefined, - undefined, - error.originalError, - ), + new GraphQLError(prefix + '; ' + error.message, { + nodes: varDefNode, + originalError: error, + }), ); }, ); @@ -155,17 +148,16 @@ function coerceVariableValues( * Note: The returned value is a plain Object with a prototype, since it is * exposed to user code. Care should be taken to not pull values from the * Object prototype. - * - * @internal */ export function getArgumentValues( - def: GraphQLField | GraphQLDirective, + def: GraphQLField | GraphQLDirective, node: FieldNode | DirectiveNode, - variableValues?: ?ObjMap, -): { [argument: string]: mixed, ... } { - const coercedValues = {}; + variableValues?: Maybe>, +): { [argument: string]: unknown } { + const coercedValues: { [argument: string]: unknown } = {}; - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const argumentNodes = node.arguments ?? []; const argNodeMap = keyMap(argumentNodes, (arg) => arg.name.value); @@ -181,7 +173,7 @@ export function getArgumentValues( throw new GraphQLError( `Argument "${name}" of required type "${inspect(argType)}" ` + 'was not provided.', - node, + { nodes: node }, ); } continue; @@ -202,7 +194,7 @@ export function getArgumentValues( throw new GraphQLError( `Argument "${name}" of required type "${inspect(argType)}" ` + `was provided the variable "$${variableName}" which was not provided a runtime value.`, - valueNode, + { nodes: valueNode }, ); } continue; @@ -214,7 +206,7 @@ export function getArgumentValues( throw new GraphQLError( `Argument "${name}" of non-null type "${inspect(argType)}" ` + 'must not be null.', - valueNode, + { nodes: valueNode }, ); } @@ -225,7 +217,7 @@ export function getArgumentValues( // continue with an invalid argument value. throw new GraphQLError( `Argument "${name}" has invalid value ${print(valueNode)}.`, - valueNode, + { nodes: valueNode }, ); } coercedValues[name] = coercedValue; @@ -246,21 +238,18 @@ export function getArgumentValues( */ export function getDirectiveValues( directiveDef: GraphQLDirective, - node: { +directives?: $ReadOnlyArray, ... }, - variableValues?: ?ObjMap, -): void | { [argument: string]: mixed, ... } { - const directiveNode = - node.directives && - find( - node.directives, - (directive) => directive.name.value === directiveDef.name, - ); + node: { readonly directives?: ReadonlyArray }, + variableValues?: Maybe>, +): undefined | { [argument: string]: unknown } { + const directiveNode = node.directives?.find( + (directive) => directive.name.value === directiveDef.name, + ); if (directiveNode) { return getArgumentValues(directiveDef, directiveNode, variableValues); } } -function hasOwnProperty(obj: mixed, prop: string): boolean { +function hasOwnProperty(obj: unknown, prop: string): boolean { return Object.prototype.hasOwnProperty.call(obj, prop); } diff --git a/src/graphql.d.ts b/src/graphql.d.ts deleted file mode 100644 index 8ba8ef72c8..0000000000 --- a/src/graphql.d.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Maybe } from './jsutils/Maybe'; - -import { Source } from './language/source'; -import { GraphQLSchema } from './type/schema'; -import { GraphQLFieldResolver, GraphQLTypeResolver } from './type/definition'; -import { ExecutionResult } from './execution/execute'; - -/** - * This is the primary entry point function for fulfilling GraphQL operations - * by parsing, validating, and executing a GraphQL document along side a - * GraphQL schema. - * - * More sophisticated GraphQL servers, such as those which persist queries, - * may wish to separate the validation and execution phases to a static time - * tooling step, and a server runtime step. - * - * Accepts either an object with named arguments, or individual arguments: - * - * schema: - * The GraphQL type system to use when validating and executing a query. - * source: - * A GraphQL language formatted string representing the requested operation. - * rootValue: - * The value provided as the first argument to resolver functions on the top - * level type (e.g. the query object type). - * contextValue: - * The context value is provided as an argument to resolver functions after - * field arguments. It is used to pass shared information useful at any point - * during executing this query, for example the currently logged in user and - * connections to databases or other services. - * variableValues: - * A mapping of variable name to runtime value to use for all variables - * defined in the requestString. - * operationName: - * The name of the operation to use if requestString contains multiple - * possible operations. Can be omitted if requestString contains only - * one operation. - * fieldResolver: - * A resolver function to use when one is not provided by the schema. - * If not provided, the default field resolver is used (which looks for a - * value or method on the source value with the field's name). - */ -export interface GraphQLArgs { - schema: GraphQLSchema; - source: string | Source; - rootValue?: any; - contextValue?: any; - variableValues?: Maybe<{ [key: string]: any }>; - operationName?: Maybe; - fieldResolver?: Maybe>; - typeResolver?: Maybe>; -} - -export function graphql(args: GraphQLArgs): Promise; -export function graphql( - schema: GraphQLSchema, - source: Source | string, - rootValue?: any, - contextValue?: any, - variableValues?: Maybe<{ [key: string]: any }>, - operationName?: Maybe, - fieldResolver?: Maybe>, - typeResolver?: Maybe>, -): Promise; - -/** - * The graphqlSync function also fulfills GraphQL operations by parsing, - * validating, and executing a GraphQL document along side a GraphQL schema. - * However, it guarantees to complete synchronously (or throw an error) assuming - * that all field resolvers are also synchronous. - */ -export function graphqlSync(args: GraphQLArgs): ExecutionResult; -export function graphqlSync( - schema: GraphQLSchema, - source: Source | string, - rootValue?: any, - contextValue?: any, - variableValues?: Maybe<{ [key: string]: any }>, - operationName?: Maybe, - fieldResolver?: Maybe>, - typeResolver?: Maybe>, -): ExecutionResult; diff --git a/src/graphql.js b/src/graphql.ts similarity index 61% rename from src/graphql.js rename to src/graphql.ts index da9428086d..bc6fb9bb72 100644 --- a/src/graphql.js +++ b/src/graphql.ts @@ -1,10 +1,10 @@ +import { devAssert } from './jsutils/devAssert'; +import { isPromise } from './jsutils/isPromise'; +import type { Maybe } from './jsutils/Maybe'; import type { PromiseOrValue } from './jsutils/PromiseOrValue'; -import isPromise from './jsutils/isPromise'; -import type { Source } from './language/source'; import { parse } from './language/parser'; - -import { validate } from './validation/validate'; +import type { Source } from './language/source'; import type { GraphQLFieldResolver, @@ -13,6 +13,8 @@ import type { import type { GraphQLSchema } from './type/schema'; import { validateSchema } from './type/validate'; +import { validate } from './validation/validate'; + import type { ExecutionResult } from './execution/execute'; import { execute } from './execution/execute'; @@ -55,57 +57,20 @@ import { execute } from './execution/execute'; * If not provided, the default type resolver is used (which looks for a * `__typename` field or alternatively calls the `isTypeOf` method). */ -export type GraphQLArgs = {| - schema: GraphQLSchema, - source: string | Source, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -|}; -declare function graphql(GraphQLArgs, ..._: []): Promise; -/* eslint-disable no-redeclare */ -declare function graphql( - schema: GraphQLSchema, - source: Source | string, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -): Promise; -export function graphql( - argsOrSchema, - source, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, -) { - /* eslint-enable no-redeclare */ +export interface GraphQLArgs { + schema: GraphQLSchema; + source: string | Source; + rootValue?: unknown; + contextValue?: unknown; + variableValues?: Maybe<{ readonly [variable: string]: unknown }>; + operationName?: Maybe; + fieldResolver?: Maybe>; + typeResolver?: Maybe>; +} + +export function graphql(args: GraphQLArgs): Promise { // Always return a Promise for a consistent API. - return new Promise((resolve) => - resolve( - // Extract arguments from object args if provided. - arguments.length === 1 - ? graphqlImpl(argsOrSchema) - : graphqlImpl({ - schema: argsOrSchema, - source, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, - }), - ), - ); + return new Promise((resolve) => resolve(graphqlImpl(args))); } /** @@ -114,43 +79,8 @@ export function graphql( * However, it guarantees to complete synchronously (or throw an error) assuming * that all field resolvers are also synchronous. */ -declare function graphqlSync(GraphQLArgs, ..._: []): ExecutionResult; -/* eslint-disable no-redeclare */ -declare function graphqlSync( - schema: GraphQLSchema, - source: Source | string, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -): ExecutionResult; -export function graphqlSync( - argsOrSchema, - source, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, -) { - /* eslint-enable no-redeclare */ - // Extract arguments from object args if provided. - const result = - arguments.length === 1 - ? graphqlImpl(argsOrSchema) - : graphqlImpl({ - schema: argsOrSchema, - source, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - typeResolver, - }); +export function graphqlSync(args: GraphQLArgs): ExecutionResult { + const result = graphqlImpl(args); // Assert that the execution was synchronous. if (isPromise(result)) { @@ -161,6 +91,12 @@ export function graphqlSync( } function graphqlImpl(args: GraphQLArgs): PromiseOrValue { + // Temporary for v15 to v16 migration. Remove in v17 + devAssert( + arguments.length < 2, + 'graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.', + ); + const { schema, source, diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 104ab88658..0000000000 --- a/src/index.js +++ /dev/null @@ -1,453 +0,0 @@ -/** - * GraphQL.js provides a reference implementation for the GraphQL specification - * but is also a useful utility for operating on GraphQL files and building - * sophisticated tools. - * - * This primary module exports a general purpose function for fulfilling all - * steps of the GraphQL specification in a single operation, but also includes - * utilities for every part of the GraphQL specification: - * - * - Parsing the GraphQL language. - * - Building a GraphQL type schema. - * - Validating a GraphQL request against a type schema. - * - Executing a GraphQL request against a type schema. - * - * This also includes utility functions for operating on GraphQL types and - * GraphQL documents to facilitate building tools. - * - * You may also import from each sub-directory directly. For example, the - * following two import statements are equivalent: - * - * import { parse } from 'graphql'; - * import { parse } from 'graphql/language'; - */ - -// The GraphQL.js version info. -export { version, versionInfo } from './version'; - -// The primary entry point into fulfilling a GraphQL request. -export type { GraphQLArgs } from './graphql'; -export { graphql, graphqlSync } from './graphql'; - -// Create and operate on GraphQL type definitions and schema. -export { - // Definitions - GraphQLSchema, - GraphQLDirective, - GraphQLScalarType, - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, - GraphQLList, - GraphQLNonNull, - // Standard GraphQL Scalars - specifiedScalarTypes, - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, - GraphQLID, - // Built-in Directives defined by the Spec - specifiedDirectives, - GraphQLIncludeDirective, - GraphQLSkipDirective, - GraphQLDeprecatedDirective, - GraphQLSpecifiedByDirective, - // "Enum" of Type Kinds - TypeKind, - // Constant Deprecation Reason - DEFAULT_DEPRECATION_REASON, - // GraphQL Types for introspection. - introspectionTypes, - __Schema, - __Directive, - __DirectiveLocation, - __Type, - __Field, - __InputValue, - __EnumValue, - __TypeKind, - // Meta-field definitions. - SchemaMetaFieldDef, - TypeMetaFieldDef, - TypeNameMetaFieldDef, - // Predicates - isSchema, - isDirective, - isType, - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, - isEnumType, - isInputObjectType, - isListType, - isNonNullType, - isInputType, - isOutputType, - isLeafType, - isCompositeType, - isAbstractType, - isWrappingType, - isNullableType, - isNamedType, - isRequiredArgument, - isRequiredInputField, - isSpecifiedScalarType, - isIntrospectionType, - isSpecifiedDirective, - // Assertions - assertSchema, - assertDirective, - assertType, - assertScalarType, - assertObjectType, - assertInterfaceType, - assertUnionType, - assertEnumType, - assertInputObjectType, - assertListType, - assertNonNullType, - assertInputType, - assertOutputType, - assertLeafType, - assertCompositeType, - assertAbstractType, - assertWrappingType, - assertNullableType, - assertNamedType, - // Un-modifiers - getNullableType, - getNamedType, - // Validate GraphQL schema. - validateSchema, - assertValidSchema, -} from './type/index'; - -export type { - GraphQLType, - GraphQLInputType, - GraphQLOutputType, - GraphQLLeafType, - GraphQLCompositeType, - GraphQLAbstractType, - GraphQLWrappingType, - GraphQLNullableType, - GraphQLNamedType, - Thunk, - GraphQLSchemaConfig, - GraphQLDirectiveConfig, - GraphQLArgument, - GraphQLArgumentConfig, - GraphQLEnumTypeConfig, - GraphQLEnumValue, - GraphQLEnumValueConfig, - GraphQLEnumValueConfigMap, - GraphQLField, - GraphQLFieldConfig, - GraphQLFieldConfigArgumentMap, - GraphQLFieldConfigMap, - GraphQLFieldMap, - GraphQLFieldResolver, - GraphQLInputField, - GraphQLInputFieldConfig, - GraphQLInputFieldConfigMap, - GraphQLInputFieldMap, - GraphQLInputObjectTypeConfig, - GraphQLInterfaceTypeConfig, - GraphQLIsTypeOfFn, - GraphQLObjectTypeConfig, - GraphQLResolveInfo, - ResponsePath, - GraphQLScalarTypeConfig, - GraphQLTypeResolver, - GraphQLUnionTypeConfig, - GraphQLScalarSerializer, - GraphQLScalarValueParser, - GraphQLScalarLiteralParser, -} from './type/index'; - -// Parse and operate on GraphQL language source files. -export { - Token, - Source, - Location, - getLocation, - // Print source location - printLocation, - printSourceLocation, - // Lex - Lexer, - TokenKind, - // Parse - parse, - parseValue, - parseType, - // Print - print, - // Visit - visit, - visitInParallel, - getVisitFn, - BREAK, - Kind, - DirectiveLocation, - // Predicates - isDefinitionNode, - isExecutableDefinitionNode, - isSelectionNode, - isValueNode, - isTypeNode, - isTypeSystemDefinitionNode, - isTypeDefinitionNode, - isTypeSystemExtensionNode, - isTypeExtensionNode, -} from './language/index'; - -export type { - ParseOptions, - SourceLocation, - TokenKindEnum, - KindEnum, - DirectiveLocationEnum, - // Visitor utilities - ASTVisitor, - Visitor, - VisitFn, - VisitorKeyMap, - // AST nodes - ASTNode, - ASTKindToNode, - // Each kind of AST node - NameNode, - DocumentNode, - DefinitionNode, - ExecutableDefinitionNode, - OperationDefinitionNode, - OperationTypeNode, - VariableDefinitionNode, - VariableNode, - SelectionSetNode, - SelectionNode, - FieldNode, - ArgumentNode, - FragmentSpreadNode, - InlineFragmentNode, - FragmentDefinitionNode, - ValueNode, - IntValueNode, - FloatValueNode, - StringValueNode, - BooleanValueNode, - NullValueNode, - EnumValueNode, - ListValueNode, - ObjectValueNode, - ObjectFieldNode, - DirectiveNode, - TypeNode, - NamedTypeNode, - ListTypeNode, - NonNullTypeNode, - TypeSystemDefinitionNode, - SchemaDefinitionNode, - OperationTypeDefinitionNode, - TypeDefinitionNode, - ScalarTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - UnionTypeDefinitionNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, - InputObjectTypeDefinitionNode, - DirectiveDefinitionNode, - TypeSystemExtensionNode, - SchemaExtensionNode, - TypeExtensionNode, - ScalarTypeExtensionNode, - ObjectTypeExtensionNode, - InterfaceTypeExtensionNode, - UnionTypeExtensionNode, - EnumTypeExtensionNode, - InputObjectTypeExtensionNode, -} from './language/index'; - -// Execute GraphQL queries. -export { - execute, - executeSync, - defaultFieldResolver, - defaultTypeResolver, - responsePathAsArray, - getDirectiveValues, -} from './execution/index'; - -export type { - ExecutionArgs, - ExecutionResult, - FormattedExecutionResult, -} from './execution/index'; - -export { subscribe, createSourceEventStream } from './subscription/index'; -export type { SubscriptionArgs } from './subscription/index'; - -// Validate GraphQL documents. -export { - validate, - ValidationContext, - // All validation rules in the GraphQL Specification. - specifiedRules, - // Individual validation rules. - ExecutableDefinitionsRule, - FieldsOnCorrectTypeRule, - FragmentsOnCompositeTypesRule, - KnownArgumentNamesRule, - KnownDirectivesRule, - KnownFragmentNamesRule, - KnownTypeNamesRule, - LoneAnonymousOperationRule, - NoFragmentCyclesRule, - NoUndefinedVariablesRule, - NoUnusedFragmentsRule, - NoUnusedVariablesRule, - OverlappingFieldsCanBeMergedRule, - PossibleFragmentSpreadsRule, - ProvidedRequiredArgumentsRule, - ScalarLeafsRule, - SingleFieldSubscriptionsRule, - UniqueArgumentNamesRule, - UniqueDirectivesPerLocationRule, - UniqueFragmentNamesRule, - UniqueInputFieldNamesRule, - UniqueOperationNamesRule, - UniqueVariableNamesRule, - ValuesOfCorrectTypeRule, - VariablesAreInputTypesRule, - VariablesInAllowedPositionRule, - // SDL-specific validation rules - LoneSchemaDefinitionRule, - UniqueOperationTypesRule, - UniqueTypeNamesRule, - UniqueEnumValueNamesRule, - UniqueFieldDefinitionNamesRule, - UniqueDirectiveNamesRule, - PossibleTypeExtensionsRule, - // Custom validation rules - NoDeprecatedCustomRule, - NoSchemaIntrospectionCustomRule, -} from './validation/index'; - -export type { ValidationRule } from './validation/index'; - -// Create, format, and print GraphQL errors. -export { - GraphQLError, - syntaxError, - locatedError, - printError, - formatError, -} from './error/index'; - -export type { GraphQLFormattedError } from './error/index'; - -// Utilities for operating on GraphQL type schema and parsed sources. -export { - // Produce the GraphQL query recommended for a full schema introspection. - // Accepts optional IntrospectionOptions. - getIntrospectionQuery, - // Gets the target Operation from a Document. - getOperationAST, - // Gets the Type for the target Operation AST. - getOperationRootType, - // Convert a GraphQLSchema to an IntrospectionQuery. - introspectionFromSchema, - // Build a GraphQLSchema from an introspection result. - buildClientSchema, - // Build a GraphQLSchema from a parsed GraphQL Schema language AST. - buildASTSchema, - // Build a GraphQLSchema from a GraphQL schema language document. - buildSchema, - // @deprecated: Get the description from a schema AST node and supports legacy - // syntax for specifying descriptions - will be removed in v16. - getDescription, - // Extends an existing GraphQLSchema from a parsed GraphQL Schema - // language AST. - extendSchema, - // Sort a GraphQLSchema. - lexicographicSortSchema, - // Print a GraphQLSchema to GraphQL Schema language. - printSchema, - // Print a GraphQLType to GraphQL Schema language. - printType, - // Prints the built-in introspection schema in the Schema Language - // format. - printIntrospectionSchema, - // Create a GraphQLType from a GraphQL language AST. - typeFromAST, - // Create a JavaScript value from a GraphQL language AST with a Type. - valueFromAST, - // Create a JavaScript value from a GraphQL language AST without a Type. - valueFromASTUntyped, - // Create a GraphQL language AST from a JavaScript value. - astFromValue, - // A helper to use within recursive-descent visitors which need to be aware of - // the GraphQL type system. - TypeInfo, - visitWithTypeInfo, - // Coerces a JavaScript value to a GraphQL type, or produces errors. - coerceInputValue, - // Concatenates multiple AST together. - concatAST, - // Separates an AST into an AST per Operation. - separateOperations, - // Strips characters that are not significant to the validity or execution - // of a GraphQL document. - stripIgnoredCharacters, - // Comparators for types - isEqualType, - isTypeSubTypeOf, - doTypesOverlap, - // Asserts a string is a valid GraphQL name. - assertValidName, - // Determine if a string is a valid GraphQL name. - isValidNameError, - // Compares two GraphQLSchemas and detects breaking changes. - BreakingChangeType, - DangerousChangeType, - findBreakingChanges, - findDangerousChanges, - // @deprecated: Report all deprecated usage within a GraphQL document. - findDeprecatedUsages, -} from './utilities/index'; - -export type { - IntrospectionOptions, - IntrospectionQuery, - IntrospectionSchema, - IntrospectionType, - IntrospectionInputType, - IntrospectionOutputType, - IntrospectionScalarType, - IntrospectionObjectType, - IntrospectionInterfaceType, - IntrospectionUnionType, - IntrospectionEnumType, - IntrospectionInputObjectType, - IntrospectionTypeRef, - IntrospectionInputTypeRef, - IntrospectionOutputTypeRef, - IntrospectionNamedTypeRef, - IntrospectionListTypeRef, - IntrospectionNonNullTypeRef, - IntrospectionField, - IntrospectionInputValue, - IntrospectionEnumValue, - IntrospectionDirective, - BuildSchemaOptions, - BreakingChange, - DangerousChange, -} from './utilities/index'; diff --git a/src/index.d.ts b/src/index.ts similarity index 88% rename from src/index.d.ts rename to src/index.ts index 0776078b8b..73c713a203 100644 --- a/src/index.d.ts +++ b/src/index.ts @@ -1,5 +1,3 @@ -// Minimum TypeScript Version: 2.6 - /** * GraphQL.js provides a reference implementation for the GraphQL specification * but is also a useful utility for operating on GraphQL files and building @@ -20,18 +18,25 @@ * You may also import from each sub-directory directly. For example, the * following two import statements are equivalent: * - * import { parse } from 'graphql'; - * import { parse } from 'graphql/language'; + * ```ts + * import { parse } from 'graphql'; + * import { parse } from 'graphql/language'; + * ``` + * + * @packageDocumentation */ // The GraphQL.js version info. export { version, versionInfo } from './version'; // The primary entry point into fulfilling a GraphQL request. -export { GraphQLArgs, graphql, graphqlSync } from './graphql'; +export type { GraphQLArgs } from './graphql'; +export { graphql, graphqlSync } from './graphql'; // Create and operate on GraphQL type definitions and schema. export { + resolveObjMapThunk, + resolveReadonlyArrayThunk, // Definitions GraphQLSchema, GraphQLDirective, @@ -50,12 +55,16 @@ export { GraphQLString, GraphQLBoolean, GraphQLID, + // Int boundaries constants + GRAPHQL_MAX_INT, + GRAPHQL_MIN_INT, // Built-in Directives defined by the Spec specifiedDirectives, GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective, + GraphQLOneOfDirective, // "Enum" of Type Kinds TypeKind, // Constant Deprecation Reason @@ -125,9 +134,12 @@ export { // Validate GraphQL schema. validateSchema, assertValidSchema, + // Upholds the spec rules about naming. + assertName, + assertEnumValueName, } from './type/index'; -export { +export type { GraphQLType, GraphQLInputType, GraphQLOutputType, @@ -137,7 +149,10 @@ export { GraphQLWrappingType, GraphQLNullableType, GraphQLNamedType, - Thunk, + GraphQLNamedInputType, + GraphQLNamedOutputType, + ThunkReadonlyArray, + ThunkObjMap, GraphQLSchemaConfig, GraphQLSchemaExtensions, GraphQLDirectiveConfig, @@ -149,19 +164,19 @@ export { GraphQLEnumTypeExtensions, GraphQLEnumValue, GraphQLEnumValueConfig, - GraphQLEnumValueExtensions, GraphQLEnumValueConfigMap, + GraphQLEnumValueExtensions, GraphQLField, GraphQLFieldConfig, - GraphQLFieldExtensions, GraphQLFieldConfigArgumentMap, GraphQLFieldConfigMap, + GraphQLFieldExtensions, GraphQLFieldMap, GraphQLFieldResolver, GraphQLInputField, GraphQLInputFieldConfig, - GraphQLInputFieldExtensions, GraphQLInputFieldConfigMap, + GraphQLInputFieldExtensions, GraphQLInputFieldMap, GraphQLInputObjectTypeConfig, GraphQLInputObjectTypeExtensions, @@ -187,8 +202,9 @@ export { Token, Source, Location, + OperationTypeNode, getLocation, - // Print source location + // Print source location. printLocation, printSourceLocation, // Lex @@ -197,6 +213,7 @@ export { // Parse parse, parseValue, + parseConstValue, parseType, // Print print, @@ -204,6 +221,7 @@ export { visit, visitInParallel, getVisitFn, + getEnterLeaveForKind, BREAK, Kind, DirectiveLocation, @@ -212,6 +230,7 @@ export { isExecutableDefinitionNode, isSelectionNode, isValueNode, + isConstValueNode, isTypeNode, isTypeSystemDefinitionNode, isTypeDefinitionNode, @@ -219,7 +238,7 @@ export { isTypeExtensionNode, } from './language/index'; -export { +export type { ParseOptions, SourceLocation, TokenKindEnum, @@ -227,9 +246,8 @@ export { DirectiveLocationEnum, // Visitor utilities ASTVisitor, - Visitor, - VisitFn, - VisitorKeyMap, + ASTVisitFn, + ASTVisitorKeyMap, // AST nodes ASTNode, ASTKindToNode, @@ -239,17 +257,18 @@ export { DefinitionNode, ExecutableDefinitionNode, OperationDefinitionNode, - OperationTypeNode, VariableDefinitionNode, VariableNode, SelectionSetNode, SelectionNode, FieldNode, ArgumentNode, + ConstArgumentNode, FragmentSpreadNode, InlineFragmentNode, FragmentDefinitionNode, ValueNode, + ConstValueNode, IntValueNode, FloatValueNode, StringValueNode, @@ -257,9 +276,13 @@ export { NullValueNode, EnumValueNode, ListValueNode, + ConstListValueNode, ObjectValueNode, + ConstObjectValueNode, ObjectFieldNode, + ConstObjectFieldNode, DirectiveNode, + ConstDirectiveNode, TypeNode, NamedTypeNode, ListTypeNode, @@ -296,17 +319,20 @@ export { defaultFieldResolver, defaultTypeResolver, responsePathAsArray, + getArgumentValues, + getVariableValues, getDirectiveValues, + subscribe, + createSourceEventStream, +} from './execution/index'; + +export type { ExecutionArgs, ExecutionResult, FormattedExecutionResult, } from './execution/index'; -export { - subscribe, - createSourceEventStream, - SubscriptionArgs, -} from './subscription/index'; +export type { SubscriptionArgs } from './subscription/index'; // Validate GraphQL documents. export { @@ -314,6 +340,7 @@ export { ValidationContext, // All validation rules in the GraphQL Specification. specifiedRules, + recommendedRules, // Individual validation rules. ExecutableDefinitionsRule, FieldsOnCorrectTypeRule, @@ -341,20 +368,23 @@ export { ValuesOfCorrectTypeRule, VariablesAreInputTypesRule, VariablesInAllowedPositionRule, + MaxIntrospectionDepthRule, // SDL-specific validation rules LoneSchemaDefinitionRule, UniqueOperationTypesRule, UniqueTypeNamesRule, UniqueEnumValueNamesRule, UniqueFieldDefinitionNamesRule, + UniqueArgumentDefinitionNamesRule, UniqueDirectiveNamesRule, PossibleTypeExtensionsRule, // Custom validation rules NoDeprecatedCustomRule, NoSchemaIntrospectionCustomRule, - ValidationRule, } from './validation/index'; +export type { ValidationRule } from './validation/index'; + // Create, format, and print GraphQL errors. export { GraphQLError, @@ -362,7 +392,13 @@ export { locatedError, printError, formatError, +} from './error/index'; + +export type { + GraphQLErrorOptions, GraphQLFormattedError, + GraphQLErrorExtensions, + GraphQLFormattedErrorExtensions, } from './error/index'; // Utilities for operating on GraphQL type schema and parsed sources. @@ -382,11 +418,7 @@ export { buildASTSchema, // Build a GraphQLSchema from a GraphQL schema language document. buildSchema, - // @deprecated: Get the description from a schema AST node and supports legacy - // syntax for specifying descriptions - will be removed in v16. - getDescription, - // Extends an existing GraphQLSchema from a parsed GraphQL Schema - // language AST. + // Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST. extendSchema, // Sort a GraphQLSchema. lexicographicSortSchema, @@ -394,8 +426,7 @@ export { printSchema, // Print a GraphQLType to GraphQL Schema language. printType, - // Prints the built-in introspection schema in the Schema Language - // format. + // Prints the built-in introspection schema in the Schema Language format. printIntrospectionSchema, // Create a GraphQLType from a GraphQL language AST. typeFromAST, @@ -405,8 +436,7 @@ export { valueFromASTUntyped, // Create a GraphQL language AST from a JavaScript value. astFromValue, - // A helper to use within recursive-descent visitors which need to be aware of - // the GraphQL type system. + // A helper to use within recursive-descent visitors which need to be aware of the GraphQL type system. TypeInfo, visitWithTypeInfo, // Coerces a JavaScript value to a GraphQL type, or produces errors. @@ -415,8 +445,7 @@ export { concatAST, // Separates an AST into an AST per Operation. separateOperations, - // Strips characters that are not significant to the validity or execution - // of a GraphQL document. + // Strips characters that are not significant to the validity or execution of a GraphQL document. stripIgnoredCharacters, // Comparators for types isEqualType, @@ -431,11 +460,9 @@ export { DangerousChangeType, findBreakingChanges, findDangerousChanges, - // @deprecated: Report all deprecated usage within a GraphQL document. - findDeprecatedUsages, } from './utilities/index'; -export { +export type { IntrospectionOptions, IntrospectionQuery, IntrospectionSchema, diff --git a/src/jsutils/Maybe.d.ts b/src/jsutils/Maybe.d.ts deleted file mode 100644 index e8b5e217d0..0000000000 --- a/src/jsutils/Maybe.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ -export type Maybe = null | undefined | T; diff --git a/src/jsutils/Maybe.ts b/src/jsutils/Maybe.ts new file mode 100644 index 0000000000..0ba64a4b64 --- /dev/null +++ b/src/jsutils/Maybe.ts @@ -0,0 +1,2 @@ +/** Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ */ +export type Maybe = null | undefined | T; diff --git a/src/jsutils/ObjMap.js b/src/jsutils/ObjMap.js deleted file mode 100644 index 9b6ef5e16e..0000000000 --- a/src/jsutils/ObjMap.js +++ /dev/null @@ -1,7 +0,0 @@ -export type ObjMap = { [key: string]: T, __proto__: null, ... }; -export type ObjMapLike = ObjMap | { [key: string]: T, ... }; - -export type ReadOnlyObjMap = { +[key: string]: T, __proto__: null, ... }; -export type ReadOnlyObjMapLike = - | ReadOnlyObjMap - | { +[key: string]: T, ... }; diff --git a/src/jsutils/ObjMap.ts b/src/jsutils/ObjMap.ts new file mode 100644 index 0000000000..2c20282187 --- /dev/null +++ b/src/jsutils/ObjMap.ts @@ -0,0 +1,13 @@ +export interface ObjMap { + [key: string]: T; +} + +export type ObjMapLike = ObjMap | { [key: string]: T }; + +export interface ReadOnlyObjMap { + readonly [key: string]: T; +} + +export type ReadOnlyObjMapLike = + | ReadOnlyObjMap + | { readonly [key: string]: T }; diff --git a/src/jsutils/Path.d.ts b/src/jsutils/Path.d.ts deleted file mode 100644 index 9a2233dd60..0000000000 --- a/src/jsutils/Path.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -export interface Path { - prev: Path | undefined; - key: string | number; - typename: string | undefined; -} - -/** - * Given a Path and a key, return a new Path containing the new key. - */ -export function addPath( - prev: Path | undefined, - key: string | number, - typename: string | undefined, -): Path; - -/** - * Given a Path, return an Array of the path keys. - */ -export function pathToArray(path: Path): Array; diff --git a/src/jsutils/Path.js b/src/jsutils/Path.ts similarity index 53% rename from src/jsutils/Path.js rename to src/jsutils/Path.ts index 47e8c7693c..64f6c78358 100644 --- a/src/jsutils/Path.js +++ b/src/jsutils/Path.ts @@ -1,16 +1,18 @@ -export type Path = {| - +prev: Path | void, - +key: string | number, - +typename: string | void, -|}; +import type { Maybe } from './Maybe'; + +export interface Path { + readonly prev: Path | undefined; + readonly key: string | number; + readonly typename: string | undefined; +} /** * Given a Path and a key, return a new Path containing the new key. */ export function addPath( - prev: $ReadOnly | void, + prev: Readonly | undefined, key: string | number, - typename: string | void, + typename: string | undefined, ): Path { return { prev, key, typename }; } @@ -18,7 +20,9 @@ export function addPath( /** * Given a Path, return an Array of the path keys. */ -export function pathToArray(path: ?$ReadOnly): Array { +export function pathToArray( + path: Maybe>, +): Array { const flattened = []; let curr = path; while (curr) { diff --git a/src/jsutils/PromiseOrValue.js b/src/jsutils/PromiseOrValue.js deleted file mode 100644 index e493c87e06..0000000000 --- a/src/jsutils/PromiseOrValue.js +++ /dev/null @@ -1 +0,0 @@ -export type PromiseOrValue<+T> = Promise | T; diff --git a/src/jsutils/PromiseOrValue.d.ts b/src/jsutils/PromiseOrValue.ts similarity index 100% rename from src/jsutils/PromiseOrValue.d.ts rename to src/jsutils/PromiseOrValue.ts diff --git a/src/jsutils/__tests__/Path-test.ts b/src/jsutils/__tests__/Path-test.ts new file mode 100644 index 0000000000..43bca192c0 --- /dev/null +++ b/src/jsutils/__tests__/Path-test.ts @@ -0,0 +1,36 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { addPath, pathToArray } from '../Path'; + +describe('Path', () => { + it('can create a Path', () => { + const first = addPath(undefined, 1, 'First'); + + expect(first).to.deep.equal({ + prev: undefined, + key: 1, + typename: 'First', + }); + }); + + it('can add a new key to an existing Path', () => { + const first = addPath(undefined, 1, 'First'); + const second = addPath(first, 'two', 'Second'); + + expect(second).to.deep.equal({ + prev: first, + key: 'two', + typename: 'Second', + }); + }); + + it('can convert a Path to an array of its keys', () => { + const root = addPath(undefined, 0, 'Root'); + const first = addPath(root, 'one', 'First'); + const second = addPath(first, 2, 'Second'); + + const path = pathToArray(second); + expect(path).to.deep.equal([0, 'one', 2]); + }); +}); diff --git a/src/jsutils/__tests__/didYouMean-test.js b/src/jsutils/__tests__/didYouMean-test.ts similarity index 95% rename from src/jsutils/__tests__/didYouMean-test.js rename to src/jsutils/__tests__/didYouMean-test.ts index 70a4ac5237..bc01e18080 100644 --- a/src/jsutils/__tests__/didYouMean-test.js +++ b/src/jsutils/__tests__/didYouMean-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import didYouMean from '../didYouMean'; +import { didYouMean } from '../didYouMean'; describe('didYouMean', () => { it('Does accept an empty list', () => { diff --git a/src/jsutils/__tests__/identityFunc-test.js b/src/jsutils/__tests__/identityFunc-test.ts similarity index 80% rename from src/jsutils/__tests__/identityFunc-test.js rename to src/jsutils/__tests__/identityFunc-test.ts index 8c7eff39bc..97cc25eb2f 100644 --- a/src/jsutils/__tests__/identityFunc-test.js +++ b/src/jsutils/__tests__/identityFunc-test.ts @@ -1,10 +1,11 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import identityFunc from '../identityFunc'; +import { identityFunc } from '../identityFunc'; describe('identityFunc', () => { it('returns the first argument it receives', () => { + // @ts-expect-error (Expects an argument) expect(identityFunc()).to.equal(undefined); expect(identityFunc(undefined)).to.equal(undefined); expect(identityFunc(null)).to.equal(null); diff --git a/src/jsutils/__tests__/inspect-test.js b/src/jsutils/__tests__/inspect-test.ts similarity index 68% rename from src/jsutils/__tests__/inspect-test.js rename to src/jsutils/__tests__/inspect-test.ts index a3fedb9d15..d1ac17313a 100644 --- a/src/jsutils/__tests__/inspect-test.js +++ b/src/jsutils/__tests__/inspect-test.ts @@ -1,9 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import inspect from '../inspect'; -import invariant from '../invariant'; -import nodejsCustomInspectSymbol from '../nodejsCustomInspectSymbol'; +import { inspect } from '../inspect'; describe('inspect', () => { it('undefined', () => { @@ -35,14 +33,16 @@ describe('inspect', () => { it('function', () => { const unnamedFuncStr = inspect( - // istanbul ignore next (Never called and used as a placeholder) - () => invariant(false), + // Never called and used as a placeholder + /* c8 ignore next */ + () => expect.fail('Should not be called'), ); expect(unnamedFuncStr).to.equal('[function]'); - // istanbul ignore next (Never called and used as a placeholder) + // Never called and used as a placeholder + /* c8 ignore next 3 */ function namedFunc() { - invariant(false); + expect.fail('Should not be called'); } expect(inspect(namedFunc)).to.equal('[function namedFunc]'); }); @@ -84,54 +84,40 @@ describe('inspect', () => { expect(inspect(map)).to.equal('{ a: true, b: null }'); }); - it('custom inspect', () => { + it('use toJSON if provided', () => { const object = { - inspect() { - return ''; + toJSON() { + return ''; }, }; - expect(inspect(object)).to.equal(''); + expect(inspect(object)).to.equal(''); }); - it('custom inspect that return `this` should work', () => { + it('handles toJSON that return `this` should work', () => { const object = { - inspect() { + toJSON() { return this; }, }; - expect(inspect(object)).to.equal('{ inspect: [function inspect] }'); + expect(inspect(object)).to.equal('{ toJSON: [function toJSON] }'); }); - it('custom symbol inspect is take precedence', () => { + it('handles toJSON returning object values', () => { const object = { - // istanbul ignore next (Never called and use just as a placeholder) - inspect() { - invariant(false); - }, - [String(nodejsCustomInspectSymbol)]() { - return ''; - }, - }; - - expect(inspect(object)).to.equal(''); - }); - - it('custom inspect returning object values', () => { - const object = { - inspect() { - return { custom: 'inspect' }; + toJSON() { + return { json: 'value' }; }, }; - expect(inspect(object)).to.equal('{ custom: "inspect" }'); + expect(inspect(object)).to.equal('{ json: "value" }'); }); - it('custom inspect function that uses this', () => { + it('handles toJSON function that uses this', () => { const object = { str: 'Hello World!', - inspect() { + toJSON() { return this.str; }, }; @@ -140,7 +126,7 @@ describe('inspect', () => { }); it('detect circular objects', () => { - const obj = {}; + const obj: { [name: string]: unknown } = {}; obj.self = obj; obj.deepSelf = { self: obj }; @@ -148,23 +134,23 @@ describe('inspect', () => { '{ self: [Circular], deepSelf: { self: [Circular] } }', ); - const array = []; + const array: any = []; array[0] = array; array[1] = [array]; expect(inspect(array)).to.equal('[[Circular], [[Circular]]]'); - const mixed = { array: [] }; + const mixed: any = { array: [] }; mixed.array[0] = mixed; expect(inspect(mixed)).to.equal('{ array: [[Circular]] }'); const customA = { - inspect: () => customB, + toJSON: () => customB, }; const customB = { - inspect: () => customA, + toJSON: () => customA, }; expect(inspect(customA)).to.equal('[Circular]'); @@ -181,13 +167,21 @@ describe('inspect', () => { expect(inspect([[new Foo()]])).to.equal('[[[Foo]]]'); - (Foo.prototype: any)[Symbol.toStringTag] = 'Bar'; - expect(inspect([[new Foo()]])).to.equal('[[[Bar]]]'); + class Foo2 { + foo: string; + + [Symbol.toStringTag] = 'Bar'; + + constructor() { + this.foo = 'bar'; + } + } + expect(inspect([[new Foo2()]])).to.equal('[[[Bar]]]'); - const objectWithoutClassName = new (function () { - // eslint-disable-next-line no-invalid-this + // eslint-disable-next-line func-names + const objectWithoutClassName = new (function (this: any) { this.foo = 1; - })(); + } as any)(); expect(inspect([[objectWithoutClassName]])).to.equal('[[[Object]]]'); }); }); diff --git a/src/jsutils/__tests__/instanceOf-test.js b/src/jsutils/__tests__/instanceOf-test.js deleted file mode 100644 index 17a8d4e46d..0000000000 --- a/src/jsutils/__tests__/instanceOf-test.js +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import instanceOf from '../instanceOf'; - -describe('instanceOf', () => { - it('fails with descriptive error message', () => { - function getFoo() { - class Foo {} - return Foo; - } - const Foo1 = getFoo(); - const Foo2 = getFoo(); - - expect(() => instanceOf(new Foo1(), Foo2)).to.throw( - /^Cannot use Foo "\[object Object\]" from another module or realm./m, - ); - expect(() => instanceOf(new Foo2(), Foo1)).to.throw( - /^Cannot use Foo "\[object Object\]" from another module or realm./m, - ); - }); -}); diff --git a/src/jsutils/__tests__/instanceOf-test.ts b/src/jsutils/__tests__/instanceOf-test.ts new file mode 100644 index 0000000000..cbd649bfa8 --- /dev/null +++ b/src/jsutils/__tests__/instanceOf-test.ts @@ -0,0 +1,79 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { instanceOf } from '../instanceOf'; + +describe('instanceOf', () => { + it('do not throw on values without prototype', () => { + class Foo { + get [Symbol.toStringTag]() { + return 'Foo'; + } + } + + expect(instanceOf(true, Foo)).to.equal(false); + expect(instanceOf(null, Foo)).to.equal(false); + expect(instanceOf(Object.create(null), Foo)).to.equal(false); + }); + + it('detect name clashes with older versions of this lib', () => { + function oldVersion() { + class Foo {} + return Foo; + } + + function newVersion() { + class Foo { + get [Symbol.toStringTag]() { + return 'Foo'; + } + } + return Foo; + } + + const NewClass = newVersion(); + const OldClass = oldVersion(); + expect(instanceOf(new NewClass(), NewClass)).to.equal(true); + expect(() => instanceOf(new OldClass(), NewClass)).to.throw(); + }); + + it('allows instances to have share the same constructor name', () => { + function getMinifiedClass(tag: string) { + class SomeNameAfterMinification { + get [Symbol.toStringTag]() { + return tag; + } + } + return SomeNameAfterMinification; + } + + const Foo = getMinifiedClass('Foo'); + const Bar = getMinifiedClass('Bar'); + expect(instanceOf(new Foo(), Bar)).to.equal(false); + expect(instanceOf(new Bar(), Foo)).to.equal(false); + + const DuplicateOfFoo = getMinifiedClass('Foo'); + expect(() => instanceOf(new DuplicateOfFoo(), Foo)).to.throw(); + expect(() => instanceOf(new Foo(), DuplicateOfFoo)).to.throw(); + }); + + it('fails with descriptive error message', () => { + function getFoo() { + class Foo { + get [Symbol.toStringTag]() { + return 'Foo'; + } + } + return Foo; + } + const Foo1 = getFoo(); + const Foo2 = getFoo(); + + expect(() => instanceOf(new Foo1(), Foo2)).to.throw( + /^Cannot use Foo "{}" from another module or realm./m, + ); + expect(() => instanceOf(new Foo2(), Foo1)).to.throw( + /^Cannot use Foo "{}" from another module or realm./m, + ); + }); +}); diff --git a/src/jsutils/__tests__/invariant-test.js b/src/jsutils/__tests__/invariant-test.ts similarity index 89% rename from src/jsutils/__tests__/invariant-test.js rename to src/jsutils/__tests__/invariant-test.ts index 97c293596e..2a438b69b3 100644 --- a/src/jsutils/__tests__/invariant-test.js +++ b/src/jsutils/__tests__/invariant-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../invariant'; +import { invariant } from '../invariant'; describe('invariant', () => { it('throws on false conditions', () => { diff --git a/src/jsutils/__tests__/isAsyncIterable-test.js b/src/jsutils/__tests__/isAsyncIterable-test.ts similarity index 63% rename from src/jsutils/__tests__/isAsyncIterable-test.js rename to src/jsutils/__tests__/isAsyncIterable-test.ts index 282e6a3474..e62bb53433 100644 --- a/src/jsutils/__tests__/isAsyncIterable-test.js +++ b/src/jsutils/__tests__/isAsyncIterable-test.ts @@ -1,22 +1,21 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import identityFunc from '../identityFunc'; -import isAsyncIterable from '../isAsyncIterable'; +import { identityFunc } from '../identityFunc'; +import { isAsyncIterable } from '../isAsyncIterable'; describe('isAsyncIterable', () => { it('should return `true` for AsyncIterable', () => { - const asyncIteratable = { [Symbol.asyncIterator]: identityFunc }; - expect(isAsyncIterable(asyncIteratable)).to.equal(true); + const asyncIterable = { [Symbol.asyncIterator]: identityFunc }; + expect(isAsyncIterable(asyncIterable)).to.equal(true); - // istanbul ignore next (Never called and use just as a placeholder) async function* asyncGeneratorFunc() { /* do nothing */ } expect(isAsyncIterable(asyncGeneratorFunc())).to.equal(true); - // But async generator function itself is not iteratable + // But async generator function itself is not iterable expect(isAsyncIterable(asyncGeneratorFunc)).to.equal(false); }); @@ -34,18 +33,20 @@ describe('isAsyncIterable', () => { expect(isAsyncIterable({})).to.equal(false); expect(isAsyncIterable({ iterable: true })).to.equal(false); - const iterator = { [Symbol.iterator]: identityFunc }; - expect(isAsyncIterable(iterator)).to.equal(false); + const asyncIteratorWithoutSymbol = { next: identityFunc }; + expect(isAsyncIterable(asyncIteratorWithoutSymbol)).to.equal(false); + + const nonAsyncIterable = { [Symbol.iterator]: identityFunc }; + expect(isAsyncIterable(nonAsyncIterable)).to.equal(false); - // istanbul ignore next (Never called and use just as a placeholder) function* generatorFunc() { /* do nothing */ } expect(isAsyncIterable(generatorFunc())).to.equal(false); - const invalidAsyncIteratable = { + const invalidAsyncIterable = { [Symbol.asyncIterator]: { next: identityFunc }, }; - expect(isAsyncIterable(invalidAsyncIteratable)).to.equal(false); + expect(isAsyncIterable(invalidAsyncIterable)).to.equal(false); }); }); diff --git a/src/jsutils/__tests__/isCollection-test.js b/src/jsutils/__tests__/isCollection-test.js deleted file mode 100644 index 0277d2eb53..0000000000 --- a/src/jsutils/__tests__/isCollection-test.js +++ /dev/null @@ -1,71 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import identityFunc from '../identityFunc'; -import isCollection from '../isCollection'; - -describe('isCollection', () => { - it('should return `true` for collections', () => { - expect(isCollection([])).to.equal(true); - expect(isCollection(new Int8Array(1))).to.equal(true); - - // eslint-disable-next-line no-new-wrappers - expect(isCollection(new String('ABC'))).to.equal(true); - - function getArguments() { - return arguments; - } - expect(isCollection(getArguments())).to.equal(true); - - const arrayLike = {}; - arrayLike[0] = 'Alpha'; - arrayLike[1] = 'Bravo'; - arrayLike[2] = 'Charlie'; - arrayLike.length = 3; - - expect(isCollection(arrayLike)).to.equal(true); - - const iterator = { [Symbol.iterator]: identityFunc }; - expect(isCollection(iterator)).to.equal(true); - - // istanbul ignore next (Never called and use just as a placeholder) - function* generatorFunc() { - /* do nothing */ - } - expect(isCollection(generatorFunc())).to.equal(true); - - // But generator function itself is not iteratable - expect(isCollection(generatorFunc)).to.equal(false); - }); - - it('should return `false` for non-collections', () => { - expect(isCollection(null)).to.equal(false); - expect(isCollection(undefined)).to.equal(false); - - expect(isCollection('ABC')).to.equal(false); - expect(isCollection('0')).to.equal(false); - expect(isCollection('')).to.equal(false); - - expect(isCollection(1)).to.equal(false); - expect(isCollection(0)).to.equal(false); - expect(isCollection(NaN)).to.equal(false); - // eslint-disable-next-line no-new-wrappers - expect(isCollection(new Number(123))).to.equal(false); - - expect(isCollection(true)).to.equal(false); - expect(isCollection(false)).to.equal(false); - // eslint-disable-next-line no-new-wrappers - expect(isCollection(new Boolean(true))).to.equal(false); - - expect(isCollection({})).to.equal(false); - expect(isCollection({ iterable: true })).to.equal(false); - - const iteratorWithoutSymbol = { next: identityFunc }; - expect(isCollection(iteratorWithoutSymbol)).to.equal(false); - - const invalidIteratable = { - [Symbol.iterator]: { next: identityFunc }, - }; - expect(isCollection(invalidIteratable)).to.equal(false); - }); -}); diff --git a/src/jsutils/__tests__/isIterableObject-test.ts b/src/jsutils/__tests__/isIterableObject-test.ts new file mode 100644 index 0000000000..c631cb4b80 --- /dev/null +++ b/src/jsutils/__tests__/isIterableObject-test.ts @@ -0,0 +1,70 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { identityFunc } from '../identityFunc'; +import { isIterableObject } from '../isIterableObject'; + +describe('isIterableObject', () => { + it('should return `true` for collections', () => { + expect(isIterableObject([])).to.equal(true); + expect(isIterableObject(new Int8Array(1))).to.equal(true); + + // eslint-disable-next-line no-new-wrappers + expect(isIterableObject(new String('ABC'))).to.equal(true); + + function getArguments() { + return arguments; + } + expect(isIterableObject(getArguments())).to.equal(true); + + const iterable = { [Symbol.iterator]: identityFunc }; + expect(isIterableObject(iterable)).to.equal(true); + + function* generatorFunc() { + /* do nothing */ + } + expect(isIterableObject(generatorFunc())).to.equal(true); + + // But generator function itself is not iterable + expect(isIterableObject(generatorFunc)).to.equal(false); + }); + + it('should return `false` for non-collections', () => { + expect(isIterableObject(null)).to.equal(false); + expect(isIterableObject(undefined)).to.equal(false); + + expect(isIterableObject('ABC')).to.equal(false); + expect(isIterableObject('0')).to.equal(false); + expect(isIterableObject('')).to.equal(false); + + expect(isIterableObject(1)).to.equal(false); + expect(isIterableObject(0)).to.equal(false); + expect(isIterableObject(NaN)).to.equal(false); + // eslint-disable-next-line no-new-wrappers + expect(isIterableObject(new Number(123))).to.equal(false); + + expect(isIterableObject(true)).to.equal(false); + expect(isIterableObject(false)).to.equal(false); + // eslint-disable-next-line no-new-wrappers + expect(isIterableObject(new Boolean(true))).to.equal(false); + + expect(isIterableObject({})).to.equal(false); + expect(isIterableObject({ iterable: true })).to.equal(false); + + const iteratorWithoutSymbol = { next: identityFunc }; + expect(isIterableObject(iteratorWithoutSymbol)).to.equal(false); + + const invalidIterable = { + [Symbol.iterator]: { next: identityFunc }, + }; + expect(isIterableObject(invalidIterable)).to.equal(false); + + const arrayLike: { [key: string]: unknown } = {}; + arrayLike[0] = 'Alpha'; + arrayLike[1] = 'Bravo'; + arrayLike[2] = 'Charlie'; + arrayLike.length = 3; + + expect(isIterableObject(arrayLike)).to.equal(false); + }); +}); diff --git a/src/jsutils/__tests__/isObjectLike-test.js b/src/jsutils/__tests__/isObjectLike-test.ts similarity index 87% rename from src/jsutils/__tests__/isObjectLike-test.js rename to src/jsutils/__tests__/isObjectLike-test.ts index 724d3ab10c..536ecb5f88 100644 --- a/src/jsutils/__tests__/isObjectLike-test.js +++ b/src/jsutils/__tests__/isObjectLike-test.ts @@ -1,8 +1,8 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import identityFunc from '../identityFunc'; -import isObjectLike from '../isObjectLike'; +import { identityFunc } from '../identityFunc'; +import { isObjectLike } from '../isObjectLike'; describe('isObjectLike', () => { it('should return `true` for objects', () => { diff --git a/src/jsutils/__tests__/naturalCompare-test.js b/src/jsutils/__tests__/naturalCompare-test.ts similarity index 97% rename from src/jsutils/__tests__/naturalCompare-test.js rename to src/jsutils/__tests__/naturalCompare-test.ts index 0aee2cae86..4c5291e579 100644 --- a/src/jsutils/__tests__/naturalCompare-test.js +++ b/src/jsutils/__tests__/naturalCompare-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import naturalCompare from '../naturalCompare'; +import { naturalCompare } from '../naturalCompare'; describe('naturalCompare', () => { it('Handles empty strings', () => { diff --git a/src/jsutils/__tests__/suggestionList-test.js b/src/jsutils/__tests__/suggestionList-test.ts similarity index 91% rename from src/jsutils/__tests__/suggestionList-test.js rename to src/jsutils/__tests__/suggestionList-test.ts index 57a2d55c71..2b90524885 100644 --- a/src/jsutils/__tests__/suggestionList-test.js +++ b/src/jsutils/__tests__/suggestionList-test.ts @@ -1,9 +1,9 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import suggestionList from '../suggestionList'; +import { suggestionList } from '../suggestionList'; -function expectSuggestions(input: string, options: Array) { +function expectSuggestions(input: string, options: ReadonlyArray) { return expect(suggestionList(input, options)); } @@ -22,9 +22,11 @@ describe('suggestionList', () => { }); it('Rejects options with distance that exceeds threshold', () => { + // spell-checker:disable expectSuggestions('aaaa', ['aaab']).to.deep.equal(['aaab']); expectSuggestions('aaaa', ['aabb']).to.deep.equal(['aabb']); expectSuggestions('aaaa', ['abbb']).to.deep.equal([]); + // spell-checker:enable expectSuggestions('ab', ['ca']).to.deep.equal([]); }); diff --git a/src/jsutils/__tests__/toObjMap-test.js b/src/jsutils/__tests__/toObjMap-test.ts similarity index 74% rename from src/jsutils/__tests__/toObjMap-test.js rename to src/jsutils/__tests__/toObjMap-test.ts index 3f5ab924f5..f9136b87b8 100644 --- a/src/jsutils/__tests__/toObjMap-test.js +++ b/src/jsutils/__tests__/toObjMap-test.ts @@ -2,12 +2,24 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import type { ObjMapLike } from '../ObjMap'; -import toObjMap from '../toObjMap'; +import { toObjMap } from '../toObjMap'; -// Workaround to make both ESLint and Flow happy -const __proto__: string = '__proto__'; +// Workaround to make both ESLint happy +const __proto__ = '__proto__'; describe('toObjMap', () => { + it('convert undefined to ObjMap', () => { + const result = toObjMap(undefined); + expect(result).to.deep.equal({}); + expect(Object.getPrototypeOf(result)).to.equal(null); + }); + + it('convert null to ObjMap', () => { + const result = toObjMap(null); + expect(result).to.deep.equal({}); + expect(Object.getPrototypeOf(result)).to.equal(null); + }); + it('convert empty object to ObjMap', () => { const result = toObjMap({}); expect(result).to.deep.equal({}); diff --git a/src/jsutils/defineInspect.js b/src/jsutils/defineInspect.js deleted file mode 100644 index b0773a9a79..0000000000 --- a/src/jsutils/defineInspect.js +++ /dev/null @@ -1,19 +0,0 @@ -import invariant from './invariant'; -import nodejsCustomInspectSymbol from './nodejsCustomInspectSymbol'; - -/** - * The `defineInspect()` function defines `inspect()` prototype method as alias of `toJSON` - */ -export default function defineInspect( - classObject: Class | ((...args: Array) => mixed), -): void { - const fn = classObject.prototype.toJSON; - invariant(typeof fn === 'function'); - - classObject.prototype.inspect = fn; - - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2317') - if (nodejsCustomInspectSymbol) { - classObject.prototype[nodejsCustomInspectSymbol] = fn; - } -} diff --git a/src/jsutils/devAssert.js b/src/jsutils/devAssert.js deleted file mode 100644 index da2adfcd00..0000000000 --- a/src/jsutils/devAssert.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function devAssert(condition: mixed, message: string): void { - const booleanCondition = Boolean(condition); - // istanbul ignore else (See transformation done in './resources/inlineInvariant.js') - if (!booleanCondition) { - throw new Error(message); - } -} diff --git a/src/jsutils/devAssert.ts b/src/jsutils/devAssert.ts new file mode 100644 index 0000000000..ff97228b9f --- /dev/null +++ b/src/jsutils/devAssert.ts @@ -0,0 +1,6 @@ +export function devAssert(condition: unknown, message: string): void { + const booleanCondition = Boolean(condition); + if (!booleanCondition) { + throw new Error(message); + } +} diff --git a/src/jsutils/didYouMean.js b/src/jsutils/didYouMean.ts similarity index 60% rename from src/jsutils/didYouMean.js rename to src/jsutils/didYouMean.ts index 45e1a93c83..33e10a42c1 100644 --- a/src/jsutils/didYouMean.js +++ b/src/jsutils/didYouMean.ts @@ -3,19 +3,18 @@ const MAX_SUGGESTIONS = 5; /** * Given [ A, B, C ] return ' Did you mean A, B, or C?'. */ -declare function didYouMean(suggestions: $ReadOnlyArray): string; -// eslint-disable-next-line no-redeclare -declare function didYouMean( +export function didYouMean(suggestions: ReadonlyArray): string; +export function didYouMean( subMessage: string, - suggestions: $ReadOnlyArray, + suggestions: ReadonlyArray, ): string; - -// eslint-disable-next-line no-redeclare -export default function didYouMean(firstArg, secondArg) { - const [subMessage, suggestionsArg] = - typeof firstArg === 'string' - ? [firstArg, secondArg] - : [undefined, firstArg]; +export function didYouMean( + firstArg: string | ReadonlyArray, + secondArg?: ReadonlyArray, +) { + const [subMessage, suggestionsArg] = secondArg + ? [firstArg as string, secondArg] + : [undefined, firstArg as ReadonlyArray]; let message = ' Did you mean '; if (subMessage) { diff --git a/src/jsutils/groupBy.ts b/src/jsutils/groupBy.ts new file mode 100644 index 0000000000..f3b0c076d1 --- /dev/null +++ b/src/jsutils/groupBy.ts @@ -0,0 +1,19 @@ +/** + * Groups array items into a Map, given a function to produce grouping key. + */ +export function groupBy( + list: ReadonlyArray, + keyFn: (item: T) => K, +): Map> { + const result = new Map>(); + for (const item of list) { + const key = keyFn(item); + const group = result.get(key); + if (group === undefined) { + result.set(key, [item]); + } else { + group.push(item); + } + } + return result; +} diff --git a/src/jsutils/identityFunc.js b/src/jsutils/identityFunc.ts similarity index 56% rename from src/jsutils/identityFunc.js rename to src/jsutils/identityFunc.ts index 94cb7e1534..a249b51c34 100644 --- a/src/jsutils/identityFunc.js +++ b/src/jsutils/identityFunc.ts @@ -1,6 +1,6 @@ /** * Returns the first argument it receives. */ -export default function identityFunc(x: T): T { +export function identityFunc(x: T): T { return x; } diff --git a/src/jsutils/inspect.js b/src/jsutils/inspect.ts similarity index 56% rename from src/jsutils/inspect.js rename to src/jsutils/inspect.ts index b33f70c825..514cbaad39 100644 --- a/src/jsutils/inspect.js +++ b/src/jsutils/inspect.ts @@ -1,26 +1,23 @@ -/* eslint-disable flowtype/no-weak-types */ -import nodejsCustomInspectSymbol from './nodejsCustomInspectSymbol'; - const MAX_ARRAY_LENGTH = 10; const MAX_RECURSIVE_DEPTH = 2; /** * Used to print values in error messages. */ -export default function inspect(value: mixed): string { +export function inspect(value: unknown): string { return formatValue(value, []); } -function formatValue(value: mixed, seenValues: Array): string { +function formatValue( + value: unknown, + seenValues: ReadonlyArray, +): string { switch (typeof value) { case 'string': return JSON.stringify(value); case 'function': return value.name ? `[function ${value.name}]` : '[function]'; case 'object': - if (value === null) { - return 'null'; - } return formatObjectValue(value, seenValues); default: return String(value); @@ -28,24 +25,27 @@ function formatValue(value: mixed, seenValues: Array): string { } function formatObjectValue( - value: Object, - previouslySeenValues: Array, + value: object | null, + previouslySeenValues: ReadonlyArray, ): string { - if (previouslySeenValues.indexOf(value) !== -1) { + if (value === null) { + return 'null'; + } + + if (previouslySeenValues.includes(value)) { return '[Circular]'; } const seenValues = [...previouslySeenValues, value]; - const customInspectFn = getCustomFn(value); - if (customInspectFn !== undefined) { - const customValue = customInspectFn.call(value); + if (isJSONable(value)) { + const jsonValue = value.toJSON(); // check for infinite recursion - if (customValue !== value) { - return typeof customValue === 'string' - ? customValue - : formatValue(customValue, seenValues); + if (jsonValue !== value) { + return typeof jsonValue === 'string' + ? jsonValue + : formatValue(jsonValue, seenValues); } } else if (Array.isArray(value)) { return formatArray(value, seenValues); @@ -54,9 +54,16 @@ function formatObjectValue( return formatObject(value, seenValues); } -function formatObject(object: Object, seenValues: Array): string { - const keys = Object.keys(object); - if (keys.length === 0) { +function isJSONable(value: any): value is { toJSON: () => unknown } { + return typeof value.toJSON === 'function'; +} + +function formatObject( + object: object, + seenValues: ReadonlyArray, +): string { + const entries = Object.entries(object); + if (entries.length === 0) { return '{}'; } @@ -64,15 +71,16 @@ function formatObject(object: Object, seenValues: Array): string { return '[' + getObjectTag(object) + ']'; } - const properties = keys.map((key) => { - const value = formatValue(object[key], seenValues); - return key + ': ' + value; - }); - + const properties = entries.map( + ([key, value]) => key + ': ' + formatValue(value, seenValues), + ); return '{ ' + properties.join(', ') + ' }'; } -function formatArray(array: Array, seenValues: Array): string { +function formatArray( + array: ReadonlyArray, + seenValues: ReadonlyArray, +): string { if (array.length === 0) { return '[]'; } @@ -98,19 +106,7 @@ function formatArray(array: Array, seenValues: Array): string { return '[' + items.join(', ') + ']'; } -function getCustomFn(object: Object) { - const customInspectFn = object[String(nodejsCustomInspectSymbol)]; - - if (typeof customInspectFn === 'function') { - return customInspectFn; - } - - if (typeof object.inspect === 'function') { - return object.inspect; - } -} - -function getObjectTag(object: Object): string { +function getObjectTag(object: object): string { const tag = Object.prototype.toString .call(object) .replace(/^\[object /, '') diff --git a/src/jsutils/instanceOf.js b/src/jsutils/instanceOf.js deleted file mode 100644 index e55cd13f73..0000000000 --- a/src/jsutils/instanceOf.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * A replacement for instanceof which includes an error warning when multi-realm - * constructors are detected. - */ -declare function instanceOf( - value: mixed, - constructor: mixed, -): boolean %checks(value instanceof constructor); - -// See: https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production -// See: https://webpack.js.org/guides/production/ -export default process.env.NODE_ENV === 'production' - ? // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') - // eslint-disable-next-line no-shadow - function instanceOf(value: mixed, constructor: mixed): boolean { - return value instanceof constructor; - } - : // eslint-disable-next-line no-shadow - function instanceOf(value: any, constructor: any): boolean { - if (value instanceof constructor) { - return true; - } - if (value) { - const valueClass = value.constructor; - const className = constructor.name; - if (className && valueClass && valueClass.name === className) { - throw new Error( - `Cannot use ${className} "${value}" from another module or realm. - -Ensure that there is only one instance of "graphql" in the node_modules -directory. If different versions of "graphql" are the dependencies of other -relied on modules, use "resolutions" to ensure only one version is installed. - -https://yarnpkg.com/en/docs/selective-version-resolutions - -Duplicate "graphql" modules cannot be used at the same time since different -versions may have different capabilities and behavior. The data from one -version used in the function from another could produce confusing and -spurious results.`, - ); - } - } - return false; - }; diff --git a/src/jsutils/instanceOf.ts b/src/jsutils/instanceOf.ts new file mode 100644 index 0000000000..27c4ab4d12 --- /dev/null +++ b/src/jsutils/instanceOf.ts @@ -0,0 +1,60 @@ +import { inspect } from './inspect'; + +/* c8 ignore next 3 */ +const isProduction = + globalThis.process && + // eslint-disable-next-line no-undef + process.env.NODE_ENV === 'production'; + +/** + * A replacement for instanceof which includes an error warning when multi-realm + * constructors are detected. + * See: https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production + * See: https://webpack.js.org/guides/production/ + */ +export const instanceOf: (value: unknown, constructor: Constructor) => boolean = + /* c8 ignore next 6 */ + // FIXME: https://github.com/graphql/graphql-js/issues/2317 + isProduction + ? function instanceOf(value: unknown, constructor: Constructor): boolean { + return value instanceof constructor; + } + : function instanceOf(value: unknown, constructor: Constructor): boolean { + if (value instanceof constructor) { + return true; + } + if (typeof value === 'object' && value !== null) { + // Prefer Symbol.toStringTag since it is immune to minification. + const className = constructor.prototype[Symbol.toStringTag]; + const valueClassName = + // We still need to support constructor's name to detect conflicts with older versions of this library. + Symbol.toStringTag in value + ? // @ts-expect-error TS bug see, https://github.com/microsoft/TypeScript/issues/38009 + value[Symbol.toStringTag] + : value.constructor?.name; + if (className === valueClassName) { + const stringifiedValue = inspect(value); + throw new Error( + `Cannot use ${className} "${stringifiedValue}" from another module or realm. + +Ensure that there is only one instance of "graphql" in the node_modules +directory. If different versions of "graphql" are the dependencies of other +relied on modules, use "resolutions" to ensure only one version is installed. + +https://yarnpkg.com/en/docs/selective-version-resolutions + +Duplicate "graphql" modules cannot be used at the same time since different +versions may have different capabilities and behavior. The data from one +version used in the function from another could produce confusing and +spurious results.`, + ); + } + } + return false; + }; + +interface Constructor extends Function { + prototype: { + [Symbol.toStringTag]: string; + }; +} diff --git a/src/jsutils/invariant.js b/src/jsutils/invariant.ts similarity index 51% rename from src/jsutils/invariant.js rename to src/jsutils/invariant.ts index 668f6ea426..f2c5d4c625 100644 --- a/src/jsutils/invariant.js +++ b/src/jsutils/invariant.ts @@ -1,6 +1,8 @@ -export default function invariant(condition: mixed, message?: string): void { +export function invariant( + condition: unknown, + message?: string, +): asserts condition { const booleanCondition = Boolean(condition); - // istanbul ignore else (See transformation done in './resources/inlineInvariant.js') if (!booleanCondition) { throw new Error( message != null ? message : 'Unexpected invariant triggered.', diff --git a/src/jsutils/isAsyncIterable.js b/src/jsutils/isAsyncIterable.js deleted file mode 100644 index 813da5770a..0000000000 --- a/src/jsutils/isAsyncIterable.js +++ /dev/null @@ -1,13 +0,0 @@ -import { SYMBOL_ASYNC_ITERATOR } from '../polyfills/symbols'; - -/** - * Returns true if the provided object implements the AsyncIterator protocol via - * either implementing a `Symbol.asyncIterator` or `"@@asyncIterator"` method. - */ -declare function isAsyncIterable(value: mixed): boolean %checks(value instanceof - AsyncIterable); - -// eslint-disable-next-line no-redeclare -export default function isAsyncIterable(maybeAsyncIterable) { - return typeof maybeAsyncIterable?.[SYMBOL_ASYNC_ITERATOR] === 'function'; -} diff --git a/src/jsutils/isAsyncIterable.ts b/src/jsutils/isAsyncIterable.ts new file mode 100644 index 0000000000..0eb4ab1d6e --- /dev/null +++ b/src/jsutils/isAsyncIterable.ts @@ -0,0 +1,9 @@ +/** + * Returns true if the provided object implements the AsyncIterator protocol via + * implementing a `Symbol.asyncIterator` method. + */ +export function isAsyncIterable( + maybeAsyncIterable: any, +): maybeAsyncIterable is AsyncIterable { + return typeof maybeAsyncIterable?.[Symbol.asyncIterator] === 'function'; +} diff --git a/src/jsutils/isCollection.js b/src/jsutils/isCollection.js deleted file mode 100644 index 731470256d..0000000000 --- a/src/jsutils/isCollection.js +++ /dev/null @@ -1,37 +0,0 @@ -import { SYMBOL_ITERATOR } from '../polyfills/symbols'; - -/** - * Returns true if the provided object is an Object (i.e. not a string literal) - * and is either Iterable or Array-like. - * - * This may be used in place of [Array.isArray()][isArray] to determine if an - * object should be iterated-over. It always excludes string literals and - * includes Arrays (regardless of if it is Iterable). It also includes other - * Array-like objects such as NodeList, TypedArray, and Buffer. - * - * @example - * - * isCollection([ 1, 2, 3 ]) // true - * isCollection('ABC') // false - * isCollection({ length: 1, 0: 'Alpha' }) // true - * isCollection({ key: 'value' }) // false - * isCollection(new Map()) // true - * - * @param obj - * An Object value which might implement the Iterable or Array-like protocols. - * @return {boolean} true if Iterable or Array-like Object. - */ -export default function isCollection(obj: mixed): boolean { - if (obj == null || typeof obj !== 'object') { - return false; - } - - // Is Array like? - const length = obj.length; - if (typeof length === 'number' && length >= 0 && length % 1 === 0) { - return true; - } - - // Is Iterable? - return typeof obj[SYMBOL_ITERATOR] === 'function'; -} diff --git a/src/jsutils/isIterableObject.ts b/src/jsutils/isIterableObject.ts new file mode 100644 index 0000000000..5c9d6fb381 --- /dev/null +++ b/src/jsutils/isIterableObject.ts @@ -0,0 +1,25 @@ +/** + * Returns true if the provided object is an Object (i.e. not a string literal) + * and implements the Iterator protocol. + * + * This may be used in place of [Array.isArray()][isArray] to determine if + * an object should be iterated-over e.g. Array, Map, Set, Int8Array, + * TypedArray, etc. but excludes string literals. + * + * @example + * ```ts + * isIterableObject([ 1, 2, 3 ]) // true + * isIterableObject(new Map()) // true + * isIterableObject('ABC') // false + * isIterableObject({ key: 'value' }) // false + * isIterableObject({ length: 1, 0: 'Alpha' }) // false + * ``` + */ +export function isIterableObject( + maybeIterable: any, +): maybeIterable is Iterable { + return ( + typeof maybeIterable === 'object' && + typeof maybeIterable?.[Symbol.iterator] === 'function' + ); +} diff --git a/src/jsutils/isObjectLike.js b/src/jsutils/isObjectLike.ts similarity index 67% rename from src/jsutils/isObjectLike.js rename to src/jsutils/isObjectLike.ts index a5f9754dd7..1d43e26718 100644 --- a/src/jsutils/isObjectLike.js +++ b/src/jsutils/isObjectLike.ts @@ -2,6 +2,8 @@ * Return true if `value` is object-like. A value is object-like if it's not * `null` and has a `typeof` result of "object". */ -export default function isObjectLike(value: mixed): boolean %checks { +export function isObjectLike( + value: unknown, +): value is { [key: string]: unknown } { return typeof value == 'object' && value !== null; } diff --git a/src/jsutils/isPromise.js b/src/jsutils/isPromise.js deleted file mode 100644 index 4bbb5768e1..0000000000 --- a/src/jsutils/isPromise.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Returns true if the value acts like a Promise, i.e. has a "then" function, - * otherwise returns false. - */ -declare function isPromise(value: mixed): boolean %checks(value instanceof - Promise); - -// eslint-disable-next-line no-redeclare -export default function isPromise(value) { - return typeof value?.then === 'function'; -} diff --git a/src/jsutils/isPromise.ts b/src/jsutils/isPromise.ts new file mode 100644 index 0000000000..5fc3c10458 --- /dev/null +++ b/src/jsutils/isPromise.ts @@ -0,0 +1,7 @@ +/** + * Returns true if the value acts like a Promise, i.e. has a "then" function, + * otherwise returns false. + */ +export function isPromise(value: any): value is Promise { + return typeof value?.then === 'function'; +} diff --git a/src/jsutils/keyMap.js b/src/jsutils/keyMap.js deleted file mode 100644 index eb847d02c9..0000000000 --- a/src/jsutils/keyMap.js +++ /dev/null @@ -1,34 +0,0 @@ -import type { ObjMap } from './ObjMap'; - -/** - * Creates a keyed JS object from an array, given a function to produce the keys - * for each value in the array. - * - * This provides a convenient lookup for the array items if the key function - * produces unique results. - * - * const phoneBook = [ - * { name: 'Jon', num: '555-1234' }, - * { name: 'Jenny', num: '867-5309' } - * ] - * - * // { Jon: { name: 'Jon', num: '555-1234' }, - * // Jenny: { name: 'Jenny', num: '867-5309' } } - * const entriesByName = keyMap( - * phoneBook, - * entry => entry.name - * ) - * - * // { name: 'Jenny', num: '857-6309' } - * const jennyEntry = entriesByName['Jenny'] - * - */ -export default function keyMap( - list: $ReadOnlyArray, - keyFn: (item: T) => string, -): ObjMap { - return list.reduce((map, item) => { - map[keyFn(item)] = item; - return map; - }, Object.create(null)); -} diff --git a/src/jsutils/keyMap.ts b/src/jsutils/keyMap.ts new file mode 100644 index 0000000000..592a98c83d --- /dev/null +++ b/src/jsutils/keyMap.ts @@ -0,0 +1,39 @@ +import type { ObjMap } from './ObjMap'; + +/** + * Creates a keyed JS object from an array, given a function to produce the keys + * for each value in the array. + * + * This provides a convenient lookup for the array items if the key function + * produces unique results. + * ```ts + * const phoneBook = [ + * { name: 'Jon', num: '555-1234' }, + * { name: 'Jenny', num: '867-5309' } + * ] + * + * const entriesByName = keyMap( + * phoneBook, + * entry => entry.name + * ) + * + * // { + * // Jon: { name: 'Jon', num: '555-1234' }, + * // Jenny: { name: 'Jenny', num: '867-5309' } + * // } + * + * const jennyEntry = entriesByName['Jenny'] + * + * // { name: 'Jenny', num: '857-6309' } + * ``` + */ +export function keyMap( + list: ReadonlyArray, + keyFn: (item: T) => string, +): ObjMap { + const result = Object.create(null); + for (const item of list) { + result[keyFn(item)] = item; + } + return result; +} diff --git a/src/jsutils/keyValMap.js b/src/jsutils/keyValMap.js deleted file mode 100644 index a91e90b447..0000000000 --- a/src/jsutils/keyValMap.js +++ /dev/null @@ -1,29 +0,0 @@ -import type { ObjMap } from './ObjMap'; - -/** - * Creates a keyed JS object from an array, given a function to produce the keys - * and a function to produce the values from each item in the array. - * - * const phoneBook = [ - * { name: 'Jon', num: '555-1234' }, - * { name: 'Jenny', num: '867-5309' } - * ] - * - * // { Jon: '555-1234', Jenny: '867-5309' } - * const phonesByName = keyValMap( - * phoneBook, - * entry => entry.name, - * entry => entry.num - * ) - * - */ -export default function keyValMap( - list: $ReadOnlyArray, - keyFn: (item: T) => string, - valFn: (item: T) => V, -): ObjMap { - return list.reduce((map, item) => { - map[keyFn(item)] = valFn(item); - return map; - }, Object.create(null)); -} diff --git a/src/jsutils/keyValMap.ts b/src/jsutils/keyValMap.ts new file mode 100644 index 0000000000..94d688c2c1 --- /dev/null +++ b/src/jsutils/keyValMap.ts @@ -0,0 +1,30 @@ +import type { ObjMap } from './ObjMap'; + +/** + * Creates a keyed JS object from an array, given a function to produce the keys + * and a function to produce the values from each item in the array. + * ```ts + * const phoneBook = [ + * { name: 'Jon', num: '555-1234' }, + * { name: 'Jenny', num: '867-5309' } + * ] + * + * // { Jon: '555-1234', Jenny: '867-5309' } + * const phonesByName = keyValMap( + * phoneBook, + * entry => entry.name, + * entry => entry.num + * ) + * ``` + */ +export function keyValMap( + list: ReadonlyArray, + keyFn: (item: T) => string, + valFn: (item: T) => V, +): ObjMap { + const result = Object.create(null); + for (const item of list) { + result[keyFn(item)] = valFn(item); + } + return result; +} diff --git a/src/jsutils/mapValue.js b/src/jsutils/mapValue.ts similarity index 50% rename from src/jsutils/mapValue.js rename to src/jsutils/mapValue.ts index a2b91be2dd..32686a29c1 100644 --- a/src/jsutils/mapValue.js +++ b/src/jsutils/mapValue.ts @@ -1,19 +1,17 @@ -import objectEntries from '../polyfills/objectEntries'; - -import type { ObjMap } from './ObjMap'; +import type { ObjMap, ReadOnlyObjMap } from './ObjMap'; /** * Creates an object map with the same keys as `map` and values generated by * running each value of `map` thru `fn`. */ -export default function mapValue( - map: ObjMap, +export function mapValue( + map: ReadOnlyObjMap, fn: (value: T, key: string) => V, ): ObjMap { const result = Object.create(null); - for (const [key, value] of objectEntries(map)) { - result[key] = fn(value, key); + for (const key of Object.keys(map)) { + result[key] = fn(map[key], key); } return result; } diff --git a/src/jsutils/memoize3.js b/src/jsutils/memoize3.js deleted file mode 100644 index be73a96fb2..0000000000 --- a/src/jsutils/memoize3.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Memoizes the provided three-argument function. - */ -export default function memoize3< - A1: { ... } | $ReadOnlyArray, - A2: { ... } | $ReadOnlyArray, - A3: { ... } | $ReadOnlyArray, - R: mixed, ->(fn: (A1, A2, A3) => R): (A1, A2, A3) => R { - let cache0; - - return function memoized(a1, a2, a3) { - if (!cache0) { - cache0 = new WeakMap(); - } - let cache1 = cache0.get(a1); - let cache2; - if (cache1) { - cache2 = cache1.get(a2); - if (cache2) { - const cachedValue = cache2.get(a3); - if (cachedValue !== undefined) { - return cachedValue; - } - } - } else { - cache1 = new WeakMap(); - cache0.set(a1, cache1); - } - if (!cache2) { - cache2 = new WeakMap(); - cache1.set(a2, cache2); - } - const newValue = fn(a1, a2, a3); - cache2.set(a3, newValue); - return newValue; - }; -} diff --git a/src/jsutils/memoize3.ts b/src/jsutils/memoize3.ts new file mode 100644 index 0000000000..213cb95d10 --- /dev/null +++ b/src/jsutils/memoize3.ts @@ -0,0 +1,37 @@ +/** + * Memoizes the provided three-argument function. + */ +export function memoize3< + A1 extends object, + A2 extends object, + A3 extends object, + R, +>(fn: (a1: A1, a2: A2, a3: A3) => R): (a1: A1, a2: A2, a3: A3) => R { + let cache0: WeakMap>>; + + return function memoized(a1, a2, a3) { + if (cache0 === undefined) { + cache0 = new WeakMap(); + } + + let cache1 = cache0.get(a1); + if (cache1 === undefined) { + cache1 = new WeakMap(); + cache0.set(a1, cache1); + } + + let cache2 = cache1.get(a2); + if (cache2 === undefined) { + cache2 = new WeakMap(); + cache1.set(a2, cache2); + } + + let fnResult = cache2.get(a3); + if (fnResult === undefined) { + fnResult = fn(a1, a2, a3); + cache2.set(a3, fnResult); + } + + return fnResult; + }; +} diff --git a/src/jsutils/naturalCompare.js b/src/jsutils/naturalCompare.ts similarity index 70% rename from src/jsutils/naturalCompare.js rename to src/jsutils/naturalCompare.ts index 5f624b70d8..7a56286306 100644 --- a/src/jsutils/naturalCompare.js +++ b/src/jsutils/naturalCompare.ts @@ -5,27 +5,27 @@ * See: https://en.wikipedia.org/wiki/Natural_sort_order * */ -export default function naturalCompare(aStr: string, bStr: string): number { - let aIdx = 0; - let bIdx = 0; +export function naturalCompare(aStr: string, bStr: string): number { + let aIndex = 0; + let bIndex = 0; - while (aIdx < aStr.length && bIdx < bStr.length) { - let aChar = aStr.charCodeAt(aIdx); - let bChar = bStr.charCodeAt(bIdx); + while (aIndex < aStr.length && bIndex < bStr.length) { + let aChar = aStr.charCodeAt(aIndex); + let bChar = bStr.charCodeAt(bIndex); if (isDigit(aChar) && isDigit(bChar)) { let aNum = 0; do { - ++aIdx; + ++aIndex; aNum = aNum * 10 + aChar - DIGIT_0; - aChar = aStr.charCodeAt(aIdx); + aChar = aStr.charCodeAt(aIndex); } while (isDigit(aChar) && aNum > 0); let bNum = 0; do { - ++bIdx; + ++bIndex; bNum = bNum * 10 + bChar - DIGIT_0; - bChar = bStr.charCodeAt(bIdx); + bChar = bStr.charCodeAt(bIndex); } while (isDigit(bChar) && bNum > 0); if (aNum < bNum) { @@ -42,8 +42,8 @@ export default function naturalCompare(aStr: string, bStr: string): number { if (aChar > bChar) { return 1; } - ++aIdx; - ++bIdx; + ++aIndex; + ++bIndex; } } diff --git a/src/jsutils/nodejsCustomInspectSymbol.js b/src/jsutils/nodejsCustomInspectSymbol.js deleted file mode 100644 index 9a646e60cf..0000000000 --- a/src/jsutils/nodejsCustomInspectSymbol.js +++ /dev/null @@ -1,7 +0,0 @@ -// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') -const nodejsCustomInspectSymbol = - typeof Symbol === 'function' && typeof Symbol.for === 'function' - ? Symbol.for('nodejs.util.inspect.custom') - : undefined; - -export default nodejsCustomInspectSymbol; diff --git a/src/jsutils/printPathArray.js b/src/jsutils/printPathArray.ts similarity index 65% rename from src/jsutils/printPathArray.js rename to src/jsutils/printPathArray.ts index 34ab13daa0..0d9fcc2b19 100644 --- a/src/jsutils/printPathArray.js +++ b/src/jsutils/printPathArray.ts @@ -1,9 +1,7 @@ /** * Build a string describing the path. */ -export default function printPathArray( - path: $ReadOnlyArray, -): string { +export function printPathArray(path: ReadonlyArray): string { return path .map((key) => typeof key === 'number' ? '[' + key.toString() + ']' : '.' + key, diff --git a/src/jsutils/promiseForObject.js b/src/jsutils/promiseForObject.js deleted file mode 100644 index bf07e4a3f0..0000000000 --- a/src/jsutils/promiseForObject.js +++ /dev/null @@ -1,21 +0,0 @@ -import type { ObjMap } from './ObjMap'; - -/** - * This function transforms a JS object `ObjMap>` into - * a `Promise>` - * - * This is akin to bluebird's `Promise.props`, but implemented only using - * `Promise.all` so it will work with any implementation of ES6 promises. - */ -export default function promiseForObject( - object: ObjMap>, -): Promise> { - const keys = Object.keys(object); - const valuesAndPromises = keys.map((name) => object[name]); - return Promise.all(valuesAndPromises).then((values) => - values.reduce((resolvedObject, value, i) => { - resolvedObject[keys[i]] = value; - return resolvedObject; - }, Object.create(null)), - ); -} diff --git a/src/jsutils/promiseForObject.ts b/src/jsutils/promiseForObject.ts new file mode 100644 index 0000000000..1074676030 --- /dev/null +++ b/src/jsutils/promiseForObject.ts @@ -0,0 +1,20 @@ +import type { ObjMap } from './ObjMap'; + +/** + * This function transforms a JS object `ObjMap>` into + * a `Promise>` + * + * This is akin to bluebird's `Promise.props`, but implemented only using + * `Promise.all` so it will work with any implementation of ES6 promises. + */ +export function promiseForObject( + object: ObjMap>, +): Promise> { + return Promise.all(Object.values(object)).then((resolvedValues) => { + const resolvedObject = Object.create(null); + for (const [i, key] of Object.keys(object).entries()) { + resolvedObject[key] = resolvedValues[i]; + } + return resolvedObject; + }); +} diff --git a/src/jsutils/promiseReduce.js b/src/jsutils/promiseReduce.js deleted file mode 100644 index 43d905283e..0000000000 --- a/src/jsutils/promiseReduce.js +++ /dev/null @@ -1,24 +0,0 @@ -import type { PromiseOrValue } from './PromiseOrValue'; - -import isPromise from './isPromise'; - -/** - * Similar to Array.prototype.reduce(), however the reducing callback may return - * a Promise, in which case reduction will continue after each promise resolves. - * - * If the callback does not return a Promise, then this function will also not - * return a Promise. - */ -export default function promiseReduce( - values: $ReadOnlyArray, - callback: (U, T) => PromiseOrValue, - initialValue: PromiseOrValue, -): PromiseOrValue { - return values.reduce( - (previous, value) => - isPromise(previous) - ? previous.then((resolved) => callback(resolved, value)) - : callback(previous, value), - initialValue, - ); -} diff --git a/src/jsutils/promiseReduce.ts b/src/jsutils/promiseReduce.ts new file mode 100644 index 0000000000..58db2e85c8 --- /dev/null +++ b/src/jsutils/promiseReduce.ts @@ -0,0 +1,23 @@ +import { isPromise } from './isPromise'; +import type { PromiseOrValue } from './PromiseOrValue'; + +/** + * Similar to Array.prototype.reduce(), however the reducing callback may return + * a Promise, in which case reduction will continue after each promise resolves. + * + * If the callback does not return a Promise, then this function will also not + * return a Promise. + */ +export function promiseReduce( + values: Iterable, + callbackFn: (accumulator: U, currentValue: T) => PromiseOrValue, + initialValue: PromiseOrValue, +): PromiseOrValue { + let accumulator = initialValue; + for (const value of values) { + accumulator = isPromise(accumulator) + ? accumulator.then((resolved) => callbackFn(resolved, value)) + : callbackFn(accumulator, value); + } + return accumulator; +} diff --git a/src/jsutils/suggestionList.js b/src/jsutils/suggestionList.ts similarity index 95% rename from src/jsutils/suggestionList.js rename to src/jsutils/suggestionList.ts index 33cc2f1dde..53ad685c8c 100644 --- a/src/jsutils/suggestionList.js +++ b/src/jsutils/suggestionList.ts @@ -1,12 +1,12 @@ -import naturalCompare from './naturalCompare'; +import { naturalCompare } from './naturalCompare'; /** * Given an invalid input string and a list of valid options, returns a filtered * list of valid options sorted based on their similarity with the input. */ -export default function suggestionList( +export function suggestionList( input: string, - options: $ReadOnlyArray, + options: ReadonlyArray, ): Array { const optionsByDistance = Object.create(null); const lexicalDistance = new LexicalDistance(input); @@ -57,7 +57,7 @@ class LexicalDistance { ]; } - measure(option: string, threshold: number): number | void { + measure(option: string, threshold: number): number | undefined { if (this._input === option) { return 0; } diff --git a/src/jsutils/toError.ts b/src/jsutils/toError.ts new file mode 100644 index 0000000000..8d562273d6 --- /dev/null +++ b/src/jsutils/toError.ts @@ -0,0 +1,20 @@ +import { inspect } from './inspect'; + +/** + * Sometimes a non-error is thrown, wrap it as an Error instance to ensure a consistent Error interface. + */ +export function toError(thrownValue: unknown): Error { + return thrownValue instanceof Error + ? thrownValue + : new NonErrorThrown(thrownValue); +} + +class NonErrorThrown extends Error { + thrownValue: unknown; + + constructor(thrownValue: unknown) { + super('Unexpected error value: ' + inspect(thrownValue)); + this.name = 'NonErrorThrown'; + this.thrownValue = thrownValue; + } +} diff --git a/src/jsutils/toObjMap.js b/src/jsutils/toObjMap.js deleted file mode 100644 index c0dc9e2fdb..0000000000 --- a/src/jsutils/toObjMap.js +++ /dev/null @@ -1,25 +0,0 @@ -import objectEntries from '../polyfills/objectEntries'; - -import type { - ObjMap, - ObjMapLike, - ReadOnlyObjMap, - ReadOnlyObjMapLike, -} from './ObjMap'; - -/* eslint-disable no-redeclare */ -declare function toObjMap(obj: ObjMapLike): ObjMap; -declare function toObjMap(obj: ReadOnlyObjMapLike): ReadOnlyObjMap; - -export default function toObjMap(obj) { - /* eslint-enable no-redeclare */ - if (Object.getPrototypeOf(obj) === null) { - return obj; - } - - const map = Object.create(null); - for (const [key, value] of objectEntries(obj)) { - map[key] = value; - } - return map; -} diff --git a/src/jsutils/toObjMap.ts b/src/jsutils/toObjMap.ts new file mode 100644 index 0000000000..6fe352db23 --- /dev/null +++ b/src/jsutils/toObjMap.ts @@ -0,0 +1,20 @@ +import type { Maybe } from './Maybe'; +import type { ReadOnlyObjMap, ReadOnlyObjMapLike } from './ObjMap'; + +export function toObjMap( + obj: Maybe>, +): ReadOnlyObjMap { + if (obj == null) { + return Object.create(null); + } + + if (Object.getPrototypeOf(obj) === null) { + return obj; + } + + const map = Object.create(null); + for (const [key, value] of Object.entries(obj)) { + map[key] = value; + } + return map; +} diff --git a/src/language/__tests__/blockString-fuzz.js b/src/language/__tests__/blockString-fuzz.js deleted file mode 100644 index 1479aa2aa7..0000000000 --- a/src/language/__tests__/blockString-fuzz.js +++ /dev/null @@ -1,66 +0,0 @@ -import { describe, it } from 'mocha'; - -import dedent from '../../__testUtils__/dedent'; -import inspectStr from '../../__testUtils__/inspectStr'; -import genFuzzStrings from '../../__testUtils__/genFuzzStrings'; - -import invariant from '../../jsutils/invariant'; - -import { Lexer } from '../lexer'; -import { Source } from '../source'; -import { printBlockString } from '../blockString'; - -function lexValue(str: string) { - const lexer = new Lexer(new Source(str)); - const value = lexer.advance().value; - - invariant(lexer.advance().kind === '', 'Expected EOF'); - return value; -} - -describe('printBlockString', () => { - it('correctly print random strings', () => { - // Testing with length >7 is taking exponentially more time. However it is - // highly recommended to test with increased limit if you make any change. - for (const fuzzStr of genFuzzStrings({ - allowedChars: ['\n', '\t', ' ', '"', 'a', '\\'], - maxLength: 7, - })) { - const testStr = '"""' + fuzzStr + '"""'; - - let testValue; - try { - testValue = lexValue(testStr); - } catch (e) { - continue; // skip invalid values - } - invariant(typeof testValue === 'string'); - - const printedValue = lexValue(printBlockString(testValue)); - - invariant( - testValue === printedValue, - dedent` - Expected lexValue(printBlockString(${inspectStr(testValue)})) - to equal ${inspectStr(testValue)} - but got ${inspectStr(printedValue)} - `, - ); - - const printedMultilineString = lexValue( - printBlockString(testValue, ' ', true), - ); - - invariant( - testValue === printedMultilineString, - dedent` - Expected lexValue(printBlockString(${inspectStr( - testValue, - )}, ' ', true)) - to equal ${inspectStr(testValue)} - but got ${inspectStr(printedMultilineString)} - `, - ); - } - }).timeout(20000); -}); diff --git a/src/language/__tests__/blockString-fuzz.ts b/src/language/__tests__/blockString-fuzz.ts new file mode 100644 index 0000000000..4ed010ccb8 --- /dev/null +++ b/src/language/__tests__/blockString-fuzz.ts @@ -0,0 +1,67 @@ +import { describe, it } from 'mocha'; + +import { dedent } from '../../__testUtils__/dedent'; +import { genFuzzStrings } from '../../__testUtils__/genFuzzStrings'; +import { inspectStr } from '../../__testUtils__/inspectStr'; + +import { invariant } from '../../jsutils/invariant'; + +import { isPrintableAsBlockString, printBlockString } from '../blockString'; +import { Lexer } from '../lexer'; +import { Source } from '../source'; + +function lexValue(str: string): string { + const lexer = new Lexer(new Source(str)); + const value = lexer.advance().value; + + invariant(typeof value === 'string'); + invariant(lexer.advance().kind === '', 'Expected EOF'); + return value; +} + +function testPrintableBlockString( + testValue: string, + options?: { minimize: boolean }, +): void { + const blockString = printBlockString(testValue, options); + const printedValue = lexValue(blockString); + invariant( + testValue === printedValue, + dedent` + Expected lexValue(${inspectStr(blockString)}) + to equal ${inspectStr(testValue)} + but got ${inspectStr(printedValue)} + `, + ); +} + +function testNonPrintableBlockString(testValue: string): void { + const blockString = printBlockString(testValue); + const printedValue = lexValue(blockString); + invariant( + testValue !== printedValue, + dedent` + Expected lexValue(${inspectStr(blockString)}) + to not equal ${inspectStr(testValue)} + `, + ); +} + +describe('printBlockString', () => { + it('correctly print random strings', () => { + // Testing with length >7 is taking exponentially more time. However it is + // highly recommended to test with increased limit if you make any change. + for (const fuzzStr of genFuzzStrings({ + allowedChars: ['\n', '\t', ' ', '"', 'a', '\\'], + maxLength: 7, + })) { + if (!isPrintableAsBlockString(fuzzStr)) { + testNonPrintableBlockString(fuzzStr); + continue; + } + + testPrintableBlockString(fuzzStr); + testPrintableBlockString(fuzzStr, { minimize: true }); + } + }).timeout(20000); +}); diff --git a/src/language/__tests__/blockString-test.js b/src/language/__tests__/blockString-test.js deleted file mode 100644 index 929404eb73..0000000000 --- a/src/language/__tests__/blockString-test.js +++ /dev/null @@ -1,186 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { - dedentBlockStringValue, - getBlockStringIndentation, - printBlockString, -} from '../blockString'; - -function joinLines(...args: Array) { - return args.join('\n'); -} - -describe('dedentBlockStringValue', () => { - it('removes uniform indentation from a string', () => { - const rawValue = joinLines( - '', - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.', - ); - expect(dedentBlockStringValue(rawValue)).to.equal( - joinLines('Hello,', ' World!', '', 'Yours,', ' GraphQL.'), - ); - }); - - it('removes empty leading and trailing lines', () => { - const rawValue = joinLines( - '', - '', - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.', - '', - '', - ); - expect(dedentBlockStringValue(rawValue)).to.equal( - joinLines('Hello,', ' World!', '', 'Yours,', ' GraphQL.'), - ); - }); - - it('removes blank leading and trailing lines', () => { - const rawValue = joinLines( - ' ', - ' ', - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.', - ' ', - ' ', - ); - expect(dedentBlockStringValue(rawValue)).to.equal( - joinLines('Hello,', ' World!', '', 'Yours,', ' GraphQL.'), - ); - }); - - it('retains indentation from first line', () => { - const rawValue = joinLines( - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.', - ); - expect(dedentBlockStringValue(rawValue)).to.equal( - joinLines(' Hello,', ' World!', '', 'Yours,', ' GraphQL.'), - ); - }); - - it('does not alter trailing spaces', () => { - const rawValue = joinLines( - ' ', - ' Hello, ', - ' World! ', - ' ', - ' Yours, ', - ' GraphQL. ', - ' ', - ); - expect(dedentBlockStringValue(rawValue)).to.equal( - joinLines( - 'Hello, ', - ' World! ', - ' ', - 'Yours, ', - ' GraphQL. ', - ), - ); - }); -}); - -describe('getBlockStringIndentation', () => { - it('returns zero for an empty string', () => { - expect(getBlockStringIndentation('')).to.equal(0); - }); - - it('do not take first line into account', () => { - expect(getBlockStringIndentation(' a')).to.equal(0); - expect(getBlockStringIndentation(' a\n b')).to.equal(2); - }); - - it('returns minimal indentation length', () => { - expect(getBlockStringIndentation('\n a\n b')).to.equal(1); - expect(getBlockStringIndentation('\n a\n b')).to.equal(1); - expect(getBlockStringIndentation('\n a\n b\nc')).to.equal(0); - }); - - it('count both tab and space as single character', () => { - expect(getBlockStringIndentation('\n\ta\n b')).to.equal(1); - expect(getBlockStringIndentation('\n\t a\n b')).to.equal(2); - expect(getBlockStringIndentation('\n \t a\n b')).to.equal(3); - }); - - it('do not take empty lines into account', () => { - expect(getBlockStringIndentation('a\n ')).to.equal(0); - expect(getBlockStringIndentation('a\n\t')).to.equal(0); - expect(getBlockStringIndentation('a\n\n b')).to.equal(1); - expect(getBlockStringIndentation('a\n \n b')).to.equal(2); - }); -}); - -describe('printBlockString', () => { - it('do not escape characters', () => { - const str = '" \\ / \b \f \n \r \t'; - expect(printBlockString(str)).to.equal('"""\n' + str + '\n"""'); - }); - - it('by default print block strings as single line', () => { - const str = 'one liner'; - expect(printBlockString(str)).to.equal('"""one liner"""'); - expect(printBlockString(str, '', true)).to.equal('"""\none liner\n"""'); - }); - - it('correctly prints single-line with leading space', () => { - const str = ' space-led string'; - expect(printBlockString(str)).to.equal('""" space-led string"""'); - expect(printBlockString(str, '', true)).to.equal( - '""" space-led string\n"""', - ); - }); - - it('correctly prints single-line with leading space and quotation', () => { - const str = ' space-led value "quoted string"'; - - expect(printBlockString(str)).to.equal( - '""" space-led value "quoted string"\n"""', - ); - - expect(printBlockString(str, '', true)).to.equal( - '""" space-led value "quoted string"\n"""', - ); - }); - - it('correctly prints single-line with trailing backslash', () => { - const str = 'backslash \\'; - - expect(printBlockString(str)).to.equal('"""\nbackslash \\\n"""'); - expect(printBlockString(str, '', true)).to.equal('"""\nbackslash \\\n"""'); - }); - - it('correctly prints string with a first line indentation', () => { - const str = joinLines( - ' first ', - ' line ', - 'indentation', - ' string', - ); - - expect(printBlockString(str)).to.equal( - joinLines( - '"""', - ' first ', - ' line ', - 'indentation', - ' string', - '"""', - ), - ); - }); -}); diff --git a/src/language/__tests__/blockString-test.ts b/src/language/__tests__/blockString-test.ts new file mode 100644 index 0000000000..21fa49b00a --- /dev/null +++ b/src/language/__tests__/blockString-test.ts @@ -0,0 +1,289 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { + dedentBlockStringLines, + isPrintableAsBlockString, + printBlockString, +} from '../blockString'; + +function joinLines(...args: ReadonlyArray) { + return args.join('\n'); +} + +describe('dedentBlockStringLines', () => { + function expectDedent(lines: ReadonlyArray) { + return expect(dedentBlockStringLines(lines)); + } + + it('handles empty string', () => { + expectDedent(['']).to.deep.equal([]); + }); + + it('does not dedent first line', () => { + expectDedent([' a']).to.deep.equal([' a']); + expectDedent([' a', ' b']).to.deep.equal([' a', 'b']); + }); + + it('removes minimal indentation length', () => { + expectDedent(['', ' a', ' b']).to.deep.equal(['a', ' b']); + expectDedent(['', ' a', ' b']).to.deep.equal([' a', 'b']); + expectDedent(['', ' a', ' b', 'c']).to.deep.equal([' a', ' b', 'c']); + }); + + it('dedent both tab and space as single character', () => { + expectDedent(['', '\ta', ' b']).to.deep.equal(['a', ' b']); + expectDedent(['', '\t a', ' b']).to.deep.equal(['a', ' b']); + expectDedent(['', ' \t a', ' b']).to.deep.equal(['a', ' b']); + }); + + it('dedent do not take empty lines into account', () => { + expectDedent(['a', '', ' b']).to.deep.equal(['a', '', 'b']); + expectDedent(['a', ' ', ' b']).to.deep.equal(['a', '', 'b']); + }); + + it('removes uniform indentation from a string', () => { + const lines = [ + '', + ' Hello,', + ' World!', + '', + ' Yours,', + ' GraphQL.', + ]; + expectDedent(lines).to.deep.equal([ + 'Hello,', + ' World!', + '', + 'Yours,', + ' GraphQL.', + ]); + }); + + it('removes empty leading and trailing lines', () => { + const lines = [ + '', + '', + ' Hello,', + ' World!', + '', + ' Yours,', + ' GraphQL.', + '', + '', + ]; + expectDedent(lines).to.deep.equal([ + 'Hello,', + ' World!', + '', + 'Yours,', + ' GraphQL.', + ]); + }); + + it('removes blank leading and trailing lines', () => { + const lines = [ + ' ', + ' ', + ' Hello,', + ' World!', + '', + ' Yours,', + ' GraphQL.', + ' ', + ' ', + ]; + expectDedent(lines).to.deep.equal([ + 'Hello,', + ' World!', + '', + 'Yours,', + ' GraphQL.', + ]); + }); + + it('retains indentation from first line', () => { + const lines = [ + ' Hello,', + ' World!', + '', + ' Yours,', + ' GraphQL.', + ]; + expectDedent(lines).to.deep.equal([ + ' Hello,', + ' World!', + '', + 'Yours,', + ' GraphQL.', + ]); + }); + + it('does not alter trailing spaces', () => { + const lines = [ + ' ', + ' Hello, ', + ' World! ', + ' ', + ' Yours, ', + ' GraphQL. ', + ' ', + ]; + expectDedent(lines).to.deep.equal([ + 'Hello, ', + ' World! ', + ' ', + 'Yours, ', + ' GraphQL. ', + ]); + }); +}); + +describe('isPrintableAsBlockString', () => { + function expectPrintable(str: string) { + return expect(isPrintableAsBlockString(str)).to.equal(true); + } + + function expectNonPrintable(str: string) { + return expect(isPrintableAsBlockString(str)).to.equal(false); + } + + it('accepts valid strings', () => { + expectPrintable(''); + expectPrintable(' a'); + expectPrintable('\t"\n"'); + expectNonPrintable('\t"\n \n\t"'); + }); + + it('rejects strings with only whitespace', () => { + expectNonPrintable(' '); + expectNonPrintable('\t'); + expectNonPrintable('\t '); + expectNonPrintable(' \t'); + }); + + it('rejects strings with non-printable characters', () => { + expectNonPrintable('\x00'); + expectNonPrintable('a\x00b'); + }); + + it('rejects strings with only empty lines', () => { + expectNonPrintable('\n'); + expectNonPrintable('\n\n'); + expectNonPrintable('\n\n\n'); + expectNonPrintable(' \n \n'); + expectNonPrintable('\t\n\t\t\n'); + }); + + it('rejects strings with carriage return', () => { + expectNonPrintable('\r'); + expectNonPrintable('\n\r'); + expectNonPrintable('\r\n'); + expectNonPrintable('a\rb'); + }); + + it('rejects strings with leading empty lines', () => { + expectNonPrintable('\na'); + expectNonPrintable(' \na'); + expectNonPrintable('\t\na'); + expectNonPrintable('\n\na'); + }); + + it('rejects strings with trailing empty lines', () => { + expectNonPrintable('a\n'); + expectNonPrintable('a\n '); + expectNonPrintable('a\n\t'); + expectNonPrintable('a\n\n'); + }); +}); + +describe('printBlockString', () => { + function expectBlockString(str: string) { + return { + toEqual(expected: string | { readable: string; minimize: string }) { + const { readable, minimize } = + typeof expected === 'string' + ? { readable: expected, minimize: expected } + : expected; + + expect(printBlockString(str)).to.equal(readable); + expect(printBlockString(str, { minimize: true })).to.equal(minimize); + }, + }; + } + + it('does not escape characters', () => { + const str = '" \\ / \b \f \n \r \t'; + expectBlockString(str).toEqual({ + readable: '"""\n' + str + '\n"""', + minimize: '"""\n' + str + '"""', + }); + }); + + it('by default print block strings as single line', () => { + const str = 'one liner'; + expectBlockString(str).toEqual('"""one liner"""'); + }); + + it('by default print block strings ending with triple quotation as multi-line', () => { + const str = 'triple quotation """'; + expectBlockString(str).toEqual({ + readable: '"""\ntriple quotation \\"""\n"""', + minimize: '"""triple quotation \\""""""', + }); + }); + + it('correctly prints single-line with leading space', () => { + const str = ' space-led string'; + expectBlockString(str).toEqual('""" space-led string"""'); + }); + + it('correctly prints single-line with leading space and trailing quotation', () => { + const str = ' space-led value "quoted string"'; + expectBlockString(str).toEqual( + '""" space-led value "quoted string"\n"""', + ); + }); + + it('correctly prints single-line with trailing backslash', () => { + const str = 'backslash \\'; + expectBlockString(str).toEqual({ + readable: '"""\nbackslash \\\n"""', + minimize: '"""backslash \\\n"""', + }); + }); + + it('correctly prints multi-line with internal indent', () => { + const str = 'no indent\n with indent'; + expectBlockString(str).toEqual({ + readable: '"""\nno indent\n with indent\n"""', + minimize: '"""\nno indent\n with indent"""', + }); + }); + + it('correctly prints string with a first line indentation', () => { + const str = joinLines( + ' first ', + ' line ', + 'indentation', + ' string', + ); + + expectBlockString(str).toEqual({ + readable: joinLines( + '"""', + ' first ', + ' line ', + 'indentation', + ' string', + '"""', + ), + minimize: joinLines( + '""" first ', + ' line ', + 'indentation', + ' string"""', + ), + }); + }); +}); diff --git a/src/language/__tests__/lexer-test.js b/src/language/__tests__/lexer-test.ts similarity index 64% rename from src/language/__tests__/lexer-test.js rename to src/language/__tests__/lexer-test.ts index 2aba2d8b78..46bf971d0a 100644 --- a/src/language/__tests__/lexer-test.js +++ b/src/language/__tests__/lexer-test.ts @@ -1,18 +1,17 @@ -// eslint-disable-next-line import/no-nodejs-modules -import { inspect as nodeInspect } from 'util'; - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; +import { expectToThrowJSON } from '../../__testUtils__/expectJSON'; -import inspect from '../../jsutils/inspect'; +import { inspect } from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; +import type { Token } from '../ast'; +import { isPunctuatorTokenKind, Lexer } from '../lexer'; import { Source } from '../source'; import { TokenKind } from '../tokenKind'; -import { Lexer, isPunctuatorTokenKind } from '../lexer'; function lexOne(str: string) { const lexer = new Lexer(new Source(str)); @@ -26,18 +25,11 @@ function lexSecond(str: string) { } function expectSyntaxError(text: string) { - return expect(() => lexSecond(text)).to.throw(); + return expectToThrowJSON(() => lexSecond(text)); } describe('Lexer', () => { - it('disallows uncommon control characters', () => { - expectSyntaxError('\u0007').to.deep.equal({ - message: 'Syntax Error: Cannot contain the invalid character "\\u0007".', - locations: [{ line: 1, column: 1 }], - }); - }); - - it('accepts BOM header', () => { + it('ignores BOM header', () => { expect(lexOne('\uFEFF foo')).to.contain({ kind: TokenKind.NAME, start: 2, @@ -116,14 +108,16 @@ describe('Lexer', () => { }); }); - it('can be JSON.stringified, util.inspected or jsutils.inspect', () => { - const token = lexOne('foo'); + it('can be Object.toStringified, JSON.stringified, or jsutils.inspected', () => { + const lexer = new Lexer(new Source('foo')); + const token = lexer.advance(); + + expect(Object.prototype.toString.call(lexer)).to.equal('[object Lexer]'); + + expect(Object.prototype.toString.call(token)).to.equal('[object Token]'); expect(JSON.stringify(token)).to.equal( '{"kind":"Name","value":"foo","line":1,"column":1}', ); - expect(nodeInspect(token)).to.equal( - "{ kind: 'Name', value: 'foo', line: 1, column: 1 }", - ); expect(inspect(token)).to.equal( '{ kind: "Name", value: "foo", line: 1, column: 1 }', ); @@ -144,6 +138,13 @@ describe('Lexer', () => { value: 'foo', }); + expect(lexOne('\t\tfoo\t\t')).to.contain({ + kind: TokenKind.NAME, + start: 2, + end: 5, + value: 'foo', + }); + expect( lexOne(` #comment @@ -167,17 +168,17 @@ describe('Lexer', () => { it('errors respect whitespace', () => { let caughtError; try { - lexOne(['', '', ' ?', ''].join('\n')); + lexOne(['', '', ' ~', ''].join('\n')); } catch (error) { caughtError = error; } - expect(String(caughtError) + '\n').to.equal(dedent` - Syntax Error: Cannot parse the unexpected character "?". + expect(String(caughtError)).to.equal(dedent` + Syntax Error: Unexpected character: "~". - GraphQL request:3:5 + GraphQL request:3:2 2 | - 3 | ? - | ^ + 3 | ~ + | ^ 4 | `); }); @@ -185,18 +186,18 @@ describe('Lexer', () => { it('updates line numbers in error for file context', () => { let caughtError; try { - const str = ['', '', ' ?', ''].join('\n'); + const str = ['', '', ' ~', ''].join('\n'); const source = new Source(str, 'foo.js', { line: 11, column: 12 }); new Lexer(source).advance(); } catch (error) { caughtError = error; } - expect(String(caughtError) + '\n').to.equal(dedent` - Syntax Error: Cannot parse the unexpected character "?". + expect(String(caughtError)).to.equal(dedent` + Syntax Error: Unexpected character: "~". foo.js:13:6 12 | - 13 | ? + 13 | ~ | ^ 14 | `); @@ -205,16 +206,16 @@ describe('Lexer', () => { it('updates column numbers in error for file context', () => { let caughtError; try { - const source = new Source('?', 'foo.js', { line: 1, column: 5 }); + const source = new Source('~', 'foo.js', { line: 1, column: 5 }); new Lexer(source).advance(); } catch (error) { caughtError = error; } - expect(String(caughtError) + '\n').to.equal(dedent` - Syntax Error: Cannot parse the unexpected character "?". + expect(String(caughtError)).to.equal(dedent` + Syntax Error: Unexpected character: "~". foo.js:1:5 - 1 | ? + 1 | ~ | ^ `); }); @@ -262,12 +263,98 @@ describe('Lexer', () => { value: 'slashes \\ /', }); + expect(lexOne('"unescaped unicode outside BMP \u{1f600}"')).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 34, + value: 'unescaped unicode outside BMP \u{1f600}', + }); + + expect( + lexOne('"unescaped maximal unicode outside BMP \u{10ffff}"'), + ).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 42, + value: 'unescaped maximal unicode outside BMP \u{10ffff}', + }); + expect(lexOne('"unicode \\u1234\\u5678\\u90AB\\uCDEF"')).to.contain({ kind: TokenKind.STRING, start: 0, end: 34, value: 'unicode \u1234\u5678\u90AB\uCDEF', }); + + expect(lexOne('"unicode \\u{1234}\\u{5678}\\u{90AB}\\u{CDEF}"')).to.contain( + { + kind: TokenKind.STRING, + start: 0, + end: 42, + value: 'unicode \u1234\u5678\u90AB\uCDEF', + }, + ); + + expect( + lexOne('"string with unicode escape outside BMP \\u{1F600}"'), + ).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 50, + value: 'string with unicode escape outside BMP \u{1f600}', + }); + + expect(lexOne('"string with minimal unicode escape \\u{0}"')).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 42, + value: 'string with minimal unicode escape \u{0}', + }); + + expect( + lexOne('"string with maximal unicode escape \\u{10FFFF}"'), + ).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 47, + value: 'string with maximal unicode escape \u{10FFFF}', + }); + + expect( + lexOne('"string with maximal minimal unicode escape \\u{00000000}"'), + ).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 57, + value: 'string with maximal minimal unicode escape \u{0}', + }); + + expect( + lexOne('"string with unicode surrogate pair escape \\uD83D\\uDE00"'), + ).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 56, + value: 'string with unicode surrogate pair escape \u{1f600}', + }); + + expect( + lexOne('"string with minimal surrogate pair escape \\uD800\\uDC00"'), + ).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 56, + value: 'string with minimal surrogate pair escape \u{10000}', + }); + + expect( + lexOne('"string with maximal surrogate pair escape \\uDBFF\\uDFFF"'), + ).to.contain({ + kind: TokenKind.STRING, + start: 0, + end: 56, + value: 'string with maximal surrogate pair escape \u{10FFFF}', + }); }); it('lex reports useful string errors', () => { @@ -297,16 +384,19 @@ describe('Lexer', () => { locations: [{ line: 1, column: 1 }], }); - expectSyntaxError('"contains unescaped \u0007 control char"').to.deep.equal( - { - message: 'Syntax Error: Invalid character within String: "\\u0007".', - locations: [{ line: 1, column: 21 }], - }, - ); + expectSyntaxError('"bad surrogate \uDEAD"').to.deep.equal({ + message: 'Syntax Error: Invalid character within String: U+DEAD.', + locations: [{ line: 1, column: 16 }], + }); - expectSyntaxError('"null-byte is not \u0000 end of file"').to.deep.equal({ - message: 'Syntax Error: Invalid character within String: "\\u0000".', - locations: [{ line: 1, column: 19 }], + expectSyntaxError('"bad high surrogate pair \uDEAD\uDEAD"').to.deep.equal({ + message: 'Syntax Error: Invalid character within String: U+DEAD.', + locations: [{ line: 1, column: 26 }], + }); + + expectSyntaxError('"bad low surrogate pair \uD800\uD800"').to.deep.equal({ + message: 'Syntax Error: Invalid character within String: U+D800.', + locations: [{ line: 1, column: 25 }], }); expectSyntaxError('"multi\nline"').to.deep.equal({ @@ -320,38 +410,125 @@ describe('Lexer', () => { }); expectSyntaxError('"bad \\z esc"').to.deep.equal({ - message: 'Syntax Error: Invalid character escape sequence: \\z.', - locations: [{ line: 1, column: 7 }], + message: 'Syntax Error: Invalid character escape sequence: "\\z".', + locations: [{ line: 1, column: 6 }], }); expectSyntaxError('"bad \\x esc"').to.deep.equal({ - message: 'Syntax Error: Invalid character escape sequence: \\x.', - locations: [{ line: 1, column: 7 }], + message: 'Syntax Error: Invalid character escape sequence: "\\x".', + locations: [{ line: 1, column: 6 }], }); expectSyntaxError('"bad \\u1 esc"').to.deep.equal({ - message: 'Syntax Error: Invalid character escape sequence: \\u1 es.', - locations: [{ line: 1, column: 7 }], + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u1 es".', + locations: [{ line: 1, column: 6 }], }); expectSyntaxError('"bad \\u0XX1 esc"').to.deep.equal({ - message: 'Syntax Error: Invalid character escape sequence: \\u0XX1.', - locations: [{ line: 1, column: 7 }], + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u0XX1".', + locations: [{ line: 1, column: 6 }], }); expectSyntaxError('"bad \\uXXXX esc"').to.deep.equal({ - message: 'Syntax Error: Invalid character escape sequence: \\uXXXX.', - locations: [{ line: 1, column: 7 }], + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uXXXX".', + locations: [{ line: 1, column: 6 }], }); expectSyntaxError('"bad \\uFXXX esc"').to.deep.equal({ - message: 'Syntax Error: Invalid character escape sequence: \\uFXXX.', - locations: [{ line: 1, column: 7 }], + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uFXXX".', + locations: [{ line: 1, column: 6 }], }); expectSyntaxError('"bad \\uXXXF esc"').to.deep.equal({ - message: 'Syntax Error: Invalid character escape sequence: \\uXXXF.', - locations: [{ line: 1, column: 7 }], + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uXXXF".', + locations: [{ line: 1, column: 6 }], + }); + + expectSyntaxError('"bad \\u{} esc"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u{}".', + locations: [{ line: 1, column: 6 }], + }); + + expectSyntaxError('"bad \\u{FXXX} esc"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u{FX".', + locations: [{ line: 1, column: 6 }], + }); + + expectSyntaxError('"bad \\u{FFFF esc"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u{FFFF ".', + locations: [{ line: 1, column: 6 }], + }); + + expectSyntaxError('"bad \\u{FFFF"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u{FFFF"".', + locations: [{ line: 1, column: 6 }], + }); + + expectSyntaxError('"too high \\u{110000} esc"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u{110000}".', + locations: [{ line: 1, column: 11 }], + }); + + expectSyntaxError('"way too high \\u{12345678} esc"').to.deep.equal({ + message: + 'Syntax Error: Invalid Unicode escape sequence: "\\u{12345678}".', + locations: [{ line: 1, column: 15 }], + }); + + expectSyntaxError('"too long \\u{000000000} esc"').to.deep.equal({ + message: + 'Syntax Error: Invalid Unicode escape sequence: "\\u{000000000".', + locations: [{ line: 1, column: 11 }], + }); + + expectSyntaxError('"bad surrogate \\uDEAD esc"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uDEAD".', + locations: [{ line: 1, column: 16 }], + }); + + expectSyntaxError('"bad surrogate \\u{DEAD} esc"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u{DEAD}".', + locations: [{ line: 1, column: 16 }], + }); + + expectSyntaxError( + '"cannot use braces for surrogate pair \\u{D83D}\\u{DE00} esc"', + ).to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\u{D83D}".', + locations: [{ line: 1, column: 39 }], + }); + + expectSyntaxError( + '"bad high surrogate pair \\uDEAD\\uDEAD esc"', + ).to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uDEAD".', + locations: [{ line: 1, column: 26 }], + }); + + expectSyntaxError( + '"bad low surrogate pair \\uD800\\uD800 esc"', + ).to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uD800".', + locations: [{ line: 1, column: 25 }], + }); + + expectSyntaxError( + '"cannot escape half a pair \uD83D\\uDE00 esc"', + ).to.deep.equal({ + message: 'Syntax Error: Invalid character within String: U+D83D.', + locations: [{ line: 1, column: 28 }], + }); + + expectSyntaxError( + '"cannot escape half a pair \\uD83D\uDE00 esc"', + ).to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uD83D".', + locations: [{ line: 1, column: 28 }], + }); + + expectSyntaxError('"bad \\uD83D\\not an escape"').to.deep.equal({ + message: 'Syntax Error: Invalid Unicode escape sequence: "\\uD83D".', + locations: [{ line: 1, column: 6 }], }); }); @@ -360,6 +537,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 6, + line: 1, + column: 1, value: '', }); @@ -367,6 +546,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 12, + line: 1, + column: 1, value: 'simple', }); @@ -374,6 +555,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 19, + line: 1, + column: 1, value: ' white space ', }); @@ -381,6 +564,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 22, + line: 1, + column: 1, value: 'contains " quote', }); @@ -388,6 +573,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 32, + line: 1, + column: 1, value: 'contains """ triple quote', }); @@ -395,6 +582,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 16, + line: 1, + column: 1, value: 'multi\nline', }); @@ -402,6 +591,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 28, + line: 1, + column: 1, value: 'multi\nline\nnormalized', }); @@ -409,13 +600,26 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 32, + line: 1, + column: 1, value: 'unescaped \\n\\r\\b\\t\\f\\u1234', }); + expect(lexOne('"""unescaped unicode outside BMP \u{1f600}"""')).to.contain({ + kind: TokenKind.BLOCK_STRING, + start: 0, + end: 38, + line: 1, + column: 1, + value: 'unescaped unicode outside BMP \u{1f600}', + }); + expect(lexOne('"""slashes \\\\ \\/"""')).to.contain({ kind: TokenKind.BLOCK_STRING, start: 0, end: 19, + line: 1, + column: 1, value: 'slashes \\\\ \\/', }); @@ -431,6 +635,8 @@ describe('Lexer', () => { kind: TokenKind.BLOCK_STRING, start: 0, end: 68, + line: 1, + column: 1, value: 'spans\n multiple\n lines', }); }); @@ -484,18 +690,9 @@ describe('Lexer', () => { locations: [{ line: 1, column: 16 }], }); - expectSyntaxError( - '"""contains unescaped \u0007 control char"""', - ).to.deep.equal({ - message: 'Syntax Error: Invalid character within String: "\\u0007".', - locations: [{ line: 1, column: 23 }], - }); - - expectSyntaxError( - '"""null-byte is not \u0000 end of file"""', - ).to.deep.equal({ - message: 'Syntax Error: Invalid character within String: "\\u0000".', - locations: [{ line: 1, column: 21 }], + expectSyntaxError('"""contains invalid surrogate \uDEAD"""').to.deep.equal({ + message: 'Syntax Error: Invalid character within String: U+DEAD.', + locations: [{ line: 1, column: 31 }], }); }); @@ -630,7 +827,7 @@ describe('Lexer', () => { }); expectSyntaxError('+1').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character "+".', + message: 'Syntax Error: Unexpected character: "+".', locations: [{ line: 1, column: 1 }], }); @@ -655,7 +852,7 @@ describe('Lexer', () => { }); expectSyntaxError('.123').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character ".".', + message: 'Syntax Error: Unexpected character: ".".', locations: [{ line: 1, column: 1 }], }); @@ -679,6 +876,11 @@ describe('Lexer', () => { locations: [{ line: 1, column: 5 }], }); + expectSyntaxError('1.0e"').to.deep.equal({ + message: "Syntax Error: Invalid number, expected digit but got: '\"'.", + locations: [{ line: 1, column: 5 }], + }); + expectSyntaxError('1.2e3e').to.deep.equal({ message: 'Syntax Error: Invalid number, expected digit but got: "e".', locations: [{ line: 1, column: 6 }], @@ -712,8 +914,8 @@ describe('Lexer', () => { message: 'Syntax Error: Invalid number, expected digit but got: "_".', locations: [{ line: 1, column: 2 }], }); - expectSyntaxError('1ß').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character "\\u00DF".', + expectSyntaxError('1\u00DF').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+00DF.', locations: [{ line: 1, column: 2 }], }); expectSyntaxError('1.23f').to.deep.equal({ @@ -724,10 +926,6 @@ describe('Lexer', () => { message: 'Syntax Error: Invalid number, expected digit but got: "_".', locations: [{ line: 1, column: 6 }], }); - expectSyntaxError('1ß').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character "\\u00DF".', - locations: [{ line: 1, column: 2 }], - }); }); it('lexes punctuation', () => { @@ -825,22 +1023,62 @@ describe('Lexer', () => { it('lex reports useful unknown character error', () => { expectSyntaxError('..').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character ".".', + message: 'Syntax Error: Unexpected character: ".".', locations: [{ line: 1, column: 1 }], }); - expectSyntaxError('?').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character "?".', + expectSyntaxError('~').to.deep.equal({ + message: 'Syntax Error: Unexpected character: "~".', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\x00').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+0000.', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\b').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+0008.', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\u00AA').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+00AA.', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\u0AAA').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+0AAA.', locations: [{ line: 1, column: 1 }], }); expectSyntaxError('\u203B').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character "\\u203B".', + message: 'Syntax Error: Unexpected character: U+203B.', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\u{1f600}').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+1F600.', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\uD83D\uDE00').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+1F600.', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\uD800\uDC00').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+10000.', + locations: [{ line: 1, column: 1 }], + }); + + expectSyntaxError('\uDBFF\uDFFF').to.deep.equal({ + message: 'Syntax Error: Unexpected character: U+10FFFF.', locations: [{ line: 1, column: 1 }], }); - expectSyntaxError('\u200b').to.deep.equal({ - message: 'Syntax Error: Cannot parse the unexpected character "\\u200B".', + expectSyntaxError('\uDEAD').to.deep.equal({ + message: 'Syntax Error: Invalid character: U+DEAD.', locations: [{ line: 1, column: 1 }], }); }); @@ -886,7 +1124,7 @@ describe('Lexer', () => { expect(endToken.next).to.equal(null); const tokens = []; - for (let tok = startToken; tok; tok = tok.next) { + for (let tok: Token | null = startToken; tok; tok = tok.next) { if (tokens.length) { // Tokens are double-linked, prev should point to last seen token. expect(tok.prev).to.equal(tokens[tokens.length - 1]); @@ -903,6 +1141,37 @@ describe('Lexer', () => { TokenKind.EOF, ]); }); + + it('lexes comments', () => { + expect(lexOne('# Comment').prev).to.contain({ + kind: TokenKind.COMMENT, + start: 0, + end: 9, + value: ' Comment', + }); + expect(lexOne('# Comment\nAnother line').prev).to.contain({ + kind: TokenKind.COMMENT, + start: 0, + end: 9, + value: ' Comment', + }); + expect(lexOne('# Comment\r\nAnother line').prev).to.contain({ + kind: TokenKind.COMMENT, + start: 0, + end: 9, + value: ' Comment', + }); + expect(lexOne('# Comment \u{1f600}').prev).to.contain({ + kind: TokenKind.COMMENT, + start: 0, + end: 12, + value: ' Comment \u{1f600}', + }); + expectSyntaxError('# Invalid surrogate \uDEAD').to.deep.equal({ + message: 'Syntax Error: Invalid character: U+DEAD.', + locations: [{ line: 1, column: 21 }], + }); + }); }); describe('isPunctuatorTokenKind', () => { diff --git a/src/language/__tests__/parser-test.js b/src/language/__tests__/parser-test.ts similarity index 70% rename from src/language/__tests__/parser-test.js rename to src/language/__tests__/parser-test.ts index 9b9c91f387..caa922a27d 100644 --- a/src/language/__tests__/parser-test.js +++ b/src/language/__tests__/parser-test.ts @@ -1,23 +1,19 @@ -// eslint-disable-next-line import/no-nodejs-modules -import { inspect as nodeInspect } from 'util'; - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; -import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; +import { dedent } from '../../__testUtils__/dedent'; +import { expectJSON, expectToThrowJSON } from '../../__testUtils__/expectJSON'; +import { kitchenSinkQuery } from '../../__testUtils__/kitchenSinkQuery'; -import inspect from '../../jsutils/inspect'; +import { inspect } from '../../jsutils/inspect'; import { Kind } from '../kinds'; +import { parse, parseConstValue, parseType, parseValue } from '../parser'; import { Source } from '../source'; import { TokenKind } from '../tokenKind'; -import { parse, parseValue, parseType } from '../parser'; - -import toJSONDeep from './toJSONDeep'; function expectSyntaxError(text: string) { - return expect(() => parse(text)).to.throw(); + return expectToThrowJSON(() => parse(text)); } describe('Parser', () => { @@ -35,7 +31,7 @@ describe('Parser', () => { locations: [{ line: 1, column: 2 }], }); - expect(String(caughtError) + '\n').to.equal(dedent` + expect(String(caughtError)).to.equal(dedent` Syntax Error: Expected Name, found . GraphQL request:1:2 @@ -79,7 +75,7 @@ describe('Parser', () => { } catch (error) { caughtError = error; } - expect(String(caughtError) + '\n').to.equal(dedent` + expect(String(caughtError)).to.equal(dedent` Syntax Error: Expected "{", found . MyQuery.graphql:1:6 @@ -88,6 +84,24 @@ describe('Parser', () => { `); }); + it('exposes the tokenCount', () => { + expect(parse('{ foo }').tokenCount).to.equal(3); + expect(parse('{ foo(bar: "baz") }').tokenCount).to.equal(8); + }); + + it('limit maximum number of tokens', () => { + expect(() => parse('{ foo }', { maxTokens: 3 })).to.not.throw(); + expect(() => parse('{ foo }', { maxTokens: 2 })).to.throw( + 'Syntax Error: Document contains more that 2 tokens. Parsing aborted.', + ); + + expect(() => parse('{ foo(bar: "baz") }', { maxTokens: 8 })).to.not.throw(); + + expect(() => parse('{ foo(bar: "baz") }', { maxTokens: 7 })).to.throw( + 'Syntax Error: Document contains more that 7 tokens. Parsing aborted.', + ); + }); + it('parses variable inline values', () => { expect(() => parse('{ field(complex: { a: { b: [ $var ] } }) }'), @@ -98,7 +112,7 @@ describe('Parser', () => { expectSyntaxError( 'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }', ).to.deep.equal({ - message: 'Syntax Error: Unexpected "$".', + message: 'Syntax Error: Unexpected variable "$var" in constant value.', locations: [{ line: 1, column: 37 }], }); }); @@ -123,6 +137,26 @@ describe('Parser', () => { }); }); + it('does not allow "true", "false", or "null" as enum value', () => { + expectSyntaxError('enum Test { VALID, true }').to.deep.equal({ + message: + 'Syntax Error: Name "true" is reserved and cannot be used for an enum value.', + locations: [{ line: 1, column: 20 }], + }); + + expectSyntaxError('enum Test { VALID, false }').to.deep.equal({ + message: + 'Syntax Error: Name "false" is reserved and cannot be used for an enum value.', + locations: [{ line: 1, column: 20 }], + }); + + expectSyntaxError('enum Test { VALID, null }').to.deep.equal({ + message: + 'Syntax Error: Name "null" is reserved and cannot be used for an enum value.', + locations: [{ line: 1, column: 20 }], + }); + }); + it('parses multi-byte characters', () => { // Note: \u0A0A could be naively interpreted as two line-feed chars. const ast = parse(` @@ -218,9 +252,9 @@ describe('Parser', () => { } `); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.DOCUMENT, - loc: { start: 0, end: 41 }, + loc: { start: 0, end: 40 }, definitions: [ { kind: Kind.OPERATION_DEFINITION, @@ -308,9 +342,9 @@ describe('Parser', () => { } `); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.DOCUMENT, - loc: { start: 0, end: 30 }, + loc: { start: 0, end: 29 }, definitions: [ { kind: Kind.OPERATION_DEFINITION, @@ -363,24 +397,24 @@ describe('Parser', () => { it('allows parsing without source location information', () => { const result = parse('{ id }', { noLocation: true }); - expect(result.loc).to.equal(undefined); + expect('loc' in result).to.equal(false); }); - it('Experimental: allows parsing fragment defined variables', () => { + it('Legacy: allows parsing fragment defined variables', () => { const document = 'fragment a($v: Boolean = false) on t { f(v: $v) }'; expect(() => - parse(document, { experimentalFragmentVariables: true }), + parse(document, { allowLegacyFragmentVariables: true }), ).to.not.throw(); expect(() => parse(document)).to.throw('Syntax Error'); }); - it('contains location information that only stringifies start/end', () => { - const result = parse('{ id }'); + it('contains location that can be Object.toStringified, JSON.stringified, or jsutils.inspected', () => { + const { loc } = parse('{ id }'); - expect(JSON.stringify(result.loc)).to.equal('{"start":0,"end":6}'); - expect(nodeInspect(result.loc)).to.equal('{ start: 0, end: 6 }'); - expect(inspect(result.loc)).to.equal('{ start: 0, end: 6 }'); + expect(Object.prototype.toString.call(loc)).to.equal('[object Location]'); + expect(JSON.stringify(loc)).to.equal('{"start":0,"end":6}'); + expect(inspect(loc)).to.equal('{ start: 0, end: 6 }'); }); it('contains references to source', () => { @@ -403,7 +437,7 @@ describe('Parser', () => { describe('parseValue', () => { it('parses null value', () => { const result = parseValue('null'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.NULL, loc: { start: 0, end: 4 }, }); @@ -411,7 +445,7 @@ describe('Parser', () => { it('parses list values', () => { const result = parseValue('[123 "abc"]'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.LIST, loc: { start: 0, end: 11 }, values: [ @@ -432,7 +466,7 @@ describe('Parser', () => { it('parses block strings', () => { const result = parseValue('["""long""" "short"]'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.LIST, loc: { start: 0, end: 20 }, values: [ @@ -451,12 +485,100 @@ describe('Parser', () => { ], }); }); + + it('allows variables', () => { + const result = parseValue('{ field: $var }'); + expectJSON(result).toDeepEqual({ + kind: Kind.OBJECT, + loc: { start: 0, end: 15 }, + fields: [ + { + kind: Kind.OBJECT_FIELD, + loc: { start: 2, end: 13 }, + name: { + kind: Kind.NAME, + loc: { start: 2, end: 7 }, + value: 'field', + }, + value: { + kind: Kind.VARIABLE, + loc: { start: 9, end: 13 }, + name: { + kind: Kind.NAME, + loc: { start: 10, end: 13 }, + value: 'var', + }, + }, + }, + ], + }); + }); + + it('correct message for incomplete variable', () => { + expect(() => parseValue('$')) + .to.throw() + .to.deep.include({ + message: 'Syntax Error: Expected Name, found .', + locations: [{ line: 1, column: 2 }], + }); + }); + + it('correct message for unexpected token', () => { + expect(() => parseValue(':')) + .to.throw() + .to.deep.include({ + message: 'Syntax Error: Unexpected ":".', + locations: [{ line: 1, column: 1 }], + }); + }); + }); + + describe('parseConstValue', () => { + it('parses values', () => { + const result = parseConstValue('[123 "abc"]'); + expectJSON(result).toDeepEqual({ + kind: Kind.LIST, + loc: { start: 0, end: 11 }, + values: [ + { + kind: Kind.INT, + loc: { start: 1, end: 4 }, + value: '123', + }, + { + kind: Kind.STRING, + loc: { start: 5, end: 10 }, + value: 'abc', + block: false, + }, + ], + }); + }); + + it('does not allow variables', () => { + expect(() => parseConstValue('{ field: $var }')) + .to.throw() + .to.deep.include({ + message: + 'Syntax Error: Unexpected variable "$var" in constant value.', + locations: [{ line: 1, column: 10 }], + }); + }); + + it('correct message for unexpected token', () => { + expect(() => parseConstValue('$')) + .to.throw() + .to.deep.include({ + message: 'Syntax Error: Unexpected "$".', + locations: [{ line: 1, column: 1 }], + }); + }); }); describe('parseType', () => { it('parses well known types', () => { const result = parseType('String'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.NAMED_TYPE, loc: { start: 0, end: 6 }, name: { @@ -469,7 +591,7 @@ describe('Parser', () => { it('parses custom types', () => { const result = parseType('MyType'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.NAMED_TYPE, loc: { start: 0, end: 6 }, name: { @@ -482,7 +604,7 @@ describe('Parser', () => { it('parses list types', () => { const result = parseType('[MyType]'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.LIST_TYPE, loc: { start: 0, end: 8 }, type: { @@ -499,7 +621,7 @@ describe('Parser', () => { it('parses non-null types', () => { const result = parseType('MyType!'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.NON_NULL_TYPE, loc: { start: 0, end: 7 }, type: { @@ -516,7 +638,7 @@ describe('Parser', () => { it('parses nested types', () => { const result = parseType('[MyType!]'); - expect(toJSONDeep(result)).to.deep.equal({ + expectJSON(result).toDeepEqual({ kind: Kind.LIST_TYPE, loc: { start: 0, end: 9 }, type: { diff --git a/src/language/__tests__/predicates-test.js b/src/language/__tests__/predicates-test.ts similarity index 80% rename from src/language/__tests__/predicates-test.js rename to src/language/__tests__/predicates-test.ts index eb620abd61..13477f8de9 100644 --- a/src/language/__tests__/predicates-test.js +++ b/src/language/__tests__/predicates-test.ts @@ -3,24 +3,25 @@ import { describe, it } from 'mocha'; import type { ASTNode } from '../ast'; import { Kind } from '../kinds'; +import { parseValue } from '../parser'; import { + isConstValueNode, isDefinitionNode, isExecutableDefinitionNode, isSelectionNode, - isValueNode, + isTypeDefinitionNode, + isTypeExtensionNode, isTypeNode, isTypeSystemDefinitionNode, - isTypeDefinitionNode, isTypeSystemExtensionNode, - isTypeExtensionNode, + isValueNode, } from '../predicates'; -const allASTNodes: Array = Object.values(Kind).map( - (kind) => ({ kind }: any), -); - -function filterNodes(predicate: (ASTNode) => boolean): Array { - return allASTNodes.filter(predicate).map(({ kind }) => kind); +function filterNodes(predicate: (node: ASTNode) => boolean): Array { + return Object.values(Kind).filter( + // @ts-expect-error create node only with kind + (kind) => predicate({ kind }), + ); } describe('AST node predicates', () => { @@ -75,6 +76,17 @@ describe('AST node predicates', () => { ]); }); + it('isConstValueNode', () => { + expect(isConstValueNode(parseValue('"value"'))).to.equal(true); + expect(isConstValueNode(parseValue('$var'))).to.equal(false); + + expect(isConstValueNode(parseValue('{ field: "value" }'))).to.equal(true); + expect(isConstValueNode(parseValue('{ field: $var }'))).to.equal(false); + + expect(isConstValueNode(parseValue('[ "value" ]'))).to.equal(true); + expect(isConstValueNode(parseValue('[ $var ]'))).to.equal(false); + }); + it('isTypeNode', () => { expect(filterNodes(isTypeNode)).to.deep.equal([ 'NamedType', diff --git a/src/language/__tests__/printLocation-test.js b/src/language/__tests__/printLocation-test.ts similarity index 89% rename from src/language/__tests__/printLocation-test.js rename to src/language/__tests__/printLocation-test.ts index 2fbcdcca4e..c5eac8cce5 100644 --- a/src/language/__tests__/printLocation-test.js +++ b/src/language/__tests__/printLocation-test.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; -import { Source } from '../source'; import { printSourceLocation } from '../printLocation'; +import { Source } from '../source'; describe('printSourceLocation', () => { it('prints minified documents', () => { @@ -16,7 +16,7 @@ describe('printSourceLocation', () => { line: 1, column: minifiedSource.body.indexOf('FIRST_ERROR_HERE') + 1, }); - expect(firstLocation + '\n').to.equal(dedent` + expect(firstLocation).to.equal(dedent` GraphQL request:1:53 1 | query SomeMinifiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) | ^ @@ -27,7 +27,7 @@ describe('printSourceLocation', () => { line: 1, column: minifiedSource.body.indexOf('SECOND_ERROR_HERE') + 1, }); - expect(secondLocation + '\n').to.equal(dedent` + expect(secondLocation).to.equal(dedent` GraphQL request:1:114 1 | query SomeMinifiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. @@ -39,7 +39,7 @@ describe('printSourceLocation', () => { line: 1, column: minifiedSource.body.indexOf('THIRD_ERROR_HERE') + 1, }); - expect(thirdLocation + '\n').to.equal(dedent` + expect(thirdLocation).to.equal(dedent` GraphQL request:1:166 1 | query SomeMinifiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. @@ -54,7 +54,7 @@ describe('printSourceLocation', () => { { line: 1, column: 1 }, ); - expect(result + '\n').to.equal(dedent` + expect(result).to.equal(dedent` Test:9:1 9 | * | ^ @@ -67,7 +67,7 @@ describe('printSourceLocation', () => { { line: 1, column: 1 }, ); - expect(result + '\n').to.equal(dedent` + expect(result).to.equal(dedent` Test:9:1 9 | * | ^ diff --git a/src/language/__tests__/printString-test.ts b/src/language/__tests__/printString-test.ts new file mode 100644 index 0000000000..fff1bfeec0 --- /dev/null +++ b/src/language/__tests__/printString-test.ts @@ -0,0 +1,82 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { printString } from '../printString'; + +describe('printString', () => { + it('prints a simple string', () => { + expect(printString('hello world')).to.equal('"hello world"'); + }); + + it('escapes quotes', () => { + expect(printString('"hello world"')).to.equal('"\\"hello world\\""'); + }); + + it('does not escape single quote', () => { + expect(printString("who's test")).to.equal('"who\'s test"'); + }); + + it('escapes backslashes', () => { + expect(printString('escape: \\')).to.equal('"escape: \\\\"'); + }); + + it('escapes well-known control chars', () => { + expect(printString('\b\f\n\r\t')).to.equal('"\\b\\f\\n\\r\\t"'); + }); + + it('escapes zero byte', () => { + expect(printString('\x00')).to.equal('"\\u0000"'); + }); + + it('does not escape space', () => { + expect(printString(' ')).to.equal('" "'); + }); + + it('does not escape non-ascii character', () => { + expect(printString('\u21BB')).to.equal('"\u21BB"'); + }); + + it('does not escape supplementary character', () => { + expect(printString('\u{1f600}')).to.equal('"\u{1f600}"'); + }); + + it('escapes all control chars', () => { + /* spellchecker:ignore abcdefghijklmnopqrstuvwxyz */ + expect( + printString( + '\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007' + + '\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F' + + '\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017' + + '\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F' + + '\u0020\u0021\u0022\u0023\u0024\u0025\u0026\u0027' + + '\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F' + + '\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037' + + '\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F' + + '\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047' + + '\u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F' + + '\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057' + + '\u0058\u0059\u005A\u005B\u005C\u005D\u005E\u005F' + + '\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067' + + '\u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F' + + '\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077' + + '\u0078\u0079\u007A\u007B\u007C\u007D\u007E\u007F' + + '\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087' + + '\u0088\u0089\u008A\u008B\u008C\u008D\u008E\u008F' + + '\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097' + + '\u0098\u0099\u009A\u009B\u009C\u009D\u009E\u009F', + ), + ).to.equal( + '"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007' + + '\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F' + + '\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017' + + '\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F' + + ' !\\"#$%&\'()*+,-./0123456789:;<=>?' + + '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_' + + '`abcdefghijklmnopqrstuvwxyz{|}~\\u007F' + + '\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087' + + '\\u0088\\u0089\\u008A\\u008B\\u008C\\u008D\\u008E\\u008F' + + '\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097' + + '\\u0098\\u0099\\u009A\\u009B\\u009C\\u009D\\u009E\\u009F"', + ); + }); +}); diff --git a/src/language/__tests__/printer-test.js b/src/language/__tests__/printer-test.ts similarity index 80% rename from src/language/__tests__/printer-test.js rename to src/language/__tests__/printer-test.ts index 55adc17a78..227e90dd44 100644 --- a/src/language/__tests__/printer-test.js +++ b/src/language/__tests__/printer-test.ts @@ -1,29 +1,26 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; -import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; +import { dedent, dedentString } from '../../__testUtils__/dedent'; +import { kitchenSinkQuery } from '../../__testUtils__/kitchenSinkQuery'; +import { Kind } from '../kinds'; import { parse } from '../parser'; import { print } from '../printer'; describe('Printer: Query document', () => { - it('does not alter ast', () => { - const ast = parse(kitchenSinkQuery); - const astBefore = JSON.stringify(ast); - print(ast); - expect(JSON.stringify(ast)).to.equal(astBefore); - }); - it('prints minimal ast', () => { - const ast = { kind: 'Field', name: { kind: 'Name', value: 'foo' } }; + const ast = { + kind: Kind.FIELD, + name: { kind: Kind.NAME, value: 'foo' }, + } as const; expect(print(ast)).to.equal('foo'); }); it('produces helpful error messages', () => { const badAST = { random: 'Data' }; - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => print(badAST)).to.throw( 'Invalid AST Node: { random: "Data" }.', ); @@ -83,15 +80,13 @@ describe('Printer: Query document', () => { parse('{trip(wheelchair:false arriveBy:false){dateTime}}'), ); - expect(printed).to.equal( - dedent` + expect(printed).to.equal(dedent` { trip(wheelchair: false, arriveBy: false) { dateTime } } - `, - ); + `); }); it('puts arguments on multiple lines if line is long (> 80 chars)', () => { @@ -101,8 +96,7 @@ describe('Printer: Query document', () => { ), ); - expect(printed).to.equal( - dedent` + expect(printed).to.equal(dedent` { trip( wheelchair: false @@ -113,16 +107,13 @@ describe('Printer: Query document', () => { dateTime } } - `, - ); + `); }); - it('Experimental: prints fragment with variable directives', () => { + it('Legacy: prints fragment with variable directives', () => { const queryASTWithVariableDirective = parse( 'fragment Foo($foo: TestType @test) on TestType @testDirective { id }', - { - experimentalFragmentVariables: true, - }, + { allowLegacyFragmentVariables: true }, ); expect(print(queryASTWithVariableDirective)).to.equal(dedent` fragment Foo($foo: TestType @test) on TestType @testDirective { @@ -131,14 +122,14 @@ describe('Printer: Query document', () => { `); }); - it('Experimental: correctly prints fragment defined variables', () => { + it('Legacy: correctly prints fragment defined variables', () => { const fragmentWithVariable = parse( ` fragment Foo($a: ComplexType, $b: Boolean = false) on TestType { id } `, - { experimentalFragmentVariables: true }, + { allowLegacyFragmentVariables: true }, ); expect(print(fragmentWithVariable)).to.equal(dedent` fragment Foo($a: ComplexType, $b: Boolean = false) on TestType { @@ -147,12 +138,18 @@ describe('Printer: Query document', () => { `); }); - it('prints kitchen sink', () => { - const printed = print(parse(kitchenSinkQuery)); + it('prints kitchen sink without altering ast', () => { + const ast = parse(kitchenSinkQuery, { noLocation: true }); + + const astBeforePrintCall = JSON.stringify(ast); + const printed = print(ast); + const printedAST = parse(printed, { noLocation: true }); + + expect(printedAST).to.deep.equal(ast); + expect(JSON.stringify(ast)).to.equal(astBeforePrintCall); expect(printed).to.equal( - // $FlowFixMe[incompatible-call] - dedent(String.raw` + dedentString(String.raw` query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { whoever123is: node(id: [123, 456]) { id @@ -182,7 +179,7 @@ describe('Printer: Query document', () => { } } - subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) @onSubscription { + subscription StoryLikeSubscription($input: StoryLikeSubscribeInput @onVariableDefinition) @onSubscription { storyLikeSubscribe(input: $input) { story { likers { @@ -200,7 +197,7 @@ describe('Printer: Query document', () => { size: $size bar: $b obj: {key: "value", block: """ - block string uses \""" + block string uses \""" """} ) } diff --git a/src/language/__tests__/schema-parser-test.js b/src/language/__tests__/schema-parser-test.ts similarity index 87% rename from src/language/__tests__/schema-parser-test.js rename to src/language/__tests__/schema-parser-test.ts index 02dab56622..cbb337c337 100644 --- a/src/language/__tests__/schema-parser-test.js +++ b/src/language/__tests__/schema-parser-test.ts @@ -1,18 +1,17 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; -import kitchenSinkSDL from '../../__testUtils__/kitchenSinkSDL'; +import { dedent } from '../../__testUtils__/dedent'; +import { expectJSON, expectToThrowJSON } from '../../__testUtils__/expectJSON'; +import { kitchenSinkSDL } from '../../__testUtils__/kitchenSinkSDL'; import { parse } from '../parser'; -import toJSONDeep from './toJSONDeep'; - function expectSyntaxError(text: string) { - return expect(() => parse(text)).to.throw(); + return expectToThrowJSON(() => parse(text)); } -function typeNode(name: mixed, loc: mixed) { +function typeNode(name: unknown, loc: unknown) { return { kind: 'NamedType', name: nameNode(name, loc), @@ -20,7 +19,7 @@ function typeNode(name: mixed, loc: mixed) { }; } -function nameNode(name: mixed, loc: mixed) { +function nameNode(name: unknown, loc: unknown) { return { kind: 'Name', value: name, @@ -28,11 +27,16 @@ function nameNode(name: mixed, loc: mixed) { }; } -function fieldNode(name: mixed, type: mixed, loc: mixed) { +function fieldNode(name: unknown, type: unknown, loc: unknown) { return fieldNodeWithArgs(name, type, [], loc); } -function fieldNodeWithArgs(name: mixed, type: mixed, args: mixed, loc: mixed) { +function fieldNodeWithArgs( + name: unknown, + type: unknown, + args: unknown, + loc: unknown, +) { return { kind: 'FieldDefinition', description: undefined, @@ -44,7 +48,7 @@ function fieldNodeWithArgs(name: mixed, type: mixed, args: mixed, loc: mixed) { }; } -function enumValueNode(name: mixed, loc: mixed) { +function enumValueNode(name: unknown, loc: unknown) { return { kind: 'EnumValueDefinition', name: nameNode(name, loc), @@ -55,10 +59,10 @@ function enumValueNode(name: mixed, loc: mixed) { } function inputValueNode( - name: mixed, - type: mixed, - defaultValue: mixed, - loc: mixed, + name: unknown, + type: unknown, + defaultValue: unknown, + loc: unknown, ) { return { kind: 'InputValueDefinition', @@ -79,7 +83,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -98,7 +102,7 @@ describe('Schema Parser', () => { loc: { start: 0, end: 30 }, }, ], - loc: { start: 0, end: 31 }, + loc: { start: 0, end: 30 }, }); }); @@ -110,15 +114,12 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.nested.property( - 'definitions[0].description', - { - kind: 'StringValue', - value: 'Description', - block: false, - loc: { start: 0, end: 13 }, - }, - ); + expectJSON(doc).toDeepNestedProperty('definitions[0].description', { + kind: 'StringValue', + value: 'Description', + block: false, + loc: { start: 0, end: 13 }, + }); }); it('parses type with description multi-line string', () => { @@ -132,15 +133,12 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.nested.property( - 'definitions[0].description', - { - kind: 'StringValue', - value: 'Description', - block: true, - loc: { start: 0, end: 19 }, - }, - ); + expectJSON(doc).toDeepNestedProperty('definitions[0].description', { + kind: 'StringValue', + value: 'Description', + block: true, + loc: { start: 0, end: 19 }, + }); }); it('parses schema with description string', () => { @@ -151,15 +149,12 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.nested.property( - 'definitions[0].description', - { - kind: 'StringValue', - value: 'Description', - block: false, - loc: { start: 0, end: 13 }, - }, - ); + expectJSON(doc).toDeepNestedProperty('definitions[0].description', { + kind: 'StringValue', + value: 'Description', + block: false, + loc: { start: 0, end: 13 }, + }); }); it('Description followed by something other than type system definition throws', () => { @@ -176,7 +171,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -194,14 +189,14 @@ describe('Schema Parser', () => { loc: { start: 0, end: 37 }, }, ], - loc: { start: 0, end: 38 }, + loc: { start: 0, end: 37 }, }); }); it('Object extension without fields', () => { const doc = parse('extend type Hello implements Greeting'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -219,7 +214,7 @@ describe('Schema Parser', () => { it('Interface extension without fields', () => { const doc = parse('extend interface Hello implements Greeting'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -242,7 +237,7 @@ describe('Schema Parser', () => { extend type Hello implements SecondGreeting `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -304,7 +299,7 @@ describe('Schema Parser', () => { extend interface Hello implements SecondGreeting `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -335,8 +330,9 @@ describe('Schema Parser', () => { world: String } `).to.deep.equal({ - message: 'Syntax Error: Unexpected Name "extend".', - locations: [{ line: 3, column: 7 }], + message: + 'Syntax Error: Unexpected description, descriptions are supported only on type definitions.', + locations: [{ line: 2, column: 7 }], }); expectSyntaxError(` @@ -356,8 +352,9 @@ describe('Schema Parser', () => { world: String } `).to.deep.equal({ - message: 'Syntax Error: Unexpected Name "extend".', - locations: [{ line: 3, column: 7 }], + message: + 'Syntax Error: Unexpected description, descriptions are supported only on type definitions.', + locations: [{ line: 2, column: 7 }], }); expectSyntaxError(` @@ -376,7 +373,7 @@ describe('Schema Parser', () => { mutation: Mutation }`; const doc = parse(body); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -400,7 +397,7 @@ describe('Schema Parser', () => { it('Schema extension with only directives', () => { const body = 'extend schema @directive'; const doc = parse(body); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -442,7 +439,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -465,13 +462,13 @@ describe('Schema Parser', () => { loc: { start: 0, end: 31 }, }, ], - loc: { start: 0, end: 32 }, + loc: { start: 0, end: 31 }, }); }); it('Simple interface inheriting interface', () => { const doc = parse('interface Hello implements World { field: String }'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -497,7 +494,7 @@ describe('Schema Parser', () => { it('Simple type inheriting interface', () => { const doc = parse('type Hello implements World { field: String }'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -523,7 +520,7 @@ describe('Schema Parser', () => { it('Simple type inheriting multiple interfaces', () => { const doc = parse('type Hello implements Wo & rld { field: String }'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -551,7 +548,7 @@ describe('Schema Parser', () => { it('Simple interface inheriting multiple interfaces', () => { const doc = parse('interface Hello implements Wo & rld { field: String }'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -580,7 +577,7 @@ describe('Schema Parser', () => { it('Simple type inheriting multiple interfaces with leading ampersand', () => { const doc = parse('type Hello implements & Wo & rld { field: String }'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -610,7 +607,7 @@ describe('Schema Parser', () => { const doc = parse( 'interface Hello implements & Wo & rld { field: String }', ); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -639,7 +636,7 @@ describe('Schema Parser', () => { it('Single value enum', () => { const doc = parse('enum Hello { WORLD }'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -658,7 +655,7 @@ describe('Schema Parser', () => { it('Double value enum', () => { const doc = parse('enum Hello { WO, RLD }'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -684,7 +681,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -703,7 +700,7 @@ describe('Schema Parser', () => { loc: { start: 0, end: 35 }, }, ], - loc: { start: 0, end: 36 }, + loc: { start: 0, end: 35 }, }); }); @@ -714,7 +711,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -741,7 +738,7 @@ describe('Schema Parser', () => { loc: { start: 0, end: 45 }, }, ], - loc: { start: 0, end: 46 }, + loc: { start: 0, end: 45 }, }); }); @@ -752,7 +749,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -783,7 +780,7 @@ describe('Schema Parser', () => { loc: { start: 0, end: 52 }, }, ], - loc: { start: 0, end: 53 }, + loc: { start: 0, end: 52 }, }); }); @@ -794,7 +791,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -825,7 +822,7 @@ describe('Schema Parser', () => { loc: { start: 0, end: 48 }, }, ], - loc: { start: 0, end: 49 }, + loc: { start: 0, end: 48 }, }); }); @@ -836,7 +833,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -869,14 +866,14 @@ describe('Schema Parser', () => { loc: { start: 0, end: 60 }, }, ], - loc: { start: 0, end: 61 }, + loc: { start: 0, end: 60 }, }); }); it('Simple union', () => { const doc = parse('union Hello = World'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -895,7 +892,7 @@ describe('Schema Parser', () => { it('Union with two types', () => { const doc = parse('union Hello = Wo | Rld'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -917,7 +914,7 @@ describe('Schema Parser', () => { it('Union with two types and leading pipe', () => { const doc = parse('union Hello = | Wo | Rld'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -967,7 +964,7 @@ describe('Schema Parser', () => { it('Scalar', () => { const doc = parse('scalar Hello'); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -988,7 +985,7 @@ input Hello { world: String }`); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -1026,7 +1023,7 @@ input Hello { const body = 'directive @foo on OBJECT | INTERFACE'; const doc = parse(body); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -1062,7 +1059,7 @@ input Hello { const body = 'directive @foo repeatable on OBJECT | INTERFACE'; const doc = parse(body); - expect(toJSONDeep(doc)).to.deep.equal({ + expectJSON(doc).toDeepEqual({ kind: 'Document', definitions: [ { @@ -1106,29 +1103,4 @@ input Hello { it('parses kitchen sink schema', () => { expect(() => parse(kitchenSinkSDL)).to.not.throw(); }); - - it('Option: allowLegacySDLEmptyFields supports type with empty fields', () => { - const body = 'type Hello { }'; - expectSyntaxError(body).to.include({ - message: 'Syntax Error: Expected Name, found "}".', - }); - - const doc = parse(body, { allowLegacySDLEmptyFields: true }); - expect(doc).to.have.deep.nested.property('definitions[0].fields', []); - }); - - it('Option: allowLegacySDLImplementsInterfaces', () => { - const body = 'type Hello implements Wo rld { field: String }'; - expectSyntaxError(body).to.include({ - message: 'Syntax Error: Unexpected Name "rld".', - }); - - const doc = parse(body, { allowLegacySDLImplementsInterfaces: true }); - expect( - toJSONDeep(doc), - ).to.have.deep.nested.property('definitions[0].interfaces', [ - typeNode('Wo', { start: 22, end: 24 }), - typeNode('rld', { start: 25, end: 28 }), - ]); - }); }); diff --git a/src/language/__tests__/schema-printer-test.js b/src/language/__tests__/schema-printer-test.ts similarity index 83% rename from src/language/__tests__/schema-printer-test.js rename to src/language/__tests__/schema-printer-test.ts index 8a9505939c..41cf6c5419 100644 --- a/src/language/__tests__/schema-printer-test.js +++ b/src/language/__tests__/schema-printer-test.ts @@ -1,39 +1,40 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; -import kitchenSinkSDL from '../../__testUtils__/kitchenSinkSDL'; +import { dedent } from '../../__testUtils__/dedent'; +import { kitchenSinkSDL } from '../../__testUtils__/kitchenSinkSDL'; +import { Kind } from '../kinds'; import { parse } from '../parser'; import { print } from '../printer'; describe('Printer: SDL document', () => { it('prints minimal ast', () => { const ast = { - kind: 'ScalarTypeDefinition', - name: { kind: 'Name', value: 'foo' }, - }; + kind: Kind.SCALAR_TYPE_DEFINITION, + name: { kind: Kind.NAME, value: 'foo' }, + } as const; expect(print(ast)).to.equal('scalar foo'); }); it('produces helpful error messages', () => { const badAST = { random: 'Data' }; - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => print(badAST)).to.throw( 'Invalid AST Node: { random: "Data" }.', ); }); - it('does not alter ast', () => { - const ast = parse(kitchenSinkSDL); - const astBefore = JSON.stringify(ast); - print(ast); - expect(JSON.stringify(ast)).to.equal(astBefore); - }); + it('prints kitchen sink without altering ast', () => { + const ast = parse(kitchenSinkSDL, { noLocation: true }); + + const astBeforePrintCall = JSON.stringify(ast); + const printed = print(ast); + const printedAST = parse(printed, { noLocation: true }); - it('prints kitchen sink', () => { - const printed = print(parse(kitchenSinkSDL)); + expect(printedAST).to.deep.equal(ast); + expect(JSON.stringify(ast)).to.equal(astBeforePrintCall); expect(printed).to.equal(dedent` """This is a description of the schema as a whole.""" @@ -60,6 +61,7 @@ describe('Printer: SDL document', () => { five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type seven(argument: Int = null): Type + eight(argument: OneOfInputType): Type } type AnnotatedObject @onObject(arg: "value") { @@ -142,6 +144,11 @@ describe('Printer: SDL document', () => { answer: Int = 42 } + input OneOfInputType @oneOf { + string: String + int: Int + } + input AnnotatedInput @onInputObject { annotatedField: Type @onInputFieldDefinition } diff --git a/src/language/__tests__/source-test.js b/src/language/__tests__/source-test.ts similarity index 88% rename from src/language/__tests__/source-test.js rename to src/language/__tests__/source-test.ts index 31a34aa16d..6bf8a93e6d 100644 --- a/src/language/__tests__/source-test.js +++ b/src/language/__tests__/source-test.ts @@ -5,14 +5,14 @@ import { Source } from '../source'; describe('Source', () => { it('asserts that a body was provided', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => new Source()).to.throw( 'Body must be a string. Received: undefined.', ); }); it('asserts that a valid body was provided', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => new Source({})).to.throw( 'Body must be a string. Received: {}.', ); @@ -25,7 +25,7 @@ describe('Source', () => { }); it('rejects invalid locationOffset', () => { - function createSource(locationOffset: {| line: number, column: number |}) { + function createSource(locationOffset: { line: number; column: number }) { return new Source('', '', locationOffset); } diff --git a/src/language/__tests__/toJSONDeep.js b/src/language/__tests__/toJSONDeep.js deleted file mode 100644 index 3c3fae57f3..0000000000 --- a/src/language/__tests__/toJSONDeep.js +++ /dev/null @@ -1,26 +0,0 @@ -import isObjectLike from '../../jsutils/isObjectLike'; - -/** - * Deeply transforms an arbitrary value to a JSON-safe value by calling toJSON - * on any nested value which defines it. - */ -export default function toJSONDeep(value: mixed): mixed { - if (!isObjectLike(value)) { - return value; - } - - if (typeof value.toJSON === 'function') { - // $FlowFixMe[incompatible-use] - return value.toJSON(); - } - - if (Array.isArray(value)) { - return value.map(toJSONDeep); - } - - const result = Object.create(null); - for (const prop of Object.keys(value)) { - result[prop] = toJSONDeep(value[prop]); - } - return result; -} diff --git a/src/language/__tests__/visitor-test.js b/src/language/__tests__/visitor-test.ts similarity index 91% rename from src/language/__tests__/visitor-test.js rename to src/language/__tests__/visitor-test.ts index 1dfce965b8..9149b103e3 100644 --- a/src/language/__tests__/visitor-test.js +++ b/src/language/__tests__/visitor-test.ts @@ -1,14 +1,14 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; +import { kitchenSinkQuery } from '../../__testUtils__/kitchenSinkQuery'; -import invariant from '../../jsutils/invariant'; - -import type { ASTNode } from '../ast'; +import type { ASTNode, SelectionSetNode } from '../ast'; +import { isNode } from '../ast'; import { Kind } from '../kinds'; import { parse } from '../parser'; -import { visit, visitInParallel, BREAK, QueryDocumentKeys } from '../visitor'; +import type { ASTVisitor, ASTVisitorKeyMap } from '../visitor'; +import { BREAK, visit, visitInParallel } from '../visitor'; function checkVisitorFnArgs(ast: any, args: any, isEdited: boolean = false) { const [node, key, parent, path, ancestors] = args; @@ -52,12 +52,17 @@ function checkVisitorFnArgs(ast: any, args: any, isEdited: boolean = false) { } function getValue(node: ASTNode) { - return node.value != null ? node.value : undefined; + return 'value' in node ? node.value : undefined; } describe('Visitor', () => { + it('handles empty visitor', () => { + const ast = parse('{ a }', { noLocation: true }); + expect(() => visit(ast, {})).to.not.throw(); + }); + it('validates path argument', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a }', { noLocation: true }); @@ -88,7 +93,7 @@ describe('Visitor', () => { it('validates ancestors argument', () => { const ast = parse('{ a }', { noLocation: true }); - const visitedNodes = []; + const visitedNodes: Array = []; visit(ast, { enter(node, key, parent, _path, ancestors) { @@ -114,33 +119,10 @@ describe('Visitor', () => { }); }); - it('allows visiting only specified nodes', () => { - const ast = parse('{ a }', { noLocation: true }); - const visited = []; - - visit(ast, { - enter: { - Field(node) { - visited.push(['enter', node.kind]); - }, - }, - leave: { - Field(node) { - visited.push(['leave', node.kind]); - }, - }, - }); - - expect(visited).to.deep.equal([ - ['enter', 'Field'], - ['leave', 'Field'], - ]); - }); - it('allows editing a node both on enter and on leave', () => { const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true }); - let selectionSet; + let selectionSet: SelectionSetNode; const editedAST = visit(ast, { OperationDefinition: { @@ -283,7 +265,7 @@ describe('Visitor', () => { if (node.kind === 'Field' && node.name.value === 'a') { return { kind: 'Field', - selectionSet: [addedField].concat(node.selectionSet), + selectionSet: [addedField, node.selectionSet], }; } if (node === addedField) { @@ -296,7 +278,7 @@ describe('Visitor', () => { }); it('allows skipping a sub-tree', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b { x }, c }', { noLocation: true }); visit(ast, { @@ -334,7 +316,7 @@ describe('Visitor', () => { }); it('allows early exit while visiting', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b { x }, c }', { noLocation: true }); visit(ast, { @@ -369,7 +351,7 @@ describe('Visitor', () => { }); it('allows early exit while leaving', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b { x }, c }', { noLocation: true }); visit(ast, { @@ -406,7 +388,7 @@ describe('Visitor', () => { }); it('allows a named functions visitor API', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b { x }, c }', { noLocation: true }); visit(ast, { @@ -438,12 +420,47 @@ describe('Visitor', () => { ]); }); - it('Experimental: visits variables defined in fragments', () => { + it('visits only the specified `Kind` in visitorKeyMap', () => { + const visited: Array = []; + + const visitorKeyMap: ASTVisitorKeyMap = { + Document: ['definitions'], + OperationDefinition: ['name'], + }; + + const visitor: ASTVisitor = { + enter(node) { + visited.push(['enter', node.kind, getValue(node)]); + }, + leave(node) { + visited.push(['leave', node.kind, getValue(node)]); + }, + }; + + const exampleDocumentAST = parse(` + query ExampleOperation { + someField + } + `); + + visit(exampleDocumentAST, visitor, visitorKeyMap); + + expect(visited).to.deep.equal([ + ['enter', 'Document', undefined], + ['enter', 'OperationDefinition', undefined], + ['enter', 'Name', 'ExampleOperation'], + ['leave', 'Name', 'ExampleOperation'], + ['leave', 'OperationDefinition', undefined], + ['leave', 'Document', undefined], + ]); + }); + + it('Legacy: visits variables defined in fragments', () => { const ast = parse('fragment a($v: Boolean = false) on t { f }', { noLocation: true, - experimentalFragmentVariables: true, + allowLegacyFragmentVariables: true, }); - const visited = []; + const visited: Array = []; visit(ast, { enter(node) { @@ -490,8 +507,8 @@ describe('Visitor', () => { it('visits kitchen sink', () => { const ast = parse(kitchenSinkQuery); - const visited = []; - const argsStack = []; + const visited: Array = []; + const argsStack: Array = []; visit(ast, { enter(node, key, parent) { @@ -499,7 +516,7 @@ describe('Visitor', () => { 'enter', node.kind, key, - parent?.kind != null ? parent.kind : undefined, + isNode(parent) ? parent.kind : undefined, ]); checkVisitorFnArgs(ast, arguments); @@ -511,7 +528,7 @@ describe('Visitor', () => { 'leave', node.kind, key, - parent?.kind != null ? parent.kind : undefined, + isNode(parent) ? parent.kind : undefined, ]); expect(argsStack.pop()).to.deep.equal([...arguments]); @@ -723,6 +740,10 @@ describe('Visitor', () => { ['enter', 'Name', 'name', 'NamedType'], ['leave', 'Name', 'name', 'NamedType'], ['leave', 'NamedType', 'type', 'VariableDefinition'], + ['enter', 'Directive', 0, undefined], + ['enter', 'Name', 'name', 'Directive'], + ['leave', 'Name', 'name', 'Directive'], + ['leave', 'Directive', 0, undefined], ['leave', 'VariableDefinition', 0, undefined], ['enter', 'Directive', 0, undefined], ['enter', 'Name', 'name', 'Directive'], @@ -865,100 +886,11 @@ describe('Visitor', () => { ]); }); - describe('Support for custom AST nodes', () => { - const customAST = parse('{ a }'); - (customAST: any).definitions[0].selectionSet.selections.push({ - kind: 'CustomField', - name: { - kind: 'Name', - value: 'b', - }, - selectionSet: { - kind: 'SelectionSet', - selections: [ - { - kind: 'CustomField', - name: { - kind: 'Name', - value: 'c', - }, - }, - ], - }, - }); - - it('does not traverse unknown node kinds', () => { - const visited = []; - visit(customAST, { - enter(node) { - visited.push(['enter', node.kind, getValue(node)]); - }, - leave(node) { - visited.push(['leave', node.kind, getValue(node)]); - }, - }); - - expect(visited).to.deep.equal([ - ['enter', 'Document', undefined], - ['enter', 'OperationDefinition', undefined], - ['enter', 'SelectionSet', undefined], - ['enter', 'Field', undefined], - ['enter', 'Name', 'a'], - ['leave', 'Name', 'a'], - ['leave', 'Field', undefined], - ['enter', 'CustomField', undefined], - ['leave', 'CustomField', undefined], - ['leave', 'SelectionSet', undefined], - ['leave', 'OperationDefinition', undefined], - ['leave', 'Document', undefined], - ]); - }); - - it('does traverse unknown node kinds with visitor keys', () => { - const customQueryDocumentKeys = { ...QueryDocumentKeys }; - (customQueryDocumentKeys: any).CustomField = ['name', 'selectionSet']; - - const visited = []; - const visitor = { - enter(node) { - visited.push(['enter', node.kind, getValue(node)]); - }, - leave(node) { - visited.push(['leave', node.kind, getValue(node)]); - }, - }; - visit(customAST, visitor, customQueryDocumentKeys); - - expect(visited).to.deep.equal([ - ['enter', 'Document', undefined], - ['enter', 'OperationDefinition', undefined], - ['enter', 'SelectionSet', undefined], - ['enter', 'Field', undefined], - ['enter', 'Name', 'a'], - ['leave', 'Name', 'a'], - ['leave', 'Field', undefined], - ['enter', 'CustomField', undefined], - ['enter', 'Name', 'b'], - ['leave', 'Name', 'b'], - ['enter', 'SelectionSet', undefined], - ['enter', 'CustomField', undefined], - ['enter', 'Name', 'c'], - ['leave', 'Name', 'c'], - ['leave', 'CustomField', undefined], - ['leave', 'SelectionSet', undefined], - ['leave', 'CustomField', undefined], - ['leave', 'SelectionSet', undefined], - ['leave', 'OperationDefinition', undefined], - ['leave', 'Document', undefined], - ]); - }); - }); - describe('visitInParallel', () => { // Note: nearly identical to the above test of the same test but // using visitInParallel. it('allows skipping a sub-tree', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b { x }, c }'); visit( @@ -1001,7 +933,7 @@ describe('Visitor', () => { }); it('allows skipping different sub-trees', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a { x }, b { y} }'); visit( @@ -1077,7 +1009,7 @@ describe('Visitor', () => { // Note: nearly identical to the above test of the same test but // using visitInParallel. it('allows early exit while visiting', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b { x }, c }'); visit( @@ -1117,7 +1049,7 @@ describe('Visitor', () => { }); it('allows early exit from different points', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a { y }, b { x } }'); visit( @@ -1131,9 +1063,9 @@ describe('Visitor', () => { return BREAK; } }, - // istanbul ignore next (Never called and used as a placeholder) + /* c8 ignore next 3 */ leave() { - invariant(false); + expect.fail('Should not be called'); }, }, { @@ -1179,7 +1111,7 @@ describe('Visitor', () => { // Note: nearly identical to the above test of the same test but // using visitInParallel. it('allows early exit while leaving', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b { x }, c }'); visit( @@ -1220,7 +1152,7 @@ describe('Visitor', () => { }); it('allows early exit from leaving different points', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a { y }, b { x } }'); visit( @@ -1296,7 +1228,7 @@ describe('Visitor', () => { }); it('allows for editing on enter', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true }); const editedAST = visit( @@ -1360,7 +1292,7 @@ describe('Visitor', () => { }); it('allows for editing on leave', () => { - const visited = []; + const visited: Array = []; const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true }); const editedAST = visit( diff --git a/src/language/ast.js b/src/language/ast.js deleted file mode 100644 index 0b69454977..0000000000 --- a/src/language/ast.js +++ /dev/null @@ -1,636 +0,0 @@ -import defineInspect from '../jsutils/defineInspect'; - -import type { Source } from './source'; -import type { TokenKindEnum } from './tokenKind'; - -/** - * Contains a range of UTF-8 character offsets and token references that - * identify the region of the source from which the AST derived. - */ -export class Location { - /** - * The character offset at which this Node begins. - */ - +start: number; - - /** - * The character offset at which this Node ends. - */ - +end: number; - - /** - * The Token at which this Node begins. - */ - +startToken: Token; - - /** - * The Token at which this Node ends. - */ - +endToken: Token; - - /** - * The Source document the AST represents. - */ - +source: Source; - - constructor(startToken: Token, endToken: Token, source: Source) { - this.start = startToken.start; - this.end = endToken.end; - this.startToken = startToken; - this.endToken = endToken; - this.source = source; - } - - toJSON(): {| start: number, end: number |} { - return { start: this.start, end: this.end }; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(Location); - -/** - * Represents a range of characters represented by a lexical token - * within a Source. - */ -export class Token { - /** - * The kind of Token. - */ - +kind: TokenKindEnum; - - /** - * The character offset at which this Node begins. - */ - +start: number; - - /** - * The character offset at which this Node ends. - */ - +end: number; - - /** - * The 1-indexed line number on which this Token appears. - */ - +line: number; - - /** - * The 1-indexed column number at which this Token begins. - */ - +column: number; - - /** - * For non-punctuation tokens, represents the interpreted value of the token. - */ - +value: string | void; - - /** - * Tokens exist as nodes in a double-linked-list amongst all tokens - * including ignored tokens. is always the first node and - * the last. - */ - +prev: Token | null; - +next: Token | null; - - constructor( - kind: TokenKindEnum, - start: number, - end: number, - line: number, - column: number, - prev: Token | null, - value?: string, - ) { - this.kind = kind; - this.start = start; - this.end = end; - this.line = line; - this.column = column; - this.value = value; - this.prev = prev; - this.next = null; - } - - toJSON(): {| - kind: TokenKindEnum, - value: string | void, - line: number, - column: number, - |} { - return { - kind: this.kind, - value: this.value, - line: this.line, - column: this.column, - }; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(Token); - -/** - * @internal - */ -export function isNode(maybeNode: mixed): boolean %checks { - return maybeNode != null && typeof maybeNode.kind === 'string'; -} - -/** - * The list of all possible AST node types. - */ -export type ASTNode = - | NameNode - | DocumentNode - | OperationDefinitionNode - | VariableDefinitionNode - | VariableNode - | SelectionSetNode - | FieldNode - | ArgumentNode - | FragmentSpreadNode - | InlineFragmentNode - | FragmentDefinitionNode - | IntValueNode - | FloatValueNode - | StringValueNode - | BooleanValueNode - | NullValueNode - | EnumValueNode - | ListValueNode - | ObjectValueNode - | ObjectFieldNode - | DirectiveNode - | NamedTypeNode - | ListTypeNode - | NonNullTypeNode - | SchemaDefinitionNode - | OperationTypeDefinitionNode - | ScalarTypeDefinitionNode - | ObjectTypeDefinitionNode - | FieldDefinitionNode - | InputValueDefinitionNode - | InterfaceTypeDefinitionNode - | UnionTypeDefinitionNode - | EnumTypeDefinitionNode - | EnumValueDefinitionNode - | InputObjectTypeDefinitionNode - | DirectiveDefinitionNode - | SchemaExtensionNode - | ScalarTypeExtensionNode - | ObjectTypeExtensionNode - | InterfaceTypeExtensionNode - | UnionTypeExtensionNode - | EnumTypeExtensionNode - | InputObjectTypeExtensionNode; - -/** - * Utility type listing all nodes indexed by their kind. - */ -export type ASTKindToNode = {| - Name: NameNode, - Document: DocumentNode, - OperationDefinition: OperationDefinitionNode, - VariableDefinition: VariableDefinitionNode, - Variable: VariableNode, - SelectionSet: SelectionSetNode, - Field: FieldNode, - Argument: ArgumentNode, - FragmentSpread: FragmentSpreadNode, - InlineFragment: InlineFragmentNode, - FragmentDefinition: FragmentDefinitionNode, - IntValue: IntValueNode, - FloatValue: FloatValueNode, - StringValue: StringValueNode, - BooleanValue: BooleanValueNode, - NullValue: NullValueNode, - EnumValue: EnumValueNode, - ListValue: ListValueNode, - ObjectValue: ObjectValueNode, - ObjectField: ObjectFieldNode, - Directive: DirectiveNode, - NamedType: NamedTypeNode, - ListType: ListTypeNode, - NonNullType: NonNullTypeNode, - SchemaDefinition: SchemaDefinitionNode, - OperationTypeDefinition: OperationTypeDefinitionNode, - ScalarTypeDefinition: ScalarTypeDefinitionNode, - ObjectTypeDefinition: ObjectTypeDefinitionNode, - FieldDefinition: FieldDefinitionNode, - InputValueDefinition: InputValueDefinitionNode, - InterfaceTypeDefinition: InterfaceTypeDefinitionNode, - UnionTypeDefinition: UnionTypeDefinitionNode, - EnumTypeDefinition: EnumTypeDefinitionNode, - EnumValueDefinition: EnumValueDefinitionNode, - InputObjectTypeDefinition: InputObjectTypeDefinitionNode, - DirectiveDefinition: DirectiveDefinitionNode, - SchemaExtension: SchemaExtensionNode, - ScalarTypeExtension: ScalarTypeExtensionNode, - ObjectTypeExtension: ObjectTypeExtensionNode, - InterfaceTypeExtension: InterfaceTypeExtensionNode, - UnionTypeExtension: UnionTypeExtensionNode, - EnumTypeExtension: EnumTypeExtensionNode, - InputObjectTypeExtension: InputObjectTypeExtensionNode, -|}; - -// Name - -export type NameNode = {| - +kind: 'Name', - +loc?: Location, - +value: string, -|}; - -// Document - -export type DocumentNode = {| - +kind: 'Document', - +loc?: Location, - +definitions: $ReadOnlyArray, -|}; - -export type DefinitionNode = - | ExecutableDefinitionNode - | TypeSystemDefinitionNode - | TypeSystemExtensionNode; - -export type ExecutableDefinitionNode = - | OperationDefinitionNode - | FragmentDefinitionNode; - -export type OperationDefinitionNode = {| - +kind: 'OperationDefinition', - +loc?: Location, - +operation: OperationTypeNode, - +name?: NameNode, - +variableDefinitions?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +selectionSet: SelectionSetNode, -|}; - -export type OperationTypeNode = 'query' | 'mutation' | 'subscription'; - -export type VariableDefinitionNode = {| - +kind: 'VariableDefinition', - +loc?: Location, - +variable: VariableNode, - +type: TypeNode, - +defaultValue?: ValueNode, - +directives?: $ReadOnlyArray, -|}; - -export type VariableNode = {| - +kind: 'Variable', - +loc?: Location, - +name: NameNode, -|}; - -export type SelectionSetNode = {| - kind: 'SelectionSet', - loc?: Location, - selections: $ReadOnlyArray, -|}; - -export type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode; - -export type FieldNode = {| - +kind: 'Field', - +loc?: Location, - +alias?: NameNode, - +name: NameNode, - +arguments?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +selectionSet?: SelectionSetNode, -|}; - -export type ArgumentNode = {| - +kind: 'Argument', - +loc?: Location, - +name: NameNode, - +value: ValueNode, -|}; - -// Fragments - -export type FragmentSpreadNode = {| - +kind: 'FragmentSpread', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type InlineFragmentNode = {| - +kind: 'InlineFragment', - +loc?: Location, - +typeCondition?: NamedTypeNode, - +directives?: $ReadOnlyArray, - +selectionSet: SelectionSetNode, -|}; - -export type FragmentDefinitionNode = {| - +kind: 'FragmentDefinition', - +loc?: Location, - +name: NameNode, - // Note: fragment variable definitions are experimental and may be changed - // or removed in the future. - +variableDefinitions?: $ReadOnlyArray, - +typeCondition: NamedTypeNode, - +directives?: $ReadOnlyArray, - +selectionSet: SelectionSetNode, -|}; - -// Values - -export type ValueNode = - | VariableNode - | IntValueNode - | FloatValueNode - | StringValueNode - | BooleanValueNode - | NullValueNode - | EnumValueNode - | ListValueNode - | ObjectValueNode; - -export type IntValueNode = {| - +kind: 'IntValue', - +loc?: Location, - +value: string, -|}; - -export type FloatValueNode = {| - +kind: 'FloatValue', - +loc?: Location, - +value: string, -|}; - -export type StringValueNode = {| - +kind: 'StringValue', - +loc?: Location, - +value: string, - +block?: boolean, -|}; - -export type BooleanValueNode = {| - +kind: 'BooleanValue', - +loc?: Location, - +value: boolean, -|}; - -export type NullValueNode = {| - +kind: 'NullValue', - +loc?: Location, -|}; - -export type EnumValueNode = {| - +kind: 'EnumValue', - +loc?: Location, - +value: string, -|}; - -export type ListValueNode = {| - +kind: 'ListValue', - +loc?: Location, - +values: $ReadOnlyArray, -|}; - -export type ObjectValueNode = {| - +kind: 'ObjectValue', - +loc?: Location, - +fields: $ReadOnlyArray, -|}; - -export type ObjectFieldNode = {| - +kind: 'ObjectField', - +loc?: Location, - +name: NameNode, - +value: ValueNode, -|}; - -// Directives - -export type DirectiveNode = {| - +kind: 'Directive', - +loc?: Location, - +name: NameNode, - +arguments?: $ReadOnlyArray, -|}; - -// Type Reference - -export type TypeNode = NamedTypeNode | ListTypeNode | NonNullTypeNode; - -export type NamedTypeNode = {| - +kind: 'NamedType', - +loc?: Location, - +name: NameNode, -|}; - -export type ListTypeNode = {| - +kind: 'ListType', - +loc?: Location, - +type: TypeNode, -|}; - -export type NonNullTypeNode = {| - +kind: 'NonNullType', - +loc?: Location, - +type: NamedTypeNode | ListTypeNode, -|}; - -// Type System Definition - -export type TypeSystemDefinitionNode = - | SchemaDefinitionNode - | TypeDefinitionNode - | DirectiveDefinitionNode; - -export type SchemaDefinitionNode = {| - +kind: 'SchemaDefinition', - +loc?: Location, - +description?: StringValueNode, - +directives?: $ReadOnlyArray, - +operationTypes: $ReadOnlyArray, -|}; - -export type OperationTypeDefinitionNode = {| - +kind: 'OperationTypeDefinition', - +loc?: Location, - +operation: OperationTypeNode, - +type: NamedTypeNode, -|}; - -// Type Definition - -export type TypeDefinitionNode = - | ScalarTypeDefinitionNode - | ObjectTypeDefinitionNode - | InterfaceTypeDefinitionNode - | UnionTypeDefinitionNode - | EnumTypeDefinitionNode - | InputObjectTypeDefinitionNode; - -export type ScalarTypeDefinitionNode = {| - +kind: 'ScalarTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type ObjectTypeDefinitionNode = {| - +kind: 'ObjectTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type FieldDefinitionNode = {| - +kind: 'FieldDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +arguments?: $ReadOnlyArray, - +type: TypeNode, - +directives?: $ReadOnlyArray, -|}; - -export type InputValueDefinitionNode = {| - +kind: 'InputValueDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +type: TypeNode, - +defaultValue?: ValueNode, - +directives?: $ReadOnlyArray, -|}; - -export type InterfaceTypeDefinitionNode = {| - +kind: 'InterfaceTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type UnionTypeDefinitionNode = {| - +kind: 'UnionTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, - +types?: $ReadOnlyArray, -|}; - -export type EnumTypeDefinitionNode = {| - +kind: 'EnumTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, - +values?: $ReadOnlyArray, -|}; - -export type EnumValueDefinitionNode = {| - +kind: 'EnumValueDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type InputObjectTypeDefinitionNode = {| - +kind: 'InputObjectTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -// Directive Definitions - -export type DirectiveDefinitionNode = {| - +kind: 'DirectiveDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +arguments?: $ReadOnlyArray, - +repeatable: boolean, - +locations: $ReadOnlyArray, -|}; - -// Type System Extensions - -export type TypeSystemExtensionNode = SchemaExtensionNode | TypeExtensionNode; - -export type SchemaExtensionNode = {| - +kind: 'SchemaExtension', - +loc?: Location, - +directives?: $ReadOnlyArray, - +operationTypes?: $ReadOnlyArray, -|}; - -// Type Extensions - -export type TypeExtensionNode = - | ScalarTypeExtensionNode - | ObjectTypeExtensionNode - | InterfaceTypeExtensionNode - | UnionTypeExtensionNode - | EnumTypeExtensionNode - | InputObjectTypeExtensionNode; - -export type ScalarTypeExtensionNode = {| - +kind: 'ScalarTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type ObjectTypeExtensionNode = {| - +kind: 'ObjectTypeExtension', - +loc?: Location, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type InterfaceTypeExtensionNode = {| - +kind: 'InterfaceTypeExtension', - +loc?: Location, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type UnionTypeExtensionNode = {| - +kind: 'UnionTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, - +types?: $ReadOnlyArray, -|}; - -export type EnumTypeExtensionNode = {| - +kind: 'EnumTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, - +values?: $ReadOnlyArray, -|}; - -export type InputObjectTypeExtensionNode = {| - +kind: 'InputObjectTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; diff --git a/src/language/ast.d.ts b/src/language/ast.ts similarity index 56% rename from src/language/ast.d.ts rename to src/language/ast.ts index 61cb9f4eb5..6137eb6c1a 100644 --- a/src/language/ast.d.ts +++ b/src/language/ast.ts @@ -1,5 +1,6 @@ -import { Source } from './source'; -import { TokenKindEnum } from './tokenKind'; +import type { Kind } from './kinds'; +import type { Source } from './source'; +import type { TokenKind } from './tokenKind'; /** * Contains a range of UTF-8 character offsets and token references that @@ -31,9 +32,21 @@ export class Location { */ readonly source: Source; - constructor(startToken: Token, endToken: Token, source: Source); + constructor(startToken: Token, endToken: Token, source: Source) { + this.start = startToken.start; + this.end = endToken.end; + this.startToken = startToken; + this.endToken = endToken; + this.source = source; + } - toJSON(): { start: number; end: number }; + get [Symbol.toStringTag]() { + return 'Location'; + } + + toJSON(): { start: number; end: number } { + return { start: this.start, end: this.end }; + } } /** @@ -44,7 +57,7 @@ export class Token { /** * The kind of Token. */ - readonly kind: TokenKindEnum; + readonly kind: TokenKind; /** * The character offset at which this Node begins. @@ -68,8 +81,11 @@ export class Token { /** * For non-punctuation tokens, represents the interpreted value of the token. + * + * Note: is undefined for punctuation tokens, but typed as string for + * convenience in the parser. */ - readonly value: string | undefined; + readonly value: string; /** * Tokens exist as nodes in a double-linked-list amongst all tokens @@ -80,28 +96,43 @@ export class Token { readonly next: Token | null; constructor( - kind: TokenKindEnum, + kind: TokenKind, start: number, end: number, line: number, column: number, - prev: Token | null, value?: string, - ); + ) { + this.kind = kind; + this.start = start; + this.end = end; + this.line = line; + this.column = column; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.value = value!; + this.prev = null; + this.next = null; + } + + get [Symbol.toStringTag]() { + return 'Token'; + } toJSON(): { - kind: TokenKindEnum; - value: string | undefined; + kind: TokenKind; + value?: string; line: number; column: number; - }; + } { + return { + kind: this.kind, + value: this.value, + line: this.line, + column: this.column, + }; + } } -/** - * @internal - */ -export function isNode(maybeNode: any): maybeNode is ASTNode; - /** * The list of all possible AST node types. */ @@ -153,66 +184,125 @@ export type ASTNode = /** * Utility type listing all nodes indexed by their kind. */ -export interface ASTKindToNode { - Name: NameNode; - Document: DocumentNode; - OperationDefinition: OperationDefinitionNode; - VariableDefinition: VariableDefinitionNode; - Variable: VariableNode; - SelectionSet: SelectionSetNode; - Field: FieldNode; - Argument: ArgumentNode; - FragmentSpread: FragmentSpreadNode; - InlineFragment: InlineFragmentNode; - FragmentDefinition: FragmentDefinitionNode; - IntValue: IntValueNode; - FloatValue: FloatValueNode; - StringValue: StringValueNode; - BooleanValue: BooleanValueNode; - NullValue: NullValueNode; - EnumValue: EnumValueNode; - ListValue: ListValueNode; - ObjectValue: ObjectValueNode; - ObjectField: ObjectFieldNode; - Directive: DirectiveNode; - NamedType: NamedTypeNode; - ListType: ListTypeNode; - NonNullType: NonNullTypeNode; - SchemaDefinition: SchemaDefinitionNode; - OperationTypeDefinition: OperationTypeDefinitionNode; - ScalarTypeDefinition: ScalarTypeDefinitionNode; - ObjectTypeDefinition: ObjectTypeDefinitionNode; - FieldDefinition: FieldDefinitionNode; - InputValueDefinition: InputValueDefinitionNode; - InterfaceTypeDefinition: InterfaceTypeDefinitionNode; - UnionTypeDefinition: UnionTypeDefinitionNode; - EnumTypeDefinition: EnumTypeDefinitionNode; - EnumValueDefinition: EnumValueDefinitionNode; - InputObjectTypeDefinition: InputObjectTypeDefinitionNode; - DirectiveDefinition: DirectiveDefinitionNode; - SchemaExtension: SchemaExtensionNode; - ScalarTypeExtension: ScalarTypeExtensionNode; - ObjectTypeExtension: ObjectTypeExtensionNode; - InterfaceTypeExtension: InterfaceTypeExtensionNode; - UnionTypeExtension: UnionTypeExtensionNode; - EnumTypeExtension: EnumTypeExtensionNode; - InputObjectTypeExtension: InputObjectTypeExtensionNode; -} - -// Name +export type ASTKindToNode = { + [NodeT in ASTNode as NodeT['kind']]: NodeT; +}; + +/** + * @internal + */ +export const QueryDocumentKeys: { + [NodeT in ASTNode as NodeT['kind']]: ReadonlyArray; +} = { + Name: [], + + Document: ['definitions'], + OperationDefinition: [ + 'name', + 'variableDefinitions', + 'directives', + 'selectionSet', + ], + VariableDefinition: ['variable', 'type', 'defaultValue', 'directives'], + Variable: ['name'], + SelectionSet: ['selections'], + Field: ['alias', 'name', 'arguments', 'directives', 'selectionSet'], + Argument: ['name', 'value'], + + FragmentSpread: ['name', 'directives'], + InlineFragment: ['typeCondition', 'directives', 'selectionSet'], + FragmentDefinition: [ + 'name', + // Note: fragment variable definitions are deprecated and will removed in v17.0.0 + 'variableDefinitions', + 'typeCondition', + 'directives', + 'selectionSet', + ], + + IntValue: [], + FloatValue: [], + StringValue: [], + BooleanValue: [], + NullValue: [], + EnumValue: [], + ListValue: ['values'], + ObjectValue: ['fields'], + ObjectField: ['name', 'value'], + + Directive: ['name', 'arguments'], + + NamedType: ['name'], + ListType: ['type'], + NonNullType: ['type'], + + SchemaDefinition: ['description', 'directives', 'operationTypes'], + OperationTypeDefinition: ['type'], + + ScalarTypeDefinition: ['description', 'name', 'directives'], + ObjectTypeDefinition: [ + 'description', + 'name', + 'interfaces', + 'directives', + 'fields', + ], + FieldDefinition: ['description', 'name', 'arguments', 'type', 'directives'], + InputValueDefinition: [ + 'description', + 'name', + 'type', + 'defaultValue', + 'directives', + ], + InterfaceTypeDefinition: [ + 'description', + 'name', + 'interfaces', + 'directives', + 'fields', + ], + UnionTypeDefinition: ['description', 'name', 'directives', 'types'], + EnumTypeDefinition: ['description', 'name', 'directives', 'values'], + EnumValueDefinition: ['description', 'name', 'directives'], + InputObjectTypeDefinition: ['description', 'name', 'directives', 'fields'], + + DirectiveDefinition: ['description', 'name', 'arguments', 'locations'], + + SchemaExtension: ['directives', 'operationTypes'], + + ScalarTypeExtension: ['name', 'directives'], + ObjectTypeExtension: ['name', 'interfaces', 'directives', 'fields'], + InterfaceTypeExtension: ['name', 'interfaces', 'directives', 'fields'], + UnionTypeExtension: ['name', 'directives', 'types'], + EnumTypeExtension: ['name', 'directives', 'values'], + InputObjectTypeExtension: ['name', 'directives', 'fields'], +}; + +const kindValues = new Set(Object.keys(QueryDocumentKeys)); +/** + * @internal + */ +export function isNode(maybeNode: any): maybeNode is ASTNode { + const maybeKind = maybeNode?.kind; + return typeof maybeKind === 'string' && kindValues.has(maybeKind); +} + +/** Name */ export interface NameNode { - readonly kind: 'Name'; + readonly kind: Kind.NAME; readonly loc?: Location; readonly value: string; } -// Document +/** Document */ export interface DocumentNode { - readonly kind: 'Document'; + readonly kind: Kind.DOCUMENT; readonly loc?: Location; readonly definitions: ReadonlyArray; + readonly tokenCount?: number | undefined; } export type DefinitionNode = @@ -225,7 +315,7 @@ export type ExecutableDefinitionNode = | FragmentDefinitionNode; export interface OperationDefinitionNode { - readonly kind: 'OperationDefinition'; + readonly kind: Kind.OPERATION_DEFINITION; readonly loc?: Location; readonly operation: OperationTypeNode; readonly name?: NameNode; @@ -234,25 +324,30 @@ export interface OperationDefinitionNode { readonly selectionSet: SelectionSetNode; } -export type OperationTypeNode = 'query' | 'mutation' | 'subscription'; +enum OperationTypeNode { + QUERY = 'query', + MUTATION = 'mutation', + SUBSCRIPTION = 'subscription', +} +export { OperationTypeNode }; export interface VariableDefinitionNode { - readonly kind: 'VariableDefinition'; + readonly kind: Kind.VARIABLE_DEFINITION; readonly loc?: Location; readonly variable: VariableNode; readonly type: TypeNode; - readonly defaultValue?: ValueNode; - readonly directives?: ReadonlyArray; + readonly defaultValue?: ConstValueNode; + readonly directives?: ReadonlyArray; } export interface VariableNode { - readonly kind: 'Variable'; + readonly kind: Kind.VARIABLE; readonly loc?: Location; readonly name: NameNode; } export interface SelectionSetNode { - kind: 'SelectionSet'; + kind: Kind.SELECTION_SET; loc?: Location; selections: ReadonlyArray; } @@ -260,7 +355,7 @@ export interface SelectionSetNode { export type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode; export interface FieldNode { - readonly kind: 'Field'; + readonly kind: Kind.FIELD; readonly loc?: Location; readonly alias?: NameNode; readonly name: NameNode; @@ -270,23 +365,30 @@ export interface FieldNode { } export interface ArgumentNode { - readonly kind: 'Argument'; + readonly kind: Kind.ARGUMENT; readonly loc?: Location; readonly name: NameNode; readonly value: ValueNode; } -// Fragments +export interface ConstArgumentNode { + readonly kind: Kind.ARGUMENT; + readonly loc?: Location; + readonly name: NameNode; + readonly value: ConstValueNode; +} + +/** Fragments */ export interface FragmentSpreadNode { - readonly kind: 'FragmentSpread'; + readonly kind: Kind.FRAGMENT_SPREAD; readonly loc?: Location; readonly name: NameNode; readonly directives?: ReadonlyArray; } export interface InlineFragmentNode { - readonly kind: 'InlineFragment'; + readonly kind: Kind.INLINE_FRAGMENT; readonly loc?: Location; readonly typeCondition?: NamedTypeNode; readonly directives?: ReadonlyArray; @@ -294,18 +396,17 @@ export interface InlineFragmentNode { } export interface FragmentDefinitionNode { - readonly kind: 'FragmentDefinition'; + readonly kind: Kind.FRAGMENT_DEFINITION; readonly loc?: Location; readonly name: NameNode; - // Note: fragment variable definitions are experimental and may be changed - // or removed in the future. + /** @deprecated variableDefinitions will be removed in v17.0.0 */ readonly variableDefinitions?: ReadonlyArray; readonly typeCondition: NamedTypeNode; readonly directives?: ReadonlyArray; readonly selectionSet: SelectionSetNode; } -// Values +/** Values */ export type ValueNode = | VariableNode @@ -318,93 +419,129 @@ export type ValueNode = | ListValueNode | ObjectValueNode; +export type ConstValueNode = + | IntValueNode + | FloatValueNode + | StringValueNode + | BooleanValueNode + | NullValueNode + | EnumValueNode + | ConstListValueNode + | ConstObjectValueNode; + export interface IntValueNode { - readonly kind: 'IntValue'; + readonly kind: Kind.INT; readonly loc?: Location; readonly value: string; } export interface FloatValueNode { - readonly kind: 'FloatValue'; + readonly kind: Kind.FLOAT; readonly loc?: Location; readonly value: string; } export interface StringValueNode { - readonly kind: 'StringValue'; + readonly kind: Kind.STRING; readonly loc?: Location; readonly value: string; readonly block?: boolean; } export interface BooleanValueNode { - readonly kind: 'BooleanValue'; + readonly kind: Kind.BOOLEAN; readonly loc?: Location; readonly value: boolean; } export interface NullValueNode { - readonly kind: 'NullValue'; + readonly kind: Kind.NULL; readonly loc?: Location; } export interface EnumValueNode { - readonly kind: 'EnumValue'; + readonly kind: Kind.ENUM; readonly loc?: Location; readonly value: string; } export interface ListValueNode { - readonly kind: 'ListValue'; + readonly kind: Kind.LIST; readonly loc?: Location; readonly values: ReadonlyArray; } +export interface ConstListValueNode { + readonly kind: Kind.LIST; + readonly loc?: Location; + readonly values: ReadonlyArray; +} + export interface ObjectValueNode { - readonly kind: 'ObjectValue'; + readonly kind: Kind.OBJECT; readonly loc?: Location; readonly fields: ReadonlyArray; } +export interface ConstObjectValueNode { + readonly kind: Kind.OBJECT; + readonly loc?: Location; + readonly fields: ReadonlyArray; +} + export interface ObjectFieldNode { - readonly kind: 'ObjectField'; + readonly kind: Kind.OBJECT_FIELD; readonly loc?: Location; readonly name: NameNode; readonly value: ValueNode; } -// Directives +export interface ConstObjectFieldNode { + readonly kind: Kind.OBJECT_FIELD; + readonly loc?: Location; + readonly name: NameNode; + readonly value: ConstValueNode; +} + +/** Directives */ export interface DirectiveNode { - readonly kind: 'Directive'; + readonly kind: Kind.DIRECTIVE; readonly loc?: Location; readonly name: NameNode; readonly arguments?: ReadonlyArray; } -// Type Reference +export interface ConstDirectiveNode { + readonly kind: Kind.DIRECTIVE; + readonly loc?: Location; + readonly name: NameNode; + readonly arguments?: ReadonlyArray; +} + +/** Type Reference */ export type TypeNode = NamedTypeNode | ListTypeNode | NonNullTypeNode; export interface NamedTypeNode { - readonly kind: 'NamedType'; + readonly kind: Kind.NAMED_TYPE; readonly loc?: Location; readonly name: NameNode; } export interface ListTypeNode { - readonly kind: 'ListType'; + readonly kind: Kind.LIST_TYPE; readonly loc?: Location; readonly type: TypeNode; } export interface NonNullTypeNode { - readonly kind: 'NonNullType'; + readonly kind: Kind.NON_NULL_TYPE; readonly loc?: Location; readonly type: NamedTypeNode | ListTypeNode; } -// Type System Definition +/** Type System Definition */ export type TypeSystemDefinitionNode = | SchemaDefinitionNode @@ -412,21 +549,21 @@ export type TypeSystemDefinitionNode = | DirectiveDefinitionNode; export interface SchemaDefinitionNode { - readonly kind: 'SchemaDefinition'; + readonly kind: Kind.SCHEMA_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly operationTypes: ReadonlyArray; } export interface OperationTypeDefinitionNode { - readonly kind: 'OperationTypeDefinition'; + readonly kind: Kind.OPERATION_TYPE_DEFINITION; readonly loc?: Location; readonly operation: OperationTypeNode; readonly type: NamedTypeNode; } -// Type Definition +/** Type Definition */ export type TypeDefinitionNode = | ScalarTypeDefinitionNode @@ -437,92 +574,92 @@ export type TypeDefinitionNode = | InputObjectTypeDefinitionNode; export interface ScalarTypeDefinitionNode { - readonly kind: 'ScalarTypeDefinition'; + readonly kind: Kind.SCALAR_TYPE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; } export interface ObjectTypeDefinitionNode { - readonly kind: 'ObjectTypeDefinition'; + readonly kind: Kind.OBJECT_TYPE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; readonly interfaces?: ReadonlyArray; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly fields?: ReadonlyArray; } export interface FieldDefinitionNode { - readonly kind: 'FieldDefinition'; + readonly kind: Kind.FIELD_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; readonly arguments?: ReadonlyArray; readonly type: TypeNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; } export interface InputValueDefinitionNode { - readonly kind: 'InputValueDefinition'; + readonly kind: Kind.INPUT_VALUE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; readonly type: TypeNode; - readonly defaultValue?: ValueNode; - readonly directives?: ReadonlyArray; + readonly defaultValue?: ConstValueNode; + readonly directives?: ReadonlyArray; } export interface InterfaceTypeDefinitionNode { - readonly kind: 'InterfaceTypeDefinition'; + readonly kind: Kind.INTERFACE_TYPE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; readonly interfaces?: ReadonlyArray; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly fields?: ReadonlyArray; } export interface UnionTypeDefinitionNode { - readonly kind: 'UnionTypeDefinition'; + readonly kind: Kind.UNION_TYPE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly types?: ReadonlyArray; } export interface EnumTypeDefinitionNode { - readonly kind: 'EnumTypeDefinition'; + readonly kind: Kind.ENUM_TYPE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly values?: ReadonlyArray; } export interface EnumValueDefinitionNode { - readonly kind: 'EnumValueDefinition'; + readonly kind: Kind.ENUM_VALUE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; } export interface InputObjectTypeDefinitionNode { - readonly kind: 'InputObjectTypeDefinition'; + readonly kind: Kind.INPUT_OBJECT_TYPE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly fields?: ReadonlyArray; } -// Directive Definitions +/** Directive Definitions */ export interface DirectiveDefinitionNode { - readonly kind: 'DirectiveDefinition'; + readonly kind: Kind.DIRECTIVE_DEFINITION; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -531,18 +668,18 @@ export interface DirectiveDefinitionNode { readonly locations: ReadonlyArray; } -// Type System Extensions +/** Type System Extensions */ export type TypeSystemExtensionNode = SchemaExtensionNode | TypeExtensionNode; export interface SchemaExtensionNode { - readonly kind: 'SchemaExtension'; + readonly kind: Kind.SCHEMA_EXTENSION; readonly loc?: Location; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly operationTypes?: ReadonlyArray; } -// Type Extensions +/** Type Extensions */ export type TypeExtensionNode = | ScalarTypeExtensionNode @@ -553,50 +690,50 @@ export type TypeExtensionNode = | InputObjectTypeExtensionNode; export interface ScalarTypeExtensionNode { - readonly kind: 'ScalarTypeExtension'; + readonly kind: Kind.SCALAR_TYPE_EXTENSION; readonly loc?: Location; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; } export interface ObjectTypeExtensionNode { - readonly kind: 'ObjectTypeExtension'; + readonly kind: Kind.OBJECT_TYPE_EXTENSION; readonly loc?: Location; readonly name: NameNode; readonly interfaces?: ReadonlyArray; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly fields?: ReadonlyArray; } export interface InterfaceTypeExtensionNode { - readonly kind: 'InterfaceTypeExtension'; + readonly kind: Kind.INTERFACE_TYPE_EXTENSION; readonly loc?: Location; readonly name: NameNode; readonly interfaces?: ReadonlyArray; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly fields?: ReadonlyArray; } export interface UnionTypeExtensionNode { - readonly kind: 'UnionTypeExtension'; + readonly kind: Kind.UNION_TYPE_EXTENSION; readonly loc?: Location; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly types?: ReadonlyArray; } export interface EnumTypeExtensionNode { - readonly kind: 'EnumTypeExtension'; + readonly kind: Kind.ENUM_TYPE_EXTENSION; readonly loc?: Location; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly values?: ReadonlyArray; } export interface InputObjectTypeExtensionNode { - readonly kind: 'InputObjectTypeExtension'; + readonly kind: Kind.INPUT_OBJECT_TYPE_EXTENSION; readonly loc?: Location; readonly name: NameNode; - readonly directives?: ReadonlyArray; + readonly directives?: ReadonlyArray; readonly fields?: ReadonlyArray; } diff --git a/src/language/blockString.d.ts b/src/language/blockString.d.ts deleted file mode 100644 index 70ffc666c7..0000000000 --- a/src/language/blockString.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Produces the value of a block string from its parsed raw value, similar to - * CoffeeScript's block string, Python's docstring trim or Ruby's strip_heredoc. - * - * This implements the GraphQL spec's BlockStringValue() static algorithm. - */ -export function dedentBlockStringValue(rawString: string): string; - -/** - * @internal - */ -export function getBlockStringIndentation(body: string): number; - -/** - * Print a block string in the indented block form by adding a leading and - * trailing blank line. However, if a block string starts with whitespace and is - * a single-line, adding a leading blank line would strip that whitespace. - */ -export function printBlockString( - value: string, - indentation?: string, - preferMultipleLines?: boolean, -): string; diff --git a/src/language/blockString.js b/src/language/blockString.js deleted file mode 100644 index de72108650..0000000000 --- a/src/language/blockString.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Produces the value of a block string from its parsed raw value, similar to - * CoffeeScript's block string, Python's docstring trim or Ruby's strip_heredoc. - * - * This implements the GraphQL spec's BlockStringValue() static algorithm. - * - * @internal - */ -export function dedentBlockStringValue(rawString: string): string { - // Expand a block string's raw value into independent lines. - const lines = rawString.split(/\r\n|[\n\r]/g); - - // Remove common indentation from all lines but first. - const commonIndent = getBlockStringIndentation(rawString); - - if (commonIndent !== 0) { - for (let i = 1; i < lines.length; i++) { - lines[i] = lines[i].slice(commonIndent); - } - } - - // Remove leading and trailing blank lines. - let startLine = 0; - while (startLine < lines.length && isBlank(lines[startLine])) { - ++startLine; - } - - let endLine = lines.length; - while (endLine > startLine && isBlank(lines[endLine - 1])) { - --endLine; - } - - // Return a string of the lines joined with U+000A. - return lines.slice(startLine, endLine).join('\n'); -} - -function isBlank(str: string): boolean { - for (let i = 0; i < str.length; ++i) { - if (str[i] !== ' ' && str[i] !== '\t') { - return false; - } - } - - return true; -} - -/** - * @internal - */ -export function getBlockStringIndentation(value: string): number { - let isFirstLine = true; - let isEmptyLine = true; - let indent = 0; - let commonIndent = null; - - for (let i = 0; i < value.length; ++i) { - switch (value.charCodeAt(i)) { - case 13: // \r - if (value.charCodeAt(i + 1) === 10) { - ++i; // skip \r\n as one symbol - } - // falls through - case 10: // \n - isFirstLine = false; - isEmptyLine = true; - indent = 0; - break; - case 9: // \t - case 32: // - ++indent; - break; - default: - if ( - isEmptyLine && - !isFirstLine && - (commonIndent === null || indent < commonIndent) - ) { - commonIndent = indent; - } - isEmptyLine = false; - } - } - - return commonIndent ?? 0; -} - -/** - * Print a block string in the indented block form by adding a leading and - * trailing blank line. However, if a block string starts with whitespace and is - * a single-line, adding a leading blank line would strip that whitespace. - * - * @internal - */ -export function printBlockString( - value: string, - indentation: string = '', - preferMultipleLines: boolean = false, -): string { - const isSingleLine = value.indexOf('\n') === -1; - const hasLeadingSpace = value[0] === ' ' || value[0] === '\t'; - const hasTrailingQuote = value[value.length - 1] === '"'; - const hasTrailingSlash = value[value.length - 1] === '\\'; - const printAsMultipleLines = - !isSingleLine || - hasTrailingQuote || - hasTrailingSlash || - preferMultipleLines; - - let result = ''; - // Format a multi-line block quote to account for leading space. - if (printAsMultipleLines && !(isSingleLine && hasLeadingSpace)) { - result += '\n' + indentation; - } - result += indentation ? value.replace(/\n/g, '\n' + indentation) : value; - if (printAsMultipleLines) { - result += '\n'; - } - - return '"""' + result.replace(/"""/g, '\\"""') + '"""'; -} diff --git a/src/language/blockString.ts b/src/language/blockString.ts new file mode 100644 index 0000000000..1c200c183a --- /dev/null +++ b/src/language/blockString.ts @@ -0,0 +1,169 @@ +import { isWhiteSpace } from './characterClasses'; + +/** + * Produces the value of a block string from its parsed raw value, similar to + * CoffeeScript's block string, Python's docstring trim or Ruby's strip_heredoc. + * + * This implements the GraphQL spec's BlockStringValue() static algorithm. + * + * @internal + */ +export function dedentBlockStringLines( + lines: ReadonlyArray, +): Array { + let commonIndent = Number.MAX_SAFE_INTEGER; + let firstNonEmptyLine = null; + let lastNonEmptyLine = -1; + + for (let i = 0; i < lines.length; ++i) { + const line = lines[i]; + const indent = leadingWhitespace(line); + + if (indent === line.length) { + continue; // skip empty lines + } + + firstNonEmptyLine = firstNonEmptyLine ?? i; + lastNonEmptyLine = i; + + if (i !== 0 && indent < commonIndent) { + commonIndent = indent; + } + } + + return ( + lines + // Remove common indentation from all lines but first. + .map((line, i) => (i === 0 ? line : line.slice(commonIndent))) + // Remove leading and trailing blank lines. + .slice(firstNonEmptyLine ?? 0, lastNonEmptyLine + 1) + ); +} + +function leadingWhitespace(str: string): number { + let i = 0; + while (i < str.length && isWhiteSpace(str.charCodeAt(i))) { + ++i; + } + return i; +} + +/** + * @internal + */ +export function isPrintableAsBlockString(value: string): boolean { + if (value === '') { + return true; // empty string is printable + } + + let isEmptyLine = true; + let hasIndent = false; + let hasCommonIndent = true; + let seenNonEmptyLine = false; + + for (let i = 0; i < value.length; ++i) { + switch (value.codePointAt(i)) { + case 0x0000: + case 0x0001: + case 0x0002: + case 0x0003: + case 0x0004: + case 0x0005: + case 0x0006: + case 0x0007: + case 0x0008: + case 0x000b: + case 0x000c: + case 0x000e: + case 0x000f: + return false; // Has non-printable characters + + case 0x000d: // \r + return false; // Has \r or \r\n which will be replaced as \n + + case 10: // \n + if (isEmptyLine && !seenNonEmptyLine) { + return false; // Has leading new line + } + seenNonEmptyLine = true; + + isEmptyLine = true; + hasIndent = false; + break; + case 9: // \t + case 32: // + hasIndent ||= isEmptyLine; + break; + default: + hasCommonIndent &&= hasIndent; + isEmptyLine = false; + } + } + + if (isEmptyLine) { + return false; // Has trailing empty lines + } + + if (hasCommonIndent && seenNonEmptyLine) { + return false; // Has internal indent + } + + return true; +} + +/** + * Print a block string in the indented block form by adding a leading and + * trailing blank line. However, if a block string starts with whitespace and is + * a single-line, adding a leading blank line would strip that whitespace. + * + * @internal + */ +export function printBlockString( + value: string, + options?: { minimize?: boolean }, +): string { + const escapedValue = value.replace(/"""/g, '\\"""'); + + // Expand a block string's raw value into independent lines. + const lines = escapedValue.split(/\r\n|[\n\r]/g); + const isSingleLine = lines.length === 1; + + // If common indentation is found we can fix some of those cases by adding leading new line + const forceLeadingNewLine = + lines.length > 1 && + lines + .slice(1) + .every((line) => line.length === 0 || isWhiteSpace(line.charCodeAt(0))); + + // Trailing triple quotes just looks confusing but doesn't force trailing new line + const hasTrailingTripleQuotes = escapedValue.endsWith('\\"""'); + + // Trailing quote (single or double) or slash forces trailing new line + const hasTrailingQuote = value.endsWith('"') && !hasTrailingTripleQuotes; + const hasTrailingSlash = value.endsWith('\\'); + const forceTrailingNewline = hasTrailingQuote || hasTrailingSlash; + + const printAsMultipleLines = + !options?.minimize && + // add leading and trailing new lines only if it improves readability + (!isSingleLine || + value.length > 70 || + forceTrailingNewline || + forceLeadingNewLine || + hasTrailingTripleQuotes); + + let result = ''; + + // Format a multi-line block quote to account for leading space. + const skipLeadingNewLine = isSingleLine && isWhiteSpace(value.charCodeAt(0)); + if ((printAsMultipleLines && !skipLeadingNewLine) || forceLeadingNewLine) { + result += '\n'; + } + + result += escapedValue; + if (printAsMultipleLines || forceTrailingNewline) { + result += '\n'; + } + + return '"""' + result + '"""'; +} diff --git a/src/language/characterClasses.ts b/src/language/characterClasses.ts new file mode 100644 index 0000000000..c1182d10da --- /dev/null +++ b/src/language/characterClasses.ts @@ -0,0 +1,64 @@ +/** + * ``` + * WhiteSpace :: + * - "Horizontal Tab (U+0009)" + * - "Space (U+0020)" + * ``` + * @internal + */ +export function isWhiteSpace(code: number): boolean { + return code === 0x0009 || code === 0x0020; +} + +/** + * ``` + * Digit :: one of + * - `0` `1` `2` `3` `4` `5` `6` `7` `8` `9` + * ``` + * @internal + */ +export function isDigit(code: number): boolean { + return code >= 0x0030 && code <= 0x0039; +} + +/** + * ``` + * Letter :: one of + * - `A` `B` `C` `D` `E` `F` `G` `H` `I` `J` `K` `L` `M` + * - `N` `O` `P` `Q` `R` `S` `T` `U` `V` `W` `X` `Y` `Z` + * - `a` `b` `c` `d` `e` `f` `g` `h` `i` `j` `k` `l` `m` + * - `n` `o` `p` `q` `r` `s` `t` `u` `v` `w` `x` `y` `z` + * ``` + * @internal + */ +export function isLetter(code: number): boolean { + return ( + (code >= 0x0061 && code <= 0x007a) || // A-Z + (code >= 0x0041 && code <= 0x005a) // a-z + ); +} + +/** + * ``` + * NameStart :: + * - Letter + * - `_` + * ``` + * @internal + */ +export function isNameStart(code: number): boolean { + return isLetter(code) || code === 0x005f; +} + +/** + * ``` + * NameContinue :: + * - Letter + * - Digit + * - `_` + * ``` + * @internal + */ +export function isNameContinue(code: number): boolean { + return isLetter(code) || isDigit(code) || code === 0x005f; +} diff --git a/src/language/directiveLocation.d.ts b/src/language/directiveLocation.d.ts deleted file mode 100644 index 225e129cd8..0000000000 --- a/src/language/directiveLocation.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * The set of allowed directive location values. - */ -export const DirectiveLocation: { - // Request Definitions - QUERY: 'QUERY'; - MUTATION: 'MUTATION'; - SUBSCRIPTION: 'SUBSCRIPTION'; - FIELD: 'FIELD'; - FRAGMENT_DEFINITION: 'FRAGMENT_DEFINITION'; - FRAGMENT_SPREAD: 'FRAGMENT_SPREAD'; - INLINE_FRAGMENT: 'INLINE_FRAGMENT'; - VARIABLE_DEFINITION: 'VARIABLE_DEFINITION'; - - // Type System Definitions - SCHEMA: 'SCHEMA'; - SCALAR: 'SCALAR'; - OBJECT: 'OBJECT'; - FIELD_DEFINITION: 'FIELD_DEFINITION'; - ARGUMENT_DEFINITION: 'ARGUMENT_DEFINITION'; - INTERFACE: 'INTERFACE'; - UNION: 'UNION'; - ENUM: 'ENUM'; - ENUM_VALUE: 'ENUM_VALUE'; - INPUT_OBJECT: 'INPUT_OBJECT'; - INPUT_FIELD_DEFINITION: 'INPUT_FIELD_DEFINITION'; -}; - -/** - * The enum type representing the directive location values. - */ -export type DirectiveLocationEnum = typeof DirectiveLocation[keyof typeof DirectiveLocation]; diff --git a/src/language/directiveLocation.js b/src/language/directiveLocation.js deleted file mode 100644 index 9fa1348cf8..0000000000 --- a/src/language/directiveLocation.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * The set of allowed directive location values. - */ -export const DirectiveLocation = Object.freeze({ - // Request Definitions - QUERY: 'QUERY', - MUTATION: 'MUTATION', - SUBSCRIPTION: 'SUBSCRIPTION', - FIELD: 'FIELD', - FRAGMENT_DEFINITION: 'FRAGMENT_DEFINITION', - FRAGMENT_SPREAD: 'FRAGMENT_SPREAD', - INLINE_FRAGMENT: 'INLINE_FRAGMENT', - VARIABLE_DEFINITION: 'VARIABLE_DEFINITION', - // Type System Definitions - SCHEMA: 'SCHEMA', - SCALAR: 'SCALAR', - OBJECT: 'OBJECT', - FIELD_DEFINITION: 'FIELD_DEFINITION', - ARGUMENT_DEFINITION: 'ARGUMENT_DEFINITION', - INTERFACE: 'INTERFACE', - UNION: 'UNION', - ENUM: 'ENUM', - ENUM_VALUE: 'ENUM_VALUE', - INPUT_OBJECT: 'INPUT_OBJECT', - INPUT_FIELD_DEFINITION: 'INPUT_FIELD_DEFINITION', -}); - -/** - * The enum type representing the directive location values. - */ -export type DirectiveLocationEnum = $Values; diff --git a/src/language/directiveLocation.ts b/src/language/directiveLocation.ts new file mode 100644 index 0000000000..5c8aeb7240 --- /dev/null +++ b/src/language/directiveLocation.ts @@ -0,0 +1,34 @@ +/** + * The set of allowed directive location values. + */ +enum DirectiveLocation { + /** Request Definitions */ + QUERY = 'QUERY', + MUTATION = 'MUTATION', + SUBSCRIPTION = 'SUBSCRIPTION', + FIELD = 'FIELD', + FRAGMENT_DEFINITION = 'FRAGMENT_DEFINITION', + FRAGMENT_SPREAD = 'FRAGMENT_SPREAD', + INLINE_FRAGMENT = 'INLINE_FRAGMENT', + VARIABLE_DEFINITION = 'VARIABLE_DEFINITION', + /** Type System Definitions */ + SCHEMA = 'SCHEMA', + SCALAR = 'SCALAR', + OBJECT = 'OBJECT', + FIELD_DEFINITION = 'FIELD_DEFINITION', + ARGUMENT_DEFINITION = 'ARGUMENT_DEFINITION', + INTERFACE = 'INTERFACE', + UNION = 'UNION', + ENUM = 'ENUM', + ENUM_VALUE = 'ENUM_VALUE', + INPUT_OBJECT = 'INPUT_OBJECT', + INPUT_FIELD_DEFINITION = 'INPUT_FIELD_DEFINITION', +} +export { DirectiveLocation }; + +/** + * The enum type representing the directive location values. + * + * @deprecated Please use `DirectiveLocation`. Will be remove in v17. + */ +export type DirectiveLocationEnum = typeof DirectiveLocation; diff --git a/src/language/experimentalOnlineParser/README.md b/src/language/experimentalOnlineParser/README.md deleted file mode 100644 index dfcd9996d7..0000000000 --- a/src/language/experimentalOnlineParser/README.md +++ /dev/null @@ -1,26 +0,0 @@ -## Experimental Online Parser - -This directory contains an experimental online parser based on JSON rules set. It is a state-full parser which parses a source string incrementally i.e. emits a token each time. - -The parser is being migrated from graphiql to graphql-js and may have frequent breaking changes. - -Example: - -```js -import { OnlineParser } from 'graphql/language/experimentalOnlineParser'; - -const source = ` - query SomeQuery { - some_field { - another_field - } - } -`; - -const parser = new OnlineParser(source); -let token; - -do { - token = parser.parseToken(); -} while (token.kind !== '' && token.kind !== 'Invalid'); -``` diff --git a/src/language/experimentalOnlineParser/grammar.d.ts b/src/language/experimentalOnlineParser/grammar.d.ts deleted file mode 100644 index 6e71a66a72..0000000000 --- a/src/language/experimentalOnlineParser/grammar.d.ts +++ /dev/null @@ -1,1006 +0,0 @@ -export interface GraphQLGrammarType { - [name: string]: GraphQLGrammarRule; -} - -export type GraphQLGrammarRule = - | GraphQLGrammarRuleName - | GraphQLGrammarRuleConstraint - | GraphQLGrammarConstraintsSet; - -export type GraphQLGrammarRuleName = string; - -export type GraphQLGrammarRuleConstraint = - | GraphQLGrammarTokenConstraint - | GraphQLGrammarOfTypeConstraint - | GraphQLGrammarListOfTypeConstraint - | GraphQLGrammarPeekConstraint; - -export type GraphQLGrammarConstraintsSet = Array< - GraphQLGrammarRuleName | GraphQLGrammarRuleConstraint ->; - -export interface GraphQLGrammarBaseRuleConstraint { - butNot?: GraphQLGrammarTokenConstraint | Array; - optional?: boolean; - eatNextOnFail?: boolean; -} - -export interface GraphQLGrammarTokenConstraint - extends GraphQLGrammarBaseRuleConstraint { - token: - | '!' - | '$' - | '&' - | '(' - | ')' - | '...' - | ':' - | '=' - | '@' - | '[' - | ']' - | '{' - | '}' - | '|' - | 'Name' - | 'Int' - | 'Float' - | 'String' - | 'BlockString' - | 'Comment'; - ofValue?: string; - oneOf?: Array; - tokenName?: string; - definitionName?: boolean; - typeName?: boolean; -} - -export interface GraphQLGrammarOfTypeConstraint - extends GraphQLGrammarBaseRuleConstraint { - ofType: GraphQLGrammarRule; - tokenName?: string; -} - -export interface GraphQLGrammarListOfTypeConstraint - extends GraphQLGrammarBaseRuleConstraint { - listOfType: GraphQLGrammarRuleName; -} - -export interface GraphQLGrammarPeekConstraint - extends GraphQLGrammarBaseRuleConstraint { - peek: Array; -} - -export interface GraphQLGrammarPeekConstraintCondition { - ifCondition: GraphQLGrammarTokenConstraint; - expect: GraphQLGrammarRule; - end?: boolean; -} - -const grammar: GraphQLGrammarType = { - Name: { token: 'Name' }, - String: { token: 'String' }, - BlockString: { token: 'BlockString' }, - - Document: { listOfType: 'Definition' }, - Definition: { - peek: [ - { - ifCondition: { - token: 'Name', - oneOf: ['query', 'mutation', 'subscription'], - }, - expect: 'OperationDefinition', - }, - { - ifCondition: { token: 'Name', ofValue: 'fragment' }, - expect: 'FragmentDefinition', - }, - { - ifCondition: { - token: 'Name', - oneOf: [ - 'schema', - 'scalar', - 'type', - 'interface', - 'union', - 'enum', - 'input', - 'directive', - ], - }, - expect: 'TypeSystemDefinition', - }, - { - ifCondition: { token: 'Name', ofValue: 'extend' }, - expect: 'TypeSystemExtension', - }, - { - ifCondition: { token: '{' }, - expect: 'OperationDefinition', - }, - { - ifCondition: 'String', - expect: 'TypeSystemDefinition', - }, - { - ifCondition: 'BlockString', - expect: 'TypeSystemDefinition', - }, - ], - }, - - OperationDefinition: { - peek: [ - { - ifCondition: { token: '{' }, - expect: 'SelectionSet', - }, - { - ifCondition: { - token: 'Name', - oneOf: ['query', 'mutation', 'subscription'], - }, - expect: [ - 'OperationType', - { - token: 'Name', - optional: true, - tokenName: 'OperationName', - definitionName: true, - }, - { ofType: 'VariableDefinitions', optional: true }, - { ofType: 'Directives', optional: true }, - 'SelectionSet', - ], - }, - ], - }, - OperationType: { - ofType: 'OperationTypeName', - }, - OperationTypeName: { - token: 'Name', - oneOf: ['query', 'mutation', 'subscription'], - definitionName: true, - }, - SelectionSet: [{ token: '{' }, { listOfType: 'Selection' }, { token: '}' }], - Selection: { - peek: [ - { - ifCondition: { token: '...' }, - expect: 'Fragment', - }, - { - ifCondition: { token: 'Name' }, - expect: 'Field', - }, - ], - }, - - Field: [ - { - ofType: 'Alias', - optional: true, - eatNextOnFail: true, - definitionName: true, - }, - { token: 'Name', tokenName: 'FieldName', definitionName: true }, - { ofType: 'Arguments', optional: true }, - { ofType: 'Directives', optional: true }, - { ofType: 'SelectionSet', optional: true }, - ], - - Arguments: [{ token: '(' }, { listOfType: 'Argument' }, { token: ')' }], - Argument: [ - { token: 'Name', tokenName: 'ArgumentName', definitionName: true }, - { token: ':' }, - 'Value', - ], - - Alias: [ - { token: 'Name', tokenName: 'AliasName', definitionName: true }, - { token: ':' }, - ], - - Fragment: [ - { token: '...' }, - { - peek: [ - { - ifCondition: 'FragmentName', - expect: 'FragmentSpread', - }, - { - ifCondition: { token: 'Name', ofValue: 'on' }, - expect: 'InlineFragment', - }, - { - ifCondition: { token: '@' }, - expect: 'InlineFragment', - }, - { - ifCondition: { token: '{' }, - expect: 'InlineFragment', - }, - ], - }, - ], - - FragmentSpread: ['FragmentName', { ofType: 'Directives', optional: true }], - FragmentDefinition: [ - { - token: 'Name', - ofValue: 'fragment', - tokenName: 'FragmentDefinitionKeyword', - }, - 'FragmentName', - 'TypeCondition', - { ofType: 'Directives', optional: true }, - 'SelectionSet', - ], - FragmentName: { - token: 'Name', - butNot: { token: 'Name', ofValue: 'on' }, - definitionName: true, - }, - - TypeCondition: [ - { token: 'Name', ofValue: 'on', tokenName: 'OnKeyword' }, - 'TypeName', - ], - - InlineFragment: [ - { ofType: 'TypeCondition', optional: true }, - { ofType: 'Directives', optional: true }, - 'SelectionSet', - ], - - Value: { - peek: [ - { - ifCondition: { token: '$' }, - expect: 'Variable', - }, - { - ifCondition: 'IntValue', - expect: { ofType: 'IntValue', tokenName: 'NumberValue' }, - }, - { - ifCondition: 'FloatValue', - expect: { ofType: 'FloatValue', tokenName: 'NumberValue' }, - }, - { - ifCondition: 'BooleanValue', - expect: { ofType: 'BooleanValue', tokenName: 'BooleanValue' }, - }, - { - ifCondition: 'EnumValue', - expect: { ofType: 'EnumValue', tokenName: 'EnumValue' }, - }, - { - ifCondition: 'String', - expect: { ofType: 'String', tokenName: 'StringValue' }, - }, - { - ifCondition: 'BlockString', - expect: { ofType: 'BlockString', tokenName: 'StringValue' }, - }, - { - ifCondition: 'NullValue', - expect: { ofType: 'NullValue', tokenName: 'NullValue' }, - }, - { - ifCondition: { token: '[' }, - expect: 'ListValue', - }, - { - ifCondition: { token: '{' }, - expect: 'ObjectValue', - }, - ], - }, - - ConstValue: { - peek: [ - { - ifCondition: 'IntValue', - expect: { ofType: 'IntValue' }, - }, - { - ifCondition: 'FloatValue', - expect: { ofType: 'FloatValue' }, - }, - { - ifCondition: 'BooleanValue', - expect: 'BooleanValue', - }, - { - ifCondition: 'EnumValue', - expect: 'EnumValue', - }, - { - ifCondition: 'String', - expect: { ofType: 'String', tokenName: 'StringValue' }, - }, - { - ifCondition: 'BlockString', - expect: { token: 'BlockString', tokenName: 'StringValue' }, - }, - { - ifCondition: 'NullValue', - expect: 'NullValue', - }, - { - ifCondition: { token: '[' }, - expect: 'ConstListValue', - }, - { - ifCondition: { token: '{' }, - expect: 'ObjectValue', - }, - ], - }, - - IntValue: { token: 'Int' }, - - FloatValue: { token: 'Float' }, - - StringValue: { - peek: [ - { - ifCondition: { token: 'String' }, - expect: { token: 'String', tokenName: 'StringValue' }, - }, - { - ifCondition: { token: 'BlockString' }, - expect: { token: 'BlockString', tokenName: 'StringValue' }, - }, - ], - }, - - BooleanValue: { - token: 'Name', - oneOf: ['true', 'false'], - tokenName: 'BooleanValue', - }, - - NullValue: { - token: 'Name', - ofValue: 'null', - tokenName: 'NullValue', - }, - - EnumValue: { - token: 'Name', - butNot: { token: 'Name', oneOf: ['null', 'true', 'false'] }, - tokenName: 'EnumValue', - }, - - ListValue: [ - { token: '[' }, - { listOfType: 'Value', optional: true }, - { token: ']' }, - ], - - ConstListValue: [ - { token: '[' }, - { listOfType: 'ConstValue', optional: true }, - { token: ']' }, - ], - - ObjectValue: [ - { token: '{' }, - { listOfType: 'ObjectField', optional: true }, - { token: '}' }, - ], - ObjectField: [ - { token: 'Name', tokenName: 'ObjectFieldName' }, - { token: ':' }, - { ofType: 'ConstValue' }, - ], - - Variable: [ - { token: '$', tokenName: 'VariableName' }, - { token: 'Name', tokenName: 'VariableName' }, - ], - VariableDefinitions: [ - { token: '(' }, - { listOfType: 'VariableDefinition' }, - { token: ')' }, - ], - VariableDefinition: [ - 'Variable', - { token: ':' }, - 'Type', - { ofType: 'DefaultValue', optional: true }, - ], - DefaultValue: [{ token: '=' }, 'ConstValue'], - - TypeName: { token: 'Name', tokenName: 'TypeName', typeName: true }, - - Type: { - peek: [ - { - ifCondition: { token: 'Name' }, - expect: ['TypeName', { token: '!', optional: true }], - }, - { - ifCondition: { token: '[' }, - expect: 'ListType', - }, - ], - }, - ListType: [ - { token: '[' }, - { listOfType: 'Type' }, - { token: ']' }, - { token: '!', optional: true }, - ], - - Directives: { listOfType: 'Directive' }, - Directive: [ - { token: '@', tokenName: 'DirectiveName' }, - { token: 'Name', tokenName: 'DirectiveName' }, - { ofType: 'Arguments', optional: true }, - ], - - TypeSystemDefinition: [ - { ofType: 'Description', optional: true }, - { - peek: [ - { - ifCondition: { - target: 'Name', - ofValue: 'schema', - }, - expect: 'SchemaDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'scalar', - }, - expect: 'ScalarTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'type', - }, - expect: 'ObjectTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'interface', - }, - expect: 'InterfaceTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'union', - }, - expect: 'UnionTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'enum', - }, - expect: 'EnumTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'input', - }, - expect: 'InputObjectTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'directive', - }, - expect: 'DirectiveDefinition', - }, - ], - }, - ], - - TypeSystemExtension: { - peek: [ - { - ifCondition: { - target: 'Name', - ofValue: 'schema', - }, - expect: 'SchemaExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'scalar', - }, - expect: 'ScalarTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'type', - }, - expect: 'ObjectTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'interface', - }, - expect: 'InterfaceTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'union', - }, - expect: 'UnionTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'enum', - }, - expect: 'EnumTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'input', - }, - expect: 'InputObjectTypeExtension', - }, - ], - }, - - SchemaDefinition: [ - { - token: 'Name', - ofValue: 'schema', - tokenName: 'SchemaDefinitionKeyword', - }, - { ofType: 'Directives', optional: true }, - { token: '{' }, - { listOfType: 'RootOperationTypeDefinition' }, - { token: '}' }, - ], - RootOperationTypeDefinition: [ - 'OperationType', - { token: ':' }, - { token: 'Name', tokenName: 'OperationTypeDefinitionName' }, - ], - - SchemaExtension: [ - { token: 'Name', ofValue: 'extend' }, - { token: 'Name', ofValue: 'schema' }, - 'Name', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { - ofType: [ - { token: '{' }, - { listOfType: 'RootOperationTypeDefinition' }, - { token: '}' }, - ], - optional: true, - }, - ], - }, - { - ifCondition: { token: '{' }, - expect: [ - { token: '{' }, - { listOfType: 'RootOperationTypeDefinition' }, - { token: '}' }, - ], - }, - ], - }, - ], - - Description: 'StringValue', - - ScalarTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'scalar', - tokenName: 'ScalarDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - ], - - ScalarTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'scalar', - tokenName: 'ScalarDefinitionKeyword', - }, - 'TypeName', - 'Directives', - ], - - ObjectTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'type', - tokenName: 'TypeDefinitionKeyword', - }, - 'TypeName', - { ofType: 'ImplementsInterfaces', optional: true }, - { ofType: 'Directives', optional: true }, - { ofType: 'FieldsDefinition', optional: true }, - ], - ImplementsInterfaces: [ - { - token: 'Name', - ofValue: 'implements', - tokenName: 'ImplementsKeyword', - }, - { token: '&', optional: true }, - 'TypeName', - { - listOfType: 'ImplementsAdditionalInterfaceName', - optional: true, - }, - ], - ImplementsAdditionalInterfaceName: [{ token: '&' }, 'TypeName'], - FieldsDefinition: [ - { token: '{' }, - { listOfType: 'FieldDefinition' }, - { token: '}' }, - ], - FieldDefinition: [ - { ofType: 'Description', optional: true }, - { token: 'Name', tokenName: 'AliasName', definitionName: true }, - { ofType: 'ArgumentsDefinition', optional: true }, - { token: ':' }, - 'Type', - { ofType: 'Directives', optional: true }, - ], - - ArgumentsDefinition: [ - { token: '(' }, - { listOfType: 'InputValueDefinition' }, - { token: ')' }, - ], - InputValueDefinition: [ - { ofType: 'Description', optional: true }, - { token: 'Name', tokenName: 'ArgumentName' }, - { token: ':' }, - 'Type', - { ofType: 'DefaultValue', optional: true }, - { ofType: 'Directives', optional: true }, - ], - - ObjectTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'type', - tokenName: 'TypeDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: 'Name', ofValue: 'interface' }, - expect: [ - 'ImplementsInterfaces', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'FieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'FieldsDefinition', - }, - ], - optional: true, - }, - ], - }, - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'FieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'FieldsDefinition', - }, - ], - }, - ], - - InterfaceTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'interface', - tokenName: 'InterfaceDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'FieldsDefinition', optional: true }, - ], - - InterfaceTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'interface', - tokenName: 'InterfaceDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'FieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'FieldsDefinition', - }, - ], - }, - ], - - UnionTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'union', - tokenName: 'UnionDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'UnionMemberTypes', optional: true }, - ], - - UnionMemberTypes: [ - { token: '=' }, - { token: '|', optional: true }, - 'Name', - { - listOfType: 'UnionMemberAdditionalTypeName', - optional: true, - }, - ], - - UnionMemberAdditionalTypeName: [{ token: '|' }, 'TypeName'], - - UnionTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'union', - tokenName: 'UnionDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'UnionMemberTypes', optional: true }, - ], - }, - { - ifCondition: { token: '=' }, - expect: 'UnionMemberTypes', - }, - ], - }, - ], - - EnumTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'enum', - tokenName: 'EnumDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'EnumValuesDefinition', optional: true }, - ], - EnumValuesDefinition: [ - { token: '{' }, - { listOfType: 'EnumValueDefinition' }, - { token: '}' }, - ], - EnumValueDefinition: [ - { ofType: 'Description', optional: true }, - 'EnumValue', - { ofType: 'Directives', optional: true }, - ], - - EnumTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'enum', - tokenName: 'EnumDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'EnumValuesDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'EnumValuesDefinition', - }, - ], - }, - ], - - InputObjectTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'input', - tokenName: 'InputDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'InputFieldsDefinition', optional: true }, - ], - InputFieldsDefinition: [ - { token: '{' }, - { listOfType: 'InputValueDefinition' }, - { token: '}' }, - ], - - InputObjectTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'input', - tokenName: 'InputDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'InputFieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'InputFieldsDefinition', - }, - ], - }, - ], - - DirectiveDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'directive', - tokenName: 'DirectiveDefinitionKeyword', - }, - { token: '@', tokenName: 'DirectiveName' }, - { token: 'Name', tokenName: 'DirectiveName' }, - { ofType: 'ArgumentsDefinition', optional: true }, - { token: 'Name', ofValue: 'on', tokenName: 'OnKeyword' }, - 'DirectiveLocations', - ], - DirectiveLocations: [ - { token: '|', optional: true }, - 'DirectiveLocation', - { - listOfType: 'DirectiveLocationAdditionalName', - optional: true, - }, - ], - DirectiveLocationAdditionalName: [{ token: '|' }, 'DirectiveLocation'], - DirectiveLocation: { - peek: [ - { - ifCondition: 'ExecutableDirectiveLocation', - expect: 'ExecutableDirectiveLocation', - }, - { - ifCondition: 'TypeSystemDirectiveLocation', - expect: 'TypeSystemDirectiveLocation', - }, - ], - }, - ExecutableDirectiveLocation: { - token: 'Name', - oneOf: [ - 'QUERY', - 'MUTATION', - 'SUBSCRIPTION', - 'FIELD', - 'FRAGMENT_DEFINITION', - 'FRAGMENT_SPREAD', - 'INLINE_FRAGMENT', - ], - tokenName: 'EnumValue', - }, - TypeSystemDirectiveLocation: { - token: 'Name', - oneOf: [ - 'SCHEMA', - 'SCALAR', - 'OBJECT', - 'FIELD_DEFINITION', - 'ARGUMENT_DEFINITION', - 'INTERFACE', - 'UNION', - 'ENUM', - 'ENUM_VALUE', - 'INPUT_OBJECT', - 'INPUT_FIELD_DEFINITION', - ], - tokenName: 'EnumValue', - }, -}; - -export default grammar; diff --git a/src/language/experimentalOnlineParser/grammar.js b/src/language/experimentalOnlineParser/grammar.js deleted file mode 100644 index 0ab7788534..0000000000 --- a/src/language/experimentalOnlineParser/grammar.js +++ /dev/null @@ -1,999 +0,0 @@ -export type GraphQLGrammarType = {| - [name: string]: GraphQLGrammarRule, -|}; -export type GraphQLGrammarRuleName = string; -export type GraphQLGrammarRuleConstraint = - | GraphQLGrammarTokenConstraint - | GraphQLGrammarOfTypeConstraint - | GraphQLGrammarListOfTypeConstraint - | GraphQLGrammarPeekConstraint; -export type GraphQLGrammarConstraintsSet = Array< - GraphQLGrammarRuleName | GraphQLGrammarRuleConstraint, ->; -export type GraphQLGrammarRule = - | GraphQLGrammarRuleName - | GraphQLGrammarRuleConstraint - | GraphQLGrammarConstraintsSet; -export interface GraphQLGrammarBaseRuleConstraint { - butNot?: - | ?GraphQLGrammarTokenConstraint - | ?Array; - optional?: boolean; - eatNextOnFail?: boolean; -} -export interface GraphQLGrammarTokenConstraint - extends GraphQLGrammarBaseRuleConstraint { - token: - | '!' - | '$' - | '&' - | '(' - | ')' - | '...' - | ':' - | '=' - | '@' - | '[' - | ']' - | '{' - | '}' - | '|' - | 'Name' - | 'Int' - | 'Float' - | 'String' - | 'BlockString' - | 'Comment'; - ofValue?: ?string; - oneOf?: ?Array; - tokenName?: string; - definitionName?: boolean; - typeName?: boolean; -} -export interface GraphQLGrammarOfTypeConstraint - extends GraphQLGrammarBaseRuleConstraint { - ofType: GraphQLGrammarRule; - tokenName?: string; -} -export interface GraphQLGrammarListOfTypeConstraint - extends GraphQLGrammarBaseRuleConstraint { - listOfType: GraphQLGrammarRuleName; -} -export interface GraphQLGrammarPeekConstraint - extends GraphQLGrammarBaseRuleConstraint { - peek: Array; -} -export interface GraphQLGrammarPeekConstraintCondition { - ifCondition: GraphQLGrammarTokenConstraint; - expect: GraphQLGrammarRule; - end?: boolean; -} - -const grammar: GraphQLGrammarType = ({ - Name: { token: 'Name' }, - String: { token: 'String' }, - BlockString: { token: 'BlockString' }, - - Document: { listOfType: 'Definition' }, - Definition: { - peek: [ - { - ifCondition: { - token: 'Name', - oneOf: ['query', 'mutation', 'subscription'], - }, - expect: 'OperationDefinition', - }, - { - ifCondition: { token: 'Name', ofValue: 'fragment' }, - expect: 'FragmentDefinition', - }, - { - ifCondition: { - token: 'Name', - oneOf: [ - 'schema', - 'scalar', - 'type', - 'interface', - 'union', - 'enum', - 'input', - 'directive', - ], - }, - expect: 'TypeSystemDefinition', - }, - { - ifCondition: { token: 'Name', ofValue: 'extend' }, - expect: 'TypeSystemExtension', - }, - { - ifCondition: { token: '{' }, - expect: 'OperationDefinition', - }, - { - ifCondition: 'String', - expect: 'TypeSystemDefinition', - }, - { - ifCondition: 'BlockString', - expect: 'TypeSystemDefinition', - }, - ], - }, - - OperationDefinition: { - peek: [ - { - ifCondition: { token: '{' }, - expect: 'SelectionSet', - }, - { - ifCondition: { - token: 'Name', - oneOf: ['query', 'mutation', 'subscription'], - }, - expect: [ - 'OperationType', - { - token: 'Name', - optional: true, - tokenName: 'OperationName', - definitionName: true, - }, - { ofType: 'VariableDefinitions', optional: true }, - { ofType: 'Directives', optional: true }, - 'SelectionSet', - ], - }, - ], - }, - OperationType: { - ofType: 'OperationTypeName', - }, - OperationTypeName: { - token: 'Name', - oneOf: ['query', 'mutation', 'subscription'], - definitionName: true, - }, - SelectionSet: [{ token: '{' }, { listOfType: 'Selection' }, { token: '}' }], - Selection: { - peek: [ - { - ifCondition: { token: '...' }, - expect: 'Fragment', - }, - { - ifCondition: { token: 'Name' }, - expect: 'Field', - }, - ], - }, - - Field: [ - { - ofType: 'Alias', - optional: true, - eatNextOnFail: true, - definitionName: true, - }, - { token: 'Name', tokenName: 'FieldName', definitionName: true }, - { ofType: 'Arguments', optional: true }, - { ofType: 'Directives', optional: true }, - { ofType: 'SelectionSet', optional: true }, - ], - - Arguments: [{ token: '(' }, { listOfType: 'Argument' }, { token: ')' }], - Argument: [ - { token: 'Name', tokenName: 'ArgumentName', definitionName: true }, - { token: ':' }, - 'Value', - ], - - Alias: [ - { token: 'Name', tokenName: 'AliasName', definitionName: true }, - { token: ':' }, - ], - - Fragment: [ - { token: '...' }, - { - peek: [ - { - ifCondition: 'FragmentName', - expect: 'FragmentSpread', - }, - { - ifCondition: { token: 'Name', ofValue: 'on' }, - expect: 'InlineFragment', - }, - { - ifCondition: { token: '@' }, - expect: 'InlineFragment', - }, - { - ifCondition: { token: '{' }, - expect: 'InlineFragment', - }, - ], - }, - ], - - FragmentSpread: ['FragmentName', { ofType: 'Directives', optional: true }], - FragmentDefinition: [ - { - token: 'Name', - ofValue: 'fragment', - tokenName: 'FragmentDefinitionKeyword', - }, - 'FragmentName', - 'TypeCondition', - { ofType: 'Directives', optional: true }, - 'SelectionSet', - ], - FragmentName: { - token: 'Name', - butNot: { token: 'Name', ofValue: 'on' }, - definitionName: true, - }, - - TypeCondition: [ - { token: 'Name', ofValue: 'on', tokenName: 'OnKeyword' }, - 'TypeName', - ], - - InlineFragment: [ - { ofType: 'TypeCondition', optional: true }, - { ofType: 'Directives', optional: true }, - 'SelectionSet', - ], - - Value: { - peek: [ - { - ifCondition: { token: '$' }, - expect: 'Variable', - }, - { - ifCondition: 'IntValue', - expect: { ofType: 'IntValue', tokenName: 'NumberValue' }, - }, - { - ifCondition: 'FloatValue', - expect: { ofType: 'FloatValue', tokenName: 'NumberValue' }, - }, - { - ifCondition: 'BooleanValue', - expect: { ofType: 'BooleanValue', tokenName: 'BooleanValue' }, - }, - { - ifCondition: 'EnumValue', - expect: { ofType: 'EnumValue', tokenName: 'EnumValue' }, - }, - { - ifCondition: 'String', - expect: { ofType: 'String', tokenName: 'StringValue' }, - }, - { - ifCondition: 'BlockString', - expect: { ofType: 'BlockString', tokenName: 'StringValue' }, - }, - { - ifCondition: 'NullValue', - expect: { ofType: 'NullValue', tokenName: 'NullValue' }, - }, - { - ifCondition: { token: '[' }, - expect: 'ListValue', - }, - { - ifCondition: { token: '{' }, - expect: 'ObjectValue', - }, - ], - }, - - ConstValue: { - peek: [ - { - ifCondition: 'IntValue', - expect: { ofType: 'IntValue' }, - }, - { - ifCondition: 'FloatValue', - expect: { ofType: 'FloatValue' }, - }, - { - ifCondition: 'BooleanValue', - expect: 'BooleanValue', - }, - { - ifCondition: 'EnumValue', - expect: 'EnumValue', - }, - { - ifCondition: 'String', - expect: { ofType: 'String', tokenName: 'StringValue' }, - }, - { - ifCondition: 'BlockString', - expect: { token: 'BlockString', tokenName: 'StringValue' }, - }, - { - ifCondition: 'NullValue', - expect: 'NullValue', - }, - { - ifCondition: { token: '[' }, - expect: 'ConstListValue', - }, - { - ifCondition: { token: '{' }, - expect: 'ObjectValue', - }, - ], - }, - - IntValue: { token: 'Int' }, - - FloatValue: { token: 'Float' }, - - StringValue: { - peek: [ - { - ifCondition: { token: 'String' }, - expect: { token: 'String', tokenName: 'StringValue' }, - }, - { - ifCondition: { token: 'BlockString' }, - expect: { token: 'BlockString', tokenName: 'StringValue' }, - }, - ], - }, - - BooleanValue: { - token: 'Name', - oneOf: ['true', 'false'], - tokenName: 'BooleanValue', - }, - - NullValue: { - token: 'Name', - ofValue: 'null', - tokenName: 'NullValue', - }, - - EnumValue: { - token: 'Name', - butNot: { token: 'Name', oneOf: ['null', 'true', 'false'] }, - tokenName: 'EnumValue', - }, - - ListValue: [ - { token: '[' }, - { listOfType: 'Value', optional: true }, - { token: ']' }, - ], - - ConstListValue: [ - { token: '[' }, - { listOfType: 'ConstValue', optional: true }, - { token: ']' }, - ], - - ObjectValue: [ - { token: '{' }, - { listOfType: 'ObjectField', optional: true }, - { token: '}' }, - ], - ObjectField: [ - { token: 'Name', tokenName: 'ObjectFieldName' }, - { token: ':' }, - { ofType: 'ConstValue' }, - ], - - Variable: [ - { token: '$', tokenName: 'VariableName' }, - { token: 'Name', tokenName: 'VariableName' }, - ], - VariableDefinitions: [ - { token: '(' }, - { listOfType: 'VariableDefinition' }, - { token: ')' }, - ], - VariableDefinition: [ - 'Variable', - { token: ':' }, - 'Type', - { ofType: 'DefaultValue', optional: true }, - ], - DefaultValue: [{ token: '=' }, 'ConstValue'], - - TypeName: { token: 'Name', tokenName: 'TypeName', typeName: true }, - - Type: { - peek: [ - { - ifCondition: { token: 'Name' }, - expect: ['TypeName', { token: '!', optional: true }], - }, - { - ifCondition: { token: '[' }, - expect: 'ListType', - }, - ], - }, - ListType: [ - { token: '[' }, - { listOfType: 'Type' }, - { token: ']' }, - { token: '!', optional: true }, - ], - - Directives: { listOfType: 'Directive' }, - Directive: [ - { token: '@', tokenName: 'DirectiveName' }, - { token: 'Name', tokenName: 'DirectiveName' }, - { ofType: 'Arguments', optional: true }, - ], - - TypeSystemDefinition: [ - { ofType: 'Description', optional: true }, - { - peek: [ - { - ifCondition: { - target: 'Name', - ofValue: 'schema', - }, - expect: 'SchemaDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'scalar', - }, - expect: 'ScalarTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'type', - }, - expect: 'ObjectTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'interface', - }, - expect: 'InterfaceTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'union', - }, - expect: 'UnionTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'enum', - }, - expect: 'EnumTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'input', - }, - expect: 'InputObjectTypeDefinition', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'directive', - }, - expect: 'DirectiveDefinition', - }, - ], - }, - ], - - TypeSystemExtension: { - peek: [ - { - ifCondition: { - target: 'Name', - ofValue: 'schema', - }, - expect: 'SchemaExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'scalar', - }, - expect: 'ScalarTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'type', - }, - expect: 'ObjectTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'interface', - }, - expect: 'InterfaceTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'union', - }, - expect: 'UnionTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'enum', - }, - expect: 'EnumTypeExtension', - }, - { - ifCondition: { - target: 'Name', - ofValue: 'input', - }, - expect: 'InputObjectTypeExtension', - }, - ], - }, - - SchemaDefinition: [ - { - token: 'Name', - ofValue: 'schema', - tokenName: 'SchemaDefinitionKeyword', - }, - { ofType: 'Directives', optional: true }, - { token: '{' }, - { listOfType: 'RootOperationTypeDefinition' }, - { token: '}' }, - ], - RootOperationTypeDefinition: [ - 'OperationType', - { token: ':' }, - { token: 'Name', tokenName: 'OperationTypeDefinitionName' }, - ], - - SchemaExtension: [ - { token: 'Name', ofValue: 'extend' }, - { token: 'Name', ofValue: 'schema' }, - 'Name', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { - ofType: [ - { token: '{' }, - { listOfType: 'RootOperationTypeDefinition' }, - { token: '}' }, - ], - optional: true, - }, - ], - }, - { - ifCondition: { token: '{' }, - expect: [ - { token: '{' }, - { listOfType: 'RootOperationTypeDefinition' }, - { token: '}' }, - ], - }, - ], - }, - ], - - Description: 'StringValue', - - ScalarTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'scalar', - tokenName: 'ScalarDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - ], - - ScalarTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'scalar', - tokenName: 'ScalarDefinitionKeyword', - }, - 'TypeName', - 'Directives', - ], - - ObjectTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'type', - tokenName: 'TypeDefinitionKeyword', - }, - 'TypeName', - { ofType: 'ImplementsInterfaces', optional: true }, - { ofType: 'Directives', optional: true }, - { ofType: 'FieldsDefinition', optional: true }, - ], - ImplementsInterfaces: [ - { - token: 'Name', - ofValue: 'implements', - tokenName: 'ImplementsKeyword', - }, - { token: '&', optional: true }, - 'TypeName', - { - listOfType: 'ImplementsAdditionalInterfaceName', - optional: true, - }, - ], - ImplementsAdditionalInterfaceName: [{ token: '&' }, 'TypeName'], - FieldsDefinition: [ - { token: '{' }, - { listOfType: 'FieldDefinition' }, - { token: '}' }, - ], - FieldDefinition: [ - { ofType: 'Description', optional: true }, - { token: 'Name', tokenName: 'AliasName', definitionName: true }, - { ofType: 'ArgumentsDefinition', optional: true }, - { token: ':' }, - 'Type', - { ofType: 'Directives', optional: true }, - ], - - ArgumentsDefinition: [ - { token: '(' }, - { listOfType: 'InputValueDefinition' }, - { token: ')' }, - ], - InputValueDefinition: [ - { ofType: 'Description', optional: true }, - { token: 'Name', tokenName: 'ArgumentName' }, - { token: ':' }, - 'Type', - { ofType: 'DefaultValue', optional: true }, - { ofType: 'Directives', optional: true }, - ], - - ObjectTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'type', - tokenName: 'TypeDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: 'Name', ofValue: 'interface' }, - expect: [ - 'ImplementsInterfaces', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'FieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'FieldsDefinition', - }, - ], - optional: true, - }, - ], - }, - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'FieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'FieldsDefinition', - }, - ], - }, - ], - - InterfaceTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'interface', - tokenName: 'InterfaceDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'FieldsDefinition', optional: true }, - ], - - InterfaceTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'interface', - tokenName: 'InterfaceDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'FieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'FieldsDefinition', - }, - ], - }, - ], - - UnionTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'union', - tokenName: 'UnionDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'UnionMemberTypes', optional: true }, - ], - - UnionMemberTypes: [ - { token: '=' }, - { token: '|', optional: true }, - 'Name', - { - listOfType: 'UnionMemberAdditionalTypeName', - optional: true, - }, - ], - - UnionMemberAdditionalTypeName: [{ token: '|' }, 'TypeName'], - - UnionTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'union', - tokenName: 'UnionDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'UnionMemberTypes', optional: true }, - ], - }, - { - ifCondition: { token: '=' }, - expect: 'UnionMemberTypes', - }, - ], - }, - ], - - EnumTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'enum', - tokenName: 'EnumDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'EnumValuesDefinition', optional: true }, - ], - EnumValuesDefinition: [ - { token: '{' }, - { listOfType: 'EnumValueDefinition' }, - { token: '}' }, - ], - EnumValueDefinition: [ - { ofType: 'Description', optional: true }, - 'EnumValue', - { ofType: 'Directives', optional: true }, - ], - - EnumTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'enum', - tokenName: 'EnumDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'EnumValuesDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'EnumValuesDefinition', - }, - ], - }, - ], - - InputObjectTypeDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'input', - tokenName: 'InputDefinitionKeyword', - }, - 'TypeName', - { ofType: 'Directives', optional: true }, - { ofType: 'InputFieldsDefinition', optional: true }, - ], - InputFieldsDefinition: [ - { token: '{' }, - { listOfType: 'InputValueDefinition' }, - { token: '}' }, - ], - - InputObjectTypeExtension: [ - { - token: 'Name', - ofValue: 'extend', - tokenName: 'ExtendDefinitionKeyword', - }, - { - token: 'Name', - ofValue: 'input', - tokenName: 'InputDefinitionKeyword', - }, - 'TypeName', - { - peek: [ - { - ifCondition: { token: '@' }, - expect: [ - 'Directives', - { ofType: 'InputFieldsDefinition', optional: true }, - ], - }, - { - ifCondition: { token: '{' }, - expect: 'InputFieldsDefinition', - }, - ], - }, - ], - - DirectiveDefinition: [ - { ofType: 'Description', optional: true }, - { - token: 'Name', - ofValue: 'directive', - tokenName: 'DirectiveDefinitionKeyword', - }, - { token: '@', tokenName: 'DirectiveName' }, - { token: 'Name', tokenName: 'DirectiveName' }, - { ofType: 'ArgumentsDefinition', optional: true }, - { token: 'Name', ofValue: 'on', tokenName: 'OnKeyword' }, - 'DirectiveLocations', - ], - DirectiveLocations: [ - { token: '|', optional: true }, - 'DirectiveLocation', - { - listOfType: 'DirectiveLocationAdditionalName', - optional: true, - }, - ], - DirectiveLocationAdditionalName: [{ token: '|' }, 'DirectiveLocation'], - DirectiveLocation: { - peek: [ - { - ifCondition: 'ExecutableDirectiveLocation', - expect: 'ExecutableDirectiveLocation', - }, - { - ifCondition: 'TypeSystemDirectiveLocation', - expect: 'TypeSystemDirectiveLocation', - }, - ], - }, - ExecutableDirectiveLocation: { - token: 'Name', - oneOf: [ - 'QUERY', - 'MUTATION', - 'SUBSCRIPTION', - 'FIELD', - 'FRAGMENT_DEFINITION', - 'FRAGMENT_SPREAD', - 'INLINE_FRAGMENT', - ], - tokenName: 'EnumValue', - }, - TypeSystemDirectiveLocation: { - token: 'Name', - oneOf: [ - 'SCHEMA', - 'SCALAR', - 'OBJECT', - 'FIELD_DEFINITION', - 'ARGUMENT_DEFINITION', - 'INTERFACE', - 'UNION', - 'ENUM', - 'ENUM_VALUE', - 'INPUT_OBJECT', - 'INPUT_FIELD_DEFINITION', - ], - tokenName: 'EnumValue', - }, - // FIXME: enforce proper typing -}: any); - -export default grammar; diff --git a/src/language/experimentalOnlineParser/index.d.ts b/src/language/experimentalOnlineParser/index.d.ts deleted file mode 100644 index 039446a16c..0000000000 --- a/src/language/experimentalOnlineParser/index.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - OnlineParser, - RuleKind, - TokenKind, - OnlineParserState, -} from './onlineParser'; diff --git a/src/language/experimentalOnlineParser/index.js b/src/language/experimentalOnlineParser/index.js deleted file mode 100644 index 039446a16c..0000000000 --- a/src/language/experimentalOnlineParser/index.js +++ /dev/null @@ -1,6 +0,0 @@ -export { - OnlineParser, - RuleKind, - TokenKind, - OnlineParserState, -} from './onlineParser'; diff --git a/src/language/experimentalOnlineParser/onlineParser.d.ts b/src/language/experimentalOnlineParser/onlineParser.d.ts deleted file mode 100644 index 9570b9e589..0000000000 --- a/src/language/experimentalOnlineParser/onlineParser.d.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { Lexer } from '../lexer'; - -import { - GraphQLGrammarTokenConstraint, - GraphQLGrammarOfTypeConstraint, - GraphQLGrammarListOfTypeConstraint, - GraphQLGrammarPeekConstraint, - GraphQLGrammarConstraintsSet, -} from './grammar'; - -interface BaseOnlineParserRule { - kind: string; - name?: string; - depth: number; - step: number; - expanded: boolean; - state: string; - optional?: boolean; - eatNextOnFail?: boolean; -} -interface TokenOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarTokenConstraint {} -interface OfTypeOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarOfTypeConstraint {} -interface ListOfTypeOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarListOfTypeConstraint {} -interface PeekOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarPeekConstraint { - index: number; - matched: boolean; -} -interface ConstraintsSetOnlineParserRule extends BaseOnlineParserRule { - constraintsSet: boolean; - constraints: GraphQLGrammarConstraintsSet; -} - -type OnlineParserRule = - | TokenOnlineParserRule - | OfTypeOnlineParserRule - | ListOfTypeOnlineParserRule - | PeekOnlineParserRule - | ConstraintsSetOnlineParserRule; - -export interface OnlineParserState { - rules: Array; - kind: () => string; - step: () => number; - levels: Array; - indentLevel: number | undefined; - name: string | null; - type: string | null; -} - -interface Token { - kind: string; - value?: string; - tokenName?: string | undefined; - ruleName?: string | undefined; -} - -type OnlineParserConfig = { - tabSize: number; -}; - -type OnlineParserConfigOption = { - tabSize?: number; -}; - -export class OnlineParser { - state: OnlineParserState; - _lexer: Lexer; - _config: OnlineParserConfig; - constructor( - source: string, - state?: OnlineParserState, - config?: OnlineParserConfigOption, - ); - static startState(): OnlineParserState; - static copyState(state: OnlineParserState): OnlineParserState; - sol(): boolean; - parseToken(): Token; - indentation(): number; - private readonly _parseTokenConstraint; - private readonly _parseListOfTypeConstraint; - private readonly _parseOfTypeConstraint; - private readonly _parsePeekConstraint; - private readonly _parseConstraintsSetRule; - private readonly _matchToken; - private readonly _butNot; - private readonly _transformLexerToken; - private readonly _getNextRule; - private readonly _popMatchedRule; - private readonly _rollbackRule; - private readonly _pushRule; - private readonly _getRuleKind; - private readonly _advanceToken; - private readonly _lookAhead; -} - -export const TokenKind: { - NAME: string; - INT: string; - FLOAT: string; - STRING: string; - BLOCK_STRING: string; - COMMENT: string; - PUNCTUATION: string; - EOF: string; - INVALID: string; -}; - -export const RuleKind: { - TOKEN_CONSTRAINT: string; - OF_TYPE_CONSTRAINT: string; - LIST_OF_TYPE_CONSTRAINT: string; - PEEK_CONSTRAINT: string; - CONSTRAINTS_SET: string; - CONSTRAINTS_SET_ROOT: string; - RULE_NAME: string; - INVALID: string; -}; diff --git a/src/language/experimentalOnlineParser/onlineParser.js b/src/language/experimentalOnlineParser/onlineParser.js deleted file mode 100644 index f296d1c8e2..0000000000 --- a/src/language/experimentalOnlineParser/onlineParser.js +++ /dev/null @@ -1,722 +0,0 @@ -import { Lexer } from '../lexer'; -import { Source } from '../source'; - -import GraphQLGrammar from './grammar'; -import type { - GraphQLGrammarRule, - GraphQLGrammarRuleName, - GraphQLGrammarRuleConstraint, - GraphQLGrammarTokenConstraint, - GraphQLGrammarOfTypeConstraint, - GraphQLGrammarListOfTypeConstraint, - GraphQLGrammarPeekConstraint, - GraphQLGrammarConstraintsSet, -} from './grammar'; - -export const TokenKind = { - NAME: 'Name', - INT: 'Int', - FLOAT: 'Float', - STRING: 'String', - BLOCK_STRING: 'BlockString', - COMMENT: 'Comment', - PUNCTUATION: 'Punctuation', - EOF: '', - INVALID: 'Invalid', -}; - -export const RuleKind = { - TOKEN_CONSTRAINT: 'TokenConstraint', - OF_TYPE_CONSTRAINT: 'OfTypeConstraint', - LIST_OF_TYPE_CONSTRAINT: 'ListOfTypeConstraint', - PEEK_CONSTRAINT: 'PeekConstraint', - CONSTRAINTS_SET: 'ConstraintsSet', - CONSTRAINTS_SET_ROOT: 'ConstraintsSetRoot', - RULE_NAME: 'RuleName', - INVALID: 'Invalid', -}; - -interface BaseOnlineParserRule { - kind: string; - name?: string; - depth: number; - step: number; - expanded: boolean; - state: string; - optional?: boolean; - eatNextOnFail?: boolean; -} -interface TokenOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarTokenConstraint {} -interface OfTypeOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarOfTypeConstraint {} -interface ListOfTypeOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarListOfTypeConstraint {} -interface PeekOnlineParserRule - extends BaseOnlineParserRule, - GraphQLGrammarPeekConstraint { - index: number; - matched: boolean; -} -interface ConstraintsSetOnlineParserRule extends BaseOnlineParserRule { - constraintsSet: boolean; - constraints: GraphQLGrammarConstraintsSet; -} - -type OnlineParserRule = - | TokenOnlineParserRule - | OfTypeOnlineParserRule - | ListOfTypeOnlineParserRule - | PeekOnlineParserRule - | ConstraintsSetOnlineParserRule; - -export type OnlineParserState = {| - rules: Array, - kind: () => string, - step: () => number, - levels: Array, - indentLevel: number, - name: string | null, - type: string | null, -|}; - -type Token = {| - kind: string, - value: string, - tokenName?: ?string, - ruleName?: ?string, -|}; - -type LexerToken = {| - kind: string, - value: ?string, -|}; - -type OnlineParserConfig = {| - tabSize: number, -|}; - -type OnlineParserConfigOption = {| - tabSize: ?number, -|}; - -export class OnlineParser { - state: OnlineParserState; - _lexer: Lexer; - _config: OnlineParserConfig; - - constructor( - source: string, - state?: OnlineParserState, - config?: OnlineParserConfigOption, - ) { - this.state = state || OnlineParser.startState(); - this._config = { - tabSize: config?.tabSize ?? 2, - }; - this._lexer = new Lexer(new Source(source)); - } - - static startState(): OnlineParserState { - return { - rules: [ - // $FlowFixMe[cannot-spread-interface] - { - name: 'Document', - state: 'Document', - kind: 'ListOfTypeConstraint', - ...GraphQLGrammar.Document, - expanded: false, - depth: 1, - step: 1, - }, - ], - name: null, - type: null, - levels: [], - indentLevel: 0, - kind(): string { - return this.rules[this.rules.length - 1]?.state || ''; - }, - step(): number { - return this.rules[this.rules.length - 1]?.step || 0; - }, - }; - } - - static copyState(state: OnlineParserState): OnlineParserState { - return { - name: state.name, - type: state.type, - rules: JSON.parse(JSON.stringify(state.rules)), - levels: [...state.levels], - indentLevel: state.indentLevel, - kind(): string { - return this.rules[this.rules.length - 1]?.state || ''; - }, - step(): number { - return this.rules[this.rules.length - 1]?.step || 0; - }, - }; - } - - sol(): boolean { - return ( - this._lexer.source.locationOffset.line === 1 && - this._lexer.source.locationOffset.column === 1 - ); - } - - parseToken(): Token { - const rule = (this._getNextRule(): any); - - if (this.sol()) { - this.state.indentLevel = Math.floor( - this.indentation() / this._config.tabSize, - ); - } - - if (!rule) { - return { - kind: TokenKind.INVALID, - value: '', - }; - } - - let token; - - if (this._lookAhead().kind === '') { - return { - kind: TokenKind.EOF, - value: '', - ruleName: rule.name, - }; - } - - switch (rule.kind) { - case RuleKind.TOKEN_CONSTRAINT: - token = this._parseTokenConstraint(rule); - break; - case RuleKind.LIST_OF_TYPE_CONSTRAINT: - token = this._parseListOfTypeConstraint(rule); - break; - case RuleKind.OF_TYPE_CONSTRAINT: - token = this._parseOfTypeConstraint(rule); - break; - case RuleKind.PEEK_CONSTRAINT: - token = this._parsePeekConstraint(rule); - break; - case RuleKind.CONSTRAINTS_SET_ROOT: - token = this._parseConstraintsSetRule(rule); - break; - default: - return { - kind: TokenKind.INVALID, - value: '', - ruleName: rule.name, - }; - } - - if (token && token.kind === TokenKind.INVALID) { - if (rule.optional === true) { - this.state.rules.pop(); - } else { - this._rollbackRule(); - } - - return this.parseToken() || token; - } - - return token; - } - - indentation(): number { - const match = this._lexer.source.body.match(/\s*/); - let indent = 0; - - if (match && match.length === 0) { - const whiteSpaces = match[0]; - let pos = 0; - while (whiteSpaces.length > pos) { - if (whiteSpaces.charCodeAt(pos) === 9) { - indent += 2; - } else { - indent++; - } - pos++; - } - } - - return indent; - } - - _parseTokenConstraint(rule: TokenOnlineParserRule): Token { - rule.expanded = true; - - const token = this._lookAhead(); - - if (!this._matchToken(token, rule)) { - return { - kind: TokenKind.INVALID, - value: '', - tokenName: rule.tokenName, - ruleName: rule.name, - }; - } - - this._advanceToken(); - const parserToken = this._transformLexerToken(token, rule); - this._popMatchedRule(parserToken); - - return parserToken; - } - - _parseListOfTypeConstraint(rule: ListOfTypeOnlineParserRule): Token { - this._pushRule( - GraphQLGrammar[rule.listOfType], - rule.depth + 1, - rule.listOfType, - 1, - rule.state, - ); - - rule.expanded = true; - - const token = this.parseToken(); - - return token; - } - - _parseOfTypeConstraint(rule: OfTypeOnlineParserRule): Token { - if (rule.expanded) { - this._popMatchedRule(); - return this.parseToken(); - } - - this._pushRule(rule.ofType, rule.depth + 1, rule.tokenName, 1, rule.state); - rule.expanded = true; - - const token = this.parseToken(); - - return token; - } - - _parsePeekConstraint(rule: PeekOnlineParserRule): Token { - if (rule.expanded) { - this._popMatchedRule(); - return this.parseToken(); - } - - while (!rule.matched && rule.index < rule.peek.length - 1) { - rule.index++; - const constraint = rule.peek[rule.index]; - - let { ifCondition } = constraint; - if (typeof ifCondition === 'string') { - ifCondition = GraphQLGrammar[ifCondition]; - } - - let token = this._lookAhead(); - if (ifCondition && this._matchToken(token, ifCondition)) { - rule.matched = true; - rule.expanded = true; - this._pushRule(constraint.expect, rule.depth + 1, '', 1, rule.state); - - token = this.parseToken(); - - return token; - } - } - - return { - kind: TokenKind.INVALID, - value: '', - ruleName: rule.name, - }; - } - - _parseConstraintsSetRule(rule: ConstraintsSetOnlineParserRule): Token { - if (rule.expanded) { - this._popMatchedRule(); - return this.parseToken(); - } - - for (let index = rule.constraints.length - 1; index >= 0; index--) { - this._pushRule( - rule.constraints[index], - rule.depth + 1, - '', - index, - rule.state, - ); - } - rule.expanded = true; - - return this.parseToken(); - } - - _matchToken( - token: Token | LexerToken, - rule: GraphQLGrammarTokenConstraint, - ): boolean { - if (typeof token.value === 'string') { - if ( - (typeof rule.ofValue === 'string' && token.value !== rule.ofValue) || - (Array.isArray(rule.oneOf) && !rule.oneOf.includes(token.value)) || - (typeof rule.ofValue !== 'string' && - !Array.isArray(rule.oneOf) && - token.kind !== rule.token) - ) { - return false; - } - - return this._butNot(token, rule); - } - - if (token.kind !== rule.token) { - return false; - } - - return this._butNot(token, rule); - } - - _butNot( - token: Token | LexerToken, - rule: GraphQLGrammarRuleConstraint, - ): boolean { - if (rule.butNot) { - if (Array.isArray(rule.butNot)) { - if ( - rule.butNot.reduce( - (matched, constraint) => - matched || this._matchToken(token, constraint), - false, - ) - ) { - return false; - } - - return true; - } - - return !this._matchToken(token, rule.butNot); - } - - return true; - } - - _transformLexerToken(lexerToken: LexerToken, rule: any): Token { - let token; - const ruleName = rule.name || ''; - const tokenName = rule.tokenName || ''; - - if (lexerToken.kind === '' || lexerToken.value !== undefined) { - token = { - kind: lexerToken.kind, - value: lexerToken.value || '', - tokenName, - ruleName, - }; - - if (token.kind === TokenKind.STRING) { - token.value = `"${token.value}"`; - } else if (token.kind === TokenKind.BLOCK_STRING) { - token.value = `"""${token.value}"""`; - } - } else { - token = { - kind: TokenKind.PUNCTUATION, - value: lexerToken.kind, - tokenName, - ruleName, - }; - - if (/^[{([]/.test(token.value)) { - if (this.state.indentLevel !== undefined) { - this.state.levels = this.state.levels.concat( - this.state.indentLevel + 1, - ); - } - } else if (/^[})\]]/.test(token.value)) { - this.state.levels.pop(); - } - } - - return token; - } - - _getNextRule(): OnlineParserRule | null { - return this.state.rules[this.state.rules.length - 1] || null; - } - - _popMatchedRule(token: ?Token) { - const rule = this.state.rules.pop(); - if (!rule) { - return; - } - - if (token && rule.kind === RuleKind.TOKEN_CONSTRAINT) { - const constraint = rule; - if (typeof constraint.definitionName === 'string') { - this.state.name = token.value || null; - } else if (typeof constraint.typeName === 'string') { - this.state.type = token.value || null; - } - } - - const nextRule = this._getNextRule(); - if (!nextRule) { - return; - } - - if ( - nextRule.depth === rule.depth - 1 && - nextRule.expanded && - nextRule.kind === RuleKind.CONSTRAINTS_SET_ROOT - ) { - this.state.rules.pop(); - } - - if ( - nextRule.depth === rule.depth - 1 && - nextRule.expanded && - nextRule.kind === RuleKind.LIST_OF_TYPE_CONSTRAINT - ) { - nextRule.expanded = false; - nextRule.optional = true; - } - } - - _rollbackRule() { - if (!this.state.rules.length) { - return; - } - - const popRule = () => { - const lastPoppedRule = this.state.rules.pop(); - - if (lastPoppedRule.eatNextOnFail === true) { - this.state.rules.pop(); - } - }; - - const poppedRule = this.state.rules.pop(); - if (!poppedRule) { - return; - } - - let popped = 0; - let nextRule = this._getNextRule(); - while ( - nextRule && - (poppedRule.kind !== RuleKind.LIST_OF_TYPE_CONSTRAINT || - nextRule.expanded) && - nextRule.depth > poppedRule.depth - 1 - ) { - this.state.rules.pop(); - popped++; - nextRule = this._getNextRule(); - } - - if (nextRule && nextRule.expanded) { - if (nextRule.optional === true) { - popRule(); - } else { - if ( - nextRule.kind === RuleKind.LIST_OF_TYPE_CONSTRAINT && - popped === 1 - ) { - this.state.rules.pop(); - return; - } - this._rollbackRule(); - } - } - } - - _pushRule( - baseRule: any, - depth: number, - name?: string, - step?: number, - state?: string, - ) { - this.state.name = null; - this.state.type = null; - let rule = baseRule; - - switch (this._getRuleKind(rule)) { - case RuleKind.RULE_NAME: - rule = (rule: GraphQLGrammarRuleName); - this._pushRule( - GraphQLGrammar[rule], - depth, - (typeof name === 'string' ? name : undefined) || rule, - step, - state, - ); - break; - case RuleKind.CONSTRAINTS_SET: - rule = (rule: GraphQLGrammarConstraintsSet); - this.state.rules.push({ - name: name || '', - depth, - expanded: false, - constraints: rule, - constraintsSet: true, - kind: RuleKind.CONSTRAINTS_SET_ROOT, - state: - (typeof name === 'string' ? name : undefined) || - (typeof state === 'string' ? state : undefined) || - this._getNextRule()?.state || - '', - step: - typeof step === 'number' - ? step - : (this._getNextRule()?.step || 0) + 1, - }); - break; - case RuleKind.OF_TYPE_CONSTRAINT: - rule = (rule: GraphQLGrammarOfTypeConstraint); - this.state.rules.push({ - name: name || '', - ofType: rule.ofType, - optional: Boolean(rule.optional), - butNot: rule.butNot, - eatNextOnFail: Boolean(rule.eatNextOnFail), - depth, - expanded: false, - kind: RuleKind.OF_TYPE_CONSTRAINT, - state: - (typeof rule.tokenName === 'string' ? rule.tokenName : undefined) || - (typeof name === 'string' ? name : undefined) || - (typeof state === 'string' ? state : undefined) || - this._getNextRule()?.state || - '', - step: - typeof step === 'number' - ? step - : (this._getNextRule()?.step || 0) + 1, - }); - break; - case RuleKind.LIST_OF_TYPE_CONSTRAINT: - rule = (rule: GraphQLGrammarListOfTypeConstraint); - this.state.rules.push({ - listOfType: rule.listOfType, - optional: Boolean(rule.optional), - butNot: rule.butNot, - eatNextOnFail: Boolean(rule.eatNextOnFail), - name: name || '', - depth, - expanded: false, - kind: RuleKind.LIST_OF_TYPE_CONSTRAINT, - state: - (typeof name === 'string' ? name : undefined) || - (typeof state === 'string' ? state : undefined) || - this._getNextRule()?.state || - '', - step: - typeof step === 'number' - ? step - : (this._getNextRule()?.step || 0) + 1, - }); - break; - case RuleKind.TOKEN_CONSTRAINT: - rule = (rule: GraphQLGrammarTokenConstraint); - this.state.rules.push({ - token: rule.token, - ofValue: rule.ofValue, - oneOf: rule.oneOf, - definitionName: Boolean(rule.definitionName), - typeName: Boolean(rule.typeName), - optional: Boolean(rule.optional), - butNot: rule.butNot, - eatNextOnFail: Boolean(rule.eatNextOnFail), - name: name || '', - depth, - expanded: false, - kind: RuleKind.TOKEN_CONSTRAINT, - state: - (typeof rule.tokenName === 'string' ? rule.tokenName : undefined) || - (typeof state === 'string' ? state : undefined) || - this._getNextRule()?.state || - '', - step: - typeof step === 'number' - ? step - : (this._getNextRule()?.step || 0) + 1, - }); - break; - case RuleKind.PEEK_CONSTRAINT: - rule = (rule: GraphQLGrammarPeekConstraint); - this.state.rules.push({ - peek: rule.peek, - optional: Boolean(rule.optional), - butNot: rule.butNot, - eatNextOnFail: Boolean(rule.eatNextOnFail), - name: name || '', - depth, - index: -1, - matched: false, - expanded: false, - kind: RuleKind.PEEK_CONSTRAINT, - state: - (typeof state === 'string' ? state : undefined) || - this._getNextRule()?.state || - '', - step: - typeof step === 'number' - ? step - : (this._getNextRule()?.step || 0) + 1, - }); - break; - } - } - - _getRuleKind(rule: GraphQLGrammarRule | OnlineParserRule): string { - if (Array.isArray(rule)) { - return RuleKind.CONSTRAINTS_SET; - } - - if (rule.constraintsSet === true) { - return RuleKind.CONSTRAINTS_SET_ROOT; - } - - if (typeof rule === 'string') { - return RuleKind.RULE_NAME; - } - - if (Object.prototype.hasOwnProperty.call(rule, 'ofType')) { - return RuleKind.OF_TYPE_CONSTRAINT; - } - - if (Object.prototype.hasOwnProperty.call(rule, 'listOfType')) { - return RuleKind.LIST_OF_TYPE_CONSTRAINT; - } - - if (Object.prototype.hasOwnProperty.call(rule, 'peek')) { - return RuleKind.PEEK_CONSTRAINT; - } - - if (Object.prototype.hasOwnProperty.call(rule, 'token')) { - return RuleKind.TOKEN_CONSTRAINT; - } - - return RuleKind.INVALID; - } - - _advanceToken(): LexerToken { - return (this._lexer.advance(): any); - } - - _lookAhead(): LexerToken { - try { - return (this._lexer.lookahead(): any); - } catch (err) { - return { kind: TokenKind.INVALID, value: '' }; - } - } -} diff --git a/src/language/index.d.ts b/src/language/index.d.ts deleted file mode 100644 index ce965383fe..0000000000 --- a/src/language/index.d.ts +++ /dev/null @@ -1,95 +0,0 @@ -export { Source } from './source'; -export { getLocation, SourceLocation } from './location'; - -export { printLocation, printSourceLocation } from './printLocation'; - -export { Kind, KindEnum } from './kinds'; -export { TokenKind, TokenKindEnum } from './tokenKind'; -export { Lexer } from './lexer'; -export { parse, parseValue, parseType, ParseOptions } from './parser'; -export { print } from './printer'; -export { - visit, - visitInParallel, - getVisitFn, - BREAK, - ASTVisitor, - Visitor, - VisitFn, - VisitorKeyMap, -} from './visitor'; - -export { - Location, - Token, - ASTNode, - ASTKindToNode, - // Each kind of AST node - NameNode, - DocumentNode, - DefinitionNode, - ExecutableDefinitionNode, - OperationDefinitionNode, - OperationTypeNode, - VariableDefinitionNode, - VariableNode, - SelectionSetNode, - SelectionNode, - FieldNode, - ArgumentNode, - FragmentSpreadNode, - InlineFragmentNode, - FragmentDefinitionNode, - ValueNode, - IntValueNode, - FloatValueNode, - StringValueNode, - BooleanValueNode, - NullValueNode, - EnumValueNode, - ListValueNode, - ObjectValueNode, - ObjectFieldNode, - DirectiveNode, - TypeNode, - NamedTypeNode, - ListTypeNode, - NonNullTypeNode, - TypeSystemDefinitionNode, - SchemaDefinitionNode, - OperationTypeDefinitionNode, - TypeDefinitionNode, - ScalarTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - UnionTypeDefinitionNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, - InputObjectTypeDefinitionNode, - DirectiveDefinitionNode, - TypeSystemExtensionNode, - SchemaExtensionNode, - TypeExtensionNode, - ScalarTypeExtensionNode, - ObjectTypeExtensionNode, - InterfaceTypeExtensionNode, - UnionTypeExtensionNode, - EnumTypeExtensionNode, - InputObjectTypeExtensionNode, -} from './ast'; - -export { - isDefinitionNode, - isExecutableDefinitionNode, - isSelectionNode, - isValueNode, - isTypeNode, - isTypeSystemDefinitionNode, - isTypeDefinitionNode, - isTypeSystemExtensionNode, - isTypeExtensionNode, -} from './predicates'; - -export { DirectiveLocation, DirectiveLocationEnum } from './directiveLocation'; diff --git a/src/language/index.js b/src/language/index.ts similarity index 81% rename from src/language/index.js rename to src/language/index.ts index 6055ff4fe3..ec4d195e1a 100644 --- a/src/language/index.js +++ b/src/language/index.ts @@ -13,15 +13,21 @@ export type { TokenKindEnum } from './tokenKind'; export { Lexer } from './lexer'; -export { parse, parseValue, parseType } from './parser'; +export { parse, parseValue, parseConstValue, parseType } from './parser'; export type { ParseOptions } from './parser'; export { print } from './printer'; -export { visit, visitInParallel, getVisitFn, BREAK } from './visitor'; -export type { ASTVisitor, Visitor, VisitFn, VisitorKeyMap } from './visitor'; +export { + visit, + visitInParallel, + getVisitFn, + getEnterLeaveForKind, + BREAK, +} from './visitor'; +export type { ASTVisitor, ASTVisitFn, ASTVisitorKeyMap } from './visitor'; -export { Location, Token } from './ast'; +export { Location, Token, OperationTypeNode } from './ast'; export type { ASTNode, ASTKindToNode, @@ -31,17 +37,18 @@ export type { DefinitionNode, ExecutableDefinitionNode, OperationDefinitionNode, - OperationTypeNode, VariableDefinitionNode, VariableNode, SelectionSetNode, SelectionNode, FieldNode, ArgumentNode, + ConstArgumentNode, FragmentSpreadNode, InlineFragmentNode, FragmentDefinitionNode, ValueNode, + ConstValueNode, IntValueNode, FloatValueNode, StringValueNode, @@ -49,9 +56,13 @@ export type { NullValueNode, EnumValueNode, ListValueNode, + ConstListValueNode, ObjectValueNode, + ConstObjectValueNode, ObjectFieldNode, + ConstObjectFieldNode, DirectiveNode, + ConstDirectiveNode, TypeNode, NamedTypeNode, ListTypeNode, @@ -86,6 +97,7 @@ export { isExecutableDefinitionNode, isSelectionNode, isValueNode, + isConstValueNode, isTypeNode, isTypeSystemDefinitionNode, isTypeDefinitionNode, diff --git a/src/language/kinds.d.ts b/src/language/kinds.d.ts deleted file mode 100644 index 35a7239923..0000000000 --- a/src/language/kinds.d.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * The set of allowed kind values for AST nodes. - */ -export const Kind: { - // Name - NAME: 'Name'; - - // Document - DOCUMENT: 'Document'; - OPERATION_DEFINITION: 'OperationDefinition'; - VARIABLE_DEFINITION: 'VariableDefinition'; - SELECTION_SET: 'SelectionSet'; - FIELD: 'Field'; - ARGUMENT: 'Argument'; - - // Fragments - FRAGMENT_SPREAD: 'FragmentSpread'; - INLINE_FRAGMENT: 'InlineFragment'; - FRAGMENT_DEFINITION: 'FragmentDefinition'; - - // Values - VARIABLE: 'Variable'; - INT: 'IntValue'; - FLOAT: 'FloatValue'; - STRING: 'StringValue'; - BOOLEAN: 'BooleanValue'; - NULL: 'NullValue'; - ENUM: 'EnumValue'; - LIST: 'ListValue'; - OBJECT: 'ObjectValue'; - OBJECT_FIELD: 'ObjectField'; - - // Directives - DIRECTIVE: 'Directive'; - - // Types - NAMED_TYPE: 'NamedType'; - LIST_TYPE: 'ListType'; - NON_NULL_TYPE: 'NonNullType'; - - // Type System Definitions - SCHEMA_DEFINITION: 'SchemaDefinition'; - OPERATION_TYPE_DEFINITION: 'OperationTypeDefinition'; - - // Type Definitions - SCALAR_TYPE_DEFINITION: 'ScalarTypeDefinition'; - OBJECT_TYPE_DEFINITION: 'ObjectTypeDefinition'; - FIELD_DEFINITION: 'FieldDefinition'; - INPUT_VALUE_DEFINITION: 'InputValueDefinition'; - INTERFACE_TYPE_DEFINITION: 'InterfaceTypeDefinition'; - UNION_TYPE_DEFINITION: 'UnionTypeDefinition'; - ENUM_TYPE_DEFINITION: 'EnumTypeDefinition'; - ENUM_VALUE_DEFINITION: 'EnumValueDefinition'; - INPUT_OBJECT_TYPE_DEFINITION: 'InputObjectTypeDefinition'; - - // Directive Definitions - DIRECTIVE_DEFINITION: 'DirectiveDefinition'; - - // Type System Extensions - SCHEMA_EXTENSION: 'SchemaExtension'; - - // Type Extensions - SCALAR_TYPE_EXTENSION: 'ScalarTypeExtension'; - OBJECT_TYPE_EXTENSION: 'ObjectTypeExtension'; - INTERFACE_TYPE_EXTENSION: 'InterfaceTypeExtension'; - UNION_TYPE_EXTENSION: 'UnionTypeExtension'; - ENUM_TYPE_EXTENSION: 'EnumTypeExtension'; - INPUT_OBJECT_TYPE_EXTENSION: 'InputObjectTypeExtension'; -}; - -/** - * The enum type representing the possible kind values of AST nodes. - */ -export type KindEnum = typeof Kind[keyof typeof Kind]; diff --git a/src/language/kinds.js b/src/language/kinds.js deleted file mode 100644 index 99e3e4a9ea..0000000000 --- a/src/language/kinds.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * The set of allowed kind values for AST nodes. - */ -export const Kind = Object.freeze({ - // Name - NAME: 'Name', - - // Document - DOCUMENT: 'Document', - OPERATION_DEFINITION: 'OperationDefinition', - VARIABLE_DEFINITION: 'VariableDefinition', - SELECTION_SET: 'SelectionSet', - FIELD: 'Field', - ARGUMENT: 'Argument', - - // Fragments - FRAGMENT_SPREAD: 'FragmentSpread', - INLINE_FRAGMENT: 'InlineFragment', - FRAGMENT_DEFINITION: 'FragmentDefinition', - - // Values - VARIABLE: 'Variable', - INT: 'IntValue', - FLOAT: 'FloatValue', - STRING: 'StringValue', - BOOLEAN: 'BooleanValue', - NULL: 'NullValue', - ENUM: 'EnumValue', - LIST: 'ListValue', - OBJECT: 'ObjectValue', - OBJECT_FIELD: 'ObjectField', - - // Directives - DIRECTIVE: 'Directive', - - // Types - NAMED_TYPE: 'NamedType', - LIST_TYPE: 'ListType', - NON_NULL_TYPE: 'NonNullType', - - // Type System Definitions - SCHEMA_DEFINITION: 'SchemaDefinition', - OPERATION_TYPE_DEFINITION: 'OperationTypeDefinition', - - // Type Definitions - SCALAR_TYPE_DEFINITION: 'ScalarTypeDefinition', - OBJECT_TYPE_DEFINITION: 'ObjectTypeDefinition', - FIELD_DEFINITION: 'FieldDefinition', - INPUT_VALUE_DEFINITION: 'InputValueDefinition', - INTERFACE_TYPE_DEFINITION: 'InterfaceTypeDefinition', - UNION_TYPE_DEFINITION: 'UnionTypeDefinition', - ENUM_TYPE_DEFINITION: 'EnumTypeDefinition', - ENUM_VALUE_DEFINITION: 'EnumValueDefinition', - INPUT_OBJECT_TYPE_DEFINITION: 'InputObjectTypeDefinition', - - // Directive Definitions - DIRECTIVE_DEFINITION: 'DirectiveDefinition', - - // Type System Extensions - SCHEMA_EXTENSION: 'SchemaExtension', - - // Type Extensions - SCALAR_TYPE_EXTENSION: 'ScalarTypeExtension', - OBJECT_TYPE_EXTENSION: 'ObjectTypeExtension', - INTERFACE_TYPE_EXTENSION: 'InterfaceTypeExtension', - UNION_TYPE_EXTENSION: 'UnionTypeExtension', - ENUM_TYPE_EXTENSION: 'EnumTypeExtension', - INPUT_OBJECT_TYPE_EXTENSION: 'InputObjectTypeExtension', -}); - -/** - * The enum type representing the possible kind values of AST nodes. - */ -export type KindEnum = $Values; diff --git a/src/language/kinds.ts b/src/language/kinds.ts new file mode 100644 index 0000000000..cd05f66a3b --- /dev/null +++ b/src/language/kinds.ts @@ -0,0 +1,77 @@ +/** + * The set of allowed kind values for AST nodes. + */ +enum Kind { + /** Name */ + NAME = 'Name', + + /** Document */ + DOCUMENT = 'Document', + OPERATION_DEFINITION = 'OperationDefinition', + VARIABLE_DEFINITION = 'VariableDefinition', + SELECTION_SET = 'SelectionSet', + FIELD = 'Field', + ARGUMENT = 'Argument', + + /** Fragments */ + FRAGMENT_SPREAD = 'FragmentSpread', + INLINE_FRAGMENT = 'InlineFragment', + FRAGMENT_DEFINITION = 'FragmentDefinition', + + /** Values */ + VARIABLE = 'Variable', + INT = 'IntValue', + FLOAT = 'FloatValue', + STRING = 'StringValue', + BOOLEAN = 'BooleanValue', + NULL = 'NullValue', + ENUM = 'EnumValue', + LIST = 'ListValue', + OBJECT = 'ObjectValue', + OBJECT_FIELD = 'ObjectField', + + /** Directives */ + DIRECTIVE = 'Directive', + + /** Types */ + NAMED_TYPE = 'NamedType', + LIST_TYPE = 'ListType', + NON_NULL_TYPE = 'NonNullType', + + /** Type System Definitions */ + SCHEMA_DEFINITION = 'SchemaDefinition', + OPERATION_TYPE_DEFINITION = 'OperationTypeDefinition', + + /** Type Definitions */ + SCALAR_TYPE_DEFINITION = 'ScalarTypeDefinition', + OBJECT_TYPE_DEFINITION = 'ObjectTypeDefinition', + FIELD_DEFINITION = 'FieldDefinition', + INPUT_VALUE_DEFINITION = 'InputValueDefinition', + INTERFACE_TYPE_DEFINITION = 'InterfaceTypeDefinition', + UNION_TYPE_DEFINITION = 'UnionTypeDefinition', + ENUM_TYPE_DEFINITION = 'EnumTypeDefinition', + ENUM_VALUE_DEFINITION = 'EnumValueDefinition', + INPUT_OBJECT_TYPE_DEFINITION = 'InputObjectTypeDefinition', + + /** Directive Definitions */ + DIRECTIVE_DEFINITION = 'DirectiveDefinition', + + /** Type System Extensions */ + SCHEMA_EXTENSION = 'SchemaExtension', + + /** Type Extensions */ + SCALAR_TYPE_EXTENSION = 'ScalarTypeExtension', + OBJECT_TYPE_EXTENSION = 'ObjectTypeExtension', + INTERFACE_TYPE_EXTENSION = 'InterfaceTypeExtension', + UNION_TYPE_EXTENSION = 'UnionTypeExtension', + ENUM_TYPE_EXTENSION = 'EnumTypeExtension', + INPUT_OBJECT_TYPE_EXTENSION = 'InputObjectTypeExtension', +} +export { Kind }; + +/** + * The enum type representing the possible kind values of AST nodes. + * + * @deprecated Please use `Kind`. Will be remove in v17. + */ +export type KindEnum = typeof Kind; diff --git a/src/language/lexer.d.ts b/src/language/lexer.d.ts deleted file mode 100644 index 40dbf9a6b2..0000000000 --- a/src/language/lexer.d.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Token } from './ast'; -import { Source } from './source'; -import { TokenKindEnum } from './tokenKind'; - -/** - * Given a Source object, this returns a Lexer for that source. - * A Lexer is a stateful stream generator in that every time - * it is advanced, it returns the next token in the Source. Assuming the - * source lexes, the final Token emitted by the lexer will be of kind - * EOF, after which the lexer will repeatedly return the same EOF token - * whenever called. - */ -export class Lexer { - source: Source; - - /** - * The previously focused non-ignored token. - */ - lastToken: Token; - - /** - * The currently focused non-ignored token. - */ - token: Token; - - /** - * The (1-indexed) line containing the current token. - */ - line: number; - - /** - * The character offset at which the current line begins. - */ - lineStart: number; - - constructor(source: Source); - - /** - * Advances the token stream to the next non-ignored token. - */ - advance(): Token; - - /** - * Looks ahead and returns the next non-ignored token, but does not change - * the state of Lexer. - */ - lookahead(): Token; -} - -/** - * @internal - */ -export function isPunctuatorToken(token: Token): boolean; - -/** - * @internal - */ -export function isPunctuatorTokenKind(kind: TokenKindEnum): boolean; diff --git a/src/language/lexer.js b/src/language/lexer.js deleted file mode 100644 index ad42ce9897..0000000000 --- a/src/language/lexer.js +++ /dev/null @@ -1,700 +0,0 @@ -import { syntaxError } from '../error/syntaxError'; - -import type { Source } from './source'; -import type { TokenKindEnum } from './tokenKind'; -import { Token } from './ast'; -import { TokenKind } from './tokenKind'; -import { dedentBlockStringValue } from './blockString'; - -/** - * Given a Source object, creates a Lexer for that source. - * A Lexer is a stateful stream generator in that every time - * it is advanced, it returns the next token in the Source. Assuming the - * source lexes, the final Token emitted by the lexer will be of kind - * EOF, after which the lexer will repeatedly return the same EOF token - * whenever called. - */ -export class Lexer { - source: Source; - - /** - * The previously focused non-ignored token. - */ - lastToken: Token; - - /** - * The currently focused non-ignored token. - */ - token: Token; - - /** - * The (1-indexed) line containing the current token. - */ - line: number; - - /** - * The character offset at which the current line begins. - */ - lineStart: number; - - constructor(source: Source) { - const startOfFileToken = new Token(TokenKind.SOF, 0, 0, 0, 0, null); - - this.source = source; - this.lastToken = startOfFileToken; - this.token = startOfFileToken; - this.line = 1; - this.lineStart = 0; - } - - /** - * Advances the token stream to the next non-ignored token. - */ - advance(): Token { - this.lastToken = this.token; - const token = (this.token = this.lookahead()); - return token; - } - - /** - * Looks ahead and returns the next non-ignored token, but does not change - * the state of Lexer. - */ - lookahead(): Token { - let token = this.token; - if (token.kind !== TokenKind.EOF) { - do { - // Note: next is only mutable during parsing, so we cast to allow this. - token = token.next ?? ((token: any).next = readToken(this, token)); - } while (token.kind === TokenKind.COMMENT); - } - return token; - } -} - -/** - * @internal - */ -export function isPunctuatorTokenKind(kind: TokenKindEnum): boolean %checks { - return ( - kind === TokenKind.BANG || - kind === TokenKind.DOLLAR || - kind === TokenKind.AMP || - kind === TokenKind.PAREN_L || - kind === TokenKind.PAREN_R || - kind === TokenKind.SPREAD || - kind === TokenKind.COLON || - kind === TokenKind.EQUALS || - kind === TokenKind.AT || - kind === TokenKind.BRACKET_L || - kind === TokenKind.BRACKET_R || - kind === TokenKind.BRACE_L || - kind === TokenKind.PIPE || - kind === TokenKind.BRACE_R - ); -} - -function printCharCode(code: number): string { - return ( - // NaN/undefined represents access beyond the end of the file. - isNaN(code) - ? TokenKind.EOF - : // Trust JSON for ASCII. - code < 0x007f - ? JSON.stringify(String.fromCharCode(code)) - : // Otherwise print the escaped form. - `"\\u${('00' + code.toString(16).toUpperCase()).slice(-4)}"` - ); -} - -/** - * Gets the next token from the source starting at the given position. - * - * This skips over whitespace until it finds the next lexable token, then lexes - * punctuators immediately or calls the appropriate helper function for more - * complicated tokens. - */ -function readToken(lexer: Lexer, prev: Token): Token { - const source = lexer.source; - const body = source.body; - const bodyLength = body.length; - - let pos = prev.end; - while (pos < bodyLength) { - const code = body.charCodeAt(pos); - - const line = lexer.line; - const col = 1 + pos - lexer.lineStart; - - // SourceCharacter - switch (code) { - case 0xfeff: // - case 9: // \t - case 32: // - case 44: // , - ++pos; - continue; - case 10: // \n - ++pos; - ++lexer.line; - lexer.lineStart = pos; - continue; - case 13: // \r - if (body.charCodeAt(pos + 1) === 10) { - pos += 2; - } else { - ++pos; - } - ++lexer.line; - lexer.lineStart = pos; - continue; - case 33: // ! - return new Token(TokenKind.BANG, pos, pos + 1, line, col, prev); - case 35: // # - return readComment(source, pos, line, col, prev); - case 36: // $ - return new Token(TokenKind.DOLLAR, pos, pos + 1, line, col, prev); - case 38: // & - return new Token(TokenKind.AMP, pos, pos + 1, line, col, prev); - case 40: // ( - return new Token(TokenKind.PAREN_L, pos, pos + 1, line, col, prev); - case 41: // ) - return new Token(TokenKind.PAREN_R, pos, pos + 1, line, col, prev); - case 46: // . - if ( - body.charCodeAt(pos + 1) === 46 && - body.charCodeAt(pos + 2) === 46 - ) { - return new Token(TokenKind.SPREAD, pos, pos + 3, line, col, prev); - } - break; - case 58: // : - return new Token(TokenKind.COLON, pos, pos + 1, line, col, prev); - case 61: // = - return new Token(TokenKind.EQUALS, pos, pos + 1, line, col, prev); - case 64: // @ - return new Token(TokenKind.AT, pos, pos + 1, line, col, prev); - case 91: // [ - return new Token(TokenKind.BRACKET_L, pos, pos + 1, line, col, prev); - case 93: // ] - return new Token(TokenKind.BRACKET_R, pos, pos + 1, line, col, prev); - case 123: // { - return new Token(TokenKind.BRACE_L, pos, pos + 1, line, col, prev); - case 124: // | - return new Token(TokenKind.PIPE, pos, pos + 1, line, col, prev); - case 125: // } - return new Token(TokenKind.BRACE_R, pos, pos + 1, line, col, prev); - case 34: // " - if ( - body.charCodeAt(pos + 1) === 34 && - body.charCodeAt(pos + 2) === 34 - ) { - return readBlockString(source, pos, line, col, prev, lexer); - } - return readString(source, pos, line, col, prev); - case 45: // - - case 48: // 0 - case 49: // 1 - case 50: // 2 - case 51: // 3 - case 52: // 4 - case 53: // 5 - case 54: // 6 - case 55: // 7 - case 56: // 8 - case 57: // 9 - return readNumber(source, pos, code, line, col, prev); - case 65: // A - case 66: // B - case 67: // C - case 68: // D - case 69: // E - case 70: // F - case 71: // G - case 72: // H - case 73: // I - case 74: // J - case 75: // K - case 76: // L - case 77: // M - case 78: // N - case 79: // O - case 80: // P - case 81: // Q - case 82: // R - case 83: // S - case 84: // T - case 85: // U - case 86: // V - case 87: // W - case 88: // X - case 89: // Y - case 90: // Z - case 95: // _ - case 97: // a - case 98: // b - case 99: // c - case 100: // d - case 101: // e - case 102: // f - case 103: // g - case 104: // h - case 105: // i - case 106: // j - case 107: // k - case 108: // l - case 109: // m - case 110: // n - case 111: // o - case 112: // p - case 113: // q - case 114: // r - case 115: // s - case 116: // t - case 117: // u - case 118: // v - case 119: // w - case 120: // x - case 121: // y - case 122: // z - return readName(source, pos, line, col, prev); - } - - throw syntaxError(source, pos, unexpectedCharacterMessage(code)); - } - - const line = lexer.line; - const col = 1 + pos - lexer.lineStart; - return new Token(TokenKind.EOF, bodyLength, bodyLength, line, col, prev); -} - -/** - * Report a message that an unexpected character was encountered. - */ -function unexpectedCharacterMessage(code: number): string { - if (code < 0x0020 && code !== 0x0009 && code !== 0x000a && code !== 0x000d) { - return `Cannot contain the invalid character ${printCharCode(code)}.`; - } - - if (code === 39) { - // ' - return 'Unexpected single quote character (\'), did you mean to use a double quote (")?'; - } - - return `Cannot parse the unexpected character ${printCharCode(code)}.`; -} - -/** - * Reads a comment token from the source file. - * - * #[\u0009\u0020-\uFFFF]* - */ -function readComment( - source: Source, - start: number, - line: number, - col: number, - prev: Token | null, -): Token { - const body = source.body; - let code; - let position = start; - - do { - code = body.charCodeAt(++position); - } while ( - !isNaN(code) && - // SourceCharacter but not LineTerminator - (code > 0x001f || code === 0x0009) - ); - - return new Token( - TokenKind.COMMENT, - start, - position, - line, - col, - prev, - body.slice(start + 1, position), - ); -} - -/** - * Reads a number token from the source file, either a float - * or an int depending on whether a decimal point appears. - * - * Int: -?(0|[1-9][0-9]*) - * Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)? - */ -function readNumber( - source: Source, - start: number, - firstCode: number, - line: number, - col: number, - prev: Token | null, -): Token { - const body = source.body; - let code = firstCode; - let position = start; - let isFloat = false; - - if (code === 45) { - // - - code = body.charCodeAt(++position); - } - - if (code === 48) { - // 0 - code = body.charCodeAt(++position); - if (code >= 48 && code <= 57) { - throw syntaxError( - source, - position, - `Invalid number, unexpected digit after 0: ${printCharCode(code)}.`, - ); - } - } else { - position = readDigits(source, position, code); - code = body.charCodeAt(position); - } - - if (code === 46) { - // . - isFloat = true; - - code = body.charCodeAt(++position); - position = readDigits(source, position, code); - code = body.charCodeAt(position); - } - - if (code === 69 || code === 101) { - // E e - isFloat = true; - - code = body.charCodeAt(++position); - if (code === 43 || code === 45) { - // + - - code = body.charCodeAt(++position); - } - position = readDigits(source, position, code); - code = body.charCodeAt(position); - } - - // Numbers cannot be followed by . or NameStart - if (code === 46 || isNameStart(code)) { - throw syntaxError( - source, - position, - `Invalid number, expected digit but got: ${printCharCode(code)}.`, - ); - } - - return new Token( - isFloat ? TokenKind.FLOAT : TokenKind.INT, - start, - position, - line, - col, - prev, - body.slice(start, position), - ); -} - -/** - * Returns the new position in the source after reading digits. - */ -function readDigits(source: Source, start: number, firstCode: number): number { - const body = source.body; - let position = start; - let code = firstCode; - if (code >= 48 && code <= 57) { - // 0 - 9 - do { - code = body.charCodeAt(++position); - } while (code >= 48 && code <= 57); // 0 - 9 - return position; - } - throw syntaxError( - source, - position, - `Invalid number, expected digit but got: ${printCharCode(code)}.`, - ); -} - -/** - * Reads a string token from the source file. - * - * "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*" - */ -function readString( - source: Source, - start: number, - line: number, - col: number, - prev: Token | null, -): Token { - const body = source.body; - let position = start + 1; - let chunkStart = position; - let code = 0; - let value = ''; - - while ( - position < body.length && - !isNaN((code = body.charCodeAt(position))) && - // not LineTerminator - code !== 0x000a && - code !== 0x000d - ) { - // Closing Quote (") - if (code === 34) { - value += body.slice(chunkStart, position); - return new Token( - TokenKind.STRING, - start, - position + 1, - line, - col, - prev, - value, - ); - } - - // SourceCharacter - if (code < 0x0020 && code !== 0x0009) { - throw syntaxError( - source, - position, - `Invalid character within String: ${printCharCode(code)}.`, - ); - } - - ++position; - if (code === 92) { - // \ - value += body.slice(chunkStart, position - 1); - code = body.charCodeAt(position); - switch (code) { - case 34: - value += '"'; - break; - case 47: - value += '/'; - break; - case 92: - value += '\\'; - break; - case 98: - value += '\b'; - break; - case 102: - value += '\f'; - break; - case 110: - value += '\n'; - break; - case 114: - value += '\r'; - break; - case 116: - value += '\t'; - break; - case 117: { - // uXXXX - const charCode = uniCharCode( - body.charCodeAt(position + 1), - body.charCodeAt(position + 2), - body.charCodeAt(position + 3), - body.charCodeAt(position + 4), - ); - if (charCode < 0) { - const invalidSequence = body.slice(position + 1, position + 5); - throw syntaxError( - source, - position, - `Invalid character escape sequence: \\u${invalidSequence}.`, - ); - } - value += String.fromCharCode(charCode); - position += 4; - break; - } - default: - throw syntaxError( - source, - position, - `Invalid character escape sequence: \\${String.fromCharCode( - code, - )}.`, - ); - } - ++position; - chunkStart = position; - } - } - - throw syntaxError(source, position, 'Unterminated string.'); -} - -/** - * Reads a block string token from the source file. - * - * """("?"?(\\"""|\\(?!=""")|[^"\\]))*""" - */ -function readBlockString( - source: Source, - start: number, - line: number, - col: number, - prev: Token | null, - lexer: Lexer, -): Token { - const body = source.body; - let position = start + 3; - let chunkStart = position; - let code = 0; - let rawValue = ''; - - while (position < body.length && !isNaN((code = body.charCodeAt(position)))) { - // Closing Triple-Quote (""") - if ( - code === 34 && - body.charCodeAt(position + 1) === 34 && - body.charCodeAt(position + 2) === 34 - ) { - rawValue += body.slice(chunkStart, position); - return new Token( - TokenKind.BLOCK_STRING, - start, - position + 3, - line, - col, - prev, - dedentBlockStringValue(rawValue), - ); - } - - // SourceCharacter - if ( - code < 0x0020 && - code !== 0x0009 && - code !== 0x000a && - code !== 0x000d - ) { - throw syntaxError( - source, - position, - `Invalid character within String: ${printCharCode(code)}.`, - ); - } - - if (code === 10) { - // new line - ++position; - ++lexer.line; - lexer.lineStart = position; - } else if (code === 13) { - // carriage return - if (body.charCodeAt(position + 1) === 10) { - position += 2; - } else { - ++position; - } - ++lexer.line; - lexer.lineStart = position; - } else if ( - // Escape Triple-Quote (\""") - code === 92 && - body.charCodeAt(position + 1) === 34 && - body.charCodeAt(position + 2) === 34 && - body.charCodeAt(position + 3) === 34 - ) { - rawValue += body.slice(chunkStart, position) + '"""'; - position += 4; - chunkStart = position; - } else { - ++position; - } - } - - throw syntaxError(source, position, 'Unterminated string.'); -} - -/** - * Converts four hexadecimal chars to the integer that the - * string represents. For example, uniCharCode('0','0','0','f') - * will return 15, and uniCharCode('0','0','f','f') returns 255. - * - * Returns a negative number on error, if a char was invalid. - * - * This is implemented by noting that char2hex() returns -1 on error, - * which means the result of ORing the char2hex() will also be negative. - */ -function uniCharCode(a: number, b: number, c: number, d: number): number { - return ( - (char2hex(a) << 12) | (char2hex(b) << 8) | (char2hex(c) << 4) | char2hex(d) - ); -} - -/** - * Converts a hex character to its integer value. - * '0' becomes 0, '9' becomes 9 - * 'A' becomes 10, 'F' becomes 15 - * 'a' becomes 10, 'f' becomes 15 - * - * Returns -1 on error. - */ -function char2hex(a: number): number { - return a >= 48 && a <= 57 - ? a - 48 // 0-9 - : a >= 65 && a <= 70 - ? a - 55 // A-F - : a >= 97 && a <= 102 - ? a - 87 // a-f - : -1; -} - -/** - * Reads an alphanumeric + underscore name from the source. - * - * [_A-Za-z][_0-9A-Za-z]* - */ -function readName( - source: Source, - start: number, - line: number, - col: number, - prev: Token | null, -): Token { - const body = source.body; - const bodyLength = body.length; - let position = start + 1; - let code = 0; - while ( - position !== bodyLength && - !isNaN((code = body.charCodeAt(position))) && - (code === 95 || // _ - (code >= 48 && code <= 57) || // 0-9 - (code >= 65 && code <= 90) || // A-Z - (code >= 97 && code <= 122)) // a-z - ) { - ++position; - } - return new Token( - TokenKind.NAME, - start, - position, - line, - col, - prev, - body.slice(start, position), - ); -} - -// _ A-Z a-z -function isNameStart(code: number): boolean { - return ( - code === 95 || (code >= 65 && code <= 90) || (code >= 97 && code <= 122) - ); -} diff --git a/src/language/lexer.ts b/src/language/lexer.ts new file mode 100644 index 0000000000..818f81b286 --- /dev/null +++ b/src/language/lexer.ts @@ -0,0 +1,854 @@ +import { syntaxError } from '../error/syntaxError'; + +import { Token } from './ast'; +import { dedentBlockStringLines } from './blockString'; +import { isDigit, isNameContinue, isNameStart } from './characterClasses'; +import type { Source } from './source'; +import { TokenKind } from './tokenKind'; + +/** + * Given a Source object, creates a Lexer for that source. + * A Lexer is a stateful stream generator in that every time + * it is advanced, it returns the next token in the Source. Assuming the + * source lexes, the final Token emitted by the lexer will be of kind + * EOF, after which the lexer will repeatedly return the same EOF token + * whenever called. + */ +export class Lexer { + source: Source; + + /** + * The previously focused non-ignored token. + */ + lastToken: Token; + + /** + * The currently focused non-ignored token. + */ + token: Token; + + /** + * The (1-indexed) line containing the current token. + */ + line: number; + + /** + * The character offset at which the current line begins. + */ + lineStart: number; + + constructor(source: Source) { + const startOfFileToken = new Token(TokenKind.SOF, 0, 0, 0, 0); + + this.source = source; + this.lastToken = startOfFileToken; + this.token = startOfFileToken; + this.line = 1; + this.lineStart = 0; + } + + get [Symbol.toStringTag]() { + return 'Lexer'; + } + + /** + * Advances the token stream to the next non-ignored token. + */ + advance(): Token { + this.lastToken = this.token; + const token = (this.token = this.lookahead()); + return token; + } + + /** + * Looks ahead and returns the next non-ignored token, but does not change + * the state of Lexer. + */ + lookahead(): Token { + let token = this.token; + if (token.kind !== TokenKind.EOF) { + do { + if (token.next) { + token = token.next; + } else { + // Read the next token and form a link in the token linked-list. + const nextToken = readNextToken(this, token.end); + // @ts-expect-error next is only mutable during parsing. + token.next = nextToken; + // @ts-expect-error prev is only mutable during parsing. + nextToken.prev = token; + token = nextToken; + } + } while (token.kind === TokenKind.COMMENT); + } + return token; + } +} + +/** + * @internal + */ +export function isPunctuatorTokenKind(kind: TokenKind): boolean { + return ( + kind === TokenKind.BANG || + kind === TokenKind.DOLLAR || + kind === TokenKind.AMP || + kind === TokenKind.PAREN_L || + kind === TokenKind.PAREN_R || + kind === TokenKind.SPREAD || + kind === TokenKind.COLON || + kind === TokenKind.EQUALS || + kind === TokenKind.AT || + kind === TokenKind.BRACKET_L || + kind === TokenKind.BRACKET_R || + kind === TokenKind.BRACE_L || + kind === TokenKind.PIPE || + kind === TokenKind.BRACE_R + ); +} + +/** + * A Unicode scalar value is any Unicode code point except surrogate code + * points. In other words, the inclusive ranges of values 0x0000 to 0xD7FF and + * 0xE000 to 0x10FFFF. + * + * SourceCharacter :: + * - "Any Unicode scalar value" + */ +function isUnicodeScalarValue(code: number): boolean { + return ( + (code >= 0x0000 && code <= 0xd7ff) || (code >= 0xe000 && code <= 0x10ffff) + ); +} + +/** + * The GraphQL specification defines source text as a sequence of unicode scalar + * values (which Unicode defines to exclude surrogate code points). However + * JavaScript defines strings as a sequence of UTF-16 code units which may + * include surrogates. A surrogate pair is a valid source character as it + * encodes a supplementary code point (above U+FFFF), but unpaired surrogate + * code points are not valid source characters. + */ +function isSupplementaryCodePoint(body: string, location: number): boolean { + return ( + isLeadingSurrogate(body.charCodeAt(location)) && + isTrailingSurrogate(body.charCodeAt(location + 1)) + ); +} + +function isLeadingSurrogate(code: number): boolean { + return code >= 0xd800 && code <= 0xdbff; +} + +function isTrailingSurrogate(code: number): boolean { + return code >= 0xdc00 && code <= 0xdfff; +} + +/** + * Prints the code point (or end of file reference) at a given location in a + * source for use in error messages. + * + * Printable ASCII is printed quoted, while other points are printed in Unicode + * code point form (ie. U+1234). + */ +function printCodePointAt(lexer: Lexer, location: number): string { + const code = lexer.source.body.codePointAt(location); + + if (code === undefined) { + return TokenKind.EOF; + } else if (code >= 0x0020 && code <= 0x007e) { + // Printable ASCII + const char = String.fromCodePoint(code); + return char === '"' ? "'\"'" : `"${char}"`; + } + + // Unicode code point + return 'U+' + code.toString(16).toUpperCase().padStart(4, '0'); +} + +/** + * Create a token with line and column location information. + */ +function createToken( + lexer: Lexer, + kind: TokenKind, + start: number, + end: number, + value?: string, +): Token { + const line = lexer.line; + const col = 1 + start - lexer.lineStart; + return new Token(kind, start, end, line, col, value); +} + +/** + * Gets the next token from the source starting at the given position. + * + * This skips over whitespace until it finds the next lexable token, then lexes + * punctuators immediately or calls the appropriate helper function for more + * complicated tokens. + */ +function readNextToken(lexer: Lexer, start: number): Token { + const body = lexer.source.body; + const bodyLength = body.length; + let position = start; + + while (position < bodyLength) { + const code = body.charCodeAt(position); + + // SourceCharacter + switch (code) { + // Ignored :: + // - UnicodeBOM + // - WhiteSpace + // - LineTerminator + // - Comment + // - Comma + // + // UnicodeBOM :: "Byte Order Mark (U+FEFF)" + // + // WhiteSpace :: + // - "Horizontal Tab (U+0009)" + // - "Space (U+0020)" + // + // Comma :: , + case 0xfeff: // + case 0x0009: // \t + case 0x0020: // + case 0x002c: // , + ++position; + continue; + // LineTerminator :: + // - "New Line (U+000A)" + // - "Carriage Return (U+000D)" [lookahead != "New Line (U+000A)"] + // - "Carriage Return (U+000D)" "New Line (U+000A)" + case 0x000a: // \n + ++position; + ++lexer.line; + lexer.lineStart = position; + continue; + case 0x000d: // \r + if (body.charCodeAt(position + 1) === 0x000a) { + position += 2; + } else { + ++position; + } + ++lexer.line; + lexer.lineStart = position; + continue; + // Comment + case 0x0023: // # + return readComment(lexer, position); + // Token :: + // - Punctuator + // - Name + // - IntValue + // - FloatValue + // - StringValue + // + // Punctuator :: one of ! $ & ( ) ... : = @ [ ] { | } + case 0x0021: // ! + return createToken(lexer, TokenKind.BANG, position, position + 1); + case 0x0024: // $ + return createToken(lexer, TokenKind.DOLLAR, position, position + 1); + case 0x0026: // & + return createToken(lexer, TokenKind.AMP, position, position + 1); + case 0x0028: // ( + return createToken(lexer, TokenKind.PAREN_L, position, position + 1); + case 0x0029: // ) + return createToken(lexer, TokenKind.PAREN_R, position, position + 1); + case 0x002e: // . + if ( + body.charCodeAt(position + 1) === 0x002e && + body.charCodeAt(position + 2) === 0x002e + ) { + return createToken(lexer, TokenKind.SPREAD, position, position + 3); + } + break; + case 0x003a: // : + return createToken(lexer, TokenKind.COLON, position, position + 1); + case 0x003d: // = + return createToken(lexer, TokenKind.EQUALS, position, position + 1); + case 0x0040: // @ + return createToken(lexer, TokenKind.AT, position, position + 1); + case 0x005b: // [ + return createToken(lexer, TokenKind.BRACKET_L, position, position + 1); + case 0x005d: // ] + return createToken(lexer, TokenKind.BRACKET_R, position, position + 1); + case 0x007b: // { + return createToken(lexer, TokenKind.BRACE_L, position, position + 1); + case 0x007c: // | + return createToken(lexer, TokenKind.PIPE, position, position + 1); + case 0x007d: // } + return createToken(lexer, TokenKind.BRACE_R, position, position + 1); + // StringValue + case 0x0022: // " + if ( + body.charCodeAt(position + 1) === 0x0022 && + body.charCodeAt(position + 2) === 0x0022 + ) { + return readBlockString(lexer, position); + } + return readString(lexer, position); + } + + // IntValue | FloatValue (Digit | -) + if (isDigit(code) || code === 0x002d) { + return readNumber(lexer, position, code); + } + + // Name + if (isNameStart(code)) { + return readName(lexer, position); + } + + throw syntaxError( + lexer.source, + position, + code === 0x0027 + ? 'Unexpected single quote character (\'), did you mean to use a double quote (")?' + : isUnicodeScalarValue(code) || isSupplementaryCodePoint(body, position) + ? `Unexpected character: ${printCodePointAt(lexer, position)}.` + : `Invalid character: ${printCodePointAt(lexer, position)}.`, + ); + } + + return createToken(lexer, TokenKind.EOF, bodyLength, bodyLength); +} + +/** + * Reads a comment token from the source file. + * + * ``` + * Comment :: # CommentChar* [lookahead != CommentChar] + * + * CommentChar :: SourceCharacter but not LineTerminator + * ``` + */ +function readComment(lexer: Lexer, start: number): Token { + const body = lexer.source.body; + const bodyLength = body.length; + let position = start + 1; + + while (position < bodyLength) { + const code = body.charCodeAt(position); + + // LineTerminator (\n | \r) + if (code === 0x000a || code === 0x000d) { + break; + } + + // SourceCharacter + if (isUnicodeScalarValue(code)) { + ++position; + } else if (isSupplementaryCodePoint(body, position)) { + position += 2; + } else { + break; + } + } + + return createToken( + lexer, + TokenKind.COMMENT, + start, + position, + body.slice(start + 1, position), + ); +} + +/** + * Reads a number token from the source file, either a FloatValue or an IntValue + * depending on whether a FractionalPart or ExponentPart is encountered. + * + * ``` + * IntValue :: IntegerPart [lookahead != {Digit, `.`, NameStart}] + * + * IntegerPart :: + * - NegativeSign? 0 + * - NegativeSign? NonZeroDigit Digit* + * + * NegativeSign :: - + * + * NonZeroDigit :: Digit but not `0` + * + * FloatValue :: + * - IntegerPart FractionalPart ExponentPart [lookahead != {Digit, `.`, NameStart}] + * - IntegerPart FractionalPart [lookahead != {Digit, `.`, NameStart}] + * - IntegerPart ExponentPart [lookahead != {Digit, `.`, NameStart}] + * + * FractionalPart :: . Digit+ + * + * ExponentPart :: ExponentIndicator Sign? Digit+ + * + * ExponentIndicator :: one of `e` `E` + * + * Sign :: one of + - + * ``` + */ +function readNumber(lexer: Lexer, start: number, firstCode: number): Token { + const body = lexer.source.body; + let position = start; + let code = firstCode; + let isFloat = false; + + // NegativeSign (-) + if (code === 0x002d) { + code = body.charCodeAt(++position); + } + + // Zero (0) + if (code === 0x0030) { + code = body.charCodeAt(++position); + if (isDigit(code)) { + throw syntaxError( + lexer.source, + position, + `Invalid number, unexpected digit after 0: ${printCodePointAt( + lexer, + position, + )}.`, + ); + } + } else { + position = readDigits(lexer, position, code); + code = body.charCodeAt(position); + } + + // Full stop (.) + if (code === 0x002e) { + isFloat = true; + + code = body.charCodeAt(++position); + position = readDigits(lexer, position, code); + code = body.charCodeAt(position); + } + + // E e + if (code === 0x0045 || code === 0x0065) { + isFloat = true; + + code = body.charCodeAt(++position); + // + - + if (code === 0x002b || code === 0x002d) { + code = body.charCodeAt(++position); + } + position = readDigits(lexer, position, code); + code = body.charCodeAt(position); + } + + // Numbers cannot be followed by . or NameStart + if (code === 0x002e || isNameStart(code)) { + throw syntaxError( + lexer.source, + position, + `Invalid number, expected digit but got: ${printCodePointAt( + lexer, + position, + )}.`, + ); + } + + return createToken( + lexer, + isFloat ? TokenKind.FLOAT : TokenKind.INT, + start, + position, + body.slice(start, position), + ); +} + +/** + * Returns the new position in the source after reading one or more digits. + */ +function readDigits(lexer: Lexer, start: number, firstCode: number): number { + if (!isDigit(firstCode)) { + throw syntaxError( + lexer.source, + start, + `Invalid number, expected digit but got: ${printCodePointAt( + lexer, + start, + )}.`, + ); + } + + const body = lexer.source.body; + let position = start + 1; // +1 to skip first firstCode + + while (isDigit(body.charCodeAt(position))) { + ++position; + } + + return position; +} + +/** + * Reads a single-quote string token from the source file. + * + * ``` + * StringValue :: + * - `""` [lookahead != `"`] + * - `"` StringCharacter+ `"` + * + * StringCharacter :: + * - SourceCharacter but not `"` or `\` or LineTerminator + * - `\u` EscapedUnicode + * - `\` EscapedCharacter + * + * EscapedUnicode :: + * - `{` HexDigit+ `}` + * - HexDigit HexDigit HexDigit HexDigit + * + * EscapedCharacter :: one of `"` `\` `/` `b` `f` `n` `r` `t` + * ``` + */ +function readString(lexer: Lexer, start: number): Token { + const body = lexer.source.body; + const bodyLength = body.length; + let position = start + 1; + let chunkStart = position; + let value = ''; + + while (position < bodyLength) { + const code = body.charCodeAt(position); + + // Closing Quote (") + if (code === 0x0022) { + value += body.slice(chunkStart, position); + return createToken(lexer, TokenKind.STRING, start, position + 1, value); + } + + // Escape Sequence (\) + if (code === 0x005c) { + value += body.slice(chunkStart, position); + const escape = + body.charCodeAt(position + 1) === 0x0075 // u + ? body.charCodeAt(position + 2) === 0x007b // { + ? readEscapedUnicodeVariableWidth(lexer, position) + : readEscapedUnicodeFixedWidth(lexer, position) + : readEscapedCharacter(lexer, position); + value += escape.value; + position += escape.size; + chunkStart = position; + continue; + } + + // LineTerminator (\n | \r) + if (code === 0x000a || code === 0x000d) { + break; + } + + // SourceCharacter + if (isUnicodeScalarValue(code)) { + ++position; + } else if (isSupplementaryCodePoint(body, position)) { + position += 2; + } else { + throw syntaxError( + lexer.source, + position, + `Invalid character within String: ${printCodePointAt( + lexer, + position, + )}.`, + ); + } + } + + throw syntaxError(lexer.source, position, 'Unterminated string.'); +} + +// The string value and lexed size of an escape sequence. +interface EscapeSequence { + value: string; + size: number; +} + +function readEscapedUnicodeVariableWidth( + lexer: Lexer, + position: number, +): EscapeSequence { + const body = lexer.source.body; + let point = 0; + let size = 3; + // Cannot be larger than 12 chars (\u{00000000}). + while (size < 12) { + const code = body.charCodeAt(position + size++); + // Closing Brace (}) + if (code === 0x007d) { + // Must be at least 5 chars (\u{0}) and encode a Unicode scalar value. + if (size < 5 || !isUnicodeScalarValue(point)) { + break; + } + return { value: String.fromCodePoint(point), size }; + } + // Append this hex digit to the code point. + point = (point << 4) | readHexDigit(code); + if (point < 0) { + break; + } + } + + throw syntaxError( + lexer.source, + position, + `Invalid Unicode escape sequence: "${body.slice( + position, + position + size, + )}".`, + ); +} + +function readEscapedUnicodeFixedWidth( + lexer: Lexer, + position: number, +): EscapeSequence { + const body = lexer.source.body; + const code = read16BitHexCode(body, position + 2); + + if (isUnicodeScalarValue(code)) { + return { value: String.fromCodePoint(code), size: 6 }; + } + + // GraphQL allows JSON-style surrogate pair escape sequences, but only when + // a valid pair is formed. + if (isLeadingSurrogate(code)) { + // \u + if ( + body.charCodeAt(position + 6) === 0x005c && + body.charCodeAt(position + 7) === 0x0075 + ) { + const trailingCode = read16BitHexCode(body, position + 8); + if (isTrailingSurrogate(trailingCode)) { + // JavaScript defines strings as a sequence of UTF-16 code units and + // encodes Unicode code points above U+FFFF using a surrogate pair of + // code units. Since this is a surrogate pair escape sequence, just + // include both codes into the JavaScript string value. Had JavaScript + // not been internally based on UTF-16, then this surrogate pair would + // be decoded to retrieve the supplementary code point. + return { value: String.fromCodePoint(code, trailingCode), size: 12 }; + } + } + } + + throw syntaxError( + lexer.source, + position, + `Invalid Unicode escape sequence: "${body.slice(position, position + 6)}".`, + ); +} + +/** + * Reads four hexadecimal characters and returns the positive integer that 16bit + * hexadecimal string represents. For example, "000f" will return 15, and "dead" + * will return 57005. + * + * Returns a negative number if any char was not a valid hexadecimal digit. + */ +function read16BitHexCode(body: string, position: number): number { + // readHexDigit() returns -1 on error. ORing a negative value with any other + // value always produces a negative value. + return ( + (readHexDigit(body.charCodeAt(position)) << 12) | + (readHexDigit(body.charCodeAt(position + 1)) << 8) | + (readHexDigit(body.charCodeAt(position + 2)) << 4) | + readHexDigit(body.charCodeAt(position + 3)) + ); +} + +/** + * Reads a hexadecimal character and returns its positive integer value (0-15). + * + * '0' becomes 0, '9' becomes 9 + * 'A' becomes 10, 'F' becomes 15 + * 'a' becomes 10, 'f' becomes 15 + * + * Returns -1 if the provided character code was not a valid hexadecimal digit. + * + * HexDigit :: one of + * - `0` `1` `2` `3` `4` `5` `6` `7` `8` `9` + * - `A` `B` `C` `D` `E` `F` + * - `a` `b` `c` `d` `e` `f` + */ +function readHexDigit(code: number): number { + return code >= 0x0030 && code <= 0x0039 // 0-9 + ? code - 0x0030 + : code >= 0x0041 && code <= 0x0046 // A-F + ? code - 0x0037 + : code >= 0x0061 && code <= 0x0066 // a-f + ? code - 0x0057 + : -1; +} + +/** + * | Escaped Character | Code Point | Character Name | + * | ----------------- | ---------- | ---------------------------- | + * | `"` | U+0022 | double quote | + * | `\` | U+005C | reverse solidus (back slash) | + * | `/` | U+002F | solidus (forward slash) | + * | `b` | U+0008 | backspace | + * | `f` | U+000C | form feed | + * | `n` | U+000A | line feed (new line) | + * | `r` | U+000D | carriage return | + * | `t` | U+0009 | horizontal tab | + */ +function readEscapedCharacter(lexer: Lexer, position: number): EscapeSequence { + const body = lexer.source.body; + const code = body.charCodeAt(position + 1); + switch (code) { + case 0x0022: // " + return { value: '\u0022', size: 2 }; + case 0x005c: // \ + return { value: '\u005c', size: 2 }; + case 0x002f: // / + return { value: '\u002f', size: 2 }; + case 0x0062: // b + return { value: '\u0008', size: 2 }; + case 0x0066: // f + return { value: '\u000c', size: 2 }; + case 0x006e: // n + return { value: '\u000a', size: 2 }; + case 0x0072: // r + return { value: '\u000d', size: 2 }; + case 0x0074: // t + return { value: '\u0009', size: 2 }; + } + throw syntaxError( + lexer.source, + position, + `Invalid character escape sequence: "${body.slice( + position, + position + 2, + )}".`, + ); +} + +/** + * Reads a block string token from the source file. + * + * ``` + * StringValue :: + * - `"""` BlockStringCharacter* `"""` + * + * BlockStringCharacter :: + * - SourceCharacter but not `"""` or `\"""` + * - `\"""` + * ``` + */ +function readBlockString(lexer: Lexer, start: number): Token { + const body = lexer.source.body; + const bodyLength = body.length; + let lineStart = lexer.lineStart; + + let position = start + 3; + let chunkStart = position; + let currentLine = ''; + + const blockLines = []; + while (position < bodyLength) { + const code = body.charCodeAt(position); + + // Closing Triple-Quote (""") + if ( + code === 0x0022 && + body.charCodeAt(position + 1) === 0x0022 && + body.charCodeAt(position + 2) === 0x0022 + ) { + currentLine += body.slice(chunkStart, position); + blockLines.push(currentLine); + + const token = createToken( + lexer, + TokenKind.BLOCK_STRING, + start, + position + 3, + // Return a string of the lines joined with U+000A. + dedentBlockStringLines(blockLines).join('\n'), + ); + + lexer.line += blockLines.length - 1; + lexer.lineStart = lineStart; + return token; + } + + // Escaped Triple-Quote (\""") + if ( + code === 0x005c && + body.charCodeAt(position + 1) === 0x0022 && + body.charCodeAt(position + 2) === 0x0022 && + body.charCodeAt(position + 3) === 0x0022 + ) { + currentLine += body.slice(chunkStart, position); + chunkStart = position + 1; // skip only slash + position += 4; + continue; + } + + // LineTerminator + if (code === 0x000a || code === 0x000d) { + currentLine += body.slice(chunkStart, position); + blockLines.push(currentLine); + + if (code === 0x000d && body.charCodeAt(position + 1) === 0x000a) { + position += 2; + } else { + ++position; + } + + currentLine = ''; + chunkStart = position; + lineStart = position; + continue; + } + + // SourceCharacter + if (isUnicodeScalarValue(code)) { + ++position; + } else if (isSupplementaryCodePoint(body, position)) { + position += 2; + } else { + throw syntaxError( + lexer.source, + position, + `Invalid character within String: ${printCodePointAt( + lexer, + position, + )}.`, + ); + } + } + + throw syntaxError(lexer.source, position, 'Unterminated string.'); +} + +/** + * Reads an alphanumeric + underscore name from the source. + * + * ``` + * Name :: + * - NameStart NameContinue* [lookahead != NameContinue] + * ``` + */ +function readName(lexer: Lexer, start: number): Token { + const body = lexer.source.body; + const bodyLength = body.length; + let position = start + 1; + + while (position < bodyLength) { + const code = body.charCodeAt(position); + if (isNameContinue(code)) { + ++position; + } else { + break; + } + } + + return createToken( + lexer, + TokenKind.NAME, + start, + position, + body.slice(start, position), + ); +} diff --git a/src/language/location.d.ts b/src/language/location.d.ts deleted file mode 100644 index a41e82f41e..0000000000 --- a/src/language/location.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Source } from './source'; - -/** - * Represents a location in a Source. - */ -export interface SourceLocation { - readonly line: number; - readonly column: number; -} - -/** - * Takes a Source and a UTF-8 character offset, and returns the corresponding - * line and column as a SourceLocation. - */ -export function getLocation(source: Source, position: number): SourceLocation; diff --git a/src/language/location.js b/src/language/location.js deleted file mode 100644 index 8da175d4f2..0000000000 --- a/src/language/location.js +++ /dev/null @@ -1,25 +0,0 @@ -import type { Source } from './source'; - -/** - * Represents a location in a Source. - */ -export type SourceLocation = {| - +line: number, - +column: number, -|}; - -/** - * Takes a Source and a UTF-8 character offset, and returns the corresponding - * line and column as a SourceLocation. - */ -export function getLocation(source: Source, position: number): SourceLocation { - const lineRegexp = /\r\n|[\n\r]/g; - let line = 1; - let column = position + 1; - let match; - while ((match = lineRegexp.exec(source.body)) && match.index < position) { - line += 1; - column = position + 1 - (match.index + match[0].length); - } - return { line, column }; -} diff --git a/src/language/location.ts b/src/language/location.ts new file mode 100644 index 0000000000..36d97f3cca --- /dev/null +++ b/src/language/location.ts @@ -0,0 +1,33 @@ +import { invariant } from '../jsutils/invariant'; + +import type { Source } from './source'; + +const LineRegExp = /\r\n|[\n\r]/g; + +/** + * Represents a location in a Source. + */ +export interface SourceLocation { + readonly line: number; + readonly column: number; +} + +/** + * Takes a Source and a UTF-8 character offset, and returns the corresponding + * line and column as a SourceLocation. + */ +export function getLocation(source: Source, position: number): SourceLocation { + let lastLineStart = 0; + let line = 1; + + for (const match of source.body.matchAll(LineRegExp)) { + invariant(typeof match.index === 'number'); + if (match.index >= position) { + break; + } + lastLineStart = match.index + match[0].length; + line += 1; + } + + return { line, column: position + 1 - lastLineStart }; +} diff --git a/src/language/parser.d.ts b/src/language/parser.d.ts deleted file mode 100644 index 368c6f8a73..0000000000 --- a/src/language/parser.d.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Source } from './source'; -import { TypeNode, ValueNode, DocumentNode } from './ast'; - -/** - * Configuration options to control parser behavior - */ -export interface ParseOptions { - /** - * By default, the parser creates AST nodes that know the location - * in the source that they correspond to. This configuration flag - * disables that behavior for performance or testing. - */ - noLocation?: boolean; - - /** - * If enabled, the parser will parse empty fields sets in the Schema - * Definition Language. Otherwise, the parser will follow the current - * specification. - * - * This option is provided to ease adoption of the final SDL specification - * and will be removed in v16. - */ - allowLegacySDLEmptyFields?: boolean; - - /** - * If enabled, the parser will parse implemented interfaces with no `&` - * character between each interface. Otherwise, the parser will follow the - * current specification. - * - * This option is provided to ease adoption of the final SDL specification - * and will be removed in v16. - */ - allowLegacySDLImplementsInterfaces?: boolean; - - /** - * EXPERIMENTAL: - * - * If enabled, the parser will understand and parse variable definitions - * contained in a fragment definition. They'll be represented in the - * `variableDefinitions` field of the FragmentDefinitionNode. - * - * The syntax is identical to normal, query-defined variables. For example: - * - * fragment A($var: Boolean = false) on T { - * ... - * } - * - * Note: this feature is experimental and may change or be removed in the - * future. - */ - experimentalFragmentVariables?: boolean; -} - -/** - * Given a GraphQL source, parses it into a Document. - * Throws GraphQLError if a syntax error is encountered. - */ -export function parse( - source: string | Source, - options?: ParseOptions, -): DocumentNode; - -/** - * Given a string containing a GraphQL value, parse the AST for that value. - * Throws GraphQLError if a syntax error is encountered. - * - * This is useful within tools that operate upon GraphQL Values directly and - * in isolation of complete GraphQL documents. - */ -export function parseValue( - source: string | Source, - options?: ParseOptions, -): ValueNode; - -/** - * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for - * that type. - * Throws GraphQLError if a syntax error is encountered. - * - * This is useful within tools that operate upon GraphQL Types directly and - * in isolation of complete GraphQL documents. - * - * Consider providing the results to the utility function: typeFromAST(). - */ -export function parseType( - source: string | Source, - options?: ParseOptions, -): TypeNode; diff --git a/src/language/parser.js b/src/language/parser.ts similarity index 74% rename from src/language/parser.js rename to src/language/parser.ts index 5d7b16186d..03e4166210 100644 --- a/src/language/parser.js +++ b/src/language/parser.ts @@ -1,93 +1,94 @@ +import type { Maybe } from '../jsutils/Maybe'; + import type { GraphQLError } from '../error/GraphQLError'; import { syntaxError } from '../error/syntaxError'; -import type { TokenKindEnum } from './tokenKind'; import type { - Token, - NameNode, - VariableNode, - DocumentNode, + ArgumentNode, + BooleanValueNode, + ConstArgumentNode, + ConstDirectiveNode, + ConstListValueNode, + ConstObjectFieldNode, + ConstObjectValueNode, + ConstValueNode, DefinitionNode, - OperationDefinitionNode, - OperationTypeNode, - VariableDefinitionNode, - SelectionSetNode, - SelectionNode, + DirectiveDefinitionNode, + DirectiveNode, + DocumentNode, + EnumTypeDefinitionNode, + EnumTypeExtensionNode, + EnumValueDefinitionNode, + EnumValueNode, + FieldDefinitionNode, FieldNode, - ArgumentNode, + FloatValueNode, + FragmentDefinitionNode, FragmentSpreadNode, InlineFragmentNode, - FragmentDefinitionNode, - ValueNode, - StringValueNode, + InputObjectTypeDefinitionNode, + InputObjectTypeExtensionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + InterfaceTypeExtensionNode, + IntValueNode, + ListTypeNode, ListValueNode, - ObjectValueNode, - ObjectFieldNode, - DirectiveNode, - TypeNode, NamedTypeNode, - TypeSystemDefinitionNode, - SchemaDefinitionNode, + NameNode, + NonNullTypeNode, + NullValueNode, + ObjectFieldNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, + ObjectValueNode, + OperationDefinitionNode, OperationTypeDefinitionNode, ScalarTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - UnionTypeDefinitionNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, - InputObjectTypeDefinitionNode, - DirectiveDefinitionNode, - TypeSystemExtensionNode, - SchemaExtensionNode, ScalarTypeExtensionNode, - ObjectTypeExtensionNode, - InterfaceTypeExtensionNode, + SchemaDefinitionNode, + SchemaExtensionNode, + SelectionNode, + SelectionSetNode, + StringValueNode, + Token, + TypeNode, + TypeSystemExtensionNode, + UnionTypeDefinitionNode, UnionTypeExtensionNode, - EnumTypeExtensionNode, - InputObjectTypeExtensionNode, + ValueNode, + VariableDefinitionNode, + VariableNode, } from './ast'; +import { Location, OperationTypeNode } from './ast'; +import { DirectiveLocation } from './directiveLocation'; import { Kind } from './kinds'; -import { Location } from './ast'; +import { isPunctuatorTokenKind, Lexer } from './lexer'; +import { isSource, Source } from './source'; import { TokenKind } from './tokenKind'; -import { Source, isSource } from './source'; -import { DirectiveLocation } from './directiveLocation'; -import { Lexer, isPunctuatorTokenKind } from './lexer'; /** * Configuration options to control parser behavior */ -export type ParseOptions = {| +export interface ParseOptions { /** * By default, the parser creates AST nodes that know the location * in the source that they correspond to. This configuration flag * disables that behavior for performance or testing. */ - noLocation?: boolean, + noLocation?: boolean; /** - * If enabled, the parser will parse empty fields sets in the Schema - * Definition Language. Otherwise, the parser will follow the current - * specification. - * - * This option is provided to ease adoption of the final SDL specification - * and will be removed in v16. + * Parser CPU and memory usage is linear to the number of tokens in a document + * however in extreme cases it becomes quadratic due to memory exhaustion. + * Parsing happens before validation so even invalid queries can burn lots of + * CPU time and memory. + * To prevent this you can set a maximum number of tokens allowed within a document. */ - allowLegacySDLEmptyFields?: boolean, + maxTokens?: number | undefined; /** - * If enabled, the parser will parse implemented interfaces with no `&` - * character between each interface. Otherwise, the parser will follow the - * current specification. - * - * This option is provided to ease adoption of the final SDL specification - * and will be removed in v16. - */ - allowLegacySDLImplementsInterfaces?: boolean, - - /** - * EXPERIMENTAL: + * @deprecated will be removed in the v17.0.0 * * If enabled, the parser will understand and parse variable definitions * contained in a fragment definition. They'll be represented in the @@ -95,15 +96,14 @@ export type ParseOptions = {| * * The syntax is identical to normal, query-defined variables. For example: * - * fragment A($var: Boolean = false) on T { - * ... - * } - * - * Note: this feature is experimental and may change or be removed in the - * future. + * ```graphql + * fragment A($var: Boolean = false) on T { + * ... + * } + * ``` */ - experimentalFragmentVariables?: boolean, -|}; + allowLegacyFragmentVariables?: boolean; +} /** * Given a GraphQL source, parses it into a Document. @@ -111,10 +111,15 @@ export type ParseOptions = {| */ export function parse( source: string | Source, - options?: ParseOptions, + options?: ParseOptions | undefined, ): DocumentNode { const parser = new Parser(source, options); - return parser.parseDocument(); + const document = parser.parseDocument(); + Object.defineProperty(document, 'tokenCount', { + enumerable: false, + value: parser.tokenCount, + }); + return document; } /** @@ -129,7 +134,7 @@ export function parse( */ export function parseValue( source: string | Source, - options?: ParseOptions, + options?: ParseOptions | undefined, ): ValueNode { const parser = new Parser(source, options); parser.expectToken(TokenKind.SOF); @@ -138,6 +143,21 @@ export function parseValue( return value; } +/** + * Similar to parseValue(), but raises a parse error if it encounters a + * variable. The return type will be a constant value. + */ +export function parseConstValue( + source: string | Source, + options?: ParseOptions | undefined, +): ConstValueNode { + const parser = new Parser(source, options); + parser.expectToken(TokenKind.SOF); + const value = parser.parseConstValueLiteral(); + parser.expectToken(TokenKind.EOF); + return value; +} + /** * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for * that type. @@ -150,7 +170,7 @@ export function parseValue( */ export function parseType( source: string | Source, - options?: ParseOptions, + options?: ParseOptions | undefined, ): TypeNode { const parser = new Parser(source, options); parser.expectToken(TokenKind.SOF); @@ -171,14 +191,20 @@ export function parseType( * @internal */ export class Parser { - _options: ?ParseOptions; - _lexer: Lexer; + protected _options: ParseOptions; + protected _lexer: Lexer; + protected _tokenCounter: number; - constructor(source: string | Source, options?: ParseOptions) { + constructor(source: string | Source, options: ParseOptions = {}) { const sourceObj = isSource(source) ? source : new Source(source); this._lexer = new Lexer(sourceObj); this._options = options; + this._tokenCounter = 0; + } + + get tokenCount(): number { + return this._tokenCounter; } /** @@ -186,11 +212,10 @@ export class Parser { */ parseName(): NameNode { const token = this.expectToken(TokenKind.NAME); - return { + return this.node(token, { kind: Kind.NAME, - value: ((token.value: any): string), - loc: this.loc(token), - }; + value: token.value, + }); } // Implements the parsing rules in the Document section. @@ -199,16 +224,14 @@ export class Parser { * Document : Definition+ */ parseDocument(): DocumentNode { - const start = this._lexer.token; - return { + return this.node(this._lexer.token, { kind: Kind.DOCUMENT, definitions: this.many( TokenKind.SOF, this.parseDefinition, TokenKind.EOF, ), - loc: this.loc(start), - }; + }); } /** @@ -220,35 +243,72 @@ export class Parser { * ExecutableDefinition : * - OperationDefinition * - FragmentDefinition + * + * TypeSystemDefinition : + * - SchemaDefinition + * - TypeDefinition + * - DirectiveDefinition + * + * TypeDefinition : + * - ScalarTypeDefinition + * - ObjectTypeDefinition + * - InterfaceTypeDefinition + * - UnionTypeDefinition + * - EnumTypeDefinition + * - InputObjectTypeDefinition */ parseDefinition(): DefinitionNode { - if (this.peek(TokenKind.NAME)) { - switch (this._lexer.token.value) { - case 'query': - case 'mutation': - case 'subscription': - return this.parseOperationDefinition(); - case 'fragment': - return this.parseFragmentDefinition(); + if (this.peek(TokenKind.BRACE_L)) { + return this.parseOperationDefinition(); + } + + // Many definitions begin with a description and require a lookahead. + const hasDescription = this.peekDescription(); + const keywordToken = hasDescription + ? this._lexer.lookahead() + : this._lexer.token; + + if (keywordToken.kind === TokenKind.NAME) { + switch (keywordToken.value) { case 'schema': + return this.parseSchemaDefinition(); case 'scalar': + return this.parseScalarTypeDefinition(); case 'type': + return this.parseObjectTypeDefinition(); case 'interface': + return this.parseInterfaceTypeDefinition(); case 'union': + return this.parseUnionTypeDefinition(); case 'enum': + return this.parseEnumTypeDefinition(); case 'input': + return this.parseInputObjectTypeDefinition(); case 'directive': - return this.parseTypeSystemDefinition(); + return this.parseDirectiveDefinition(); + } + + if (hasDescription) { + throw syntaxError( + this._lexer.source, + this._lexer.token.start, + 'Unexpected description, descriptions are supported only on type definitions.', + ); + } + + switch (keywordToken.value) { + case 'query': + case 'mutation': + case 'subscription': + return this.parseOperationDefinition(); + case 'fragment': + return this.parseFragmentDefinition(); case 'extend': return this.parseTypeSystemExtension(); } - } else if (this.peek(TokenKind.BRACE_L)) { - return this.parseOperationDefinition(); - } else if (this.peekDescription()) { - return this.parseTypeSystemDefinition(); } - throw this.unexpected(); + throw this.unexpected(keywordToken); } // Implements the parsing rules in the Operations section. @@ -261,30 +321,28 @@ export class Parser { parseOperationDefinition(): OperationDefinitionNode { const start = this._lexer.token; if (this.peek(TokenKind.BRACE_L)) { - return { + return this.node(start, { kind: Kind.OPERATION_DEFINITION, - operation: 'query', + operation: OperationTypeNode.QUERY, name: undefined, variableDefinitions: [], directives: [], selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; + }); } const operation = this.parseOperationType(); let name; if (this.peek(TokenKind.NAME)) { name = this.parseName(); } - return { + return this.node(start, { kind: Kind.OPERATION_DEFINITION, operation, name, variableDefinitions: this.parseVariableDefinitions(), directives: this.parseDirectives(false), selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; + }); } /** @@ -294,11 +352,11 @@ export class Parser { const operationToken = this.expectToken(TokenKind.NAME); switch (operationToken.value) { case 'query': - return 'query'; + return OperationTypeNode.QUERY; case 'mutation': - return 'mutation'; + return OperationTypeNode.MUTATION; case 'subscription': - return 'subscription'; + return OperationTypeNode.SUBSCRIPTION; } throw this.unexpected(operationToken); @@ -319,17 +377,15 @@ export class Parser { * VariableDefinition : Variable : Type DefaultValue? Directives[Const]? */ parseVariableDefinition(): VariableDefinitionNode { - const start = this._lexer.token; - return { + return this.node(this._lexer.token, { kind: Kind.VARIABLE_DEFINITION, variable: this.parseVariable(), type: (this.expectToken(TokenKind.COLON), this.parseTypeReference()), defaultValue: this.expectOptionalToken(TokenKind.EQUALS) - ? this.parseValueLiteral(true) + ? this.parseConstValueLiteral() : undefined, - directives: this.parseDirectives(true), - loc: this.loc(start), - }; + directives: this.parseConstDirectives(), + }); } /** @@ -338,27 +394,26 @@ export class Parser { parseVariable(): VariableNode { const start = this._lexer.token; this.expectToken(TokenKind.DOLLAR); - return { + return this.node(start, { kind: Kind.VARIABLE, name: this.parseName(), - loc: this.loc(start), - }; + }); } /** + * ``` * SelectionSet : { Selection+ } + * ``` */ parseSelectionSet(): SelectionSetNode { - const start = this._lexer.token; - return { + return this.node(this._lexer.token, { kind: Kind.SELECTION_SET, selections: this.many( TokenKind.BRACE_L, this.parseSelection, TokenKind.BRACE_R, ), - loc: this.loc(start), - }; + }); } /** @@ -391,7 +446,7 @@ export class Parser { name = nameOrAlias; } - return { + return this.node(start, { kind: Kind.FIELD, alias, name, @@ -400,13 +455,14 @@ export class Parser { selectionSet: this.peek(TokenKind.BRACE_L) ? this.parseSelectionSet() : undefined, - loc: this.loc(start), - }; + }); } /** * Arguments[Const] : ( Argument[?Const]+ ) */ + parseArguments(isConst: true): Array; + parseArguments(isConst: boolean): Array; parseArguments(isConst: boolean): Array { const item = isConst ? this.parseConstArgument : this.parseArgument; return this.optionalMany(TokenKind.PAREN_L, item, TokenKind.PAREN_R); @@ -415,27 +471,22 @@ export class Parser { /** * Argument[Const] : Name : Value[?Const] */ - parseArgument(): ArgumentNode { + parseArgument(isConst: true): ConstArgumentNode; + parseArgument(isConst?: boolean): ArgumentNode; + parseArgument(isConst: boolean = false): ArgumentNode { const start = this._lexer.token; const name = this.parseName(); this.expectToken(TokenKind.COLON); - return { + return this.node(start, { kind: Kind.ARGUMENT, name, - value: this.parseValueLiteral(false), - loc: this.loc(start), - }; + value: this.parseValueLiteral(isConst), + }); } - parseConstArgument(): ArgumentNode { - const start = this._lexer.token; - return { - kind: Kind.ARGUMENT, - name: this.parseName(), - value: (this.expectToken(TokenKind.COLON), this.parseValueLiteral(true)), - loc: this.loc(start), - }; + parseConstArgument(): ConstArgumentNode { + return this.parseArgument(true); } // Implements the parsing rules in the Fragments section. @@ -453,20 +504,18 @@ export class Parser { const hasTypeCondition = this.expectOptionalKeyword('on'); if (!hasTypeCondition && this.peek(TokenKind.NAME)) { - return { + return this.node(start, { kind: Kind.FRAGMENT_SPREAD, name: this.parseFragmentName(), directives: this.parseDirectives(false), - loc: this.loc(start), - }; + }); } - return { + return this.node(start, { kind: Kind.INLINE_FRAGMENT, typeCondition: hasTypeCondition ? this.parseNamedType() : undefined, directives: this.parseDirectives(false), selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; + }); } /** @@ -478,28 +527,26 @@ export class Parser { parseFragmentDefinition(): FragmentDefinitionNode { const start = this._lexer.token; this.expectKeyword('fragment'); - // Experimental support for defining variables within fragments changes + // Legacy support for defining variables within fragments changes // the grammar of FragmentDefinition: // - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet - if (this._options?.experimentalFragmentVariables === true) { - return { + if (this._options.allowLegacyFragmentVariables === true) { + return this.node(start, { kind: Kind.FRAGMENT_DEFINITION, name: this.parseFragmentName(), variableDefinitions: this.parseVariableDefinitions(), typeCondition: (this.expectKeyword('on'), this.parseNamedType()), directives: this.parseDirectives(false), selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; + }); } - return { + return this.node(start, { kind: Kind.FRAGMENT_DEFINITION, name: this.parseFragmentName(), typeCondition: (this.expectKeyword('on'), this.parseNamedType()), directives: this.parseDirectives(false), selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; + }); } /** @@ -532,6 +579,8 @@ export class Parser { * * EnumValue : Name but not `true`, `false` or `null` */ + parseValueLiteral(isConst: true): ConstValueNode; + parseValueLiteral(isConst: boolean): ValueNode; parseValueLiteral(isConst: boolean): ValueNode { const token = this._lexer.token; switch (token.kind) { @@ -540,56 +589,73 @@ export class Parser { case TokenKind.BRACE_L: return this.parseObject(isConst); case TokenKind.INT: - this._lexer.advance(); - return { + this.advanceLexer(); + return this.node(token, { kind: Kind.INT, - value: ((token.value: any): string), - loc: this.loc(token), - }; + value: token.value, + }); case TokenKind.FLOAT: - this._lexer.advance(); - return { + this.advanceLexer(); + return this.node(token, { kind: Kind.FLOAT, - value: ((token.value: any): string), - loc: this.loc(token), - }; + value: token.value, + }); case TokenKind.STRING: case TokenKind.BLOCK_STRING: return this.parseStringLiteral(); case TokenKind.NAME: - this._lexer.advance(); + this.advanceLexer(); switch (token.value) { case 'true': - return { kind: Kind.BOOLEAN, value: true, loc: this.loc(token) }; + return this.node(token, { + kind: Kind.BOOLEAN, + value: true, + }); case 'false': - return { kind: Kind.BOOLEAN, value: false, loc: this.loc(token) }; + return this.node(token, { + kind: Kind.BOOLEAN, + value: false, + }); case 'null': - return { kind: Kind.NULL, loc: this.loc(token) }; + return this.node(token, { kind: Kind.NULL }); default: - return { + return this.node(token, { kind: Kind.ENUM, - value: ((token.value: any): string), - loc: this.loc(token), - }; + value: token.value, + }); } case TokenKind.DOLLAR: - if (!isConst) { - return this.parseVariable(); + if (isConst) { + this.expectToken(TokenKind.DOLLAR); + if (this._lexer.token.kind === TokenKind.NAME) { + const varName = this._lexer.token.value; + throw syntaxError( + this._lexer.source, + token.start, + `Unexpected variable "$${varName}" in constant value.`, + ); + } else { + throw this.unexpected(token); + } } - break; + return this.parseVariable(); + default: + throw this.unexpected(); } - throw this.unexpected(); + } + + parseConstValueLiteral(): ConstValueNode { + return this.parseValueLiteral(true); } parseStringLiteral(): StringValueNode { const token = this._lexer.token; - this._lexer.advance(); - return { + this.advanceLexer(); + return this.node(token, { kind: Kind.STRING, - value: ((token.value: any): string), + value: token.value, block: token.kind === TokenKind.BLOCK_STRING, - loc: this.loc(token), - }; + }); } /** @@ -597,45 +663,47 @@ export class Parser { * - [ ] * - [ Value[?Const]+ ] */ + parseList(isConst: true): ConstListValueNode; + parseList(isConst: boolean): ListValueNode; parseList(isConst: boolean): ListValueNode { - const start = this._lexer.token; const item = () => this.parseValueLiteral(isConst); - return { + return this.node(this._lexer.token, { kind: Kind.LIST, values: this.any(TokenKind.BRACKET_L, item, TokenKind.BRACKET_R), - loc: this.loc(start), - }; + }); } /** + * ``` * ObjectValue[Const] : * - { } * - { ObjectField[?Const]+ } + * ``` */ + parseObject(isConst: true): ConstObjectValueNode; + parseObject(isConst: boolean): ObjectValueNode; parseObject(isConst: boolean): ObjectValueNode { - const start = this._lexer.token; const item = () => this.parseObjectField(isConst); - return { + return this.node(this._lexer.token, { kind: Kind.OBJECT, fields: this.any(TokenKind.BRACE_L, item, TokenKind.BRACE_R), - loc: this.loc(start), - }; + }); } /** * ObjectField[Const] : Name : Value[?Const] */ + parseObjectField(isConst: true): ConstObjectFieldNode; + parseObjectField(isConst: boolean): ObjectFieldNode; parseObjectField(isConst: boolean): ObjectFieldNode { const start = this._lexer.token; const name = this.parseName(); this.expectToken(TokenKind.COLON); - - return { + return this.node(start, { kind: Kind.OBJECT_FIELD, name, value: this.parseValueLiteral(isConst), - loc: this.loc(start), - }; + }); } // Implements the parsing rules in the Directives section. @@ -643,6 +711,8 @@ export class Parser { /** * Directives[Const] : Directive[?Const]+ */ + parseDirectives(isConst: true): Array; + parseDirectives(isConst: boolean): Array; parseDirectives(isConst: boolean): Array { const directives = []; while (this.peek(TokenKind.AT)) { @@ -651,18 +721,25 @@ export class Parser { return directives; } + parseConstDirectives(): Array { + return this.parseDirectives(true); + } + /** + * ``` * Directive[Const] : @ Name Arguments[?Const]? + * ``` */ + parseDirective(isConst: true): ConstDirectiveNode; + parseDirective(isConst: boolean): DirectiveNode; parseDirective(isConst: boolean): DirectiveNode { const start = this._lexer.token; this.expectToken(TokenKind.AT); - return { + return this.node(start, { kind: Kind.DIRECTIVE, name: this.parseName(), arguments: this.parseArguments(isConst), - loc: this.loc(start), - }; + }); } // Implements the parsing rules in the Types section. @@ -677,24 +754,23 @@ export class Parser { const start = this._lexer.token; let type; if (this.expectOptionalToken(TokenKind.BRACKET_L)) { - type = this.parseTypeReference(); + const innerType = this.parseTypeReference(); this.expectToken(TokenKind.BRACKET_R); - type = { + type = this.node(start, { kind: Kind.LIST_TYPE, - type, - loc: this.loc(start), - }; + type: innerType, + }); } else { type = this.parseNamedType(); } if (this.expectOptionalToken(TokenKind.BANG)) { - return { + return this.node(start, { kind: Kind.NON_NULL_TYPE, type, - loc: this.loc(start), - }; + }); } + return type; } @@ -702,60 +778,14 @@ export class Parser { * NamedType : Name */ parseNamedType(): NamedTypeNode { - const start = this._lexer.token; - return { + return this.node(this._lexer.token, { kind: Kind.NAMED_TYPE, name: this.parseName(), - loc: this.loc(start), - }; + }); } // Implements the parsing rules in the Type Definition section. - /** - * TypeSystemDefinition : - * - SchemaDefinition - * - TypeDefinition - * - DirectiveDefinition - * - * TypeDefinition : - * - ScalarTypeDefinition - * - ObjectTypeDefinition - * - InterfaceTypeDefinition - * - UnionTypeDefinition - * - EnumTypeDefinition - * - InputObjectTypeDefinition - */ - parseTypeSystemDefinition(): TypeSystemDefinitionNode { - // Many definitions begin with a description and require a lookahead. - const keywordToken = this.peekDescription() - ? this._lexer.lookahead() - : this._lexer.token; - - if (keywordToken.kind === TokenKind.NAME) { - switch (keywordToken.value) { - case 'schema': - return this.parseSchemaDefinition(); - case 'scalar': - return this.parseScalarTypeDefinition(); - case 'type': - return this.parseObjectTypeDefinition(); - case 'interface': - return this.parseInterfaceTypeDefinition(); - case 'union': - return this.parseUnionTypeDefinition(); - case 'enum': - return this.parseEnumTypeDefinition(); - case 'input': - return this.parseInputObjectTypeDefinition(); - case 'directive': - return this.parseDirectiveDefinition(); - } - } - - throw this.unexpected(keywordToken); - } - peekDescription(): boolean { return this.peek(TokenKind.STRING) || this.peek(TokenKind.BLOCK_STRING); } @@ -763,32 +793,33 @@ export class Parser { /** * Description : StringValue */ - parseDescription(): void | StringValueNode { + parseDescription(): undefined | StringValueNode { if (this.peekDescription()) { return this.parseStringLiteral(); } } /** + * ``` * SchemaDefinition : Description? schema Directives[Const]? { OperationTypeDefinition+ } + * ``` */ parseSchemaDefinition(): SchemaDefinitionNode { const start = this._lexer.token; const description = this.parseDescription(); this.expectKeyword('schema'); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const operationTypes = this.many( TokenKind.BRACE_L, this.parseOperationTypeDefinition, TokenKind.BRACE_R, ); - return { + return this.node(start, { kind: Kind.SCHEMA_DEFINITION, description, directives, operationTypes, - loc: this.loc(start), - }; + }); } /** @@ -799,12 +830,11 @@ export class Parser { const operation = this.parseOperationType(); this.expectToken(TokenKind.COLON); const type = this.parseNamedType(); - return { + return this.node(start, { kind: Kind.OPERATION_TYPE_DEFINITION, operation, type, - loc: this.loc(start), - }; + }); } /** @@ -815,14 +845,13 @@ export class Parser { const description = this.parseDescription(); this.expectKeyword('scalar'); const name = this.parseName(); - const directives = this.parseDirectives(true); - return { + const directives = this.parseConstDirectives(); + return this.node(start, { kind: Kind.SCALAR_TYPE_DEFINITION, description, name, directives, - loc: this.loc(start), - }; + }); } /** @@ -836,17 +865,16 @@ export class Parser { this.expectKeyword('type'); const name = this.parseName(); const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const fields = this.parseFieldsDefinition(); - return { + return this.node(start, { kind: Kind.OBJECT_TYPE_DEFINITION, description, name, interfaces, directives, fields, - loc: this.loc(start), - }; + }); } /** @@ -855,40 +883,17 @@ export class Parser { * - ImplementsInterfaces & NamedType */ parseImplementsInterfaces(): Array { - if (!this.expectOptionalKeyword('implements')) { - return []; - } - - if (this._options?.allowLegacySDLImplementsInterfaces === true) { - const types = []; - // Optional leading ampersand - this.expectOptionalToken(TokenKind.AMP); - do { - types.push(this.parseNamedType()); - } while ( - this.expectOptionalToken(TokenKind.AMP) || - this.peek(TokenKind.NAME) - ); - return types; - } - - return this.delimitedMany(TokenKind.AMP, this.parseNamedType); + return this.expectOptionalKeyword('implements') + ? this.delimitedMany(TokenKind.AMP, this.parseNamedType) + : []; } /** + * ``` * FieldsDefinition : { FieldDefinition+ } + * ``` */ parseFieldsDefinition(): Array { - // Legacy support for the SDL? - if ( - this._options?.allowLegacySDLEmptyFields === true && - this.peek(TokenKind.BRACE_L) && - this._lexer.lookahead().kind === TokenKind.BRACE_R - ) { - this._lexer.advance(); - this._lexer.advance(); - return []; - } return this.optionalMany( TokenKind.BRACE_L, this.parseFieldDefinition, @@ -907,16 +912,15 @@ export class Parser { const args = this.parseArgumentDefs(); this.expectToken(TokenKind.COLON); const type = this.parseTypeReference(); - const directives = this.parseDirectives(true); - return { + const directives = this.parseConstDirectives(); + return this.node(start, { kind: Kind.FIELD_DEFINITION, description, name, arguments: args, type, directives, - loc: this.loc(start), - }; + }); } /** @@ -942,18 +946,17 @@ export class Parser { const type = this.parseTypeReference(); let defaultValue; if (this.expectOptionalToken(TokenKind.EQUALS)) { - defaultValue = this.parseValueLiteral(true); + defaultValue = this.parseConstValueLiteral(); } - const directives = this.parseDirectives(true); - return { + const directives = this.parseConstDirectives(); + return this.node(start, { kind: Kind.INPUT_VALUE_DEFINITION, description, name, type, defaultValue, directives, - loc: this.loc(start), - }; + }); } /** @@ -966,17 +969,16 @@ export class Parser { this.expectKeyword('interface'); const name = this.parseName(); const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const fields = this.parseFieldsDefinition(); - return { + return this.node(start, { kind: Kind.INTERFACE_TYPE_DEFINITION, description, name, interfaces, directives, fields, - loc: this.loc(start), - }; + }); } /** @@ -988,16 +990,15 @@ export class Parser { const description = this.parseDescription(); this.expectKeyword('union'); const name = this.parseName(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const types = this.parseUnionMemberTypes(); - return { + return this.node(start, { kind: Kind.UNION_TYPE_DEFINITION, description, name, directives, types, - loc: this.loc(start), - }; + }); } /** @@ -1020,20 +1021,21 @@ export class Parser { const description = this.parseDescription(); this.expectKeyword('enum'); const name = this.parseName(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const values = this.parseEnumValuesDefinition(); - return { + return this.node(start, { kind: Kind.ENUM_TYPE_DEFINITION, description, name, directives, values, - loc: this.loc(start), - }; + }); } /** + * ``` * EnumValuesDefinition : { EnumValueDefinition+ } + * ``` */ parseEnumValuesDefinition(): Array { return this.optionalMany( @@ -1045,21 +1047,38 @@ export class Parser { /** * EnumValueDefinition : Description? EnumValue Directives[Const]? - * - * EnumValue : Name */ parseEnumValueDefinition(): EnumValueDefinitionNode { const start = this._lexer.token; const description = this.parseDescription(); - const name = this.parseName(); - const directives = this.parseDirectives(true); - return { + const name = this.parseEnumValueName(); + const directives = this.parseConstDirectives(); + return this.node(start, { kind: Kind.ENUM_VALUE_DEFINITION, description, name, directives, - loc: this.loc(start), - }; + }); + } + + /** + * EnumValue : Name but not `true`, `false` or `null` + */ + parseEnumValueName(): NameNode { + if ( + this._lexer.token.value === 'true' || + this._lexer.token.value === 'false' || + this._lexer.token.value === 'null' + ) { + throw syntaxError( + this._lexer.source, + this._lexer.token.start, + `${getTokenDesc( + this._lexer.token, + )} is reserved and cannot be used for an enum value.`, + ); + } + return this.parseName(); } /** @@ -1071,20 +1090,21 @@ export class Parser { const description = this.parseDescription(); this.expectKeyword('input'); const name = this.parseName(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const fields = this.parseInputFieldsDefinition(); - return { + return this.node(start, { kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, description, name, directives, fields, - loc: this.loc(start), - }; + }); } /** + * ``` * InputFieldsDefinition : { InputValueDefinition+ } + * ``` */ parseInputFieldsDefinition(): Array { return this.optionalMany( @@ -1133,15 +1153,17 @@ export class Parser { } /** + * ``` * SchemaExtension : * - extend schema Directives[Const]? { OperationTypeDefinition+ } * - extend schema Directives[Const] + * ``` */ parseSchemaExtension(): SchemaExtensionNode { const start = this._lexer.token; this.expectKeyword('extend'); this.expectKeyword('schema'); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const operationTypes = this.optionalMany( TokenKind.BRACE_L, this.parseOperationTypeDefinition, @@ -1150,12 +1172,11 @@ export class Parser { if (directives.length === 0 && operationTypes.length === 0) { throw this.unexpected(); } - return { + return this.node(start, { kind: Kind.SCHEMA_EXTENSION, directives, operationTypes, - loc: this.loc(start), - }; + }); } /** @@ -1167,16 +1188,15 @@ export class Parser { this.expectKeyword('extend'); this.expectKeyword('scalar'); const name = this.parseName(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); if (directives.length === 0) { throw this.unexpected(); } - return { + return this.node(start, { kind: Kind.SCALAR_TYPE_EXTENSION, name, directives, - loc: this.loc(start), - }; + }); } /** @@ -1191,7 +1211,7 @@ export class Parser { this.expectKeyword('type'); const name = this.parseName(); const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const fields = this.parseFieldsDefinition(); if ( interfaces.length === 0 && @@ -1200,14 +1220,13 @@ export class Parser { ) { throw this.unexpected(); } - return { + return this.node(start, { kind: Kind.OBJECT_TYPE_EXTENSION, name, interfaces, directives, fields, - loc: this.loc(start), - }; + }); } /** @@ -1222,7 +1241,7 @@ export class Parser { this.expectKeyword('interface'); const name = this.parseName(); const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const fields = this.parseFieldsDefinition(); if ( interfaces.length === 0 && @@ -1231,14 +1250,13 @@ export class Parser { ) { throw this.unexpected(); } - return { + return this.node(start, { kind: Kind.INTERFACE_TYPE_EXTENSION, name, interfaces, directives, fields, - loc: this.loc(start), - }; + }); } /** @@ -1251,18 +1269,17 @@ export class Parser { this.expectKeyword('extend'); this.expectKeyword('union'); const name = this.parseName(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const types = this.parseUnionMemberTypes(); if (directives.length === 0 && types.length === 0) { throw this.unexpected(); } - return { + return this.node(start, { kind: Kind.UNION_TYPE_EXTENSION, name, directives, types, - loc: this.loc(start), - }; + }); } /** @@ -1275,18 +1292,17 @@ export class Parser { this.expectKeyword('extend'); this.expectKeyword('enum'); const name = this.parseName(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const values = this.parseEnumValuesDefinition(); if (directives.length === 0 && values.length === 0) { throw this.unexpected(); } - return { + return this.node(start, { kind: Kind.ENUM_TYPE_EXTENSION, name, directives, values, - loc: this.loc(start), - }; + }); } /** @@ -1299,23 +1315,24 @@ export class Parser { this.expectKeyword('extend'); this.expectKeyword('input'); const name = this.parseName(); - const directives = this.parseDirectives(true); + const directives = this.parseConstDirectives(); const fields = this.parseInputFieldsDefinition(); if (directives.length === 0 && fields.length === 0) { throw this.unexpected(); } - return { + return this.node(start, { kind: Kind.INPUT_OBJECT_TYPE_EXTENSION, name, directives, fields, - loc: this.loc(start), - }; + }); } /** + * ``` * DirectiveDefinition : * - Description? directive @ Name ArgumentsDefinition? `repeatable`? on DirectiveLocations + * ``` */ parseDirectiveDefinition(): DirectiveDefinitionNode { const start = this._lexer.token; @@ -1327,15 +1344,14 @@ export class Parser { const repeatable = this.expectOptionalKeyword('repeatable'); this.expectKeyword('on'); const locations = this.parseDirectiveLocations(); - return { + return this.node(start, { kind: Kind.DIRECTIVE_DEFINITION, description, name, arguments: args, repeatable, locations, - loc: this.loc(start), - }; + }); } /** @@ -1377,7 +1393,7 @@ export class Parser { parseDirectiveLocation(): NameNode { const start = this._lexer.token; const name = this.parseName(); - if (DirectiveLocation[name.value] !== undefined) { + if (Object.prototype.hasOwnProperty.call(DirectiveLocation, name.value)) { return name; } throw this.unexpected(start); @@ -1386,22 +1402,25 @@ export class Parser { // Core parsing utility functions /** - * Returns a location object, used to identify the place in the source that created a given parsed object. + * Returns a node that, if configured to do so, sets a "loc" field as a + * location object, used to identify the place in the source that created a + * given parsed object. */ - loc(startToken: Token): Location | void { - if (this._options?.noLocation !== true) { - return new Location( + node(startToken: Token, node: T): T { + if (this._options.noLocation !== true) { + node.loc = new Location( startToken, this._lexer.lastToken, this._lexer.source, ); } + return node; } /** * Determines if the next token is of a given kind */ - peek(kind: TokenKindEnum): boolean { + peek(kind: TokenKind): boolean { return this._lexer.token.kind === kind; } @@ -1409,10 +1428,10 @@ export class Parser { * If the next token is of the given kind, return that token after advancing the lexer. * Otherwise, do not change the parser state and throw an error. */ - expectToken(kind: TokenKindEnum): Token { + expectToken(kind: TokenKind): Token { const token = this._lexer.token; if (token.kind === kind) { - this._lexer.advance(); + this.advanceLexer(); return token; } @@ -1424,26 +1443,26 @@ export class Parser { } /** - * If the next token is of the given kind, return that token after advancing the lexer. - * Otherwise, do not change the parser state and return undefined. + * If the next token is of the given kind, return "true" after advancing the lexer. + * Otherwise, do not change the parser state and return "false". */ - expectOptionalToken(kind: TokenKindEnum): ?Token { + expectOptionalToken(kind: TokenKind): boolean { const token = this._lexer.token; if (token.kind === kind) { - this._lexer.advance(); - return token; + this.advanceLexer(); + return true; } - return undefined; + return false; } /** * If the next token is a given keyword, advance the lexer. * Otherwise, do not change the parser state and throw an error. */ - expectKeyword(value: string) { + expectKeyword(value: string): void { const token = this._lexer.token; if (token.kind === TokenKind.NAME && token.value === value) { - this._lexer.advance(); + this.advanceLexer(); } else { throw syntaxError( this._lexer.source, @@ -1460,7 +1479,7 @@ export class Parser { expectOptionalKeyword(value: string): boolean { const token = this._lexer.token; if (token.kind === TokenKind.NAME && token.value === value) { - this._lexer.advance(); + this.advanceLexer(); return true; } return false; @@ -1469,7 +1488,7 @@ export class Parser { /** * Helper function for creating an error when an unexpected lexed token is encountered. */ - unexpected(atToken?: ?Token): GraphQLError { + unexpected(atToken?: Maybe): GraphQLError { const token = atToken ?? this._lexer.token; return syntaxError( this._lexer.source, @@ -1484,9 +1503,9 @@ export class Parser { * Advances the parser to the next lex token after the closing token. */ any( - openKind: TokenKindEnum, + openKind: TokenKind, parseFn: () => T, - closeKind: TokenKindEnum, + closeKind: TokenKind, ): Array { this.expectToken(openKind); const nodes = []; @@ -1503,9 +1522,9 @@ export class Parser { * Advances the parser to the next lex token after the closing token. */ optionalMany( - openKind: TokenKindEnum, + openKind: TokenKind, parseFn: () => T, - closeKind: TokenKindEnum, + closeKind: TokenKind, ): Array { if (this.expectOptionalToken(openKind)) { const nodes = []; @@ -1523,9 +1542,9 @@ export class Parser { * Advances the parser to the next lex token after the closing token. */ many( - openKind: TokenKindEnum, + openKind: TokenKind, parseFn: () => T, - closeKind: TokenKindEnum, + closeKind: TokenKind, ): Array { this.expectToken(openKind); const nodes = []; @@ -1540,7 +1559,7 @@ export class Parser { * This list may begin with a lex token of delimiterKind followed by items separated by lex tokens of tokenKind. * Advances the parser to the next lex token after last item in the list. */ - delimitedMany(delimiterKind: TokenKindEnum, parseFn: () => T): Array { + delimitedMany(delimiterKind: TokenKind, parseFn: () => T): Array { this.expectOptionalToken(delimiterKind); const nodes = []; @@ -1549,6 +1568,22 @@ export class Parser { } while (this.expectOptionalToken(delimiterKind)); return nodes; } + + advanceLexer(): void { + const { maxTokens } = this._options; + const token = this._lexer.advance(); + + if (token.kind !== TokenKind.EOF) { + ++this._tokenCounter; + if (maxTokens !== undefined && this._tokenCounter > maxTokens) { + throw syntaxError( + this._lexer.source, + token.start, + `Document contains more that ${maxTokens} tokens. Parsing aborted.`, + ); + } + } + } } /** @@ -1562,6 +1597,6 @@ function getTokenDesc(token: Token): string { /** * A helper function to describe a token kind as a string for debugging. */ -function getTokenKindDesc(kind: TokenKindEnum): string { +function getTokenKindDesc(kind: TokenKind): string { return isPunctuatorTokenKind(kind) ? `"${kind}"` : kind; } diff --git a/src/language/predicates.d.ts b/src/language/predicates.d.ts deleted file mode 100644 index cdbe1f9fd6..0000000000 --- a/src/language/predicates.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { - ASTNode, - DefinitionNode, - ExecutableDefinitionNode, - SelectionNode, - ValueNode, - TypeNode, - TypeSystemDefinitionNode, - TypeDefinitionNode, - TypeSystemExtensionNode, - TypeExtensionNode, -} from './ast'; - -export function isDefinitionNode(node: ASTNode): node is DefinitionNode; - -export function isExecutableDefinitionNode( - node: ASTNode, -): node is ExecutableDefinitionNode; - -export function isSelectionNode(node: ASTNode): node is SelectionNode; - -export function isValueNode(node: ASTNode): node is ValueNode; - -export function isTypeNode(node: ASTNode): node is TypeNode; - -export function isTypeSystemDefinitionNode( - node: ASTNode, -): node is TypeSystemDefinitionNode; - -export function isTypeDefinitionNode(node: ASTNode): node is TypeDefinitionNode; - -export function isTypeSystemExtensionNode( - node: ASTNode, -): node is TypeSystemExtensionNode; - -export function isTypeExtensionNode(node: ASTNode): node is TypeExtensionNode; diff --git a/src/language/predicates.js b/src/language/predicates.ts similarity index 56% rename from src/language/predicates.js rename to src/language/predicates.ts index b9108f87ad..a390f4ee55 100644 --- a/src/language/predicates.js +++ b/src/language/predicates.ts @@ -1,7 +1,19 @@ -import type { ASTNode } from './ast'; +import type { + ASTNode, + ConstValueNode, + DefinitionNode, + ExecutableDefinitionNode, + SelectionNode, + TypeDefinitionNode, + TypeExtensionNode, + TypeNode, + TypeSystemDefinitionNode, + TypeSystemExtensionNode, + ValueNode, +} from './ast'; import { Kind } from './kinds'; -export function isDefinitionNode(node: ASTNode): boolean %checks { +export function isDefinitionNode(node: ASTNode): node is DefinitionNode { return ( isExecutableDefinitionNode(node) || isTypeSystemDefinitionNode(node) || @@ -9,14 +21,16 @@ export function isDefinitionNode(node: ASTNode): boolean %checks { ); } -export function isExecutableDefinitionNode(node: ASTNode): boolean %checks { +export function isExecutableDefinitionNode( + node: ASTNode, +): node is ExecutableDefinitionNode { return ( node.kind === Kind.OPERATION_DEFINITION || node.kind === Kind.FRAGMENT_DEFINITION ); } -export function isSelectionNode(node: ASTNode): boolean %checks { +export function isSelectionNode(node: ASTNode): node is SelectionNode { return ( node.kind === Kind.FIELD || node.kind === Kind.FRAGMENT_SPREAD || @@ -24,7 +38,7 @@ export function isSelectionNode(node: ASTNode): boolean %checks { ); } -export function isValueNode(node: ASTNode): boolean %checks { +export function isValueNode(node: ASTNode): node is ValueNode { return ( node.kind === Kind.VARIABLE || node.kind === Kind.INT || @@ -38,7 +52,18 @@ export function isValueNode(node: ASTNode): boolean %checks { ); } -export function isTypeNode(node: ASTNode): boolean %checks { +export function isConstValueNode(node: ASTNode): node is ConstValueNode { + return ( + isValueNode(node) && + (node.kind === Kind.LIST + ? node.values.some(isConstValueNode) + : node.kind === Kind.OBJECT + ? node.fields.some((field) => isConstValueNode(field.value)) + : node.kind !== Kind.VARIABLE) + ); +} + +export function isTypeNode(node: ASTNode): node is TypeNode { return ( node.kind === Kind.NAMED_TYPE || node.kind === Kind.LIST_TYPE || @@ -46,7 +71,9 @@ export function isTypeNode(node: ASTNode): boolean %checks { ); } -export function isTypeSystemDefinitionNode(node: ASTNode): boolean %checks { +export function isTypeSystemDefinitionNode( + node: ASTNode, +): node is TypeSystemDefinitionNode { return ( node.kind === Kind.SCHEMA_DEFINITION || isTypeDefinitionNode(node) || @@ -54,7 +81,9 @@ export function isTypeSystemDefinitionNode(node: ASTNode): boolean %checks { ); } -export function isTypeDefinitionNode(node: ASTNode): boolean %checks { +export function isTypeDefinitionNode( + node: ASTNode, +): node is TypeDefinitionNode { return ( node.kind === Kind.SCALAR_TYPE_DEFINITION || node.kind === Kind.OBJECT_TYPE_DEFINITION || @@ -65,11 +94,13 @@ export function isTypeDefinitionNode(node: ASTNode): boolean %checks { ); } -export function isTypeSystemExtensionNode(node: ASTNode): boolean %checks { +export function isTypeSystemExtensionNode( + node: ASTNode, +): node is TypeSystemExtensionNode { return node.kind === Kind.SCHEMA_EXTENSION || isTypeExtensionNode(node); } -export function isTypeExtensionNode(node: ASTNode): boolean %checks { +export function isTypeExtensionNode(node: ASTNode): node is TypeExtensionNode { return ( node.kind === Kind.SCALAR_TYPE_EXTENSION || node.kind === Kind.OBJECT_TYPE_EXTENSION || diff --git a/src/language/printLocation.d.ts b/src/language/printLocation.d.ts deleted file mode 100644 index 7d0c34705b..0000000000 --- a/src/language/printLocation.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Location } from './ast'; -import { Source } from './source'; -import { SourceLocation } from './location'; - -/** - * Render a helpful description of the location in the GraphQL Source document. - */ -export function printLocation(location: Location): string; - -/** - * Render a helpful description of the location in the GraphQL Source document. - */ -export function printSourceLocation( - source: Source, - sourceLocation: SourceLocation, -): string; diff --git a/src/language/printLocation.js b/src/language/printLocation.ts similarity index 68% rename from src/language/printLocation.js rename to src/language/printLocation.ts index fbf3504634..3d44f5cea5 100644 --- a/src/language/printLocation.js +++ b/src/language/printLocation.ts @@ -1,7 +1,7 @@ -import type { Source } from './source'; import type { Location } from './ast'; import type { SourceLocation } from './location'; import { getLocation } from './location'; +import type { Source } from './source'; /** * Render a helpful description of the location in the GraphQL Source document. @@ -21,7 +21,7 @@ export function printSourceLocation( sourceLocation: SourceLocation, ): string { const firstLineColumnOffset = source.locationOffset.column - 1; - const body = whitespace(firstLineColumnOffset) + source.body; + const body = ''.padStart(firstLineColumnOffset) + source.body; const lineIndex = sourceLocation.line - 1; const lineOffset = source.locationOffset.line - 1; @@ -38,7 +38,7 @@ export function printSourceLocation( if (locationLine.length > 120) { const subLineIndex = Math.floor(columnNum / 80); const subLineColumnNum = columnNum % 80; - const subLines = []; + const subLines: Array = []; for (let i = 0; i < locationLine.length; i += 80) { subLines.push(locationLine.slice(i, i + 80)); } @@ -46,10 +46,12 @@ export function printSourceLocation( return ( locationStr + printPrefixedLines([ - [`${lineNum}`, subLines[0]], - ...subLines.slice(1, subLineIndex + 1).map((subLine) => ['', subLine]), - [' ', whitespace(subLineColumnNum - 1) + '^'], - ['', subLines[subLineIndex + 1]], + [`${lineNum} |`, subLines[0]], + ...subLines + .slice(1, subLineIndex + 1) + .map((subLine) => ['|', subLine] as const), + ['|', '^'.padStart(subLineColumnNum)], + ['|', subLines[subLineIndex + 1]], ]) ); } @@ -58,30 +60,21 @@ export function printSourceLocation( locationStr + printPrefixedLines([ // Lines specified like this: ["prefix", "string"], - [`${lineNum - 1}`, lines[lineIndex - 1]], - [`${lineNum}`, locationLine], - ['', whitespace(columnNum - 1) + '^'], - [`${lineNum + 1}`, lines[lineIndex + 1]], + [`${lineNum - 1} |`, lines[lineIndex - 1]], + [`${lineNum} |`, locationLine], + ['|', '^'.padStart(columnNum)], + [`${lineNum + 1} |`, lines[lineIndex + 1]], ]) ); } -function printPrefixedLines(lines: $ReadOnlyArray<[string, string]>): string { +function printPrefixedLines( + lines: ReadonlyArray, +): string { const existingLines = lines.filter(([_, line]) => line !== undefined); const padLen = Math.max(...existingLines.map(([prefix]) => prefix.length)); return existingLines - .map( - ([prefix, line]) => - leftPad(padLen, prefix) + (line ? ' | ' + line : ' |'), - ) + .map(([prefix, line]) => prefix.padStart(padLen) + (line ? ' ' + line : '')) .join('\n'); } - -function whitespace(len: number): string { - return Array(len + 1).join(' '); -} - -function leftPad(len: number, str: string): string { - return whitespace(len - str.length) + str; -} diff --git a/src/language/printString.ts b/src/language/printString.ts new file mode 100644 index 0000000000..b091bcc2c1 --- /dev/null +++ b/src/language/printString.ts @@ -0,0 +1,38 @@ +/** + * Prints a string as a GraphQL StringValue literal. Replaces control characters + * and excluded characters (" U+0022 and \\ U+005C) with escape sequences. + */ +export function printString(str: string): string { + return `"${str.replace(escapedRegExp, escapedReplacer)}"`; +} + +// eslint-disable-next-line no-control-regex +const escapedRegExp = /[\x00-\x1f\x22\x5c\x7f-\x9f]/g; + +function escapedReplacer(str: string): string { + return escapeSequences[str.charCodeAt(0)]; +} + +// prettier-ignore +const escapeSequences = [ + '\\u0000', '\\u0001', '\\u0002', '\\u0003', '\\u0004', '\\u0005', '\\u0006', '\\u0007', + '\\b', '\\t', '\\n', '\\u000B', '\\f', '\\r', '\\u000E', '\\u000F', + '\\u0010', '\\u0011', '\\u0012', '\\u0013', '\\u0014', '\\u0015', '\\u0016', '\\u0017', + '\\u0018', '\\u0019', '\\u001A', '\\u001B', '\\u001C', '\\u001D', '\\u001E', '\\u001F', + '', '', '\\"', '', '', '', '', '', + '', '', '', '', '', '', '', '', // 2F + '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', // 3F + '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', // 4F + '', '', '', '', '', '', '', '', + '', '', '', '', '\\\\', '', '', '', // 5F + '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', // 6F + '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '\\u007F', + '\\u0080', '\\u0081', '\\u0082', '\\u0083', '\\u0084', '\\u0085', '\\u0086', '\\u0087', + '\\u0088', '\\u0089', '\\u008A', '\\u008B', '\\u008C', '\\u008D', '\\u008E', '\\u008F', + '\\u0090', '\\u0091', '\\u0092', '\\u0093', '\\u0094', '\\u0095', '\\u0096', '\\u0097', + '\\u0098', '\\u0099', '\\u009A', '\\u009B', '\\u009C', '\\u009D', '\\u009E', '\\u009F', +]; diff --git a/src/language/printer.d.ts b/src/language/printer.d.ts deleted file mode 100644 index 9329b45956..0000000000 --- a/src/language/printer.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ASTNode } from './ast'; - -/** - * Converts an AST into a string, using one set of reasonable - * formatting rules. - */ -export function print(ast: ASTNode): string; diff --git a/src/language/printer.js b/src/language/printer.js deleted file mode 100644 index 8ca8fb2dad..0000000000 --- a/src/language/printer.js +++ /dev/null @@ -1,291 +0,0 @@ -import type { ASTNode } from './ast'; - -import { visit } from './visitor'; -import { printBlockString } from './blockString'; - -/** - * Converts an AST into a string, using one set of reasonable - * formatting rules. - */ -export function print(ast: ASTNode): string { - return visit(ast, { leave: printDocASTReducer }); -} - -const MAX_LINE_LENGTH = 80; - -// TODO: provide better type coverage in future -const printDocASTReducer: any = { - Name: (node) => node.value, - Variable: (node) => '$' + node.name, - - // Document - - Document: (node) => join(node.definitions, '\n\n') + '\n', - - OperationDefinition(node) { - const op = node.operation; - const name = node.name; - const varDefs = wrap('(', join(node.variableDefinitions, ', '), ')'); - const directives = join(node.directives, ' '); - const selectionSet = node.selectionSet; - // Anonymous queries with no directives or variable definitions can use - // the query short form. - return !name && !directives && !varDefs && op === 'query' - ? selectionSet - : join([op, join([name, varDefs]), directives, selectionSet], ' '); - }, - - VariableDefinition: ({ variable, type, defaultValue, directives }) => - variable + - ': ' + - type + - wrap(' = ', defaultValue) + - wrap(' ', join(directives, ' ')), - SelectionSet: ({ selections }) => block(selections), - - Field: ({ alias, name, arguments: args, directives, selectionSet }) => { - const prefix = wrap('', alias, ': ') + name; - let argsLine = prefix + wrap('(', join(args, ', '), ')'); - - if (argsLine.length > MAX_LINE_LENGTH) { - argsLine = prefix + wrap('(\n', indent(join(args, '\n')), '\n)'); - } - - return join([argsLine, join(directives, ' '), selectionSet], ' '); - }, - - Argument: ({ name, value }) => name + ': ' + value, - - // Fragments - - FragmentSpread: ({ name, directives }) => - '...' + name + wrap(' ', join(directives, ' ')), - - InlineFragment: ({ typeCondition, directives, selectionSet }) => - join( - ['...', wrap('on ', typeCondition), join(directives, ' '), selectionSet], - ' ', - ), - - FragmentDefinition: ({ - name, - typeCondition, - variableDefinitions, - directives, - selectionSet, - }) => - // Note: fragment variable definitions are experimental and may be changed - // or removed in the future. - `fragment ${name}${wrap('(', join(variableDefinitions, ', '), ')')} ` + - `on ${typeCondition} ${wrap('', join(directives, ' '), ' ')}` + - selectionSet, - - // Value - - IntValue: ({ value }) => value, - FloatValue: ({ value }) => value, - StringValue: ({ value, block: isBlockString }, key) => - isBlockString - ? printBlockString(value, key === 'description' ? '' : ' ') - : JSON.stringify(value), - BooleanValue: ({ value }) => (value ? 'true' : 'false'), - NullValue: () => 'null', - EnumValue: ({ value }) => value, - ListValue: ({ values }) => '[' + join(values, ', ') + ']', - ObjectValue: ({ fields }) => '{' + join(fields, ', ') + '}', - ObjectField: ({ name, value }) => name + ': ' + value, - - // Directive - - Directive: ({ name, arguments: args }) => - '@' + name + wrap('(', join(args, ', '), ')'), - - // Type - - NamedType: ({ name }) => name, - ListType: ({ type }) => '[' + type + ']', - NonNullType: ({ type }) => type + '!', - - // Type System Definitions - - SchemaDefinition: addDescription(({ directives, operationTypes }) => - join(['schema', join(directives, ' '), block(operationTypes)], ' '), - ), - - OperationTypeDefinition: ({ operation, type }) => operation + ': ' + type, - - ScalarTypeDefinition: addDescription(({ name, directives }) => - join(['scalar', name, join(directives, ' ')], ' '), - ), - - ObjectTypeDefinition: addDescription( - ({ name, interfaces, directives, fields }) => - join( - [ - 'type', - name, - wrap('implements ', join(interfaces, ' & ')), - join(directives, ' '), - block(fields), - ], - ' ', - ), - ), - - FieldDefinition: addDescription( - ({ name, arguments: args, type, directives }) => - name + - (hasMultilineItems(args) - ? wrap('(\n', indent(join(args, '\n')), '\n)') - : wrap('(', join(args, ', '), ')')) + - ': ' + - type + - wrap(' ', join(directives, ' ')), - ), - - InputValueDefinition: addDescription( - ({ name, type, defaultValue, directives }) => - join( - [name + ': ' + type, wrap('= ', defaultValue), join(directives, ' ')], - ' ', - ), - ), - - InterfaceTypeDefinition: addDescription( - ({ name, interfaces, directives, fields }) => - join( - [ - 'interface', - name, - wrap('implements ', join(interfaces, ' & ')), - join(directives, ' '), - block(fields), - ], - ' ', - ), - ), - - UnionTypeDefinition: addDescription(({ name, directives, types }) => - join( - [ - 'union', - name, - join(directives, ' '), - types && types.length !== 0 ? '= ' + join(types, ' | ') : '', - ], - ' ', - ), - ), - - EnumTypeDefinition: addDescription(({ name, directives, values }) => - join(['enum', name, join(directives, ' '), block(values)], ' '), - ), - - EnumValueDefinition: addDescription(({ name, directives }) => - join([name, join(directives, ' ')], ' '), - ), - - InputObjectTypeDefinition: addDescription(({ name, directives, fields }) => - join(['input', name, join(directives, ' '), block(fields)], ' '), - ), - - DirectiveDefinition: addDescription( - ({ name, arguments: args, repeatable, locations }) => - 'directive @' + - name + - (hasMultilineItems(args) - ? wrap('(\n', indent(join(args, '\n')), '\n)') - : wrap('(', join(args, ', '), ')')) + - (repeatable ? ' repeatable' : '') + - ' on ' + - join(locations, ' | '), - ), - - SchemaExtension: ({ directives, operationTypes }) => - join(['extend schema', join(directives, ' '), block(operationTypes)], ' '), - - ScalarTypeExtension: ({ name, directives }) => - join(['extend scalar', name, join(directives, ' ')], ' '), - - ObjectTypeExtension: ({ name, interfaces, directives, fields }) => - join( - [ - 'extend type', - name, - wrap('implements ', join(interfaces, ' & ')), - join(directives, ' '), - block(fields), - ], - ' ', - ), - - InterfaceTypeExtension: ({ name, interfaces, directives, fields }) => - join( - [ - 'extend interface', - name, - wrap('implements ', join(interfaces, ' & ')), - join(directives, ' '), - block(fields), - ], - ' ', - ), - - UnionTypeExtension: ({ name, directives, types }) => - join( - [ - 'extend union', - name, - join(directives, ' '), - types && types.length !== 0 ? '= ' + join(types, ' | ') : '', - ], - ' ', - ), - - EnumTypeExtension: ({ name, directives, values }) => - join(['extend enum', name, join(directives, ' '), block(values)], ' '), - - InputObjectTypeExtension: ({ name, directives, fields }) => - join(['extend input', name, join(directives, ' '), block(fields)], ' '), -}; - -function addDescription(cb) { - return (node) => join([node.description, cb(node)], '\n'); -} - -/** - * Given maybeArray, print an empty string if it is null or empty, otherwise - * print all items together separated by separator if provided - */ -function join(maybeArray: ?Array, separator = ''): string { - return maybeArray?.filter((x) => x).join(separator) ?? ''; -} - -/** - * Given array, print each item on its own line, wrapped in an - * indented "{ }" block. - */ -function block(array: ?Array): string { - return wrap('{\n', indent(join(array, '\n')), '\n}'); -} - -/** - * If maybeString is not null or empty, then wrap with start and end, otherwise print an empty string. - */ -function wrap(start: string, maybeString: ?string, end: string = ''): string { - return maybeString != null && maybeString !== '' - ? start + maybeString + end - : ''; -} - -function indent(str: string): string { - return wrap(' ', str.replace(/\n/g, '\n ')); -} - -function isMultiline(str: string): boolean { - return str.indexOf('\n') !== -1; -} - -function hasMultilineItems(maybeArray: ?Array): boolean { - return maybeArray != null && maybeArray.some(isMultiline); -} diff --git a/src/language/printer.ts b/src/language/printer.ts new file mode 100644 index 0000000000..e95c118d8b --- /dev/null +++ b/src/language/printer.ts @@ -0,0 +1,347 @@ +import type { Maybe } from '../jsutils/Maybe'; + +import type { ASTNode } from './ast'; +import { printBlockString } from './blockString'; +import { printString } from './printString'; +import type { ASTReducer } from './visitor'; +import { visit } from './visitor'; + +/** + * Converts an AST into a string, using one set of reasonable + * formatting rules. + */ +export function print(ast: ASTNode): string { + return visit(ast, printDocASTReducer); +} + +const MAX_LINE_LENGTH = 80; + +const printDocASTReducer: ASTReducer = { + Name: { leave: (node) => node.value }, + Variable: { leave: (node) => '$' + node.name }, + + // Document + + Document: { + leave: (node) => join(node.definitions, '\n\n'), + }, + + OperationDefinition: { + leave(node) { + const varDefs = wrap('(', join(node.variableDefinitions, ', '), ')'); + const prefix = join( + [ + node.operation, + join([node.name, varDefs]), + join(node.directives, ' '), + ], + ' ', + ); + + // Anonymous queries with no directives or variable definitions can use + // the query short form. + return (prefix === 'query' ? '' : prefix + ' ') + node.selectionSet; + }, + }, + + VariableDefinition: { + leave: ({ variable, type, defaultValue, directives }) => + variable + + ': ' + + type + + wrap(' = ', defaultValue) + + wrap(' ', join(directives, ' ')), + }, + SelectionSet: { leave: ({ selections }) => block(selections) }, + + Field: { + leave({ alias, name, arguments: args, directives, selectionSet }) { + const prefix = wrap('', alias, ': ') + name; + let argsLine = prefix + wrap('(', join(args, ', '), ')'); + + if (argsLine.length > MAX_LINE_LENGTH) { + argsLine = prefix + wrap('(\n', indent(join(args, '\n')), '\n)'); + } + + return join([argsLine, join(directives, ' '), selectionSet], ' '); + }, + }, + + Argument: { leave: ({ name, value }) => name + ': ' + value }, + + // Fragments + + FragmentSpread: { + leave: ({ name, directives }) => + '...' + name + wrap(' ', join(directives, ' ')), + }, + + InlineFragment: { + leave: ({ typeCondition, directives, selectionSet }) => + join( + [ + '...', + wrap('on ', typeCondition), + join(directives, ' '), + selectionSet, + ], + ' ', + ), + }, + + FragmentDefinition: { + leave: ({ + name, + typeCondition, + variableDefinitions, + directives, + selectionSet, + }) => + // Note: fragment variable definitions are experimental and may be changed + // or removed in the future. + `fragment ${name}${wrap('(', join(variableDefinitions, ', '), ')')} ` + + `on ${typeCondition} ${wrap('', join(directives, ' '), ' ')}` + + selectionSet, + }, + + // Value + + IntValue: { leave: ({ value }) => value }, + FloatValue: { leave: ({ value }) => value }, + StringValue: { + leave: ({ value, block: isBlockString }) => + isBlockString ? printBlockString(value) : printString(value), + }, + BooleanValue: { leave: ({ value }) => (value ? 'true' : 'false') }, + NullValue: { leave: () => 'null' }, + EnumValue: { leave: ({ value }) => value }, + ListValue: { leave: ({ values }) => '[' + join(values, ', ') + ']' }, + ObjectValue: { leave: ({ fields }) => '{' + join(fields, ', ') + '}' }, + ObjectField: { leave: ({ name, value }) => name + ': ' + value }, + + // Directive + + Directive: { + leave: ({ name, arguments: args }) => + '@' + name + wrap('(', join(args, ', '), ')'), + }, + + // Type + + NamedType: { leave: ({ name }) => name }, + ListType: { leave: ({ type }) => '[' + type + ']' }, + NonNullType: { leave: ({ type }) => type + '!' }, + + // Type System Definitions + + SchemaDefinition: { + leave: ({ description, directives, operationTypes }) => + wrap('', description, '\n') + + join(['schema', join(directives, ' '), block(operationTypes)], ' '), + }, + + OperationTypeDefinition: { + leave: ({ operation, type }) => operation + ': ' + type, + }, + + ScalarTypeDefinition: { + leave: ({ description, name, directives }) => + wrap('', description, '\n') + + join(['scalar', name, join(directives, ' ')], ' '), + }, + + ObjectTypeDefinition: { + leave: ({ description, name, interfaces, directives, fields }) => + wrap('', description, '\n') + + join( + [ + 'type', + name, + wrap('implements ', join(interfaces, ' & ')), + join(directives, ' '), + block(fields), + ], + ' ', + ), + }, + + FieldDefinition: { + leave: ({ description, name, arguments: args, type, directives }) => + wrap('', description, '\n') + + name + + (hasMultilineItems(args) + ? wrap('(\n', indent(join(args, '\n')), '\n)') + : wrap('(', join(args, ', '), ')')) + + ': ' + + type + + wrap(' ', join(directives, ' ')), + }, + + InputValueDefinition: { + leave: ({ description, name, type, defaultValue, directives }) => + wrap('', description, '\n') + + join( + [name + ': ' + type, wrap('= ', defaultValue), join(directives, ' ')], + ' ', + ), + }, + + InterfaceTypeDefinition: { + leave: ({ description, name, interfaces, directives, fields }) => + wrap('', description, '\n') + + join( + [ + 'interface', + name, + wrap('implements ', join(interfaces, ' & ')), + join(directives, ' '), + block(fields), + ], + ' ', + ), + }, + + UnionTypeDefinition: { + leave: ({ description, name, directives, types }) => + wrap('', description, '\n') + + join( + ['union', name, join(directives, ' '), wrap('= ', join(types, ' | '))], + ' ', + ), + }, + + EnumTypeDefinition: { + leave: ({ description, name, directives, values }) => + wrap('', description, '\n') + + join(['enum', name, join(directives, ' '), block(values)], ' '), + }, + + EnumValueDefinition: { + leave: ({ description, name, directives }) => + wrap('', description, '\n') + join([name, join(directives, ' ')], ' '), + }, + + InputObjectTypeDefinition: { + leave: ({ description, name, directives, fields }) => + wrap('', description, '\n') + + join(['input', name, join(directives, ' '), block(fields)], ' '), + }, + + DirectiveDefinition: { + leave: ({ description, name, arguments: args, repeatable, locations }) => + wrap('', description, '\n') + + 'directive @' + + name + + (hasMultilineItems(args) + ? wrap('(\n', indent(join(args, '\n')), '\n)') + : wrap('(', join(args, ', '), ')')) + + (repeatable ? ' repeatable' : '') + + ' on ' + + join(locations, ' | '), + }, + + SchemaExtension: { + leave: ({ directives, operationTypes }) => + join( + ['extend schema', join(directives, ' '), block(operationTypes)], + ' ', + ), + }, + + ScalarTypeExtension: { + leave: ({ name, directives }) => + join(['extend scalar', name, join(directives, ' ')], ' '), + }, + + ObjectTypeExtension: { + leave: ({ name, interfaces, directives, fields }) => + join( + [ + 'extend type', + name, + wrap('implements ', join(interfaces, ' & ')), + join(directives, ' '), + block(fields), + ], + ' ', + ), + }, + + InterfaceTypeExtension: { + leave: ({ name, interfaces, directives, fields }) => + join( + [ + 'extend interface', + name, + wrap('implements ', join(interfaces, ' & ')), + join(directives, ' '), + block(fields), + ], + ' ', + ), + }, + + UnionTypeExtension: { + leave: ({ name, directives, types }) => + join( + [ + 'extend union', + name, + join(directives, ' '), + wrap('= ', join(types, ' | ')), + ], + ' ', + ), + }, + + EnumTypeExtension: { + leave: ({ name, directives, values }) => + join(['extend enum', name, join(directives, ' '), block(values)], ' '), + }, + + InputObjectTypeExtension: { + leave: ({ name, directives, fields }) => + join(['extend input', name, join(directives, ' '), block(fields)], ' '), + }, +}; + +/** + * Given maybeArray, print an empty string if it is null or empty, otherwise + * print all items together separated by separator if provided + */ +function join( + maybeArray: Maybe>, + separator = '', +): string { + return maybeArray?.filter((x) => x).join(separator) ?? ''; +} + +/** + * Given array, print each item on its own line, wrapped in an indented `{ }` block. + */ +function block(array: Maybe>): string { + return wrap('{\n', indent(join(array, '\n')), '\n}'); +} + +/** + * If maybeString is not null or empty, then wrap with start and end, otherwise print an empty string. + */ +function wrap( + start: string, + maybeString: Maybe, + end: string = '', +): string { + return maybeString != null && maybeString !== '' + ? start + maybeString + end + : ''; +} + +function indent(str: string): string { + return wrap(' ', str.replace(/\n/g, '\n ')); +} + +function hasMultilineItems(maybeArray: Maybe>): boolean { + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ + return maybeArray?.some((str) => str.includes('\n')) ?? false; +} diff --git a/src/language/source.d.ts b/src/language/source.d.ts deleted file mode 100644 index a7df7cbb6b..0000000000 --- a/src/language/source.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -interface Location { - line: number; - column: number; -} - -/** - * A representation of source input to GraphQL. The `name` and `locationOffset` parameters are - * optional, but they are useful for clients who store GraphQL documents in source files. - * For example, if the GraphQL input starts at line 40 in a file named `Foo.graphql`, it might - * be useful for `name` to be `"Foo.graphql"` and location to be `{ line: 40, column: 1 }`. - * The `line` and `column` properties in `locationOffset` are 1-indexed. - */ -export class Source { - body: string; - name: string; - locationOffset: Location; - constructor(body: string, name?: string, locationOffset?: Location); -} - -/** - * Test if the given value is a Source object. - * - * @internal - */ -export function isSource(source: any): source is Source; diff --git a/src/language/source.js b/src/language/source.ts similarity index 70% rename from src/language/source.js rename to src/language/source.ts index a7181f4df7..15f65fceee 100644 --- a/src/language/source.js +++ b/src/language/source.ts @@ -1,13 +1,11 @@ -import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols'; +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; +import { instanceOf } from '../jsutils/instanceOf'; -import inspect from '../jsutils/inspect'; -import devAssert from '../jsutils/devAssert'; -import instanceOf from '../jsutils/instanceOf'; - -type Location = {| - line: number, - column: number, -|}; +interface Location { + line: number; + column: number; +} /** * A representation of source input to GraphQL. The `name` and `locationOffset` parameters are @@ -44,8 +42,7 @@ export class Source { ); } - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { + get [Symbol.toStringTag]() { return 'Source'; } } @@ -55,9 +52,6 @@ export class Source { * * @internal */ -declare function isSource(source: mixed): boolean %checks(source instanceof - Source); -// eslint-disable-next-line no-redeclare -export function isSource(source) { +export function isSource(source: unknown): source is Source { return instanceOf(source, Source); } diff --git a/src/language/tokenKind.d.ts b/src/language/tokenKind.d.ts deleted file mode 100644 index fa27e23293..0000000000 --- a/src/language/tokenKind.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * An exported enum describing the different kinds of tokens that the - * lexer emits. - */ -export const TokenKind: { - SOF: ''; - EOF: ''; - BANG: '!'; - DOLLAR: '$'; - AMP: '&'; - PAREN_L: '('; - PAREN_R: ')'; - SPREAD: '...'; - COLON: ':'; - EQUALS: '='; - AT: '@'; - BRACKET_L: '['; - BRACKET_R: ']'; - BRACE_L: '{'; - PIPE: '|'; - BRACE_R: '}'; - NAME: 'Name'; - INT: 'Int'; - FLOAT: 'Float'; - STRING: 'String'; - BLOCK_STRING: 'BlockString'; - COMMENT: 'Comment'; -}; - -/** - * The enum type representing the token kinds values. - */ -export type TokenKindEnum = typeof TokenKind[keyof typeof TokenKind]; diff --git a/src/language/tokenKind.js b/src/language/tokenKind.js deleted file mode 100644 index b4f5248c13..0000000000 --- a/src/language/tokenKind.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * An exported enum describing the different kinds of tokens that the - * lexer emits. - */ -export const TokenKind = Object.freeze({ - SOF: '', - EOF: '', - BANG: '!', - DOLLAR: '$', - AMP: '&', - PAREN_L: '(', - PAREN_R: ')', - SPREAD: '...', - COLON: ':', - EQUALS: '=', - AT: '@', - BRACKET_L: '[', - BRACKET_R: ']', - BRACE_L: '{', - PIPE: '|', - BRACE_R: '}', - NAME: 'Name', - INT: 'Int', - FLOAT: 'Float', - STRING: 'String', - BLOCK_STRING: 'BlockString', - COMMENT: 'Comment', -}); - -/** - * The enum type representing the token kinds values. - */ -export type TokenKindEnum = $Values; diff --git a/src/language/tokenKind.ts b/src/language/tokenKind.ts new file mode 100644 index 0000000000..0c260df99e --- /dev/null +++ b/src/language/tokenKind.ts @@ -0,0 +1,36 @@ +/** + * An exported enum describing the different kinds of tokens that the + * lexer emits. + */ +enum TokenKind { + SOF = '', + EOF = '', + BANG = '!', + DOLLAR = '$', + AMP = '&', + PAREN_L = '(', + PAREN_R = ')', + SPREAD = '...', + COLON = ':', + EQUALS = '=', + AT = '@', + BRACKET_L = '[', + BRACKET_R = ']', + BRACE_L = '{', + PIPE = '|', + BRACE_R = '}', + NAME = 'Name', + INT = 'Int', + FLOAT = 'Float', + STRING = 'String', + BLOCK_STRING = 'BlockString', + COMMENT = 'Comment', +} +export { TokenKind }; + +/** + * The enum type representing the token kinds values. + * + * @deprecated Please use `TokenKind`. Will be remove in v17. + */ +export type TokenKindEnum = typeof TokenKind; diff --git a/src/language/visitor.d.ts b/src/language/visitor.d.ts deleted file mode 100644 index 22e634663c..0000000000 --- a/src/language/visitor.d.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { ASTNode, ASTKindToNode } from './ast'; - -/** - * A visitor is provided to visit, it contains the collection of - * relevant functions to be called during the visitor's traversal. - */ -export type ASTVisitor = Visitor; -export type Visitor = - | EnterLeaveVisitor - | ShapeMapVisitor; - -interface EnterLeave { - readonly enter?: T; - readonly leave?: T; -} - -type EnterLeaveVisitor = EnterLeave< - VisitFn | { [K in keyof KindToNode]?: VisitFn } ->; - -type ShapeMapVisitor = { - [K in keyof KindToNode]?: - | VisitFn - | EnterLeave>; -}; - -/** - * A visitor is comprised of visit functions, which are called on each node - * during the visitor's traversal. - */ -export type VisitFn = ( - /** The current node being visiting. */ - node: TVisitedNode, - /** The index or key to this node from the parent node or Array. */ - key: string | number | undefined, - /** The parent immediately above this node, which may be an Array. */ - parent: TAnyNode | ReadonlyArray | undefined, - /** The key path to get to this node from the root node. */ - path: ReadonlyArray, - /** - * All nodes and Arrays visited before reaching parent of this node. - * These correspond to array indices in `path`. - * Note: ancestors includes arrays which contain the parent of visited node. - */ - ancestors: ReadonlyArray>, -) => any; - -/** - * A KeyMap describes each the traversable properties of each kind of node. - */ -export type VisitorKeyMap = { [P in keyof T]: ReadonlyArray }; - -// TODO: Should be `[]`, but that requires TypeScript@3 -type EmptyTuple = Array; - -export const QueryDocumentKeys: { - Name: EmptyTuple; - - Document: ['definitions']; - // Prettier forces trailing commas, but TS pre 3.2 doesn't allow them. - // prettier-ignore - OperationDefinition: [ - 'name', - 'variableDefinitions', - 'directives', - 'selectionSet' - ]; - VariableDefinition: ['variable', 'type', 'defaultValue', 'directives']; - Variable: ['name']; - SelectionSet: ['selections']; - Field: ['alias', 'name', 'arguments', 'directives', 'selectionSet']; - Argument: ['name', 'value']; - - FragmentSpread: ['name', 'directives']; - InlineFragment: ['typeCondition', 'directives', 'selectionSet']; - // prettier-ignore - FragmentDefinition: [ - 'name', - // Note: fragment variable definitions are experimental and may be changed - // or removed in the future. - 'variableDefinitions', - 'typeCondition', - 'directives', - 'selectionSet' - ]; - - IntValue: EmptyTuple; - FloatValue: EmptyTuple; - StringValue: EmptyTuple; - BooleanValue: EmptyTuple; - NullValue: EmptyTuple; - EnumValue: EmptyTuple; - ListValue: ['values']; - ObjectValue: ['fields']; - ObjectField: ['name', 'value']; - - Directive: ['name', 'arguments']; - - NamedType: ['name']; - ListType: ['type']; - NonNullType: ['type']; - - SchemaDefinition: ['description', 'directives', 'operationTypes']; - OperationTypeDefinition: ['type']; - - ScalarTypeDefinition: ['description', 'name', 'directives']; - // prettier-ignore - ObjectTypeDefinition: [ - 'description', - 'name', - 'interfaces', - 'directives', - 'fields' - ]; - FieldDefinition: ['description', 'name', 'arguments', 'type', 'directives']; - // prettier-ignore - InputValueDefinition: [ - 'description', - 'name', - 'type', - 'defaultValue', - 'directives' - ]; - // prettier-ignore - InterfaceTypeDefinition: [ - 'description', - 'name', - 'interfaces', - 'directives', - 'fields' - ]; - UnionTypeDefinition: ['description', 'name', 'directives', 'types']; - EnumTypeDefinition: ['description', 'name', 'directives', 'values']; - EnumValueDefinition: ['description', 'name', 'directives']; - InputObjectTypeDefinition: ['description', 'name', 'directives', 'fields']; - - DirectiveDefinition: ['description', 'name', 'arguments', 'locations']; - - SchemaExtension: ['directives', 'operationTypes']; - - ScalarTypeExtension: ['name', 'directives']; - ObjectTypeExtension: ['name', 'interfaces', 'directives', 'fields']; - InterfaceTypeExtension: ['name', 'interfaces', 'directives', 'fields']; - UnionTypeExtension: ['name', 'directives', 'types']; - EnumTypeExtension: ['name', 'directives', 'values']; - InputObjectTypeExtension: ['name', 'directives', 'fields']; -}; - -export const BREAK: any; - -/** - * visit() will walk through an AST using a depth-first traversal, calling - * the visitor's enter function at each node in the traversal, and calling the - * leave function after visiting that node and all of its child nodes. - * - * By returning different values from the enter and leave functions, the - * behavior of the visitor can be altered, including skipping over a sub-tree of - * the AST (by returning false), editing the AST by returning a value or null - * to remove the value, or to stop the whole traversal by returning BREAK. - * - * When using visit() to edit an AST, the original AST will not be modified, and - * a new version of the AST with the changes applied will be returned from the - * visit function. - * - * const editedAST = visit(ast, { - * enter(node, key, parent, path, ancestors) { - * // @return - * // undefined: no action - * // false: skip visiting this node - * // visitor.BREAK: stop visiting altogether - * // null: delete this node - * // any value: replace this node with the returned value - * }, - * leave(node, key, parent, path, ancestors) { - * // @return - * // undefined: no action - * // false: no action - * // visitor.BREAK: stop visiting altogether - * // null: delete this node - * // any value: replace this node with the returned value - * } - * }); - * - * Alternatively to providing enter() and leave() functions, a visitor can - * instead provide functions named the same as the kinds of AST nodes, or - * enter/leave visitors at a named key, leading to four permutations of the - * visitor API: - * - * 1) Named visitors triggered when entering a node of a specific kind. - * - * visit(ast, { - * Kind(node) { - * // enter the "Kind" node - * } - * }) - * - * 2) Named visitors that trigger upon entering and leaving a node of - * a specific kind. - * - * visit(ast, { - * Kind: { - * enter(node) { - * // enter the "Kind" node - * } - * leave(node) { - * // leave the "Kind" node - * } - * } - * }) - * - * 3) Generic visitors that trigger upon entering and leaving any node. - * - * visit(ast, { - * enter(node) { - * // enter any node - * }, - * leave(node) { - * // leave any node - * } - * }) - * - * 4) Parallel visitors for entering and leaving nodes of a specific kind. - * - * visit(ast, { - * enter: { - * Kind(node) { - * // enter the "Kind" node - * } - * }, - * leave: { - * Kind(node) { - * // leave the "Kind" node - * } - * } - * }) - */ -export function visit( - root: ASTNode, - visitor: Visitor, - visitorKeys?: VisitorKeyMap, // default: QueryDocumentKeys -): any; - -/** - * Creates a new visitor instance which delegates to many visitors to run in - * parallel. Each visitor will be visited for each node before moving on. - * - * If a prior visitor edits a node, no following visitors will see that node. - */ -export function visitInParallel( - visitors: ReadonlyArray>, -): Visitor; - -/** - * Given a visitor instance, if it is leaving or not, and a node kind, return - * the function the visitor runtime should call. - */ -export function getVisitFn( - visitor: Visitor, - kind: string, - isLeaving: boolean, -): Maybe>; diff --git a/src/language/visitor.js b/src/language/visitor.js deleted file mode 100644 index 5e367ce4a9..0000000000 --- a/src/language/visitor.js +++ /dev/null @@ -1,436 +0,0 @@ -import inspect from '../jsutils/inspect'; - -import type { ASTNode, ASTKindToNode } from './ast'; -import { isNode } from './ast'; - -/** - * A visitor is provided to visit, it contains the collection of - * relevant functions to be called during the visitor's traversal. - */ -export type ASTVisitor = Visitor; -export type Visitor> = - | EnterLeave< - | VisitFn - | ShapeMap(Node) => VisitFn>, - > - | ShapeMap< - KindToNode, - (Node) => VisitFn | EnterLeave>, - >; -type EnterLeave = {| +enter?: T, +leave?: T |}; -type ShapeMap = $Shape<$ObjMap>; - -/** - * A visitor is comprised of visit functions, which are called on each node - * during the visitor's traversal. - */ -export type VisitFn = ( - // The current node being visiting. - node: TVisitedNode, - // The index or key to this node from the parent node or Array. - key: string | number | void, - // The parent immediately above this node, which may be an Array. - parent: TAnyNode | $ReadOnlyArray | void, - // The key path to get to this node from the root node. - path: $ReadOnlyArray, - // All nodes and Arrays visited before reaching parent of this node. - // These correspond to array indices in `path`. - // Note: ancestors includes arrays which contain the parent of visited node. - ancestors: $ReadOnlyArray>, -) => any; - -/** - * A KeyMap describes each the traversable properties of each kind of node. - */ -export type VisitorKeyMap = $ObjMap< - KindToNode, - (T) => $ReadOnlyArray<$Keys>, ->; - -export const QueryDocumentKeys: VisitorKeyMap = { - Name: [], - - Document: ['definitions'], - OperationDefinition: [ - 'name', - 'variableDefinitions', - 'directives', - 'selectionSet', - ], - VariableDefinition: ['variable', 'type', 'defaultValue', 'directives'], - Variable: ['name'], - SelectionSet: ['selections'], - Field: ['alias', 'name', 'arguments', 'directives', 'selectionSet'], - Argument: ['name', 'value'], - - FragmentSpread: ['name', 'directives'], - InlineFragment: ['typeCondition', 'directives', 'selectionSet'], - FragmentDefinition: [ - 'name', - // Note: fragment variable definitions are experimental and may be changed - // or removed in the future. - 'variableDefinitions', - 'typeCondition', - 'directives', - 'selectionSet', - ], - - IntValue: [], - FloatValue: [], - StringValue: [], - BooleanValue: [], - NullValue: [], - EnumValue: [], - ListValue: ['values'], - ObjectValue: ['fields'], - ObjectField: ['name', 'value'], - - Directive: ['name', 'arguments'], - - NamedType: ['name'], - ListType: ['type'], - NonNullType: ['type'], - - SchemaDefinition: ['description', 'directives', 'operationTypes'], - OperationTypeDefinition: ['type'], - - ScalarTypeDefinition: ['description', 'name', 'directives'], - ObjectTypeDefinition: [ - 'description', - 'name', - 'interfaces', - 'directives', - 'fields', - ], - FieldDefinition: ['description', 'name', 'arguments', 'type', 'directives'], - InputValueDefinition: [ - 'description', - 'name', - 'type', - 'defaultValue', - 'directives', - ], - InterfaceTypeDefinition: [ - 'description', - 'name', - 'interfaces', - 'directives', - 'fields', - ], - UnionTypeDefinition: ['description', 'name', 'directives', 'types'], - EnumTypeDefinition: ['description', 'name', 'directives', 'values'], - EnumValueDefinition: ['description', 'name', 'directives'], - InputObjectTypeDefinition: ['description', 'name', 'directives', 'fields'], - - DirectiveDefinition: ['description', 'name', 'arguments', 'locations'], - - SchemaExtension: ['directives', 'operationTypes'], - - ScalarTypeExtension: ['name', 'directives'], - ObjectTypeExtension: ['name', 'interfaces', 'directives', 'fields'], - InterfaceTypeExtension: ['name', 'interfaces', 'directives', 'fields'], - UnionTypeExtension: ['name', 'directives', 'types'], - EnumTypeExtension: ['name', 'directives', 'values'], - InputObjectTypeExtension: ['name', 'directives', 'fields'], -}; - -export const BREAK: { ... } = Object.freeze({}); - -/** - * visit() will walk through an AST using a depth-first traversal, calling - * the visitor's enter function at each node in the traversal, and calling the - * leave function after visiting that node and all of its child nodes. - * - * By returning different values from the enter and leave functions, the - * behavior of the visitor can be altered, including skipping over a sub-tree of - * the AST (by returning false), editing the AST by returning a value or null - * to remove the value, or to stop the whole traversal by returning BREAK. - * - * When using visit() to edit an AST, the original AST will not be modified, and - * a new version of the AST with the changes applied will be returned from the - * visit function. - * - * const editedAST = visit(ast, { - * enter(node, key, parent, path, ancestors) { - * // @return - * // undefined: no action - * // false: skip visiting this node - * // visitor.BREAK: stop visiting altogether - * // null: delete this node - * // any value: replace this node with the returned value - * }, - * leave(node, key, parent, path, ancestors) { - * // @return - * // undefined: no action - * // false: no action - * // visitor.BREAK: stop visiting altogether - * // null: delete this node - * // any value: replace this node with the returned value - * } - * }); - * - * Alternatively to providing enter() and leave() functions, a visitor can - * instead provide functions named the same as the kinds of AST nodes, or - * enter/leave visitors at a named key, leading to four permutations of the - * visitor API: - * - * 1) Named visitors triggered when entering a node of a specific kind. - * - * visit(ast, { - * Kind(node) { - * // enter the "Kind" node - * } - * }) - * - * 2) Named visitors that trigger upon entering and leaving a node of - * a specific kind. - * - * visit(ast, { - * Kind: { - * enter(node) { - * // enter the "Kind" node - * } - * leave(node) { - * // leave the "Kind" node - * } - * } - * }) - * - * 3) Generic visitors that trigger upon entering and leaving any node. - * - * visit(ast, { - * enter(node) { - * // enter any node - * }, - * leave(node) { - * // leave any node - * } - * }) - * - * 4) Parallel visitors for entering and leaving nodes of a specific kind. - * - * visit(ast, { - * enter: { - * Kind(node) { - * // enter the "Kind" node - * } - * }, - * leave: { - * Kind(node) { - * // leave the "Kind" node - * } - * } - * }) - */ -export function visit( - root: ASTNode, - visitor: Visitor, - visitorKeys: VisitorKeyMap = QueryDocumentKeys, -): any { - /* eslint-disable no-undef-init */ - let stack: any = undefined; - let inArray = Array.isArray(root); - let keys: any = [root]; - let index = -1; - let edits = []; - let node: any = undefined; - let key: any = undefined; - let parent: any = undefined; - const path: any = []; - const ancestors = []; - let newRoot = root; - /* eslint-enable no-undef-init */ - - do { - index++; - const isLeaving = index === keys.length; - const isEdited = isLeaving && edits.length !== 0; - if (isLeaving) { - key = ancestors.length === 0 ? undefined : path[path.length - 1]; - node = parent; - parent = ancestors.pop(); - if (isEdited) { - if (inArray) { - node = node.slice(); - } else { - const clone = {}; - for (const k of Object.keys(node)) { - clone[k] = node[k]; - } - node = clone; - } - let editOffset = 0; - for (let ii = 0; ii < edits.length; ii++) { - let editKey: any = edits[ii][0]; - const editValue = edits[ii][1]; - if (inArray) { - editKey -= editOffset; - } - if (inArray && editValue === null) { - node.splice(editKey, 1); - editOffset++; - } else { - node[editKey] = editValue; - } - } - } - index = stack.index; - keys = stack.keys; - edits = stack.edits; - inArray = stack.inArray; - stack = stack.prev; - } else { - key = parent ? (inArray ? index : keys[index]) : undefined; - node = parent ? parent[key] : newRoot; - if (node === null || node === undefined) { - continue; - } - if (parent) { - path.push(key); - } - } - - let result; - if (!Array.isArray(node)) { - if (!isNode(node)) { - throw new Error(`Invalid AST Node: ${inspect(node)}.`); - } - const visitFn = getVisitFn(visitor, node.kind, isLeaving); - if (visitFn) { - result = visitFn.call(visitor, node, key, parent, path, ancestors); - - if (result === BREAK) { - break; - } - - if (result === false) { - if (!isLeaving) { - path.pop(); - continue; - } - } else if (result !== undefined) { - edits.push([key, result]); - if (!isLeaving) { - if (isNode(result)) { - node = result; - } else { - path.pop(); - continue; - } - } - } - } - } - - if (result === undefined && isEdited) { - edits.push([key, node]); - } - - if (isLeaving) { - path.pop(); - } else { - stack = { inArray, index, keys, edits, prev: stack }; - inArray = Array.isArray(node); - keys = inArray ? node : visitorKeys[node.kind] ?? []; - index = -1; - edits = []; - if (parent) { - ancestors.push(parent); - } - parent = node; - } - } while (stack !== undefined); - - if (edits.length !== 0) { - newRoot = edits[edits.length - 1][1]; - } - - return newRoot; -} - -/** - * Creates a new visitor instance which delegates to many visitors to run in - * parallel. Each visitor will be visited for each node before moving on. - * - * If a prior visitor edits a node, no following visitors will see that node. - */ -export function visitInParallel( - visitors: $ReadOnlyArray>, -): Visitor { - const skipping = new Array(visitors.length); - - return { - enter(node) { - for (let i = 0; i < visitors.length; i++) { - if (skipping[i] == null) { - const fn = getVisitFn(visitors[i], node.kind, /* isLeaving */ false); - if (fn) { - const result = fn.apply(visitors[i], arguments); - if (result === false) { - skipping[i] = node; - } else if (result === BREAK) { - skipping[i] = BREAK; - } else if (result !== undefined) { - return result; - } - } - } - } - }, - leave(node) { - for (let i = 0; i < visitors.length; i++) { - if (skipping[i] == null) { - const fn = getVisitFn(visitors[i], node.kind, /* isLeaving */ true); - if (fn) { - const result = fn.apply(visitors[i], arguments); - if (result === BREAK) { - skipping[i] = BREAK; - } else if (result !== undefined && result !== false) { - return result; - } - } - } else if (skipping[i] === node) { - skipping[i] = null; - } - } - }, - }; -} - -/** - * Given a visitor instance, if it is leaving or not, and a node kind, return - * the function the visitor runtime should call. - */ -export function getVisitFn( - visitor: Visitor, - kind: string, - isLeaving: boolean, -): ?VisitFn { - const kindVisitor = visitor[kind]; - if (kindVisitor) { - if (!isLeaving && typeof kindVisitor === 'function') { - // { Kind() {} } - return kindVisitor; - } - const kindSpecificVisitor = isLeaving - ? kindVisitor.leave - : kindVisitor.enter; - if (typeof kindSpecificVisitor === 'function') { - // { Kind: { enter() {}, leave() {} } } - return kindSpecificVisitor; - } - } else { - const specificVisitor = isLeaving ? visitor.leave : visitor.enter; - if (specificVisitor) { - if (typeof specificVisitor === 'function') { - // { enter() {}, leave() {} } - return specificVisitor; - } - const specificKindVisitor = specificVisitor[kind]; - if (typeof specificKindVisitor === 'function') { - // { enter: { Kind() {} }, leave: { Kind() {} } } - return specificKindVisitor; - } - } - } -} diff --git a/src/language/visitor.ts b/src/language/visitor.ts new file mode 100644 index 0000000000..daf96497bf --- /dev/null +++ b/src/language/visitor.ts @@ -0,0 +1,412 @@ +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; + +import type { ASTNode } from './ast'; +import { isNode, QueryDocumentKeys } from './ast'; +import { Kind } from './kinds'; + +/** + * A visitor is provided to visit, it contains the collection of + * relevant functions to be called during the visitor's traversal. + */ +export type ASTVisitor = EnterLeaveVisitor | KindVisitor; + +type KindVisitor = { + readonly [NodeT in ASTNode as NodeT['kind']]?: + | ASTVisitFn + | EnterLeaveVisitor; +}; + +interface EnterLeaveVisitor { + readonly enter?: ASTVisitFn; + readonly leave?: ASTVisitFn; +} + +/** + * A visitor is comprised of visit functions, which are called on each node + * during the visitor's traversal. + */ +export type ASTVisitFn = ( + /** The current node being visiting. */ + node: TVisitedNode, + /** The index or key to this node from the parent node or Array. */ + key: string | number | undefined, + /** The parent immediately above this node, which may be an Array. */ + parent: ASTNode | ReadonlyArray | undefined, + /** The key path to get to this node from the root node. */ + path: ReadonlyArray, + /** + * All nodes and Arrays visited before reaching parent of this node. + * These correspond to array indices in `path`. + * Note: ancestors includes arrays which contain the parent of visited node. + */ + ancestors: ReadonlyArray>, +) => any; + +/** + * A reducer is comprised of reducer functions which convert AST nodes into + * another form. + */ +export type ASTReducer = { + readonly [NodeT in ASTNode as NodeT['kind']]?: { + readonly enter?: ASTVisitFn; + readonly leave: ASTReducerFn; + }; +}; + +type ASTReducerFn = ( + /** The current node being visiting. */ + node: { [K in keyof TReducedNode]: ReducedField }, + /** The index or key to this node from the parent node or Array. */ + key: string | number | undefined, + /** The parent immediately above this node, which may be an Array. */ + parent: ASTNode | ReadonlyArray | undefined, + /** The key path to get to this node from the root node. */ + path: ReadonlyArray, + /** + * All nodes and Arrays visited before reaching parent of this node. + * These correspond to array indices in `path`. + * Note: ancestors includes arrays which contain the parent of visited node. + */ + ancestors: ReadonlyArray>, +) => R; + +type ReducedField = T extends null | undefined + ? T + : T extends ReadonlyArray + ? ReadonlyArray + : R; + +/** + * A KeyMap describes each the traversable properties of each kind of node. + * + * @deprecated Please inline it. Will be removed in v17 + */ +export type ASTVisitorKeyMap = { + [NodeT in ASTNode as NodeT['kind']]?: ReadonlyArray; +}; + +export const BREAK: unknown = Object.freeze({}); + +/** + * visit() will walk through an AST using a depth-first traversal, calling + * the visitor's enter function at each node in the traversal, and calling the + * leave function after visiting that node and all of its child nodes. + * + * By returning different values from the enter and leave functions, the + * behavior of the visitor can be altered, including skipping over a sub-tree of + * the AST (by returning false), editing the AST by returning a value or null + * to remove the value, or to stop the whole traversal by returning BREAK. + * + * When using visit() to edit an AST, the original AST will not be modified, and + * a new version of the AST with the changes applied will be returned from the + * visit function. + * + * ```ts + * const editedAST = visit(ast, { + * enter(node, key, parent, path, ancestors) { + * // @return + * // undefined: no action + * // false: skip visiting this node + * // visitor.BREAK: stop visiting altogether + * // null: delete this node + * // any value: replace this node with the returned value + * }, + * leave(node, key, parent, path, ancestors) { + * // @return + * // undefined: no action + * // false: no action + * // visitor.BREAK: stop visiting altogether + * // null: delete this node + * // any value: replace this node with the returned value + * } + * }); + * ``` + * + * Alternatively to providing enter() and leave() functions, a visitor can + * instead provide functions named the same as the kinds of AST nodes, or + * enter/leave visitors at a named key, leading to three permutations of the + * visitor API: + * + * 1) Named visitors triggered when entering a node of a specific kind. + * + * ```ts + * visit(ast, { + * Kind(node) { + * // enter the "Kind" node + * } + * }) + * ``` + * + * 2) Named visitors that trigger upon entering and leaving a node of a specific kind. + * + * ```ts + * visit(ast, { + * Kind: { + * enter(node) { + * // enter the "Kind" node + * } + * leave(node) { + * // leave the "Kind" node + * } + * } + * }) + * ``` + * + * 3) Generic visitors that trigger upon entering and leaving any node. + * + * ```ts + * visit(ast, { + * enter(node) { + * // enter any node + * }, + * leave(node) { + * // leave any node + * } + * }) + * ``` + */ +export function visit( + root: N, + visitor: ASTVisitor, + visitorKeys?: ASTVisitorKeyMap, +): N; +export function visit( + root: ASTNode, + visitor: ASTReducer, + visitorKeys?: ASTVisitorKeyMap, +): R; +export function visit( + root: ASTNode, + visitor: ASTVisitor | ASTReducer, + visitorKeys: ASTVisitorKeyMap = QueryDocumentKeys, +): any { + const enterLeaveMap = new Map>(); + for (const kind of Object.values(Kind)) { + enterLeaveMap.set(kind, getEnterLeaveForKind(visitor, kind)); + } + + /* eslint-disable no-undef-init */ + let stack: any = undefined; + let inArray = Array.isArray(root); + let keys: any = [root]; + let index = -1; + let edits = []; + let node: any = root; + let key: any = undefined; + let parent: any = undefined; + const path: any = []; + const ancestors = []; + /* eslint-enable no-undef-init */ + + do { + index++; + const isLeaving = index === keys.length; + const isEdited = isLeaving && edits.length !== 0; + if (isLeaving) { + key = ancestors.length === 0 ? undefined : path[path.length - 1]; + node = parent; + parent = ancestors.pop(); + if (isEdited) { + if (inArray) { + node = node.slice(); + + let editOffset = 0; + for (const [editKey, editValue] of edits) { + const arrayKey = editKey - editOffset; + if (editValue === null) { + node.splice(arrayKey, 1); + editOffset++; + } else { + node[arrayKey] = editValue; + } + } + } else { + node = Object.defineProperties( + {}, + Object.getOwnPropertyDescriptors(node), + ); + for (const [editKey, editValue] of edits) { + node[editKey] = editValue; + } + } + } + index = stack.index; + keys = stack.keys; + edits = stack.edits; + inArray = stack.inArray; + stack = stack.prev; + } else if (parent) { + key = inArray ? index : keys[index]; + node = parent[key]; + if (node === null || node === undefined) { + continue; + } + path.push(key); + } + + let result; + if (!Array.isArray(node)) { + devAssert(isNode(node), `Invalid AST Node: ${inspect(node)}.`); + + const visitFn = isLeaving + ? enterLeaveMap.get(node.kind)?.leave + : enterLeaveMap.get(node.kind)?.enter; + + result = visitFn?.call(visitor, node, key, parent, path, ancestors); + + if (result === BREAK) { + break; + } + + if (result === false) { + if (!isLeaving) { + path.pop(); + continue; + } + } else if (result !== undefined) { + edits.push([key, result]); + if (!isLeaving) { + if (isNode(result)) { + node = result; + } else { + path.pop(); + continue; + } + } + } + } + + if (result === undefined && isEdited) { + edits.push([key, node]); + } + + if (isLeaving) { + path.pop(); + } else { + stack = { inArray, index, keys, edits, prev: stack }; + inArray = Array.isArray(node); + keys = inArray ? node : (visitorKeys as any)[node.kind] ?? []; + index = -1; + edits = []; + if (parent) { + ancestors.push(parent); + } + parent = node; + } + } while (stack !== undefined); + + if (edits.length !== 0) { + // New root + return edits[edits.length - 1][1]; + } + + return root; +} + +/** + * Creates a new visitor instance which delegates to many visitors to run in + * parallel. Each visitor will be visited for each node before moving on. + * + * If a prior visitor edits a node, no following visitors will see that node. + */ +export function visitInParallel( + visitors: ReadonlyArray, +): ASTVisitor { + const skipping = new Array(visitors.length).fill(null); + const mergedVisitor = Object.create(null); + + for (const kind of Object.values(Kind)) { + let hasVisitor = false; + const enterList = new Array(visitors.length).fill(undefined); + const leaveList = new Array(visitors.length).fill(undefined); + + for (let i = 0; i < visitors.length; ++i) { + const { enter, leave } = getEnterLeaveForKind(visitors[i], kind); + hasVisitor ||= enter != null || leave != null; + enterList[i] = enter; + leaveList[i] = leave; + } + + if (!hasVisitor) { + continue; + } + + const mergedEnterLeave: EnterLeaveVisitor = { + enter(...args) { + const node = args[0]; + for (let i = 0; i < visitors.length; i++) { + if (skipping[i] === null) { + const result = enterList[i]?.apply(visitors[i], args); + if (result === false) { + skipping[i] = node; + } else if (result === BREAK) { + skipping[i] = BREAK; + } else if (result !== undefined) { + return result; + } + } + } + }, + leave(...args) { + const node = args[0]; + for (let i = 0; i < visitors.length; i++) { + if (skipping[i] === null) { + const result = leaveList[i]?.apply(visitors[i], args); + if (result === BREAK) { + skipping[i] = BREAK; + } else if (result !== undefined && result !== false) { + return result; + } + } else if (skipping[i] === node) { + skipping[i] = null; + } + } + }, + }; + + mergedVisitor[kind] = mergedEnterLeave; + } + + return mergedVisitor; +} + +/** + * Given a visitor instance and a node kind, return EnterLeaveVisitor for that kind. + */ +export function getEnterLeaveForKind( + visitor: ASTVisitor, + kind: Kind, +): EnterLeaveVisitor { + const kindVisitor: + | ASTVisitFn + | EnterLeaveVisitor + | undefined = (visitor as any)[kind]; + + if (typeof kindVisitor === 'object') { + // { Kind: { enter() {}, leave() {} } } + return kindVisitor; + } else if (typeof kindVisitor === 'function') { + // { Kind() {} } + return { enter: kindVisitor, leave: undefined }; + } + + // { enter() {}, leave() {} } + return { enter: (visitor as any).enter, leave: (visitor as any).leave }; +} + +/** + * Given a visitor instance, if it is leaving or not, and a node kind, return + * the function the visitor runtime should call. + * + * @deprecated Please use `getEnterLeaveForKind` instead. Will be removed in v17 + */ +/* c8 ignore next 8 */ +export function getVisitFn( + visitor: ASTVisitor, + kind: Kind, + isLeaving: boolean, +): ASTVisitFn | undefined { + const { enter, leave } = getEnterLeaveForKind(visitor, kind); + return isLeaving ? leave : enter; +} diff --git a/src/polyfills/README.md b/src/polyfills/README.md deleted file mode 100644 index 20c9f6ee58..0000000000 --- a/src/polyfills/README.md +++ /dev/null @@ -1,8 +0,0 @@ -## Polyfills - -This directory contains dependency-free polyfills for ES6 & ES7 functions used -throughout the codebase. - -Each polyfill should belong in its own file and be the default export. - -These functions are not part of the module interface and are subject to change. diff --git a/src/polyfills/arrayFrom.js b/src/polyfills/arrayFrom.js deleted file mode 100644 index 2d153c56da..0000000000 --- a/src/polyfills/arrayFrom.js +++ /dev/null @@ -1,57 +0,0 @@ -import { SYMBOL_ITERATOR } from './symbols'; - -declare function arrayFrom(arrayLike: Iterable): Array; -// eslint-disable-next-line no-redeclare -declare function arrayFrom( - arrayLike: mixed, - mapFn?: (elem: mixed, index: number) => T, - thisArg?: mixed, -): Array; - -/* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] -const arrayFrom = - Array.from || - function (obj, mapFn, thisArg) { - if (obj == null) { - throw new TypeError( - 'Array.from requires an array-like object - not null or undefined', - ); - } - - // Is Iterable? - const iteratorMethod = obj[SYMBOL_ITERATOR]; - if (typeof iteratorMethod === 'function') { - const iterator = iteratorMethod.call(obj); - const result = []; - let step; - - for (let i = 0; !(step = iterator.next()).done; ++i) { - result.push(mapFn.call(thisArg, step.value, i)); - // Infinite Iterators could cause forEach to run forever. - // After a very large number of iterations, produce an error. - // istanbul ignore if (Too big to actually test) - if (i > 9999999) { - throw new TypeError('Near-infinite iteration.'); - } - } - return result; - } - - // Is Array like? - const length = obj.length; - if (typeof length === 'number' && length >= 0 && length % 1 === 0) { - const result = []; - - for (let i = 0; i < length; ++i) { - if (Object.prototype.hasOwnProperty.call(obj, i)) { - result.push(mapFn.call(thisArg, obj[i], i)); - } - } - return result; - } - - return []; - }; - -export default arrayFrom; diff --git a/src/polyfills/find.js b/src/polyfills/find.js deleted file mode 100644 index 403ba0f2b7..0000000000 --- a/src/polyfills/find.js +++ /dev/null @@ -1,19 +0,0 @@ -declare function find( - list: $ReadOnlyArray, - predicate: (item: T) => boolean, -): T | void; - -/* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] -const find = Array.prototype.find - ? function (list, predicate) { - return Array.prototype.find.call(list, predicate); - } - : function (list, predicate) { - for (const value of list) { - if (predicate(value)) { - return value; - } - } - }; -export default find; diff --git a/src/polyfills/isFinite.js b/src/polyfills/isFinite.js deleted file mode 100644 index 58f8614b9f..0000000000 --- a/src/polyfills/isFinite.js +++ /dev/null @@ -1,12 +0,0 @@ -declare function isFinitePolyfill( - value: mixed, -): boolean %checks(typeof value === 'number'); - -/* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 -const isFinitePolyfill = - Number.isFinite || - function (value) { - return typeof value === 'number' && isFinite(value); - }; -export default isFinitePolyfill; diff --git a/src/polyfills/isInteger.js b/src/polyfills/isInteger.js deleted file mode 100644 index fdd50ff247..0000000000 --- a/src/polyfills/isInteger.js +++ /dev/null @@ -1,15 +0,0 @@ -declare function isInteger(value: mixed): boolean %checks(typeof value === - 'number'); - -/* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 -const isInteger = - Number.isInteger || - function (value) { - return ( - typeof value === 'number' && - isFinite(value) && - Math.floor(value) === value - ); - }; -export default isInteger; diff --git a/src/polyfills/objectEntries.js b/src/polyfills/objectEntries.js deleted file mode 100644 index 30e5585272..0000000000 --- a/src/polyfills/objectEntries.js +++ /dev/null @@ -1,10 +0,0 @@ -import type { ObjMap } from '../jsutils/ObjMap'; - -declare function objectEntries(obj: ObjMap): Array<[string, T]>; - -/* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 -const objectEntries = - Object.entries || ((obj) => Object.keys(obj).map((key) => [key, obj[key]])); - -export default objectEntries; diff --git a/src/polyfills/objectValues.js b/src/polyfills/objectValues.js deleted file mode 100644 index 943362a640..0000000000 --- a/src/polyfills/objectValues.js +++ /dev/null @@ -1,9 +0,0 @@ -import type { ObjMap } from '../jsutils/ObjMap'; - -declare function objectValues(obj: ObjMap): Array; - -/* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 -const objectValues = - Object.values || ((obj) => Object.keys(obj).map((key) => obj[key])); -export default objectValues; diff --git a/src/polyfills/symbols.js b/src/polyfills/symbols.js deleted file mode 100644 index e13d8b4f3a..0000000000 --- a/src/polyfills/symbols.js +++ /dev/null @@ -1,19 +0,0 @@ -// In ES2015 (or a polyfilled) environment, this will be Symbol.iterator -// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') -export const SYMBOL_ITERATOR: string = - typeof Symbol === 'function' && Symbol.iterator != null - ? Symbol.iterator - : '@@iterator'; - -// In ES2017 (or a polyfilled) environment, this will be Symbol.asyncIterator -// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') -export const SYMBOL_ASYNC_ITERATOR: string = - typeof Symbol === 'function' && Symbol.asyncIterator != null - ? Symbol.asyncIterator - : '@@asyncIterator'; - -// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') -export const SYMBOL_TO_STRING_TAG: string = - typeof Symbol === 'function' && Symbol.toStringTag != null - ? Symbol.toStringTag - : '@@toStringTag'; diff --git a/src/subscription/README.md b/src/subscription/README.md index c938354c2b..7e099d2cfc 100644 --- a/src/subscription/README.md +++ b/src/subscription/README.md @@ -1,5 +1,7 @@ ## GraphQL Subscription +NOTE: the `graphql/subscription` module has been deprecated with its exported functions integrated into the `graphql/execution` module, to better conform with the terminology of the GraphQL specification. For backwards compatibility, the `graphql/subscription` module currently re-exports the moved functions from the `graphql/execution` module. In the next major release, the `graphql/subscription` module will be dropped entirely. + The `graphql/subscription` module is responsible for subscribing to updates on specific data. ```js diff --git a/src/subscription/index.d.ts b/src/subscription/index.d.ts deleted file mode 100644 index ba8835f196..0000000000 --- a/src/subscription/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - subscribe, - createSourceEventStream, - SubscriptionArgs, -} from './subscribe'; diff --git a/src/subscription/index.js b/src/subscription/index.js deleted file mode 100644 index 899e443b6b..0000000000 --- a/src/subscription/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { subscribe, createSourceEventStream } from './subscribe'; -export type { SubscriptionArgs } from './subscribe'; diff --git a/src/subscription/index.ts b/src/subscription/index.ts new file mode 100644 index 0000000000..9de1b86968 --- /dev/null +++ b/src/subscription/index.ts @@ -0,0 +1,23 @@ +/** + * NOTE: the `graphql/subscription` module has been deprecated with its + * exported functions integrated into the `graphql/execution` module, to + * better conform with the terminology of the GraphQL specification. + * + * For backwards compatibility, the `graphql/subscription` module + * currently re-exports the moved functions from the `graphql/execution` + * module. In the next major release, the `graphql/subscription` module + * will be dropped entirely. + */ + +import type { ExecutionArgs } from '../execution/execute'; + +/** + * @deprecated use ExecutionArgs instead. Will be removed in v17 + * + * ExecutionArgs has been broadened to include all properties within SubscriptionArgs. + * The SubscriptionArgs type is retained for backwards compatibility. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SubscriptionArgs extends ExecutionArgs {} + +export { subscribe, createSourceEventStream } from '../execution/subscribe'; diff --git a/src/subscription/mapAsyncIterator.d.ts b/src/subscription/mapAsyncIterator.d.ts deleted file mode 100644 index 22e8a34ace..0000000000 --- a/src/subscription/mapAsyncIterator.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { PromiseOrValue } from '../jsutils/PromiseOrValue'; - -/** - * Given an AsyncIterable and a callback function, return an AsyncIterator - * which produces values mapped via calling the callback function. - */ -export default function mapAsyncIterator( - iterable: AsyncIterable, - callback: (arg: T) => PromiseOrValue, - rejectCallback?: (arg: any) => PromiseOrValue, -): any; // TS_SPECIFIC: AsyncGenerator requires typescript@3.6 diff --git a/src/subscription/mapAsyncIterator.js b/src/subscription/mapAsyncIterator.js deleted file mode 100644 index 8ab691d391..0000000000 --- a/src/subscription/mapAsyncIterator.js +++ /dev/null @@ -1,73 +0,0 @@ -import { SYMBOL_ASYNC_ITERATOR } from '../polyfills/symbols'; - -import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; - -/** - * Given an AsyncIterable and a callback function, return an AsyncIterator - * which produces values mapped via calling the callback function. - */ -export default function mapAsyncIterator( - iterable: AsyncIterable | AsyncGenerator, - callback: (T) => PromiseOrValue, - rejectCallback?: (any) => PromiseOrValue, -): AsyncGenerator { - // $FlowFixMe[prop-missing] - const iteratorMethod = iterable[SYMBOL_ASYNC_ITERATOR]; - const iterator: any = iteratorMethod.call(iterable); - let $return: any; - let abruptClose; - if (typeof iterator.return === 'function') { - $return = iterator.return; - abruptClose = (error: mixed) => { - const rethrow = () => Promise.reject(error); - return $return.call(iterator).then(rethrow, rethrow); - }; - } - - function mapResult(result: IteratorResult) { - return result.done - ? result - : asyncMapValue(result.value, callback).then(iteratorResult, abruptClose); - } - - let mapReject; - if (rejectCallback) { - // Capture rejectCallback to ensure it cannot be null. - const reject = rejectCallback; - mapReject = (error: mixed) => - asyncMapValue(error, reject).then(iteratorResult, abruptClose); - } - - /* TODO: Flow doesn't support symbols as keys: - https://github.com/facebook/flow/issues/3258 */ - return ({ - next(): Promise> { - return iterator.next().then(mapResult, mapReject); - }, - return() { - return $return - ? $return.call(iterator).then(mapResult, mapReject) - : Promise.resolve({ value: undefined, done: true }); - }, - throw(error?: mixed): Promise> { - if (typeof iterator.throw === 'function') { - return iterator.throw(error).then(mapResult, mapReject); - } - return Promise.reject(error).catch(abruptClose); - }, - [SYMBOL_ASYNC_ITERATOR]() { - return this; - }, - }: $FlowFixMe); -} - -function asyncMapValue( - value: T, - callback: (T) => PromiseOrValue, -): Promise { - return new Promise((resolve) => resolve(callback(value))); -} - -function iteratorResult(value: T): IteratorResult { - return { value, done: false }; -} diff --git a/src/subscription/subscribe.d.ts b/src/subscription/subscribe.d.ts deleted file mode 100644 index 3ed750a328..0000000000 --- a/src/subscription/subscribe.d.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { DocumentNode } from '../language/ast'; -import { ExecutionResult } from '../execution/execute'; -import { GraphQLSchema } from '../type/schema'; -import { GraphQLFieldResolver } from '../type/definition'; - -export interface SubscriptionArgs { - schema: GraphQLSchema; - document: DocumentNode; - rootValue?: any; - contextValue?: any; - variableValues?: Maybe>; - operationName?: Maybe; - fieldResolver?: Maybe>; - subscribeFieldResolver?: Maybe>; -} - -/** - * Implements the "Subscribe" algorithm described in the GraphQL specification. - * - * Returns a Promise which resolves to either an AsyncIterator (if successful) - * or an ExecutionResult (client error). The promise will be rejected if a - * server error occurs. - * - * If the client-provided arguments to this function do not result in a - * compliant subscription, a GraphQL Response (ExecutionResult) with - * descriptive errors and no data will be returned. - * - * If the the source stream could not be created due to faulty subscription - * resolver logic or underlying systems, the promise will resolve to a single - * ExecutionResult containing `errors` and no `data`. - * - * If the operation succeeded, the promise resolves to an AsyncIterator, which - * yields a stream of ExecutionResults representing the response stream. - * - * Accepts either an object with named arguments, or individual arguments. - */ -export function subscribe( - args: SubscriptionArgs, -): Promise | ExecutionResult>; - -export function subscribe( - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: any, - contextValue?: any, - variableValues?: Maybe<{ [key: string]: any }>, - operationName?: Maybe, - fieldResolver?: Maybe>, - subscribeFieldResolver?: Maybe>, -): Promise | ExecutionResult>; - -/** - * Implements the "CreateSourceEventStream" algorithm described in the - * GraphQL specification, resolving the subscription source event stream. - * - * Returns a Promise. - * - * If the client-provided invalid arguments, the source stream could not be - * created, or the resolver did not return an AsyncIterable, this function will - * will throw an error, which should be caught and handled by the caller. - * - * A Source Event Stream represents a sequence of events, each of which triggers - * a GraphQL execution for that event. - * - * This may be useful when hosting the stateful subscription service in a - * different process or machine than the stateless GraphQL execution engine, - * or otherwise separating these two steps. For more on this, see the - * "Supporting Subscriptions at Scale" information in the GraphQL specification. - */ -export function createSourceEventStream( - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: any, - contextValue?: any, - variableValues?: { [key: string]: any }, - operationName?: Maybe, - fieldResolver?: Maybe>, -): Promise | ExecutionResult>; diff --git a/src/subscription/subscribe.js b/src/subscription/subscribe.js deleted file mode 100644 index 3a20d23ab1..0000000000 --- a/src/subscription/subscribe.js +++ /dev/null @@ -1,297 +0,0 @@ -import inspect from '../jsutils/inspect'; -import isAsyncIterable from '../jsutils/isAsyncIterable'; -import { addPath, pathToArray } from '../jsutils/Path'; - -import { GraphQLError } from '../error/GraphQLError'; -import { locatedError } from '../error/locatedError'; - -import type { DocumentNode } from '../language/ast'; - -import type { ExecutionResult, ExecutionContext } from '../execution/execute'; -import { getArgumentValues } from '../execution/values'; -import { - assertValidExecutionArguments, - buildExecutionContext, - buildResolveInfo, - collectFields, - execute, - getFieldDef, -} from '../execution/execute'; - -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLFieldResolver } from '../type/definition'; - -import { getOperationRootType } from '../utilities/getOperationRootType'; - -import mapAsyncIterator from './mapAsyncIterator'; - -export type SubscriptionArgs = {| - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - subscribeFieldResolver?: ?GraphQLFieldResolver, -|}; - -/** - * Implements the "Subscribe" algorithm described in the GraphQL specification. - * - * Returns a Promise which resolves to either an AsyncIterator (if successful) - * or an ExecutionResult (error). The promise will be rejected if the schema or - * other arguments to this function are invalid, or if the resolved event stream - * is not an async iterable. - * - * If the client-provided arguments to this function do not result in a - * compliant subscription, a GraphQL Response (ExecutionResult) with - * descriptive errors and no data will be returned. - * - * If the source stream could not be created due to faulty subscription - * resolver logic or underlying systems, the promise will resolve to a single - * ExecutionResult containing `errors` and no `data`. - * - * If the operation succeeded, the promise resolves to an AsyncIterator, which - * yields a stream of ExecutionResults representing the response stream. - * - * Accepts either an object with named arguments, or individual arguments. - */ -declare function subscribe( - SubscriptionArgs, - ..._: [] -): Promise | ExecutionResult>; -/* eslint-disable no-redeclare */ -declare function subscribe( - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - subscribeFieldResolver?: ?GraphQLFieldResolver, -): Promise | ExecutionResult>; -export function subscribe( - argsOrSchema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - subscribeFieldResolver, -) { - /* eslint-enable no-redeclare */ - // Extract arguments from object args if provided. - return arguments.length === 1 - ? subscribeImpl(argsOrSchema) - : subscribeImpl({ - schema: argsOrSchema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - subscribeFieldResolver, - }); -} - -/** - * This function checks if the error is a GraphQLError. If it is, report it as - * an ExecutionResult, containing only errors and no data. Otherwise treat the - * error as a system-class error and re-throw it. - */ -function reportGraphQLError(error: mixed): ExecutionResult { - if (error instanceof GraphQLError) { - return { errors: [error] }; - } - throw error; -} - -function subscribeImpl( - args: SubscriptionArgs, -): Promise | ExecutionResult> { - const { - schema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - subscribeFieldResolver, - } = args; - - const sourcePromise = createSourceEventStream( - schema, - document, - rootValue, - contextValue, - variableValues, - operationName, - subscribeFieldResolver, - ); - - // For each payload yielded from a subscription, map it over the normal - // GraphQL `execute` function, with `payload` as the rootValue. - // This implements the "MapSourceToResponseEvent" algorithm described in - // the GraphQL specification. The `execute` function provides the - // "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the - // "ExecuteQuery" algorithm, for which `execute` is also used. - const mapSourceToResponse = (payload) => - execute({ - schema, - document, - rootValue: payload, - contextValue, - variableValues, - operationName, - fieldResolver, - }); - - // Resolve the Source Stream, then map every source value to a - // ExecutionResult value as described above. - return sourcePromise.then((resultOrStream) => - // Note: Flow can't refine isAsyncIterable, so explicit casts are used. - isAsyncIterable(resultOrStream) - ? mapAsyncIterator( - resultOrStream, - mapSourceToResponse, - reportGraphQLError, - ) - : ((resultOrStream: any): ExecutionResult), - ); -} - -/** - * Implements the "CreateSourceEventStream" algorithm described in the - * GraphQL specification, resolving the subscription source event stream. - * - * Returns a Promise which resolves to either an AsyncIterable (if successful) - * or an ExecutionResult (error). The promise will be rejected if the schema or - * other arguments to this function are invalid, or if the resolved event stream - * is not an async iterable. - * - * If the client-provided arguments to this function do not result in a - * compliant subscription, a GraphQL Response (ExecutionResult) with - * descriptive errors and no data will be returned. - * - * If the the source stream could not be created due to faulty subscription - * resolver logic or underlying systems, the promise will resolve to a single - * ExecutionResult containing `errors` and no `data`. - * - * If the operation succeeded, the promise resolves to the AsyncIterable for the - * event stream returned by the resolver. - * - * A Source Event Stream represents a sequence of events, each of which triggers - * a GraphQL execution for that event. - * - * This may be useful when hosting the stateful subscription service in a - * different process or machine than the stateless GraphQL execution engine, - * or otherwise separating these two steps. For more on this, see the - * "Supporting Subscriptions at Scale" information in the GraphQL specification. - */ -export function createSourceEventStream( - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, -): Promise | ExecutionResult> { - // If arguments are missing or incorrectly typed, this is an internal - // developer mistake which should throw an early error. - assertValidExecutionArguments(schema, document, variableValues); - - return new Promise((resolve) => { - // If a valid context cannot be created due to incorrect arguments, - // this will throw an error. - const exeContext = buildExecutionContext( - schema, - document, - rootValue, - contextValue, - variableValues, - operationName, - fieldResolver, - ); - - resolve( - // Return early errors if execution context failed. - Array.isArray(exeContext) - ? { errors: exeContext } - : executeSubscription(exeContext), - ); - }).catch(reportGraphQLError); -} - -function executeSubscription( - exeContext: ExecutionContext, -): Promise> { - const { schema, operation, variableValues, rootValue } = exeContext; - const type = getOperationRootType(schema, operation); - const fields = collectFields( - exeContext, - type, - operation.selectionSet, - Object.create(null), - Object.create(null), - ); - const responseNames = Object.keys(fields); - const responseName = responseNames[0]; - const fieldNodes = fields[responseName]; - const fieldNode = fieldNodes[0]; - const fieldName = fieldNode.name.value; - const fieldDef = getFieldDef(schema, type, fieldName); - - if (!fieldDef) { - throw new GraphQLError( - `The subscription field "${fieldName}" is not defined.`, - fieldNodes, - ); - } - - const path = addPath(undefined, responseName, type.name); - const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, type, path); - - // Coerce to Promise for easier error handling and consistent return type. - return new Promise((resolveResult) => { - // Implements the "ResolveFieldEventStream" algorithm from GraphQL specification. - // It differs from "ResolveFieldValue" due to providing a different `resolveFn`. - - // Build a JS object of arguments from the field.arguments AST, using the - // variables scope to fulfill any variable references. - const args = getArgumentValues(fieldDef, fieldNodes[0], variableValues); - - // The resolve function's optional third argument is a context value that - // is provided to every resolve function within an execution. It is commonly - // used to represent an authenticated user, or request-specific caches. - const contextValue = exeContext.contextValue; - - // Call the `subscribe()` resolver or the default resolver to produce an - // AsyncIterable yielding raw payloads. - const resolveFn = fieldDef.subscribe ?? exeContext.fieldResolver; - resolveResult(resolveFn(rootValue, args, contextValue, info)); - }).then( - (eventStream) => { - if (eventStream instanceof Error) { - throw locatedError(eventStream, fieldNodes, pathToArray(path)); - } - - // Assert field returned an event stream, otherwise yield an error. - if (!isAsyncIterable(eventStream)) { - throw new Error( - 'Subscription field must return Async Iterable. ' + - `Received: ${inspect(eventStream)}.`, - ); - } - return eventStream; - }, - (error) => { - throw locatedError(error, fieldNodes, pathToArray(path)); - }, - ); -} diff --git a/src/type/__tests__/assertName-test.ts b/src/type/__tests__/assertName-test.ts new file mode 100644 index 0000000000..268b1c6ecb --- /dev/null +++ b/src/type/__tests__/assertName-test.ts @@ -0,0 +1,69 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { assertEnumValueName, assertName } from '../assertName'; + +describe('assertName', () => { + it('passthrough valid name', () => { + expect(assertName('_ValidName123')).to.equal('_ValidName123'); + }); + + it('throws for non-strings', () => { + // @ts-expect-error + expect(() => assertName({})).to.throw('Expected name to be a string.'); + }); + + it('throws on empty strings', () => { + expect(() => assertName('')).to.throw( + 'Expected name to be a non-empty string.', + ); + }); + + it('throws for names with invalid characters', () => { + expect(() => assertName('>--()-->')).to.throw( + 'Names must only contain [_a-zA-Z0-9] but ">--()-->" does not.', + ); + }); + + it('throws for names starting with invalid characters', () => { + expect(() => assertName('42MeaningsOfLife')).to.throw( + 'Names must start with [_a-zA-Z] but "42MeaningsOfLife" does not.', + ); + }); +}); + +describe('assertEnumValueName', () => { + it('passthrough valid name', () => { + expect(assertEnumValueName('_ValidName123')).to.equal('_ValidName123'); + }); + + it('throws on empty strings', () => { + expect(() => assertEnumValueName('')).to.throw( + 'Expected name to be a non-empty string.', + ); + }); + + it('throws for names with invalid characters', () => { + expect(() => assertEnumValueName('>--()-->')).to.throw( + 'Names must only contain [_a-zA-Z0-9] but ">--()-->" does not.', + ); + }); + + it('throws for names starting with invalid characters', () => { + expect(() => assertEnumValueName('42MeaningsOfLife')).to.throw( + 'Names must start with [_a-zA-Z] but "42MeaningsOfLife" does not.', + ); + }); + + it('throws for restricted names', () => { + expect(() => assertEnumValueName('true')).to.throw( + 'Enum values cannot be named: true', + ); + expect(() => assertEnumValueName('false')).to.throw( + 'Enum values cannot be named: false', + ); + expect(() => assertEnumValueName('null')).to.throw( + 'Enum values cannot be named: null', + ); + }); +}); diff --git a/src/type/__tests__/definition-test.js b/src/type/__tests__/definition-test.ts similarity index 83% rename from src/type/__tests__/definition-test.js rename to src/type/__tests__/definition-test.ts index d63bc922aa..19d482915a 100644 --- a/src/type/__tests__/definition-test.js +++ b/src/type/__tests__/definition-test.ts @@ -1,21 +1,21 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import inspect from '../../jsutils/inspect'; -import identityFunc from '../../jsutils/identityFunc'; +import { identityFunc } from '../../jsutils/identityFunc'; +import { inspect } from '../../jsutils/inspect'; import { parseValue } from '../../language/parser'; -import type { GraphQLType, GraphQLNullableType } from '../definition'; +import type { GraphQLNullableType, GraphQLType } from '../definition'; import { + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, - GraphQLScalarType, GraphQLObjectType, - GraphQLInterfaceType, + GraphQLScalarType, GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, } from '../definition'; const ScalarType = new GraphQLScalarType({ name: 'Scalar' }); @@ -36,22 +36,20 @@ const NonNullScalarType = new GraphQLNonNull(ScalarType); const ListOfNonNullScalarsType = new GraphQLList(NonNullScalarType); const NonNullListOfScalars = new GraphQLNonNull(ListOfScalarsType); -// istanbul ignore next (Never called and used as a placeholder) -const dummyFunc = () => { - /* empty */ -}; +/* c8 ignore next */ +const dummyFunc = () => expect.fail('Never called and used as a placeholder'); describe('Type System: Scalars', () => { it('accepts a Scalar type defining serialize', () => { expect(() => new GraphQLScalarType({ name: 'SomeScalar' })).to.not.throw(); }); - it('accepts a Scalar type defining specifiedByUrl', () => { + it('accepts a Scalar type defining specifiedByURL', () => { expect( () => new GraphQLScalarType({ name: 'SomeScalar', - specifiedByUrl: 'https://example.com/foo_spec', + specifiedByURL: 'https://example.com/foo_spec', }), ).not.to.throw(); }); @@ -95,7 +93,7 @@ describe('Type System: Scalars', () => { }); it('rejects a Scalar type without name', () => { - // $FlowExpectedError[prop-missing] + // @ts-expect-error expect(() => new GraphQLScalarType({})).to.throw('Must provide name.'); }); @@ -104,7 +102,7 @@ describe('Type System: Scalars', () => { () => new GraphQLScalarType({ name: 'SomeScalar', - // $FlowExpectedError[prop-missing] + // @ts-expect-error serialize: {}, }), ).to.throw( @@ -129,9 +127,9 @@ describe('Type System: Scalars', () => { () => new GraphQLScalarType({ name: 'SomeScalar', - // $FlowExpectedError[prop-missing] + // @ts-expect-error parseValue: {}, - // $FlowExpectedError[prop-missing] + // @ts-expect-error parseLiteral: {}, }), ).to.throw( @@ -139,16 +137,16 @@ describe('Type System: Scalars', () => { ); }); - it('rejects a Scalar type defining specifiedByUrl with an incorrect type', () => { + it('rejects a Scalar type defining specifiedByURL with an incorrect type', () => { expect( () => new GraphQLScalarType({ name: 'SomeScalar', - // $FlowExpectedError[incompatible-call] - specifiedByUrl: {}, + // @ts-expect-error + specifiedByURL: {}, }), ).to.throw( - 'SomeScalar must provide "specifiedByUrl" as a string, but got: {}.', + 'SomeScalar must provide "specifiedByURL" as a string, but got: {}.', ); }); }); @@ -225,13 +223,11 @@ describe('Type System: Objects', () => { expect(TypeWithDeprecatedField.getFields().bar).to.include({ name: 'bar', - isDeprecated: true, deprecationReason: 'A terrible reason', }); expect(TypeWithDeprecatedField.getFields().baz).to.include({ name: 'baz', - isDeprecated: true, deprecationReason: '', }); }); @@ -251,9 +247,8 @@ describe('Type System: Objects', () => { args: [], resolve: undefined, subscribe: undefined, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, }); @@ -283,15 +278,14 @@ describe('Type System: Objects', () => { type: ScalarType, defaultValue: undefined, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, ], resolve: undefined, subscribe: undefined, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, }); @@ -328,16 +322,17 @@ describe('Type System: Objects', () => { expect(() => objType.getFields()).to.not.throw(); }); - it('rejects an Object type without name', () => { - // $FlowExpectedError[prop-missing] - expect(() => new GraphQLObjectType({})).to.throw('Must provide name.'); + it('rejects an Object type with invalid name', () => { + expect( + () => new GraphQLObjectType({ name: 'bad-name', fields: {} }), + ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.'); }); it('rejects an Object type field with undefined config', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', fields: { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (must not be undefined) f: undefined, }, }); @@ -349,7 +344,7 @@ describe('Type System: Objects', () => { it('rejects an Object type with incorrectly typed fields', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', - // $FlowExpectedError[incompatible-call] + // @ts-expect-error fields: [{ field: ScalarType }], }); expect(() => objType.getFields()).to.throw( @@ -357,11 +352,23 @@ describe('Type System: Objects', () => { ); }); + it('rejects an Object type with incorrectly named fields', () => { + const objType = new GraphQLObjectType({ + name: 'SomeObject', + fields: { + 'bad-name': { type: ScalarType }, + }, + }); + expect(() => objType.getFields()).to.throw( + 'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.', + ); + }); + it('rejects an Object type with a field function that returns incorrect type', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', + // @ts-expect-error (Wrong type of return) fields() { - // $FlowExpectedError[incompatible-call] return [{ field: ScalarType }]; }, }); @@ -374,7 +381,7 @@ describe('Type System: Objects', () => { fields: { badField: { type: ScalarType, - // $FlowExpectedError[incompatible-call] + // @ts-expect-error args: [{ badArg: ScalarType }], }, }, @@ -384,17 +391,20 @@ describe('Type System: Objects', () => { ); }); - it('rejects an Object type with an isDeprecated instead of deprecationReason on field', () => { - const OldObject = new GraphQLObjectType({ - name: 'OldObject', - // $FlowExpectedError[incompatible-call] + it('rejects an Object type with incorrectly named field args', () => { + const objType = new GraphQLObjectType({ + name: 'SomeObject', fields: { - field: { type: ScalarType, isDeprecated: true }, + badField: { + type: ScalarType, + args: { + 'bad-name': { type: ScalarType }, + }, + }, }, }); - - expect(() => OldObject.getFields()).to.throw( - 'OldObject.field should provide "deprecationReason" instead of "isDeprecated".', + expect(() => objType.getFields()).to.throw( + 'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.', ); }); @@ -402,7 +412,7 @@ describe('Type System: Objects', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', fields: {}, - // $FlowExpectedError[incompatible-call] + // @ts-expect-error interfaces: {}, }); expect(() => objType.getInterfaces()).to.throw( @@ -414,8 +424,8 @@ describe('Type System: Objects', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', fields: {}, + // @ts-expect-error (Expected interfaces to return array) interfaces() { - // $FlowExpectedError[incompatible-call] return {}; }, }); @@ -427,8 +437,8 @@ describe('Type System: Objects', () => { it('rejects an empty Object field resolver', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', - // $FlowExpectedError[incompatible-call] fields: { + // @ts-expect-error (Expected resolve to be a function) field: { type: ScalarType, resolve: {} }, }, }); @@ -441,8 +451,8 @@ describe('Type System: Objects', () => { it('rejects a constant scalar value resolver', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', - // $FlowExpectedError[incompatible-call] fields: { + // @ts-expect-error (Expected resolve to be a function) field: { type: ScalarType, resolve: 0 }, }, }); @@ -458,7 +468,7 @@ describe('Type System: Objects', () => { new GraphQLObjectType({ name: 'AnotherObject', fields: {}, - // $FlowExpectedError[prop-missing] + // @ts-expect-error isTypeOf: {}, }), ).to.throw( @@ -496,16 +506,17 @@ describe('Type System: Interfaces', () => { expect(implementing.getInterfaces()).to.deep.equal([InterfaceType]); }); - it('rejects an Interface type without name', () => { - // $FlowExpectedError[prop-missing] - expect(() => new GraphQLInterfaceType({})).to.throw('Must provide name.'); + it('rejects an Interface type with invalid name', () => { + expect( + () => new GraphQLInterfaceType({ name: 'bad-name', fields: {} }), + ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.'); }); it('rejects an Interface type with incorrectly typed interfaces', () => { const objType = new GraphQLInterfaceType({ name: 'AnotherInterface', fields: {}, - // $FlowExpectedError[incompatible-call] + // @ts-expect-error interfaces: {}, }); expect(() => objType.getInterfaces()).to.throw( @@ -517,8 +528,8 @@ describe('Type System: Interfaces', () => { const objType = new GraphQLInterfaceType({ name: 'AnotherInterface', fields: {}, + // @ts-expect-error (Expected Array return) interfaces() { - // $FlowExpectedError[incompatible-call] return {}; }, }); @@ -533,7 +544,7 @@ describe('Type System: Interfaces', () => { new GraphQLInterfaceType({ name: 'AnotherInterface', fields: {}, - // $FlowExpectedError[prop-missing] + // @ts-expect-error resolveType: {}, }), ).to.throw( @@ -577,9 +588,10 @@ describe('Type System: Unions', () => { expect(unionType.getTypes()).to.deep.equal([]); }); - it('rejects an Union type without name', () => { - // $FlowExpectedError[prop-missing] - expect(() => new GraphQLUnionType({})).to.throw('Must provide name.'); + it('rejects an Union type with invalid name', () => { + expect( + () => new GraphQLUnionType({ name: 'bad-name', types: [] }), + ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.'); }); it('rejects an Union type with an incorrect type for resolveType', () => { @@ -588,7 +600,7 @@ describe('Type System: Unions', () => { new GraphQLUnionType({ name: 'SomeUnion', types: [], - // $FlowExpectedError[prop-missing] + // @ts-expect-error resolveType: {}, }), ).to.throw( @@ -599,7 +611,7 @@ describe('Type System: Unions', () => { it('rejects a Union type with incorrectly typed types', () => { const unionType = new GraphQLUnionType({ name: 'SomeUnion', - // $FlowExpectedError[incompatible-call] + // @ts-expect-error types: { ObjectType }, }); @@ -621,13 +633,11 @@ describe('Type System: Enums', () => { expect(EnumTypeWithDeprecatedValue.getValues()[0]).to.include({ name: 'foo', - isDeprecated: true, deprecationReason: 'Just because', }); expect(EnumTypeWithDeprecatedValue.getValues()[1]).to.include({ name: 'bar', - isDeprecated: true, deprecationReason: '', }); }); @@ -647,27 +657,24 @@ describe('Type System: Enums', () => { name: 'NULL', description: undefined, value: null, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, { name: 'NAN', description: undefined, value: NaN, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, { name: 'NO_CUSTOM_VALUE', description: undefined, value: 'NO_CUSTOM_VALUE', - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, ]); @@ -697,11 +704,10 @@ describe('Type System: Enums', () => { expect(enumType.getValue('BAR')).has.property('value', 20); }); - it('rejects an Enum type without name', () => { - // $FlowExpectedError[prop-missing] - expect(() => new GraphQLEnumType({ values: {} })).to.throw( - 'Must provide name.', - ); + it('rejects an Enum type with invalid name', () => { + expect( + () => new GraphQLEnumType({ name: 'bad-name', values: {} }), + ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.'); }); it('rejects an Enum type with incorrectly typed values', () => { @@ -709,50 +715,47 @@ describe('Type System: Enums', () => { () => new GraphQLEnumType({ name: 'SomeEnum', - // $FlowExpectedError[incompatible-call] + // @ts-expect-error values: [{ FOO: 10 }], }), ).to.throw('SomeEnum values must be an object with value names as keys.'); }); - it('rejects an Enum type with missing value definition', () => { + it('rejects an Enum type with incorrectly named values', () => { expect( () => new GraphQLEnumType({ name: 'SomeEnum', - // $FlowExpectedError[incompatible-call] - values: { FOO: null }, + values: { + 'bad-name': {}, + }, }), - ).to.throw( - 'SomeEnum.FOO must refer to an object with a "value" key representing an internal value but got: null.', - ); + ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.'); }); - it('rejects an Enum type with incorrectly typed value definition', () => { + it('rejects an Enum type with missing value definition', () => { expect( () => new GraphQLEnumType({ name: 'SomeEnum', - // $FlowExpectedError[incompatible-call] - values: { FOO: 10 }, + // @ts-expect-error (must not be null) + values: { FOO: null }, }), ).to.throw( - 'SomeEnum.FOO must refer to an object with a "value" key representing an internal value but got: 10.', + 'SomeEnum.FOO must refer to an object with a "value" key representing an internal value but got: null.', ); }); - it('does not allow isDeprecated instead of deprecationReason on enum', () => { + it('rejects an Enum type with incorrectly typed value definition', () => { expect( () => new GraphQLEnumType({ name: 'SomeEnum', - // $FlowExpectedError[prop-missing] - values: { - FOO: { isDeprecated: true }, - }, + // @ts-expect-error + values: { FOO: 10 }, }), ).to.throw( - 'SomeEnum.FOO should provide "deprecationReason" instead of "isDeprecated".', + 'SomeEnum.FOO must refer to an object with a "value" key representing an internal value but got: 10.', ); }); }); @@ -773,7 +776,7 @@ describe('Type System: Input Objects', () => { type: ScalarType, defaultValue: undefined, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, }); @@ -792,24 +795,25 @@ describe('Type System: Input Objects', () => { description: undefined, type: ScalarType, defaultValue: undefined, - extensions: undefined, + extensions: {}, deprecationReason: undefined, astNode: undefined, }, }); }); - it('rejects an Input Object type without name', () => { - // $FlowExpectedError[prop-missing] - expect(() => new GraphQLInputObjectType({})).to.throw( - 'Must provide name.', + it('rejects an Input Object type with invalid name', () => { + expect( + () => new GraphQLInputObjectType({ name: 'bad-name', fields: {} }), + ).to.throw( + 'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.', ); }); it('rejects an Input Object type with incorrect fields', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $FlowExpectedError[incompatible-call] + // @ts-expect-error fields: [], }); expect(() => inputObjType.getFields()).to.throw( @@ -820,21 +824,33 @@ describe('Type System: Input Objects', () => { it('rejects an Input Object type with fields function that returns incorrect type', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $FlowExpectedError[incompatible-call] + // @ts-expect-error fields: () => [], }); expect(() => inputObjType.getFields()).to.throw( 'SomeInputObject fields must be an object with field names as keys or a function which returns such an object.', ); }); + + it('rejects an Input Object type with incorrectly named fields', () => { + const inputObjType = new GraphQLInputObjectType({ + name: 'SomeInputObject', + fields: { + 'bad-name': { type: ScalarType }, + }, + }); + expect(() => inputObjType.getFields()).to.throw( + 'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.', + ); + }); }); describe('Input Object fields must not have resolvers', () => { it('rejects an Input Object type with resolvers', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $FlowExpectedError[incompatible-call] fields: { + // @ts-expect-error (Input fields cannot have resolvers) f: { type: ScalarType, resolve: dummyFunc }, }, }); @@ -846,8 +862,8 @@ describe('Type System: Input Objects', () => { it('rejects an Input Object type with resolver constant', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $FlowExpectedError[incompatible-call] fields: { + // @ts-expect-error (Input fields cannot have resolvers) f: { type: ScalarType, resolve: {} }, }, }); @@ -856,6 +872,22 @@ describe('Type System: Input Objects', () => { ); }); }); + + it('Deprecation reason is preserved on fields', () => { + const inputObjType = new GraphQLInputObjectType({ + name: 'SomeInputObject', + fields: { + deprecatedField: { + type: ScalarType, + deprecationReason: 'not used anymore', + }, + }, + }); + expect(inputObjType.toConfig()).to.have.nested.property( + 'fields.deprecatedField.deprecationReason', + 'not used anymore', + ); + }); }); describe('Type System: List', () => { @@ -875,15 +907,15 @@ describe('Type System: List', () => { }); it('rejects a non-type as item type of list', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expectList({}).to.throw('Expected {} to be a GraphQL type.'); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expectList(String).to.throw( 'Expected [function String] to be a GraphQL type.', ); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (must provide type) expectList(null).to.throw('Expected null to be a GraphQL type.'); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (must provide type) expectList(undefined).to.throw('Expected undefined to be a GraphQL type.'); }); }); @@ -905,21 +937,20 @@ describe('Type System: Non-Null', () => { }); it('rejects a non-type as nullable type of non-null', () => { - // $FlowExpectedError[incompatible-call] expectNonNull(NonNullScalarType).to.throw( 'Expected Scalar! to be a GraphQL nullable type.', ); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expectNonNull({}).to.throw('Expected {} to be a GraphQL nullable type.'); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expectNonNull(String).to.throw( 'Expected [function String] to be a GraphQL nullable type.', ); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (must provide type) expectNonNull(null).to.throw( 'Expected null to be a GraphQL nullable type.', ); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (must provide type) expectNonNull(undefined).to.throw( 'Expected undefined to be a GraphQL nullable type.', ); @@ -960,7 +991,7 @@ describe('Type System: test utility methods', () => { }); it('Object.toStringifies types', () => { - function toString(obj: mixed): string { + function toString(obj: unknown): string { return Object.prototype.toString.call(obj); } diff --git a/src/type/__tests__/directive-test.js b/src/type/__tests__/directive-test.ts similarity index 69% rename from src/type/__tests__/directive-test.js rename to src/type/__tests__/directive-test.ts index 0dc7de5132..110a3cc940 100644 --- a/src/type/__tests__/directive-test.js +++ b/src/type/__tests__/directive-test.ts @@ -1,14 +1,16 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import { DirectiveLocation } from '../../language/directiveLocation'; + import { GraphQLDirective } from '../directives'; -import { GraphQLString, GraphQLInt } from '../scalars'; +import { GraphQLInt, GraphQLString } from '../scalars'; describe('Type System: Directive', () => { it('defines a directive with no args', () => { const directive = new GraphQLDirective({ name: 'Foo', - locations: ['QUERY'], + locations: [DirectiveLocation.QUERY], }); expect(directive).to.deep.include({ @@ -26,7 +28,7 @@ describe('Type System: Directive', () => { foo: { type: GraphQLString }, bar: { type: GraphQLInt }, }, - locations: ['QUERY'], + locations: [DirectiveLocation.QUERY], }); expect(directive).to.deep.include({ @@ -38,7 +40,7 @@ describe('Type System: Directive', () => { type: GraphQLString, defaultValue: undefined, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, { @@ -47,7 +49,7 @@ describe('Type System: Directive', () => { type: GraphQLInt, defaultValue: undefined, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, ], @@ -60,7 +62,7 @@ describe('Type System: Directive', () => { const directive = new GraphQLDirective({ name: 'Foo', isRepeatable: true, - locations: ['QUERY'], + locations: [DirectiveLocation.QUERY], }); expect(directive).to.deep.include({ @@ -74,7 +76,7 @@ describe('Type System: Directive', () => { it('can be stringified, JSON.stringified and Object.toStringified', () => { const directive = new GraphQLDirective({ name: 'Foo', - locations: ['QUERY'], + locations: [DirectiveLocation.QUERY], }); expect(String(directive)).to.equal('@Foo'); @@ -84,11 +86,14 @@ describe('Type System: Directive', () => { ); }); - it('rejects an unnamed directive', () => { - // $FlowExpectedError[prop-missing] - expect(() => new GraphQLDirective({ locations: ['QUERY'] })).to.throw( - 'Directive must be named.', - ); + it('rejects a directive with invalid name', () => { + expect( + () => + new GraphQLDirective({ + name: 'bad-name', + locations: [DirectiveLocation.QUERY], + }), + ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.'); }); it('rejects a directive with incorrectly typed args', () => { @@ -96,22 +101,35 @@ describe('Type System: Directive', () => { () => new GraphQLDirective({ name: 'Foo', - locations: ['QUERY'], - // $FlowExpectedError[incompatible-call] + locations: [DirectiveLocation.QUERY], + // @ts-expect-error args: [], }), ).to.throw('@Foo args must be an object with argument names as keys.'); }); + it('rejects a directive with incorrectly named arg', () => { + expect( + () => + new GraphQLDirective({ + name: 'Foo', + locations: [DirectiveLocation.QUERY], + args: { + 'bad-name': { type: GraphQLString }, + }, + }), + ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.'); + }); + it('rejects a directive with undefined locations', () => { - // $FlowExpectedError[prop-missing] + // @ts-expect-error expect(() => new GraphQLDirective({ name: 'Foo' })).to.throw( '@Foo locations must be an Array.', ); }); it('rejects a directive with incorrectly typed locations', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => new GraphQLDirective({ name: 'Foo', locations: {} })).to.throw( '@Foo locations must be an Array.', ); diff --git a/src/type/__tests__/enumType-test.js b/src/type/__tests__/enumType-test.ts similarity index 89% rename from src/type/__tests__/enumType-test.js rename to src/type/__tests__/enumType-test.ts index e9dbeedec2..d5cfadc635 100644 --- a/src/type/__tests__/enumType-test.js +++ b/src/type/__tests__/enumType-test.ts @@ -1,12 +1,15 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { graphqlSync } from '../../graphql'; +import { expectJSON } from '../../__testUtils__/expectJSON'; + import { introspectionFromSchema } from '../../utilities/introspectionFromSchema'; -import { GraphQLSchema } from '../schema'; +import { graphqlSync } from '../../graphql'; + import { GraphQLEnumType, GraphQLObjectType } from '../definition'; -import { GraphQLInt, GraphQLString, GraphQLBoolean } from '../scalars'; +import { GraphQLBoolean, GraphQLInt, GraphQLString } from '../scalars'; +import { GraphQLSchema } from '../schema'; const ColorType = new GraphQLEnumType({ name: 'Color', @@ -28,6 +31,14 @@ const ComplexEnum = new GraphQLEnumType({ }, }); +const ThunkValuesEnum = new GraphQLEnumType({ + name: 'ThunkValues', + values: () => ({ + A: { value: 'a' }, + B: { value: 'b' }, + }), +}); + const QueryType = new GraphQLObjectType({ name: 'Query', fields: { @@ -81,6 +92,15 @@ const QueryType = new GraphQLObjectType({ return fromEnum; }, }, + thunkValuesString: { + type: GraphQLString, + args: { + fromEnum: { type: ThunkValuesEnum }, + }, + resolve(_source, { fromEnum }) { + return fromEnum; + }, + }, }, }); @@ -114,7 +134,7 @@ const schema = new GraphQLSchema({ function executeQuery( source: string, - variableValues?: { +[variable: string]: mixed, ... }, + variableValues?: { readonly [variable: string]: unknown }, ) { return graphqlSync({ schema, source, variableValues }); } @@ -147,7 +167,7 @@ describe('Type System: Enum Values', () => { it('does not accept string literals', () => { const result = executeQuery('{ colorEnum(fromEnum: "GREEN") }'); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -161,7 +181,7 @@ describe('Type System: Enum Values', () => { it('does not accept values not in the enum', () => { const result = executeQuery('{ colorEnum(fromEnum: GREENISH) }'); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -175,7 +195,7 @@ describe('Type System: Enum Values', () => { it('does not accept values with incorrect casing', () => { const result = executeQuery('{ colorEnum(fromEnum: green) }'); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -189,7 +209,7 @@ describe('Type System: Enum Values', () => { it('does not accept incorrect internal value', () => { const result = executeQuery('{ colorEnum(fromString: "GREEN") }'); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { colorEnum: null }, errors: [ { @@ -204,7 +224,7 @@ describe('Type System: Enum Values', () => { it('does not accept internal value in place of enum literal', () => { const result = executeQuery('{ colorEnum(fromEnum: 1) }'); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: 'Enum "Color" cannot represent non-enum value: 1.', @@ -217,7 +237,7 @@ describe('Type System: Enum Values', () => { it('does not accept enum literal in place of int', () => { const result = executeQuery('{ colorEnum(fromInt: GREEN) }'); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: 'Int cannot represent non-integer value: GREEN', @@ -259,7 +279,7 @@ describe('Type System: Enum Values', () => { const doc = 'query ($color: Color!) { colorEnum(fromEnum: $color) }'; const result = executeQuery(doc, { color: 2 }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -274,7 +294,7 @@ describe('Type System: Enum Values', () => { const doc = 'query ($color: String!) { colorEnum(fromEnum: $color) }'; const result = executeQuery(doc, { color: 'BLUE' }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -292,7 +312,7 @@ describe('Type System: Enum Values', () => { const doc = 'query ($color: Int!) { colorEnum(fromEnum: $color) }'; const result = executeQuery(doc, { color: 2 }); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ errors: [ { message: @@ -345,18 +365,16 @@ describe('Type System: Enum Values', () => { name: 'ONE', description: undefined, value: Complex1, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, { name: 'TWO', description: undefined, value: Complex2, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: {}, astNode: undefined, }, ]); @@ -366,7 +384,7 @@ describe('Type System: Enum Values', () => { const oneValue = ComplexEnum.getValue('ONE'); expect(oneValue).to.include({ name: 'ONE', value: Complex1 }); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const badUsage = ComplexEnum.getValue(Complex1); expect(badUsage).to.equal(undefined); }); @@ -381,7 +399,7 @@ describe('Type System: Enum Values', () => { } `); - expect(result).to.deep.equal({ + expectJSON(result).toDeepEqual({ data: { first: 'ONE', second: 'TWO', @@ -399,6 +417,14 @@ describe('Type System: Enum Values', () => { }); }); + it('may have values specified via a callback', () => { + const result = executeQuery('{ thunkValuesString(fromEnum: B) }'); + + expect(result).to.deep.equal({ + data: { thunkValuesString: 'b' }, + }); + }); + it('can be introspected without error', () => { expect(() => introspectionFromSchema(schema)).to.not.throw(); }); diff --git a/src/type/__tests__/extensions-test.js b/src/type/__tests__/extensions-test.ts similarity index 85% rename from src/type/__tests__/extensions-test.js rename to src/type/__tests__/extensions-test.ts index 76dd0ee233..4fb0827485 100644 --- a/src/type/__tests__/extensions-test.js +++ b/src/type/__tests__/extensions-test.ts @@ -1,22 +1,22 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; +import { invariant } from '../../jsutils/invariant'; -import { GraphQLSchema } from '../schema'; -import { GraphQLDirective } from '../directives'; import { - GraphQLScalarType, - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLScalarType, + GraphQLUnionType, } from '../definition'; +import { GraphQLDirective } from '../directives'; +import { GraphQLSchema } from '../schema'; const dummyType = new GraphQLScalarType({ name: 'DummyScalar' }); -function expectObjMap(value: mixed) { +function expectObjMap(value: unknown) { invariant(value != null && typeof value === 'object'); expect(Object.getPrototypeOf(value)).to.equal(null); return expect(value); @@ -26,10 +26,10 @@ describe('Type System: Extensions', () => { describe('GraphQLScalarType', () => { it('without extensions', () => { const someScalar = new GraphQLScalarType({ name: 'SomeScalar' }); - expect(someScalar.extensions).to.equal(undefined); + expect(someScalar.extensions).to.deep.equal({}); const config = someScalar.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); }); it('with extensions', () => { @@ -62,19 +62,19 @@ describe('Type System: Extensions', () => { }, }); - expect(someObject.extensions).to.equal(undefined); + expect(someObject.extensions).to.deep.equal({}); const someField = someObject.getFields().someField; - expect(someField.extensions).to.equal(undefined); + expect(someField.extensions).to.deep.equal({}); const someArg = someField.args[0]; - expect(someArg.extensions).to.equal(undefined); + expect(someArg.extensions).to.deep.equal({}); const config = someObject.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); const someFieldConfig = config.fields.someField; - expect(someFieldConfig.extensions).to.equal(undefined); + expect(someFieldConfig.extensions).to.deep.equal({}); invariant(someFieldConfig.args); const someArgConfig = someFieldConfig.args.someArg; - expect(someArgConfig.extensions).to.equal(undefined); + expect(someArgConfig.extensions).to.deep.equal({}); }); it('with extensions', () => { @@ -131,19 +131,19 @@ describe('Type System: Extensions', () => { }, }); - expect(someInterface.extensions).to.equal(undefined); + expect(someInterface.extensions).to.deep.equal({}); const someField = someInterface.getFields().someField; - expect(someField.extensions).to.equal(undefined); + expect(someField.extensions).to.deep.equal({}); const someArg = someField.args[0]; - expect(someArg.extensions).to.equal(undefined); + expect(someArg.extensions).to.deep.equal({}); const config = someInterface.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); const someFieldConfig = config.fields.someField; - expect(someFieldConfig.extensions).to.equal(undefined); + expect(someFieldConfig.extensions).to.deep.equal({}); invariant(someFieldConfig.args); const someArgConfig = someFieldConfig.args.someArg; - expect(someArgConfig.extensions).to.equal(undefined); + expect(someArgConfig.extensions).to.deep.equal({}); }); it('with extensions', () => { @@ -193,10 +193,10 @@ describe('Type System: Extensions', () => { types: [], }); - expect(someUnion.extensions).to.equal(undefined); + expect(someUnion.extensions).to.deep.equal({}); const config = someUnion.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); }); it('with extensions', () => { @@ -224,14 +224,14 @@ describe('Type System: Extensions', () => { }, }); - expect(someEnum.extensions).to.equal(undefined); + expect(someEnum.extensions).to.deep.equal({}); const someValue = someEnum.getValues()[0]; - expect(someValue.extensions).to.equal(undefined); + expect(someValue.extensions).to.deep.equal({}); const config = someEnum.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); const someValueConfig = config.values.SOME_VALUE; - expect(someValueConfig.extensions).to.equal(undefined); + expect(someValueConfig.extensions).to.deep.equal({}); }); it('with extensions', () => { @@ -270,14 +270,14 @@ describe('Type System: Extensions', () => { }, }); - expect(someInputObject.extensions).to.equal(undefined); + expect(someInputObject.extensions).to.deep.equal({}); const someInputField = someInputObject.getFields().someInputField; - expect(someInputField.extensions).to.equal(undefined); + expect(someInputField.extensions).to.deep.equal({}); const config = someInputObject.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); const someInputFieldConfig = config.fields.someInputField; - expect(someInputFieldConfig.extensions).to.equal(undefined); + expect(someInputFieldConfig.extensions).to.deep.equal({}); }); it('with extensions', () => { @@ -328,14 +328,14 @@ describe('Type System: Extensions', () => { locations: [], }); - expect(someDirective.extensions).to.equal(undefined); + expect(someDirective.extensions).to.deep.equal({}); const someArg = someDirective.args[0]; - expect(someArg.extensions).to.equal(undefined); + expect(someArg.extensions).to.deep.equal({}); const config = someDirective.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); const someArgConfig = config.args.someArg; - expect(someArgConfig.extensions).to.equal(undefined); + expect(someArgConfig.extensions).to.deep.equal({}); }); it('with extensions', () => { @@ -371,10 +371,10 @@ describe('Type System: Extensions', () => { it('without extensions', () => { const schema = new GraphQLSchema({}); - expect(schema.extensions).to.equal(undefined); + expect(schema.extensions).to.deep.equal({}); const config = schema.toConfig(); - expect(config.extensions).to.equal(undefined); + expect(config.extensions).to.deep.equal({}); }); it('with extensions', () => { diff --git a/src/type/__tests__/introspection-test.js b/src/type/__tests__/introspection-test.ts similarity index 89% rename from src/type/__tests__/introspection-test.js rename to src/type/__tests__/introspection-test.ts index 478cc9bd18..8c5cacba0d 100644 --- a/src/type/__tests__/introspection-test.js +++ b/src/type/__tests__/introspection-test.ts @@ -1,13 +1,15 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; +import { expectJSON } from '../../__testUtils__/expectJSON'; import { buildSchema } from '../../utilities/buildASTSchema'; import { getIntrospectionQuery } from '../../utilities/getIntrospectionQuery'; import { graphqlSync } from '../../graphql'; +import type { GraphQLResolveInfo } from '../definition'; + describe('Introspection', () => { it('executes an introspection query', () => { const schema = buildSchema(` @@ -30,14 +32,14 @@ describe('Introspection', () => { expect(result).to.deep.equal({ data: { __schema: { - queryType: { name: 'SomeObject' }, + queryType: { name: 'SomeObject', kind: 'OBJECT' }, mutationType: null, subscriptionType: null, types: [ { kind: 'OBJECT', name: 'SomeObject', - specifiedByUrl: null, + specifiedByURL: null, fields: [ { name: 'someField', @@ -59,7 +61,7 @@ describe('Introspection', () => { { kind: 'SCALAR', name: 'String', - specifiedByUrl: null, + specifiedByURL: null, fields: null, inputFields: null, interfaces: null, @@ -69,7 +71,7 @@ describe('Introspection', () => { { kind: 'SCALAR', name: 'Boolean', - specifiedByUrl: null, + specifiedByURL: null, fields: null, inputFields: null, interfaces: null, @@ -79,7 +81,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Schema', - specifiedByUrl: null, + specifiedByURL: null, fields: [ { name: 'description', @@ -184,7 +186,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Type', - specifiedByUrl: null, + specifiedByURL: null, fields: [ { name: 'kind', @@ -224,7 +226,7 @@ describe('Introspection', () => { deprecationReason: null, }, { - name: 'specifiedByUrl', + name: 'specifiedByURL', args: [], type: { kind: 'SCALAR', @@ -370,6 +372,17 @@ describe('Introspection', () => { isDeprecated: false, deprecationReason: null, }, + { + name: 'isOneOf', + args: [], + type: { + kind: 'SCALAR', + name: 'Boolean', + ofType: null, + }, + isDeprecated: false, + deprecationReason: null, + }, ], inputFields: null, interfaces: [], @@ -379,7 +392,7 @@ describe('Introspection', () => { { kind: 'ENUM', name: '__TypeKind', - specifiedByUrl: null, + specifiedByURL: null, fields: null, inputFields: null, interfaces: null, @@ -430,7 +443,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Field', - specifiedByUrl: null, + specifiedByURL: null, fields: [ { name: 'name', @@ -541,7 +554,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__InputValue', - specifiedByUrl: null, + specifiedByURL: null, fields: [ { name: 'name', @@ -630,7 +643,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__EnumValue', - specifiedByUrl: null, + specifiedByURL: null, fields: [ { name: 'name', @@ -693,7 +706,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Directive', - specifiedByUrl: null, + specifiedByURL: null, fields: [ { name: 'name', @@ -761,7 +774,17 @@ describe('Introspection', () => { }, { name: 'args', - args: [], + args: [ + { + name: 'includeDeprecated', + type: { + kind: 'SCALAR', + name: 'Boolean', + ofType: null, + }, + defaultValue: 'false', + }, + ], type: { kind: 'NON_NULL', name: null, @@ -791,7 +814,7 @@ describe('Introspection', () => { { kind: 'ENUM', name: '__DirectiveLocation', - specifiedByUrl: null, + specifiedByURL: null, fields: null, inputFields: null, interfaces: null, @@ -977,6 +1000,12 @@ describe('Introspection', () => { }, ], }, + { + name: 'oneOf', + isRepeatable: false, + locations: ['INPUT_OBJECT'], + args: [], + }, ], }, }, @@ -1070,6 +1099,52 @@ describe('Introspection', () => { }); }); + it('introspects any default value', () => { + const schema = buildSchema(` + input InputObjectWithDefaultValues { + a: String = "Emoji: \\u{1F600}" + b: Complex = {x: ["abc"], y: 123} + } + + input Complex { + x: [String] + y: Int + } + + type Query { + someField(someArg: InputObjectWithDefaultValues): String + } + `); + + const source = ` + { + __type(name: "InputObjectWithDefaultValues") { + inputFields { + name + defaultValue + } + } + } + `; + + expect(graphqlSync({ schema, source })).to.deep.equal({ + data: { + __type: { + inputFields: [ + { + name: 'a', + defaultValue: '"Emoji: \u{1F600}"', + }, + { + name: 'b', + defaultValue: '{x: ["abc"], y: 123}', + }, + ], + }, + }, + }); + }); + it('supports the __type root field', () => { const schema = buildSchema(` type Query { @@ -1461,6 +1536,95 @@ describe('Introspection', () => { }); }); + it('identifies oneOf for input objects', () => { + const schema = buildSchema(` + input SomeInputObject @oneOf { + a: String + } + + input AnotherInputObject { + a: String + b: String + } + + type Query { + someField(someArg: SomeInputObject): String + anotherField(anotherArg: AnotherInputObject): String + } + `); + + const source = ` + { + oneOfInputObject: __type(name: "SomeInputObject") { + isOneOf + } + inputObject: __type(name: "AnotherInputObject") { + isOneOf + } + } + `; + + expect(graphqlSync({ schema, source })).to.deep.equal({ + data: { + oneOfInputObject: { + isOneOf: true, + }, + inputObject: { + isOneOf: false, + }, + }, + }); + }); + + it('returns null for oneOf for other types', () => { + const schema = buildSchema(` + type SomeObject implements SomeInterface { + fieldA: String + } + enum SomeEnum { + SomeObject + } + interface SomeInterface { + fieldA: String + } + union SomeUnion = SomeObject + type Query { + someField(enum: SomeEnum): SomeUnion + anotherField(enum: SomeEnum): SomeInterface + } + `); + + const source = ` + { + object: __type(name: "SomeObject") { + isOneOf + } + enum: __type(name: "SomeEnum") { + isOneOf + } + interface: __type(name: "SomeInterface") { + isOneOf + } + scalar: __type(name: "String") { + isOneOf + } + union: __type(name: "SomeUnion") { + isOneOf + } + } + `; + + expect(graphqlSync({ schema, source })).to.deep.equal({ + data: { + object: { isOneOf: null }, + enum: { isOneOf: null }, + interface: { isOneOf: null }, + scalar: { isOneOf: null }, + union: { isOneOf: null }, + }, + }); + }); + it('fails as expected on the __type root field without an arg', () => { const schema = buildSchema(` type Query { @@ -1476,7 +1640,7 @@ describe('Introspection', () => { } `; - expect(graphqlSync({ schema, source })).to.deep.equal({ + expectJSON(graphqlSync({ schema, source })).toDeepEqual({ errors: [ { message: @@ -1567,23 +1731,27 @@ describe('Introspection', () => { schemaDescription: true, }); - // istanbul ignore next (Called only to fail test) - function fieldResolver(_1, _2, _3, info) { - invariant(false, `Called on ${info.parentType.name}::${info.fieldName}`); + /* c8 ignore start */ + function fieldResolver( + _1: any, + _2: any, + _3: any, + info: GraphQLResolveInfo, + ): never { + expect.fail(`Called on ${info.parentType.name}::${info.fieldName}`); } - // istanbul ignore next (Called only to fail test) - function typeResolver(_1, _2, info) { - invariant(false, `Called on ${info.parentType.name}::${info.fieldName}`); + function typeResolver(_1: any, _2: any, info: GraphQLResolveInfo): never { + expect.fail(`Called on ${info.parentType.name}::${info.fieldName}`); } + /* c8 ignore stop */ - expect(() => - graphqlSync({ - schema, - source, - fieldResolver, - typeResolver, - }), - ).to.not.throw(); + const result = graphqlSync({ + schema, + source, + fieldResolver, + typeResolver, + }); + expect(result).to.not.have.property('errors'); }); }); diff --git a/src/type/__tests__/predicate-test.js b/src/type/__tests__/predicate-test.ts similarity index 95% rename from src/type/__tests__/predicate-test.js rename to src/type/__tests__/predicate-test.ts index 33c2c49f57..81e721e7df 100644 --- a/src/type/__tests__/predicate-test.js +++ b/src/type/__tests__/predicate-test.ts @@ -1,72 +1,78 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import type { GraphQLArgument, GraphQLInputField } from '../definition'; -import { - GraphQLDirective, - GraphQLSkipDirective, - GraphQLIncludeDirective, - GraphQLDeprecatedDirective, - assertDirective, - isDirective, - isSpecifiedDirective, -} from '../directives'; -import { - GraphQLID, - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, - isSpecifiedScalarType, -} from '../scalars'; +import { DirectiveLocation } from '../../language/directiveLocation'; + +import type { + GraphQLArgument, + GraphQLInputField, + GraphQLInputType, +} from '../definition'; import { - GraphQLList, - GraphQLNonNull, - GraphQLScalarType, + assertAbstractType, + assertCompositeType, + assertEnumType, + assertInputObjectType, + assertInputType, + assertInterfaceType, + assertLeafType, + assertListType, + assertNamedType, + assertNonNullType, + assertNullableType, + assertObjectType, + assertOutputType, + assertScalarType, + assertType, + assertUnionType, + assertWrappingType, + getNamedType, + getNullableType, GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, GraphQLObjectType, + GraphQLScalarType, GraphQLUnionType, - isType, - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, + isAbstractType, + isCompositeType, isEnumType, isInputObjectType, - isListType, - isNonNullType, isInputType, - isOutputType, + isInterfaceType, isLeafType, - isCompositeType, - isAbstractType, - isWrappingType, - isNullableType, + isListType, isNamedType, + isNonNullType, + isNullableType, + isObjectType, + isOutputType, isRequiredArgument, isRequiredInputField, - assertType, - assertScalarType, - assertObjectType, - assertInterfaceType, - assertUnionType, - assertEnumType, - assertInputObjectType, - assertListType, - assertNonNullType, - assertInputType, - assertOutputType, - assertLeafType, - assertCompositeType, - assertAbstractType, - assertWrappingType, - assertNullableType, - assertNamedType, - getNullableType, - getNamedType, + isScalarType, + isType, + isUnionType, + isWrappingType, } from '../definition'; +import { + assertDirective, + GraphQLDeprecatedDirective, + GraphQLDirective, + GraphQLIncludeDirective, + GraphQLSkipDirective, + isDirective, + isSpecifiedDirective, +} from '../directives'; +import { + GraphQLBoolean, + GraphQLFloat, + GraphQLID, + GraphQLInt, + GraphQLString, + isSpecifiedScalarType, +} from '../scalars'; const ObjectType = new GraphQLObjectType({ name: 'Object', fields: {} }); const InterfaceType = new GraphQLInterfaceType({ @@ -82,7 +88,7 @@ const InputObjectType = new GraphQLInputObjectType({ const ScalarType = new GraphQLScalarType({ name: 'Scalar' }); const Directive = new GraphQLDirective({ name: 'Directive', - locations: ['QUERY'], + locations: [DirectiveLocation.QUERY], }); describe('Type predicates', () => { @@ -296,7 +302,7 @@ describe('Type predicates', () => { }); describe('isInputType', () => { - function expectInputType(type: mixed) { + function expectInputType(type: unknown) { expect(isInputType(type)).to.equal(true); expect(() => assertInputType(type)).to.not.throw(); } @@ -317,7 +323,7 @@ describe('Type predicates', () => { expectInputType(new GraphQLNonNull(InputObjectType)); }); - function expectNonInputType(type: mixed) { + function expectNonInputType(type: unknown) { expect(isInputType(type)).to.equal(false); expect(() => assertInputType(type)).to.throw(); } @@ -340,7 +346,7 @@ describe('Type predicates', () => { }); describe('isOutputType', () => { - function expectOutputType(type: mixed) { + function expectOutputType(type: unknown) { expect(isOutputType(type)).to.equal(true); expect(() => assertOutputType(type)).to.not.throw(); } @@ -367,7 +373,7 @@ describe('Type predicates', () => { expectOutputType(new GraphQLNonNull(EnumType)); }); - function expectNonOutputType(type: mixed) { + function expectNonOutputType(type: unknown) { expect(isOutputType(type)).to.equal(false); expect(() => assertOutputType(type)).to.throw(); } @@ -503,7 +509,7 @@ describe('Type predicates', () => { describe('getNullableType', () => { it('returns undefined for no type', () => { - expect(getNullableType()).to.equal(undefined); + expect(getNullableType(undefined)).to.equal(undefined); expect(getNullableType(null)).to.equal(undefined); }); @@ -536,7 +542,7 @@ describe('Type predicates', () => { describe('getNamedType', () => { it('returns undefined for no type', () => { - expect(getNamedType()).to.equal(undefined); + expect(getNamedType(undefined)).to.equal(undefined); expect(getNamedType(null)).to.equal(undefined); }); @@ -559,15 +565,18 @@ describe('Type predicates', () => { }); describe('isRequiredArgument', () => { - function buildArg(config: $Shape) { + function buildArg(config: { + type: GraphQLInputType; + defaultValue?: unknown; + }): GraphQLArgument { return { name: 'someArg', + type: config.type, description: undefined, - defaultValue: undefined, + defaultValue: config.defaultValue, deprecationReason: null, - extensions: undefined, + extensions: Object.create(null), astNode: undefined, - ...config, }; } @@ -604,15 +613,18 @@ describe('Type predicates', () => { }); describe('isRequiredInputField', () => { - function buildInputField(config: $Shape) { + function buildInputField(config: { + type: GraphQLInputType; + defaultValue?: unknown; + }): GraphQLInputField { return { name: 'someInputField', + type: config.type, description: undefined, - defaultValue: undefined, + defaultValue: config.defaultValue, deprecationReason: null, - extensions: undefined, + extensions: Object.create(null), astNode: undefined, - ...config, }; } diff --git a/src/type/__tests__/scalars-test.js b/src/type/__tests__/scalars-test.ts similarity index 96% rename from src/type/__tests__/scalars-test.js rename to src/type/__tests__/scalars-test.ts index 6e901c3fb0..4d563aee10 100644 --- a/src/type/__tests__/scalars-test.js +++ b/src/type/__tests__/scalars-test.ts @@ -4,17 +4,17 @@ import { describe, it } from 'mocha'; import { parseValue as parseValueToAST } from '../../language/parser'; import { + GraphQLBoolean, + GraphQLFloat, GraphQLID, GraphQLInt, - GraphQLFloat, GraphQLString, - GraphQLBoolean, } from '../scalars'; describe('Type System: Specified scalar types', () => { describe('GraphQLInt', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLInt.parseValue(value); } @@ -66,7 +66,7 @@ describe('Type System: Specified scalar types', () => { it('parseLiteral', () => { function parseLiteral(str: string) { - return GraphQLInt.parseLiteral(parseValueToAST(str)); + return GraphQLInt.parseLiteral(parseValueToAST(str), undefined); } expect(parseLiteral('1')).to.equal(1); @@ -110,7 +110,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLInt.serialize(value); } @@ -183,7 +183,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLFloat', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLFloat.parseValue(value); } @@ -231,7 +231,7 @@ describe('Type System: Specified scalar types', () => { it('parseLiteral', () => { function parseLiteral(str: string) { - return GraphQLFloat.parseLiteral(parseValueToAST(str)); + return GraphQLFloat.parseLiteral(parseValueToAST(str), undefined); } expect(parseLiteral('1')).to.equal(1); @@ -270,7 +270,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLFloat.serialize(value); } @@ -313,7 +313,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLString', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLString.parseValue(value); } @@ -344,7 +344,7 @@ describe('Type System: Specified scalar types', () => { it('parseLiteral', () => { function parseLiteral(str: string) { - return GraphQLString.parseLiteral(parseValueToAST(str)); + return GraphQLString.parseLiteral(parseValueToAST(str), undefined); } expect(parseLiteral('"foo"')).to.equal('foo'); @@ -377,7 +377,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLString.serialize(value); } @@ -418,7 +418,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLBoolean', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLBoolean.parseValue(value); } @@ -456,7 +456,7 @@ describe('Type System: Specified scalar types', () => { it('parseLiteral', () => { function parseLiteral(str: string) { - return GraphQLBoolean.parseLiteral(parseValueToAST(str)); + return GraphQLBoolean.parseLiteral(parseValueToAST(str), undefined); } expect(parseLiteral('true')).to.equal(true); @@ -495,7 +495,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLBoolean.serialize(value); } @@ -507,7 +507,7 @@ describe('Type System: Specified scalar types', () => { serialize({ value: true, valueOf() { - return this.value; + return (this as { value: boolean }).value; }, }), ).to.equal(true); @@ -532,7 +532,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLID', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLID.parseValue(value); } @@ -571,7 +571,7 @@ describe('Type System: Specified scalar types', () => { it('parseLiteral', () => { function parseLiteral(str: string) { - return GraphQLID.parseLiteral(parseValueToAST(str)); + return GraphQLID.parseLiteral(parseValueToAST(str), undefined); } expect(parseLiteral('""')).to.equal(''); @@ -610,7 +610,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLID.serialize(value); } diff --git a/src/type/__tests__/schema-test.js b/src/type/__tests__/schema-test.ts similarity index 93% rename from src/type/__tests__/schema-test.js rename to src/type/__tests__/schema-test.ts index 1d8817e3c6..8a31b50ada 100644 --- a/src/type/__tests__/schema-test.js +++ b/src/type/__tests__/schema-test.ts @@ -1,20 +1,22 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; + +import { DirectiveLocation } from '../../language/directiveLocation'; import { printSchema } from '../../utilities/printSchema'; -import { GraphQLSchema } from '../schema'; -import { GraphQLDirective } from '../directives'; -import { GraphQLInt, GraphQLString, GraphQLBoolean } from '../scalars'; import { + GraphQLInputObjectType, + GraphQLInterfaceType, GraphQLList, - GraphQLScalarType, GraphQLObjectType, - GraphQLInterfaceType, - GraphQLInputObjectType, + GraphQLScalarType, } from '../definition'; +import { GraphQLDirective } from '../directives'; +import { GraphQLBoolean, GraphQLInt, GraphQLString } from '../scalars'; +import { GraphQLSchema } from '../schema'; describe('Type System: Schema', () => { it('Define sample schema', () => { @@ -27,7 +29,7 @@ describe('Type System: Schema', () => { }, }); - const BlogAuthor = new GraphQLObjectType({ + const BlogAuthor: GraphQLObjectType = new GraphQLObjectType({ name: 'Author', fields: () => ({ id: { type: GraphQLString }, @@ -40,7 +42,7 @@ describe('Type System: Schema', () => { }), }); - const BlogArticle = new GraphQLObjectType({ + const BlogArticle: GraphQLObjectType = new GraphQLObjectType({ name: 'Article', fields: { id: { type: GraphQLString }, @@ -140,19 +142,19 @@ describe('Type System: Schema', () => { it('defines a query root', () => { const schema = new GraphQLSchema({ query: testType }); expect(schema.getQueryType()).to.equal(testType); - expect(schema.getTypeMap()).to.include.key('TestType'); + expect(schema.getTypeMap()).to.include.keys('TestType'); }); it('defines a mutation root', () => { const schema = new GraphQLSchema({ mutation: testType }); expect(schema.getMutationType()).to.equal(testType); - expect(schema.getTypeMap()).to.include.key('TestType'); + expect(schema.getTypeMap()).to.include.keys('TestType'); }); it('defines a subscription root', () => { const schema = new GraphQLSchema({ subscription: testType }); expect(schema.getSubscriptionType()).to.equal(testType); - expect(schema.getTypeMap()).to.include.key('TestType'); + expect(schema.getTypeMap()).to.include.keys('TestType'); }); }); @@ -183,7 +185,6 @@ describe('Type System: Schema', () => { expect(schema.getType('SomeSubtype')).to.equal(SomeSubtype); expect(schema.isSubType(SomeInterface, SomeSubtype)).to.equal(true); - expect(schema.isPossibleType(SomeInterface, SomeSubtype)).to.equal(true); }); it("includes interface's thunk subtypes in the type map", () => { @@ -241,7 +242,7 @@ describe('Type System: Schema', () => { it('includes input types only used in directives', () => { const directive = new GraphQLDirective({ name: 'dir', - locations: ['OBJECT'], + locations: [DirectiveLocation.OBJECT], args: { arg: { type: new GraphQLInputObjectType({ name: 'Foo', fields: {} }), @@ -329,11 +330,11 @@ describe('Type System: Schema', () => { }); it('checks the configuration for mistakes', () => { - // $FlowExpectedError[incompatible-exact] + // @ts-expect-error expect(() => new GraphQLSchema(JSON.parse)).to.throw(); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => new GraphQLSchema({ types: {} })).to.throw(); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => new GraphQLSchema({ directives: {} })).to.throw(); }); }); @@ -362,7 +363,7 @@ describe('Type System: Schema', () => { }); const types = [{}, query, {}]; - // $FlowExpectedError[incompatible-call] + // @ts-expect-error expect(() => new GraphQLSchema({ query, types })).to.throw( 'One of the provided types for building the Schema is missing a name.', ); diff --git a/src/type/__tests__/validation-test.js b/src/type/__tests__/validation-test.ts similarity index 86% rename from src/type/__tests__/validation-test.js rename to src/type/__tests__/validation-test.ts index a3e35443da..d5b8773700 100644 --- a/src/type/__tests__/validation-test.js +++ b/src/type/__tests__/validation-test.ts @@ -1,43 +1,44 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; +import { expectJSON } from '../../__testUtils__/expectJSON'; -import inspect from '../../jsutils/inspect'; +import { inspect } from '../../jsutils/inspect'; +import { DirectiveLocation } from '../../language/directiveLocation'; import { parse } from '../../language/parser'; -import { extendSchema } from '../../utilities/extendSchema'; import { buildSchema } from '../../utilities/buildASTSchema'; +import { extendSchema } from '../../utilities/extendSchema'; import type { - GraphQLNamedType, - GraphQLInputType, - GraphQLOutputType, - GraphQLFieldConfig, GraphQLArgumentConfig, + GraphQLFieldConfig, GraphQLInputFieldConfig, - GraphQLEnumValueConfigMap, + GraphQLInputType, + GraphQLNamedType, + GraphQLOutputType, } from '../definition'; -import { GraphQLSchema } from '../schema'; -import { GraphQLString } from '../scalars'; -import { validateSchema, assertValidSchema } from '../validate'; -import { GraphQLDirective, assertDirective } from '../directives'; import { + assertEnumType, + assertInputObjectType, + assertInterfaceType, + assertObjectType, + assertScalarType, + assertUnionType, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLInterfaceType, GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, - assertScalarType, - assertInterfaceType, - assertObjectType, - assertUnionType, - assertEnumType, - assertInputObjectType, } from '../definition'; +import { assertDirective, GraphQLDirective } from '../directives'; +import { GraphQLString } from '../scalars'; +import { GraphQLSchema } from '../schema'; +import { assertValidSchema, validateSchema } from '../validate'; const SomeSchema = buildSchema(` scalar SomeScalar @@ -68,7 +69,7 @@ const SomeInputObjectType = assertInputObjectType( const SomeDirective = assertDirective(SomeSchema.getDirective('SomeDirective')); -function withModifiers( +function withModifiers( type: T, ): Array | GraphQLNonNull>> { return [ @@ -79,7 +80,7 @@ function withModifiers( ]; } -const outputTypes: Array = [ +const outputTypes: ReadonlyArray = [ ...withModifiers(GraphQLString), ...withModifiers(SomeScalarType), ...withModifiers(SomeEnumType), @@ -88,18 +89,18 @@ const outputTypes: Array = [ ...withModifiers(SomeInterfaceType), ]; -const notOutputTypes: Array = [ +const notOutputTypes: ReadonlyArray = [ ...withModifiers(SomeInputObjectType), ]; -const inputTypes: Array = [ +const inputTypes: ReadonlyArray = [ ...withModifiers(GraphQLString), ...withModifiers(SomeScalarType), ...withModifiers(SomeEnumType), ...withModifiers(SomeInputObjectType), ]; -const notInputTypes: Array = [ +const notInputTypes: ReadonlyArray = [ ...withModifiers(SomeObjectType), ...withModifiers(SomeUnionType), ...withModifiers(SomeInterfaceType), @@ -121,7 +122,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); const schemaWithDef = buildSchema(` schema { @@ -132,7 +133,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schemaWithDef)).to.deep.equal([]); + expectJSON(validateSchema(schemaWithDef)).toDeepEqual([]); }); it('accepts a Schema whose query and mutation types are object types', () => { @@ -145,7 +146,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); const schemaWithDef = buildSchema(` schema { @@ -161,7 +162,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schemaWithDef)).to.deep.equal([]); + expectJSON(validateSchema(schemaWithDef)).toDeepEqual([]); }); it('accepts a Schema whose query and subscription types are object types', () => { @@ -174,7 +175,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); const schemaWithDef = buildSchema(` schema { @@ -190,7 +191,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schemaWithDef)).to.deep.equal([]); + expectJSON(validateSchema(schemaWithDef)).toDeepEqual([]); }); it('rejects a Schema without a query type', () => { @@ -199,7 +200,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Query root type must be provided.', }, @@ -214,7 +215,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schemaWithDef)).to.deep.equal([ + expectJSON(validateSchema(schemaWithDef)).toDeepEqual([ { message: 'Query root type must be provided.', locations: [{ line: 2, column: 7 }], @@ -228,7 +229,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Query root type must be Object type, it cannot be Query.', locations: [{ line: 2, column: 7 }], @@ -244,7 +245,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schemaWithDef)).to.deep.equal([ + expectJSON(validateSchema(schemaWithDef)).toDeepEqual([ { message: 'Query root type must be Object type, it cannot be SomeInputObject.', @@ -263,7 +264,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Mutation root type must be Object type if provided, it cannot be Mutation.', @@ -285,7 +286,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schemaWithDef)).to.deep.equal([ + expectJSON(validateSchema(schemaWithDef)).toDeepEqual([ { message: 'Mutation root type must be Object type if provided, it cannot be SomeInputObject.', @@ -304,7 +305,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Subscription root type must be Object type if provided, it cannot be Subscription.', @@ -326,7 +327,7 @@ describe('Type System: A Schema must have Object root types', () => { test: String } `); - expect(validateSchema(schemaWithDef)).to.deep.equal([ + expectJSON(validateSchema(schemaWithDef)).toDeepEqual([ { message: 'Subscription root type must be Object type if provided, it cannot be SomeInputObject.', @@ -335,7 +336,7 @@ describe('Type System: A Schema must have Object root types', () => { ]); }); - it('rejects a schema extended with invalid root types', () => { + it('rejects a Schema extended with invalid root types', () => { let schema = buildSchema(` input SomeInputObject { test: String @@ -369,7 +370,7 @@ describe('Type System: A Schema must have Object root types', () => { `), ); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Query root type must be Object type, it cannot be SomeInputObject.', @@ -391,10 +392,10 @@ describe('Type System: A Schema must have Object root types', () => { it('rejects a Schema whose types are incorrectly typed', () => { const schema = new GraphQLSchema({ query: SomeObjectType, - // $FlowExpectedError[incompatible-call] + // @ts-expect-error types: [{ name: 'SomeType' }, SomeDirective], }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Expected GraphQL named type but got: { name: "SomeType" }.', }, @@ -408,10 +409,10 @@ describe('Type System: A Schema must have Object root types', () => { it('rejects a Schema whose directives are incorrectly typed', () => { const schema = new GraphQLSchema({ query: SomeObjectType, - // $FlowExpectedError[incompatible-call] + // @ts-expect-error directives: [null, 'SomeDirective', SomeScalarType], }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Expected directive but got: null.', }, @@ -424,6 +425,23 @@ describe('Type System: A Schema must have Object root types', () => { }, ]); }); + + it('rejects a Schema whose directives have empty locations', () => { + const badDirective = new GraphQLDirective({ + name: 'BadDirective', + args: {}, + locations: [], + }); + const schema = new GraphQLSchema({ + query: SomeObjectType, + directives: [badDirective], + }); + expectJSON(validateSchema(schema)).toDeepEqual([ + { + message: 'Directive @BadDirective must include 1 or more locations.', + }, + ]); + }); }); describe('Type System: Objects must have fields', () => { @@ -437,7 +455,7 @@ describe('Type System: Objects must have fields', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Object type with missing fields', () => { @@ -448,7 +466,7 @@ describe('Type System: Objects must have fields', () => { type IncompleteObject `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type IncompleteObject must define one or more fields.', locations: [{ line: 6, column: 7 }], @@ -461,7 +479,7 @@ describe('Type System: Objects must have fields', () => { fields: {}, }), ); - expect(validateSchema(manualSchema)).to.deep.equal([ + expectJSON(validateSchema(manualSchema)).toDeepEqual([ { message: 'Type IncompleteObject must define one or more fields.', }, @@ -475,7 +493,7 @@ describe('Type System: Objects must have fields', () => { }, }), ); - expect(validateSchema(manualSchema2)).to.deep.equal([ + expectJSON(validateSchema(manualSchema2)).toDeepEqual([ { message: 'Type IncompleteObject must define one or more fields.', }, @@ -486,13 +504,15 @@ describe('Type System: Objects must have fields', () => { const schema = schemaWithFieldType( new GraphQLObjectType({ name: 'SomeObject', - fields: { 'bad-name-with-dashes': { type: GraphQLString } }, + fields: { + __badName: { type: GraphQLString }, + }, }), ); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "bad-name-with-dashes" does not.', + 'Name "__badName" must not begin with "__", which is reserved by GraphQL introspection.', }, ]); }); @@ -513,7 +533,7 @@ describe('Type System: Fields args must be properly named', () => { }, }), ); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects field arg with invalid names', () => { @@ -524,17 +544,17 @@ describe('Type System: Fields args must be properly named', () => { badField: { type: GraphQLString, args: { - 'bad-name-with-dashes': { type: GraphQLString }, + __badName: { type: GraphQLString }, }, }, }, }), ); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "bad-name-with-dashes" does not.', + 'Name "__badName" must not begin with "__", which is reserved by GraphQL introspection.', }, ]); }); @@ -559,7 +579,7 @@ describe('Type System: Union types must be valid', () => { | TypeA | TypeB `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects a Union type with empty types', () => { @@ -580,7 +600,7 @@ describe('Type System: Union types must be valid', () => { `), ); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Union type BadUnion must define one or more member types.', locations: [ @@ -611,7 +631,7 @@ describe('Type System: Union types must be valid', () => { | TypeA `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Union type BadUnion can only include type TypeA once.', locations: [ @@ -623,7 +643,7 @@ describe('Type System: Union types must be valid', () => { schema = extendSchema(schema, parse('extend union BadUnion = TypeB')); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Union type BadUnion can only include type TypeA once.', locations: [ @@ -663,7 +683,7 @@ describe('Type System: Union types must be valid', () => { schema = extendSchema(schema, parse('extend union BadUnion = Int')); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Union type BadUnion can only include Object types, it cannot include String.', @@ -688,11 +708,11 @@ describe('Type System: Union types must be valid', () => { for (const memberType of badUnionMemberTypes) { const badUnion = new GraphQLUnionType({ name: 'BadUnion', - // $FlowExpectedError[incompatible-call] + // @ts-expect-error types: [memberType], }); const badSchema = schemaWithFieldType(badUnion); - expect(validateSchema(badSchema)).to.deep.equal([ + expectJSON(validateSchema(badSchema)).toDeepEqual([ { message: 'Union type BadUnion can only include Object types, ' + @@ -714,7 +734,7 @@ describe('Type System: Input Objects must have fields', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Input Object type with missing fields', () => { @@ -735,7 +755,7 @@ describe('Type System: Input Objects must have fields', () => { `), ); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Input Object type SomeInputObject must define one or more fields.', @@ -766,7 +786,7 @@ describe('Type System: Input Objects must have fields', () => { } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Input Object with non-breakable circular reference', () => { @@ -780,7 +800,7 @@ describe('Type System: Input Objects must have fields', () => { } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "nonNullSelf".', @@ -808,7 +828,7 @@ describe('Type System: Input Objects must have fields', () => { } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "startLoop.nextInLoop.closeLoop".', @@ -842,7 +862,7 @@ describe('Type System: Input Objects must have fields', () => { } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "startLoop.closeLoop".', @@ -885,7 +905,7 @@ describe('Type System: Input Objects must have fields', () => { goodInputObject: SomeInputObject } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of SomeInputObject.badObject must be Input Type but got: SomeObject.', @@ -911,7 +931,7 @@ describe('Type System: Input Objects must have fields', () => { anotherOptionalField: String! = "" @deprecated } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Required input field SomeInputObject.badField cannot be deprecated.', @@ -943,7 +963,7 @@ describe('Type System: Enum types must be well defined', () => { `), ); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Enum type SomeEnum must define one or more values.', locations: [ @@ -955,59 +975,27 @@ describe('Type System: Enum types must be well defined', () => { }); it('rejects an Enum type with incorrectly named values', () => { - function schemaWithEnum(values: GraphQLEnumValueConfigMap): GraphQLSchema { - return schemaWithFieldType( - new GraphQLEnumType({ - name: 'SomeEnum', - values, - }), - ); - } - - const schema1 = schemaWithEnum({ '#value': {} }); - expect(validateSchema(schema1)).to.deep.equal([ - { - message: - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "#value" does not.', - }, - ]); - - const schema2 = schemaWithEnum({ '1value': {} }); - expect(validateSchema(schema2)).to.deep.equal([ - { - message: - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "1value" does not.', - }, - ]); + const schema = schemaWithFieldType( + new GraphQLEnumType({ + name: 'SomeEnum', + values: { + __badName: {}, + }, + }), + ); - const schema3 = schemaWithEnum({ 'KEBAB-CASE': {} }); - expect(validateSchema(schema3)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "KEBAB-CASE" does not.', + 'Name "__badName" must not begin with "__", which is reserved by GraphQL introspection.', }, ]); - - const schema4 = schemaWithEnum({ true: {} }); - expect(validateSchema(schema4)).to.deep.equal([ - { message: 'Enum type SomeEnum cannot include value: true.' }, - ]); - - const schema5 = schemaWithEnum({ false: {} }); - expect(validateSchema(schema5)).to.deep.equal([ - { message: 'Enum type SomeEnum cannot include value: false.' }, - ]); - - const schema6 = schemaWithEnum({ null: {} }); - expect(validateSchema(schema6)).to.deep.equal([ - { message: 'Enum type SomeEnum cannot include value: null.' }, - ]); }); }); describe('Type System: Object fields must have output types', () => { function schemaWithObjectField( - fieldConfig: GraphQLFieldConfig, + fieldConfig: GraphQLFieldConfig, ): GraphQLSchema { const BadObjectType = new GraphQLObjectType({ name: 'BadObject', @@ -1031,14 +1019,14 @@ describe('Type System: Object fields must have output types', () => { const typeName = inspect(type); it(`accepts an output type as an Object field type: ${typeName}`, () => { const schema = schemaWithObjectField({ type }); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); } it('rejects an empty Object field type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (type field must not be undefined) const schema = schemaWithObjectField({ type: undefined }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of BadObject.badField must be Output Type but got: undefined.', @@ -1049,9 +1037,9 @@ describe('Type System: Object fields must have output types', () => { for (const type of notOutputTypes) { const typeStr = inspect(type); it(`rejects a non-output type as an Object field type: ${typeStr}`, () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithObjectField({ type }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: `The type of BadObject.badField must be Output Type but got: ${typeStr}.`, }, @@ -1060,9 +1048,9 @@ describe('Type System: Object fields must have output types', () => { } it('rejects a non-type value as an Object field type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithObjectField({ type: Number }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of BadObject.badField must be Output Type but got: [function Number].', @@ -1083,7 +1071,7 @@ describe('Type System: Object fields must have output types', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of Query.field must be Output Type but got: [SomeInputObject].', @@ -1094,17 +1082,17 @@ describe('Type System: Object fields must have output types', () => { }); describe('Type System: Objects can only implement unique interfaces', () => { - it('rejects an Object implementing a non-type values', () => { + it('rejects an Object implementing a non-type value', () => { const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'BadObject', - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (interfaces must not contain undefined) interfaces: [undefined], fields: { f: { type: GraphQLString } }, }), }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type BadObject must only implement Interface types, it cannot implement undefined.', @@ -1126,7 +1114,7 @@ describe('Type System: Objects can only implement unique interfaces', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type BadObject must only implement Interface types, it cannot implement SomeInputObject.', @@ -1149,7 +1137,7 @@ describe('Type System: Objects can only implement unique interfaces', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type AnotherObject can only implement AnotherInterface once.', locations: [ @@ -1178,7 +1166,7 @@ describe('Type System: Objects can only implement unique interfaces', () => { schema, parse('extend type AnotherObject implements AnotherInterface'), ); - expect(validateSchema(extendedSchema)).to.deep.equal([ + expectJSON(validateSchema(extendedSchema)).toDeepEqual([ { message: 'Type AnotherObject can only implement AnotherInterface once.', locations: [ @@ -1217,7 +1205,7 @@ describe('Type System: Interface extensions should be valid', () => { } `), ); - expect(validateSchema(extendedSchema)).to.deep.equal([ + expectJSON(validateSchema(extendedSchema)).toDeepEqual([ { message: 'Interface field AnotherInterface.newField expected but AnotherObject does not provide it.', @@ -1256,7 +1244,7 @@ describe('Type System: Interface extensions should be valid', () => { } `), ); - expect(validateSchema(extendedSchema)).to.deep.equal([ + expectJSON(validateSchema(extendedSchema)).toDeepEqual([ { message: 'Interface field argument AnotherInterface.newField(test:) expected but AnotherObject.newField does not provide it.', @@ -1307,7 +1295,7 @@ describe('Type System: Interface extensions should be valid', () => { } `), ); - expect(validateSchema(extendedSchema)).to.deep.equal([ + expectJSON(validateSchema(extendedSchema)).toDeepEqual([ { message: 'Interface field AnotherInterface.newInterfaceField expects type NewInterface but AnotherObject.newInterfaceField is type MismatchingInterface.', @@ -1322,7 +1310,7 @@ describe('Type System: Interface extensions should be valid', () => { describe('Type System: Interface fields must have output types', () => { function schemaWithInterfaceField( - fieldConfig: GraphQLFieldConfig, + fieldConfig: GraphQLFieldConfig, ): GraphQLSchema { const fields = { badField: fieldConfig }; @@ -1352,14 +1340,14 @@ describe('Type System: Interface fields must have output types', () => { const typeName = inspect(type); it(`accepts an output type as an Interface field type: ${typeName}`, () => { const schema = schemaWithInterfaceField({ type }); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); } it('rejects an empty Interface field type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (type field must not be undefined) const schema = schemaWithInterfaceField({ type: undefined }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of BadImplementing.badField must be Output Type but got: undefined.', @@ -1374,9 +1362,9 @@ describe('Type System: Interface fields must have output types', () => { for (const type of notOutputTypes) { const typeStr = inspect(type); it(`rejects a non-output type as an Interface field type: ${typeStr}`, () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithInterfaceField({ type }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: `The type of BadImplementing.badField must be Output Type but got: ${typeStr}.`, }, @@ -1388,9 +1376,9 @@ describe('Type System: Interface fields must have output types', () => { } it('rejects a non-type value as an Interface field type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithInterfaceField({ type: Number }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of BadImplementing.badField must be Output Type but got: [function Number].', @@ -1423,7 +1411,7 @@ describe('Type System: Interface fields must have output types', () => { field: SomeInputObject } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of SomeInterface.field must be Output Type but got: SomeInputObject.', @@ -1447,7 +1435,7 @@ describe('Type System: Interface fields must have output types', () => { foo: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); }); @@ -1478,7 +1466,7 @@ describe('Type System: Arguments must have input types', () => { args: { badArg: argConfig, }, - locations: ['QUERY'], + locations: [DirectiveLocation.QUERY], }), ], }); @@ -1488,14 +1476,14 @@ describe('Type System: Arguments must have input types', () => { const typeName = inspect(type); it(`accepts an input type as a field arg type: ${typeName}`, () => { const schema = schemaWithArg({ type }); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); } it('rejects an empty field arg type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (type field must not be undefined) const schema = schemaWithArg({ type: undefined }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of @BadDirective(badArg:) must be Input Type but got: undefined.', @@ -1510,9 +1498,9 @@ describe('Type System: Arguments must have input types', () => { for (const type of notInputTypes) { const typeStr = inspect(type); it(`rejects a non-input type as a field arg type: ${typeStr}`, () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithArg({ type }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: `The type of @BadDirective(badArg:) must be Input Type but got: ${typeStr}.`, }, @@ -1524,9 +1512,9 @@ describe('Type System: Arguments must have input types', () => { } it('rejects a non-type value as a field arg type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithArg({ type: Number }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of @BadDirective(badArg:) must be Input Type but got: [function Number].', @@ -1541,7 +1529,7 @@ describe('Type System: Arguments must have input types', () => { ]); }); - it('rejects an required argument that is deprecated', () => { + it('rejects a required argument that is deprecated', () => { const schema = buildSchema(` directive @BadDirective( badArg: String! @deprecated @@ -1557,7 +1545,7 @@ describe('Type System: Arguments must have input types', () => { ): String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Required argument @BadDirective(badArg:) cannot be deprecated.', @@ -1586,7 +1574,7 @@ describe('Type System: Arguments must have input types', () => { foo: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of Query.test(arg:) must be Input Type but got: SomeObject.', @@ -1626,14 +1614,14 @@ describe('Type System: Input Object fields must have input types', () => { const typeName = inspect(type); it(`accepts an input type as an input field type: ${typeName}`, () => { const schema = schemaWithInputField({ type }); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); } it('rejects an empty input field type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (type field must not be undefined) const schema = schemaWithInputField({ type: undefined }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of BadInputObject.badField must be Input Type but got: undefined.', @@ -1644,9 +1632,9 @@ describe('Type System: Input Object fields must have input types', () => { for (const type of notInputTypes) { const typeStr = inspect(type); it(`rejects a non-input type as an input field type: ${typeStr}`, () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithInputField({ type }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: `The type of BadInputObject.badField must be Input Type but got: ${typeStr}.`, }, @@ -1655,9 +1643,9 @@ describe('Type System: Input Object fields must have input types', () => { } it('rejects a non-type value as an input field type', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error const schema = schemaWithInputField({ type: Number }); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of BadInputObject.badField must be Input Type but got: [function Number].', @@ -1682,7 +1670,7 @@ describe('Type System: Input Object fields must have input types', () => { bar: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'The type of SomeInputObject.foo must be Input Type but got: SomeObject.', @@ -1692,6 +1680,47 @@ describe('Type System: Input Object fields must have input types', () => { }); }); +describe('Type System: OneOf Input Object fields must be nullable', () => { + it('rejects non-nullable fields', () => { + const schema = buildSchema(` + type Query { + test(arg: SomeInputObject): String + } + + input SomeInputObject @oneOf { + a: String + b: String! + } + `); + expectJSON(validateSchema(schema)).toDeepEqual([ + { + message: 'OneOf input field SomeInputObject.b must be nullable.', + locations: [{ line: 8, column: 12 }], + }, + ]); + }); + + it('rejects fields with default values', () => { + const schema = buildSchema(` + type Query { + test(arg: SomeInputObject): String + } + + input SomeInputObject @oneOf { + a: String + b: String = "foo" + } + `); + expectJSON(validateSchema(schema)).toDeepEqual([ + { + message: + 'OneOf input field SomeInputObject.b cannot have a default value.', + locations: [{ line: 8, column: 9 }], + }, + ]); + }); +}); + describe('Objects must adhere to Interface they implement', () => { it('accepts an Object which implements an Interface', () => { const schema = buildSchema(` @@ -1707,7 +1736,7 @@ describe('Objects must adhere to Interface they implement', () => { field(input: String): String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('accepts an Object which implements an Interface along with more fields', () => { @@ -1725,7 +1754,7 @@ describe('Objects must adhere to Interface they implement', () => { anotherField: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('accepts an Object which implements an Interface field along with additional optional arguments', () => { @@ -1742,7 +1771,7 @@ describe('Objects must adhere to Interface they implement', () => { field(input: String, anotherInput: String): String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Object missing an Interface field', () => { @@ -1759,7 +1788,7 @@ describe('Objects must adhere to Interface they implement', () => { anotherField: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field AnotherInterface.field expected but AnotherObject does not provide it.', @@ -1785,7 +1814,7 @@ describe('Objects must adhere to Interface they implement', () => { field(input: String): Int } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field AnotherInterface.field expects type String but AnotherObject.field is type Int.', @@ -1814,7 +1843,7 @@ describe('Objects must adhere to Interface they implement', () => { field: B } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field AnotherInterface.field expects type A but AnotherObject.field is type B.', @@ -1840,7 +1869,7 @@ describe('Objects must adhere to Interface they implement', () => { field: AnotherObject } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('accepts an Object with a subtyped Interface field (union)', () => { @@ -1863,7 +1892,7 @@ describe('Objects must adhere to Interface they implement', () => { field: SomeObject } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Object missing an Interface argument', () => { @@ -1880,7 +1909,7 @@ describe('Objects must adhere to Interface they implement', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field argument AnotherInterface.field(input:) expected but AnotherObject.field does not provide it.', @@ -1906,7 +1935,7 @@ describe('Objects must adhere to Interface they implement', () => { field(input: Int): String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field argument AnotherInterface.field(input:) expects type String but AnotherObject.field(input:) is type Int.', @@ -1932,7 +1961,7 @@ describe('Objects must adhere to Interface they implement', () => { field(input: Int): Int } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field AnotherInterface.field expects type String but AnotherObject.field is type Int.', @@ -1971,7 +2000,7 @@ describe('Objects must adhere to Interface they implement', () => { ): String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Object field AnotherObject.field includes required argument requiredArg that is missing from the Interface field AnotherInterface.field.', @@ -1997,7 +2026,7 @@ describe('Objects must adhere to Interface they implement', () => { field: [String]! } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Object with a non-list Interface field list type', () => { @@ -2014,7 +2043,7 @@ describe('Objects must adhere to Interface they implement', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field AnotherInterface.field expects type [String] but AnotherObject.field is type String.', @@ -2040,7 +2069,7 @@ describe('Objects must adhere to Interface they implement', () => { field: [String] } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field AnotherInterface.field expects type String but AnotherObject.field is type [String].', @@ -2066,7 +2095,7 @@ describe('Objects must adhere to Interface they implement', () => { field: String! } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Object with a superset nullable Interface field type', () => { @@ -2083,7 +2112,7 @@ describe('Objects must adhere to Interface they implement', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field AnotherInterface.field expects type String! but AnotherObject.field is type String.', @@ -2113,7 +2142,7 @@ describe('Objects must adhere to Interface they implement', () => { field: String! } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type AnotherObject must implement SuperInterface because it is implemented by AnotherInterface.', @@ -2141,7 +2170,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field(input: String): String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('accepts an Interface which implements an Interface along with more fields', () => { @@ -2159,7 +2188,7 @@ describe('Interfaces must adhere to Interface they implement', () => { anotherField: String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('accepts an Interface which implements an Interface field along with additional optional arguments', () => { @@ -2176,7 +2205,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field(input: String, anotherInput: String): String } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Interface missing an Interface field', () => { @@ -2193,7 +2222,7 @@ describe('Interfaces must adhere to Interface they implement', () => { anotherField: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field ParentInterface.field expected but ChildInterface does not provide it.', @@ -2219,7 +2248,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field(input: String): Int } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field ParentInterface.field expects type String but ChildInterface.field is type Int.', @@ -2248,7 +2277,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: B } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field ParentInterface.field expects type A but ChildInterface.field is type B.', @@ -2274,7 +2303,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: ChildInterface } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('accepts an Interface with a subtyped Interface field (union)', () => { @@ -2297,7 +2326,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: SomeObject } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Interface implementing a non-Interface type', () => { @@ -2314,7 +2343,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type BadInterface must only implement Interface types, it cannot implement SomeInputObject.', @@ -2337,7 +2366,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field argument ParentInterface.field(input:) expected but ChildInterface.field does not provide it.', @@ -2363,7 +2392,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field(input: Int): String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field argument ParentInterface.field(input:) expects type String but ChildInterface.field(input:) is type Int.', @@ -2389,7 +2418,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field(input: Int): Int } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field ParentInterface.field expects type String but ChildInterface.field is type Int.', @@ -2428,7 +2457,7 @@ describe('Interfaces must adhere to Interface they implement', () => { ): String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Object field ChildInterface.field includes required argument requiredArg that is missing from the Interface field ParentInterface.field.', @@ -2454,7 +2483,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: [String]! } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Interface with a non-list Interface field list type', () => { @@ -2471,7 +2500,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field ParentInterface.field expects type [String] but ChildInterface.field is type String.', @@ -2497,7 +2526,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: [String] } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field ParentInterface.field expects type String but ChildInterface.field is type [String].', @@ -2523,7 +2552,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: String! } `); - expect(validateSchema(schema)).to.deep.equal([]); + expectJSON(validateSchema(schema)).toDeepEqual([]); }); it('rejects an Interface with a superset nullable Interface field type', () => { @@ -2540,7 +2569,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: String } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Interface field ParentInterface.field expects type String! but ChildInterface.field is type String.', @@ -2570,7 +2599,7 @@ describe('Interfaces must adhere to Interface they implement', () => { field: String! } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type ChildInterface must implement SuperInterface because it is implemented by ParentInterface.', @@ -2593,7 +2622,7 @@ describe('Interfaces must adhere to Interface they implement', () => { } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type FooInterface cannot implement itself because it would create a circular reference.', @@ -2617,7 +2646,7 @@ describe('Interfaces must adhere to Interface they implement', () => { } `); - expect(validateSchema(schema)).to.deep.equal([ + expectJSON(validateSchema(schema)).toDeepEqual([ { message: 'Type FooInterface cannot implement BarInterface because it would create a circular reference.', @@ -2639,7 +2668,7 @@ describe('Interfaces must adhere to Interface they implement', () => { }); describe('assertValidSchema', () => { - it('do not throw on valid schemas', () => { + it('does not throw on valid schemas', () => { const schema = buildSchema(` type Query { foo: String @@ -2648,7 +2677,7 @@ describe('assertValidSchema', () => { expect(() => assertValidSchema(schema)).to.not.throw(); }); - it('include multiple errors into a description', () => { + it('combines multiple errors', () => { const schema = buildSchema('type SomeType'); expect(() => assertValidSchema(schema)).to.throw(dedent` Query root type must be provided. diff --git a/src/type/assertName.ts b/src/type/assertName.ts new file mode 100644 index 0000000000..f4f96fda4e --- /dev/null +++ b/src/type/assertName.ts @@ -0,0 +1,45 @@ +import { devAssert } from '../jsutils/devAssert'; + +import { GraphQLError } from '../error/GraphQLError'; + +import { isNameContinue, isNameStart } from '../language/characterClasses'; + +/** + * Upholds the spec rules about naming. + */ +export function assertName(name: string): string { + devAssert(name != null, 'Must provide name.'); + devAssert(typeof name === 'string', 'Expected name to be a string.'); + + if (name.length === 0) { + throw new GraphQLError('Expected name to be a non-empty string.'); + } + + for (let i = 1; i < name.length; ++i) { + if (!isNameContinue(name.charCodeAt(i))) { + throw new GraphQLError( + `Names must only contain [_a-zA-Z0-9] but "${name}" does not.`, + ); + } + } + + if (!isNameStart(name.charCodeAt(0))) { + throw new GraphQLError( + `Names must start with [_a-zA-Z] but "${name}" does not.`, + ); + } + + return name; +} + +/** + * Upholds the spec rules about naming enum values. + * + * @internal + */ +export function assertEnumValueName(name: string): string { + if (name === 'true' || name === 'false' || name === 'null') { + throw new GraphQLError(`Enum values cannot be named: ${name}`); + } + return assertName(name); +} diff --git a/src/type/definition.d.ts b/src/type/definition.d.ts deleted file mode 100644 index 06799981f9..0000000000 --- a/src/type/definition.d.ts +++ /dev/null @@ -1,947 +0,0 @@ -// FIXME -/* eslint-disable import/no-cycle */ - -import { Maybe } from '../jsutils/Maybe'; - -import { PromiseOrValue } from '../jsutils/PromiseOrValue'; -import { Path } from '../jsutils/Path'; - -import { - ScalarTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - UnionTypeDefinitionNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, - InputObjectTypeDefinitionNode, - ObjectTypeExtensionNode, - InterfaceTypeExtensionNode, - OperationDefinitionNode, - FieldNode, - FragmentDefinitionNode, - ValueNode, - ScalarTypeExtensionNode, - UnionTypeExtensionNode, - EnumTypeExtensionNode, - InputObjectTypeExtensionNode, -} from '../language/ast'; - -import { GraphQLSchema } from './schema'; - -/** - * These are all of the possible kinds of types. - */ -export type GraphQLType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList - | GraphQLNonNull; - -export function isType(type: any): type is GraphQLType; - -export function assertType(type: any): GraphQLType; - -export function isScalarType(type: any): type is GraphQLScalarType; - -export function assertScalarType(type: any): GraphQLScalarType; - -export function isObjectType(type: any): type is GraphQLObjectType; - -export function assertObjectType(type: any): GraphQLObjectType; - -export function isInterfaceType(type: any): type is GraphQLInterfaceType; - -export function assertInterfaceType(type: any): GraphQLInterfaceType; - -export function isUnionType(type: any): type is GraphQLUnionType; - -export function assertUnionType(type: any): GraphQLUnionType; - -export function isEnumType(type: any): type is GraphQLEnumType; - -export function assertEnumType(type: any): GraphQLEnumType; - -export function isInputObjectType(type: any): type is GraphQLInputObjectType; - -export function assertInputObjectType(type: any): GraphQLInputObjectType; - -export function isListType(type: any): type is GraphQLList; - -export function assertListType(type: any): GraphQLList; - -export function isNonNullType(type: any): type is GraphQLNonNull; - -export function assertNonNullType(type: any): GraphQLNonNull; - -/** - * These types may be used as input types for arguments and directives. - */ -// TS_SPECIFIC: TS does not allow recursive type definitions, hence the `any`s -export type GraphQLInputType = - | GraphQLScalarType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList - | GraphQLNonNull< - | GraphQLScalarType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList - >; - -export function isInputType(type: any): type is GraphQLInputType; - -export function assertInputType(type: any): GraphQLInputType; - -/** - * These types may be used as output types as the result of fields. - */ -// TS_SPECIFIC: TS does not allow recursive type definitions, hence the `any`s -export type GraphQLOutputType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLList - | GraphQLNonNull< - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLList - >; - -export function isOutputType(type: any): type is GraphQLOutputType; - -export function assertOutputType(type: any): GraphQLOutputType; - -/** - * These types may describe types which may be leaf values. - */ -export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; - -export function isLeafType(type: any): type is GraphQLLeafType; - -export function assertLeafType(type: any): GraphQLLeafType; - -/** - * These types may describe the parent context of a selection set. - */ -export type GraphQLCompositeType = - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType; - -export function isCompositeType(type: any): type is GraphQLCompositeType; - -export function assertCompositeType(type: any): GraphQLCompositeType; - -/** - * These types may describe the parent context of a selection set. - */ -export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; - -export function isAbstractType(type: any): type is GraphQLAbstractType; - -export function assertAbstractType(type: any): GraphQLAbstractType; - -/** - * List Modifier - * - * A list is a kind of type marker, a wrapping type which points to another - * type. Lists are often created within the context of defining the fields - * of an object type. - * - * Example: - * - * const PersonType = new GraphQLObjectType({ - * name: 'Person', - * fields: () => ({ - * parents: { type: new GraphQLList(Person) }, - * children: { type: new GraphQLList(Person) }, - * }) - * }) - * - */ -interface GraphQLList { - readonly ofType: T; - toString: () => string; - toJSON: () => string; - inspect: () => string; -} - -interface _GraphQLList { - (type: T): GraphQLList; - new (type: T): GraphQLList; -} - -// eslint-disable-next-line @typescript-eslint/no-redeclare -export const GraphQLList: _GraphQLList; - -/** - * Non-Null Modifier - * - * A non-null is a kind of type marker, a wrapping type which points to another - * type. Non-null types enforce that their values are never null and can ensure - * an error is raised if this ever occurs during a request. It is useful for - * fields which you can make a strong guarantee on non-nullability, for example - * usually the id field of a database row will never be null. - * - * Example: - * - * const RowType = new GraphQLObjectType({ - * name: 'Row', - * fields: () => ({ - * id: { type: new GraphQLNonNull(GraphQLString) }, - * }) - * }) - * - * Note: the enforcement of non-nullability occurs within the executor. - */ -interface GraphQLNonNull { - readonly ofType: T; - toString: () => string; - toJSON: () => string; - inspect: () => string; -} - -interface _GraphQLNonNull { - (type: T): GraphQLNonNull; - new (type: T): GraphQLNonNull; -} - -// eslint-disable-next-line @typescript-eslint/no-redeclare -export const GraphQLNonNull: _GraphQLNonNull; - -export type GraphQLWrappingType = GraphQLList | GraphQLNonNull; - -export function isWrappingType(type: any): type is GraphQLWrappingType; - -export function assertWrappingType(type: any): GraphQLWrappingType; - -/** - * These types can all accept null as a value. - */ -export type GraphQLNullableType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList; - -export function isNullableType(type: any): type is GraphQLNullableType; - -export function assertNullableType(type: any): GraphQLNullableType; - -export function getNullableType(type: undefined): undefined; -export function getNullableType(type: T): T; -export function getNullableType( - // FIXME Disabled because of https://github.com/yaacovCR/graphql-tools-fork/issues/40#issuecomment-586671219 - // eslint-disable-next-line @typescript-eslint/unified-signatures - type: GraphQLNonNull, -): T; - -/** - * These named types do not include modifiers like List or NonNull. - */ -export type GraphQLNamedType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType; - -export function isNamedType(type: any): type is GraphQLNamedType; - -export function assertNamedType(type: any): GraphQLNamedType; - -export function getNamedType(type: undefined): undefined; -export function getNamedType(type: GraphQLType): GraphQLNamedType; - -/** - * Used while defining GraphQL types to allow for circular references in - * otherwise immutable type definitions. - */ -export type Thunk = (() => T) | T; - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLScalarTypeExtensions { - [attributeName: string]: any; -} - -/** - * Scalar Type Definition - * - * The leaf values of any request and input values to arguments are - * Scalars (or Enums) and are defined with a name and a series of functions - * used to parse input from ast or variables and to ensure validity. - * - * Example: - * - * const OddType = new GraphQLScalarType({ - * name: 'Odd', - * serialize(value) { - * return value % 2 === 1 ? value : null; - * } - * }); - * - */ -export class GraphQLScalarType { - name: string; - description: Maybe; - specifiedByUrl: Maybe; - serialize: GraphQLScalarSerializer; - parseValue: GraphQLScalarValueParser; - parseLiteral: GraphQLScalarLiteralParser; - extensions: Maybe>; - astNode: Maybe; - extensionASTNodes: Maybe>; - - constructor(config: Readonly>); - - toConfig(): GraphQLScalarTypeConfig & { - specifiedByUrl: Maybe; - serialize: GraphQLScalarSerializer; - parseValue: GraphQLScalarValueParser; - parseLiteral: GraphQLScalarLiteralParser; - extensions: Maybe>; - extensionASTNodes: ReadonlyArray; - }; - - toString(): string; - toJSON(): string; - inspect(): string; -} - -export type GraphQLScalarSerializer = ( - value: any, -) => Maybe; -export type GraphQLScalarValueParser = ( - value: any, -) => Maybe; -export type GraphQLScalarLiteralParser = ( - valueNode: ValueNode, - variables: Maybe<{ [key: string]: any }>, -) => Maybe; - -export interface GraphQLScalarTypeConfig { - name: string; - description?: Maybe; - specifiedByUrl?: Maybe; - // Serializes an internal value to include in a response. - serialize?: GraphQLScalarSerializer; - // Parses an externally provided value to use as an input. - parseValue?: GraphQLScalarValueParser; - // Parses an externally provided literal value to use as an input. - parseLiteral?: GraphQLScalarLiteralParser; - extensions?: Maybe>; - astNode?: Maybe; - extensionASTNodes?: Maybe>; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - * - * We've provided these template arguments because this is an open type and - * you may find them useful. - */ -export interface GraphQLObjectTypeExtensions<_TSource = any, _TContext = any> { - [attributeName: string]: any; -} - -/** - * Object Type Definition - * - * Almost all of the GraphQL types you define will be object types. Object types - * have a name, but most importantly describe their fields. - * - * Example: - * - * const AddressType = new GraphQLObjectType({ - * name: 'Address', - * fields: { - * street: { type: GraphQLString }, - * number: { type: GraphQLInt }, - * formatted: { - * type: GraphQLString, - * resolve(obj) { - * return obj.number + ' ' + obj.street - * } - * } - * } - * }); - * - * When two types need to refer to each other, or a type needs to refer to - * itself in a field, you can use a function expression (aka a closure or a - * thunk) to supply the fields lazily. - * - * Example: - * - * const PersonType = new GraphQLObjectType({ - * name: 'Person', - * fields: () => ({ - * name: { type: GraphQLString }, - * bestFriend: { type: PersonType }, - * }) - * }); - * - */ -export class GraphQLObjectType { - name: string; - description: Maybe; - isTypeOf: Maybe>; - extensions: Maybe>>; - astNode: Maybe; - extensionASTNodes: Maybe>; - - constructor(config: Readonly>); - - getFields(): GraphQLFieldMap; - getInterfaces(): Array; - - toConfig(): GraphQLObjectTypeConfig & { - interfaces: Array; - fields: GraphQLFieldConfigMap; - extensions: Maybe>>; - extensionASTNodes: ReadonlyArray; - }; - - toString(): string; - toJSON(): string; - inspect(): string; -} - -export function argsToArgsConfig( - args: ReadonlyArray, -): GraphQLFieldConfigArgumentMap; - -export interface GraphQLObjectTypeConfig { - name: string; - description?: Maybe; - interfaces?: Thunk>>; - fields: Thunk>; - isTypeOf?: Maybe>; - extensions?: Maybe>>; - astNode?: Maybe; - extensionASTNodes?: Maybe>; -} - -export type GraphQLTypeResolver = ( - value: TSource, - context: TContext, - info: GraphQLResolveInfo, - abstractType: GraphQLAbstractType, -) => PromiseOrValue | string>>; - -export type GraphQLIsTypeOfFn = ( - source: TSource, - context: TContext, - info: GraphQLResolveInfo, -) => PromiseOrValue; - -export type GraphQLFieldResolver< - TSource, - TContext, - TArgs = { [argName: string]: any } -> = ( - source: TSource, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo, -) => any; - -export interface GraphQLResolveInfo { - readonly fieldName: string; - readonly fieldNodes: ReadonlyArray; - readonly returnType: GraphQLOutputType; - readonly parentType: GraphQLObjectType; - readonly path: Path; - readonly schema: GraphQLSchema; - readonly fragments: { [key: string]: FragmentDefinitionNode }; - readonly rootValue: any; - readonly operation: OperationDefinitionNode; - readonly variableValues: { [variableName: string]: any }; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - * - * We've provided these template arguments because this is an open type and - * you may find them useful. - */ -export interface GraphQLFieldExtensions< - _TSource, - _TContext, - _TArgs = { [argName: string]: any } -> { - [attributeName: string]: any; -} - -export interface GraphQLFieldConfig< - TSource, - TContext, - TArgs = { [argName: string]: any } -> { - description?: Maybe; - type: GraphQLOutputType; - args?: GraphQLFieldConfigArgumentMap; - resolve?: GraphQLFieldResolver; - subscribe?: GraphQLFieldResolver; - deprecationReason?: Maybe; - extensions?: Maybe< - Readonly> - >; - astNode?: Maybe; -} - -export interface GraphQLFieldConfigArgumentMap { - [key: string]: GraphQLArgumentConfig; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLArgumentExtensions { - [attributeName: string]: any; -} - -export interface GraphQLArgumentConfig { - description?: Maybe; - type: GraphQLInputType; - defaultValue?: any; - deprecationReason?: Maybe; - extensions?: Maybe>; - astNode?: Maybe; -} - -export interface GraphQLFieldConfigMap { - [key: string]: GraphQLFieldConfig; -} - -export interface GraphQLField< - TSource, - TContext, - TArgs = { [key: string]: any } -> { - name: string; - description: Maybe; - type: GraphQLOutputType; - args: Array; - resolve?: GraphQLFieldResolver; - subscribe?: GraphQLFieldResolver; - deprecationReason: Maybe; - extensions: Maybe>>; - astNode?: Maybe; - - // @deprecated and will be removed in v16 - isDeprecated: boolean; -} - -export interface GraphQLArgument { - name: string; - description: Maybe; - type: GraphQLInputType; - defaultValue: any; - deprecationReason: Maybe; - extensions: Maybe>; - astNode: Maybe; -} - -export function isRequiredArgument(arg: GraphQLArgument): boolean; - -export interface GraphQLFieldMap { - [key: string]: GraphQLField; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLInterfaceTypeExtensions { - [attributeName: string]: any; -} - -/** - * Interface Type Definition - * - * When a field can return one of a heterogeneous set of types, a Interface type - * is used to describe what types are possible, what fields are in common across - * all types, as well as a function to determine which type is actually used - * when the field is resolved. - * - * Example: - * - * const EntityType = new GraphQLInterfaceType({ - * name: 'Entity', - * fields: { - * name: { type: GraphQLString } - * } - * }); - * - */ -export class GraphQLInterfaceType { - name: string; - description: Maybe; - resolveType: Maybe>; - extensions: Maybe>; - astNode?: Maybe; - extensionASTNodes: Maybe>; - - constructor(config: Readonly>); - getFields(): GraphQLFieldMap; - getInterfaces(): Array; - - toConfig(): GraphQLInterfaceTypeConfig & { - interfaces: Array; - fields: GraphQLFieldConfigMap; - extensions: Maybe>; - extensionASTNodes: ReadonlyArray; - }; - - toString(): string; - toJSON(): string; - inspect(): string; -} - -export interface GraphQLInterfaceTypeConfig { - name: string; - description?: Maybe; - interfaces?: Thunk>>; - fields: Thunk>; - /** - * Optionally provide a custom type resolver function. If one is not provided, - * the default implementation will call `isTypeOf` on each implementing - * Object type. - */ - resolveType?: Maybe>; - extensions?: Maybe>; - astNode?: Maybe; - extensionASTNodes?: Maybe>; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLUnionTypeExtensions { - [attributeName: string]: any; -} - -/** - * Union Type Definition - * - * When a field can return one of a heterogeneous set of types, a Union type - * is used to describe what types are possible as well as providing a function - * to determine which type is actually used when the field is resolved. - * - * Example: - * - * const PetType = new GraphQLUnionType({ - * name: 'Pet', - * types: [ DogType, CatType ], - * resolveType(value) { - * if (value instanceof Dog) { - * return DogType; - * } - * if (value instanceof Cat) { - * return CatType; - * } - * } - * }); - * - */ -export class GraphQLUnionType { - name: string; - description: Maybe; - resolveType: Maybe>; - extensions: Maybe>; - astNode: Maybe; - extensionASTNodes: Maybe>; - - constructor(config: Readonly>); - getTypes(): Array; - - toConfig(): GraphQLUnionTypeConfig & { - types: Array; - extensions: Maybe>; - extensionASTNodes: ReadonlyArray; - }; - - toString(): string; - toJSON(): string; - inspect(): string; -} - -export interface GraphQLUnionTypeConfig { - name: string; - description?: Maybe; - types: Thunk>; - /** - * Optionally provide a custom type resolver function. If one is not provided, - * the default implementation will call `isTypeOf` on each implementing - * Object type. - */ - resolveType?: Maybe>; - extensions?: Maybe>; - astNode?: Maybe; - extensionASTNodes?: Maybe>; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLEnumTypeExtensions { - [attributeName: string]: any; -} - -/** - * Enum Type Definition - * - * Some leaf values of requests and input values are Enums. GraphQL serializes - * Enum values as strings, however internally Enums can be represented by any - * kind of type, often integers. - * - * Example: - * - * const RGBType = new GraphQLEnumType({ - * name: 'RGB', - * values: { - * RED: { value: 0 }, - * GREEN: { value: 1 }, - * BLUE: { value: 2 } - * } - * }); - * - * Note: If a value is not provided in a definition, the name of the enum value - * will be used as its internal value. - */ -export class GraphQLEnumType { - name: string; - description: Maybe; - extensions: Maybe>; - astNode: Maybe; - extensionASTNodes: Maybe>; - - constructor(config: Readonly); - getValues(): Array; - getValue(name: string): Maybe; - serialize(value: any): Maybe; - parseValue(value: any): Maybe; - parseLiteral( - valueNode: ValueNode, - _variables: Maybe<{ [key: string]: any }>, - ): Maybe; - - toConfig(): GraphQLEnumTypeConfig & { - extensions: Maybe>; - extensionASTNodes: ReadonlyArray; - }; - - toString(): string; - toJSON(): string; - inspect(): string; -} - -export interface GraphQLEnumTypeConfig { - name: string; - description?: Maybe; - values: GraphQLEnumValueConfigMap; - extensions?: Maybe>; - astNode?: Maybe; - extensionASTNodes?: Maybe>; -} - -export interface GraphQLEnumValueConfigMap { - [key: string]: GraphQLEnumValueConfig; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLEnumValueExtensions { - [attributeName: string]: any; -} - -export interface GraphQLEnumValueConfig { - description?: Maybe; - value?: any; - deprecationReason?: Maybe; - extensions?: Maybe>; - astNode?: Maybe; -} - -export interface GraphQLEnumValue { - name: string; - description: Maybe; - value: any; - deprecationReason: Maybe; - extensions: Maybe>; - astNode?: Maybe; - - // @deprecated and will be removed in v16 - isDeprecated: boolean; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLInputObjectTypeExtensions { - [attributeName: string]: any; -} - -/** - * Input Object Type Definition - * - * An input object defines a structured collection of fields which may be - * supplied to a field argument. - * - * Using `NonNull` will ensure that a value must be provided by the query - * - * Example: - * - * const GeoPoint = new GraphQLInputObjectType({ - * name: 'GeoPoint', - * fields: { - * lat: { type: new GraphQLNonNull(GraphQLFloat) }, - * lon: { type: new GraphQLNonNull(GraphQLFloat) }, - * alt: { type: GraphQLFloat, defaultValue: 0 }, - * } - * }); - * - */ -export class GraphQLInputObjectType { - name: string; - description: Maybe; - extensions: Maybe>; - astNode: Maybe; - extensionASTNodes: Maybe>; - - constructor(config: Readonly); - getFields(): GraphQLInputFieldMap; - - toConfig(): GraphQLInputObjectTypeConfig & { - fields: GraphQLInputFieldConfigMap; - extensions: Maybe>; - extensionASTNodes: ReadonlyArray; - }; - - toString(): string; - toJSON(): string; - inspect(): string; -} - -export interface GraphQLInputObjectTypeConfig { - name: string; - description?: Maybe; - fields: Thunk; - extensions?: Maybe>; - astNode?: Maybe; - extensionASTNodes?: Maybe>; -} - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLInputFieldExtensions { - [attributeName: string]: any; -} - -export interface GraphQLInputFieldConfig { - description?: Maybe; - type: GraphQLInputType; - defaultValue?: any; - deprecationReason?: Maybe; - extensions?: Maybe>; - astNode?: Maybe; -} - -export interface GraphQLInputFieldConfigMap { - [key: string]: GraphQLInputFieldConfig; -} - -export interface GraphQLInputField { - name: string; - description?: Maybe; - type: GraphQLInputType; - defaultValue?: any; - deprecationReason: Maybe; - extensions: Maybe>; - astNode?: Maybe; -} - -export function isRequiredInputField(field: GraphQLInputField): boolean; - -export interface GraphQLInputFieldMap { - [key: string]: GraphQLInputField; -} diff --git a/src/type/definition.js b/src/type/definition.js deleted file mode 100644 index f8d25ac11c..0000000000 --- a/src/type/definition.js +++ /dev/null @@ -1,1649 +0,0 @@ -import objectEntries from '../polyfills/objectEntries'; -import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols'; - -import type { Path } from '../jsutils/Path'; -import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; -import type { - ObjMap, - ReadOnlyObjMap, - ReadOnlyObjMapLike, -} from '../jsutils/ObjMap'; -import inspect from '../jsutils/inspect'; -import keyMap from '../jsutils/keyMap'; -import mapValue from '../jsutils/mapValue'; -import toObjMap from '../jsutils/toObjMap'; -import devAssert from '../jsutils/devAssert'; -import keyValMap from '../jsutils/keyValMap'; -import instanceOf from '../jsutils/instanceOf'; -import didYouMean from '../jsutils/didYouMean'; -import isObjectLike from '../jsutils/isObjectLike'; -import identityFunc from '../jsutils/identityFunc'; -import defineInspect from '../jsutils/defineInspect'; -import suggestionList from '../jsutils/suggestionList'; - -import { GraphQLError } from '../error/GraphQLError'; - -import { Kind } from '../language/kinds'; -import { print } from '../language/printer'; -import type { - ScalarTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - UnionTypeDefinitionNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, - InputObjectTypeDefinitionNode, - ScalarTypeExtensionNode, - ObjectTypeExtensionNode, - InterfaceTypeExtensionNode, - UnionTypeExtensionNode, - EnumTypeExtensionNode, - InputObjectTypeExtensionNode, - OperationDefinitionNode, - FieldNode, - FragmentDefinitionNode, - ValueNode, -} from '../language/ast'; - -import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped'; - -import type { GraphQLSchema } from './schema'; - -// Predicates & Assertions - -/** - * These are all of the possible kinds of types. - */ -export type GraphQLType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList - | GraphQLNonNull; - -export function isType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isObjectType(type) || - isInterfaceType(type) || - isUnionType(type) || - isEnumType(type) || - isInputObjectType(type) || - isListType(type) || - isNonNullType(type) - ); -} - -export function assertType(type: mixed): GraphQLType { - if (!isType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`); - } - return type; -} - -/** - * There are predicates for each kind of GraphQL type. - */ - -declare function isScalarType(type: mixed): boolean %checks(type instanceof - GraphQLScalarType); -// eslint-disable-next-line no-redeclare -export function isScalarType(type) { - return instanceOf(type, GraphQLScalarType); -} - -export function assertScalarType(type: mixed): GraphQLScalarType { - if (!isScalarType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`); - } - return type; -} - -declare function isObjectType(type: mixed): boolean %checks(type instanceof - GraphQLObjectType); -// eslint-disable-next-line no-redeclare -export function isObjectType(type) { - return instanceOf(type, GraphQLObjectType); -} - -export function assertObjectType(type: mixed): GraphQLObjectType { - if (!isObjectType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`); - } - return type; -} - -declare function isInterfaceType(type: mixed): boolean %checks(type instanceof - GraphQLInterfaceType); -// eslint-disable-next-line no-redeclare -export function isInterfaceType(type) { - return instanceOf(type, GraphQLInterfaceType); -} - -export function assertInterfaceType(type: mixed): GraphQLInterfaceType { - if (!isInterfaceType(type)) { - throw new Error( - `Expected ${inspect(type)} to be a GraphQL Interface type.`, - ); - } - return type; -} - -declare function isUnionType(type: mixed): boolean %checks(type instanceof - GraphQLUnionType); -// eslint-disable-next-line no-redeclare -export function isUnionType(type) { - return instanceOf(type, GraphQLUnionType); -} - -export function assertUnionType(type: mixed): GraphQLUnionType { - if (!isUnionType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`); - } - return type; -} - -declare function isEnumType(type: mixed): boolean %checks(type instanceof - GraphQLEnumType); -// eslint-disable-next-line no-redeclare -export function isEnumType(type) { - return instanceOf(type, GraphQLEnumType); -} - -export function assertEnumType(type: mixed): GraphQLEnumType { - if (!isEnumType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`); - } - return type; -} - -declare function isInputObjectType(type: mixed): boolean %checks(type instanceof - GraphQLInputObjectType); -// eslint-disable-next-line no-redeclare -export function isInputObjectType(type) { - return instanceOf(type, GraphQLInputObjectType); -} - -export function assertInputObjectType(type: mixed): GraphQLInputObjectType { - if (!isInputObjectType(type)) { - throw new Error( - `Expected ${inspect(type)} to be a GraphQL Input Object type.`, - ); - } - return type; -} - -declare function isListType(type: mixed): boolean %checks(type instanceof - GraphQLList); -// eslint-disable-next-line no-redeclare -export function isListType(type) { - return instanceOf(type, GraphQLList); -} - -export function assertListType(type: mixed): GraphQLList { - if (!isListType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`); - } - return type; -} - -declare function isNonNullType(type: mixed): boolean %checks(type instanceof - GraphQLNonNull); -// eslint-disable-next-line no-redeclare -export function isNonNullType(type) { - return instanceOf(type, GraphQLNonNull); -} - -export function assertNonNullType(type: mixed): GraphQLNonNull { - if (!isNonNullType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`); - } - return type; -} - -/** - * These types may be used as input types for arguments and directives. - */ -export type GraphQLInputType = - | GraphQLScalarType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList - | GraphQLNonNull< - | GraphQLScalarType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList, - >; - -export function isInputType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isEnumType(type) || - isInputObjectType(type) || - (isWrappingType(type) && isInputType(type.ofType)) - ); -} - -export function assertInputType(type: mixed): GraphQLInputType { - if (!isInputType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL input type.`); - } - return type; -} - -/** - * These types may be used as output types as the result of fields. - */ -export type GraphQLOutputType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLList - | GraphQLNonNull< - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLList, - >; - -export function isOutputType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isObjectType(type) || - isInterfaceType(type) || - isUnionType(type) || - isEnumType(type) || - (isWrappingType(type) && isOutputType(type.ofType)) - ); -} - -export function assertOutputType(type: mixed): GraphQLOutputType { - if (!isOutputType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`); - } - return type; -} - -/** - * These types may describe types which may be leaf values. - */ -export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; - -export function isLeafType(type: mixed): boolean %checks { - return isScalarType(type) || isEnumType(type); -} - -export function assertLeafType(type: mixed): GraphQLLeafType { - if (!isLeafType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`); - } - return type; -} - -/** - * These types may describe the parent context of a selection set. - */ -export type GraphQLCompositeType = - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType; - -export function isCompositeType(type: mixed): boolean %checks { - return isObjectType(type) || isInterfaceType(type) || isUnionType(type); -} - -export function assertCompositeType(type: mixed): GraphQLCompositeType { - if (!isCompositeType(type)) { - throw new Error( - `Expected ${inspect(type)} to be a GraphQL composite type.`, - ); - } - return type; -} - -/** - * These types may describe the parent context of a selection set. - */ -export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; - -export function isAbstractType(type: mixed): boolean %checks { - return isInterfaceType(type) || isUnionType(type); -} - -export function assertAbstractType(type: mixed): GraphQLAbstractType { - if (!isAbstractType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL abstract type.`); - } - return type; -} - -/** - * List Type Wrapper - * - * A list is a wrapping type which points to another type. - * Lists are often created within the context of defining the fields of - * an object type. - * - * Example: - * - * const PersonType = new GraphQLObjectType({ - * name: 'Person', - * fields: () => ({ - * parents: { type: new GraphQLList(PersonType) }, - * children: { type: new GraphQLList(PersonType) }, - * }) - * }) - * - */ -// FIXME: workaround to fix issue with Babel parser -/* :: -declare class GraphQLList<+T: GraphQLType> { - +ofType: T; - static (ofType: T): GraphQLList; - // Note: constructors cannot be used for covariant types. Drop the "new". - constructor(ofType: GraphQLType): void; -} -*/ - -export function GraphQLList(ofType) { - // istanbul ignore else (to be removed in v16.0.0) - if (this instanceof GraphQLList) { - this.ofType = assertType(ofType); - } else { - return new GraphQLList(ofType); - } -} - -// Need to cast through any to alter the prototype. -(GraphQLList.prototype: any).toString = function toString() { - return '[' + String(this.ofType) + ']'; -}; - -(GraphQLList.prototype: any).toJSON = function toJSON() { - return this.toString(); -}; - -Object.defineProperty(GraphQLList.prototype, SYMBOL_TO_STRING_TAG, { - get() { - return 'GraphQLList'; - }, -}); - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLList); - -/** - * Non-Null Type Wrapper - * - * A non-null is a wrapping type which points to another type. - * Non-null types enforce that their values are never null and can ensure - * an error is raised if this ever occurs during a request. It is useful for - * fields which you can make a strong guarantee on non-nullability, for example - * usually the id field of a database row will never be null. - * - * Example: - * - * const RowType = new GraphQLObjectType({ - * name: 'Row', - * fields: () => ({ - * id: { type: new GraphQLNonNull(GraphQLString) }, - * }) - * }) - * - * Note: the enforcement of non-nullability occurs within the executor. - */ -// FIXME: workaround to fix issue with Babel parser -/* :: -declare class GraphQLNonNull<+T: GraphQLNullableType> { - +ofType: T; - static (ofType: T): GraphQLNonNull; - // Note: constructors cannot be used for covariant types. Drop the "new". - constructor(ofType: GraphQLType): void; -} -*/ - -export function GraphQLNonNull(ofType) { - // istanbul ignore else (to be removed in v16.0.0) - if (this instanceof GraphQLNonNull) { - this.ofType = assertNullableType(ofType); - } else { - return new GraphQLNonNull(ofType); - } -} - -// Need to cast through any to alter the prototype. -(GraphQLNonNull.prototype: any).toString = function toString() { - return String(this.ofType) + '!'; -}; - -(GraphQLNonNull.prototype: any).toJSON = function toJSON() { - return this.toString(); -}; - -Object.defineProperty(GraphQLNonNull.prototype, SYMBOL_TO_STRING_TAG, { - get() { - return 'GraphQLNonNull'; - }, -}); - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLNonNull); - -/** - * These types wrap and modify other types - */ - -export type GraphQLWrappingType = GraphQLList | GraphQLNonNull; - -export function isWrappingType(type: mixed): boolean %checks { - return isListType(type) || isNonNullType(type); -} - -export function assertWrappingType(type: mixed): GraphQLWrappingType { - if (!isWrappingType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`); - } - return type; -} - -/** - * These types can all accept null as a value. - */ -export type GraphQLNullableType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList; - -export function isNullableType(type: mixed): boolean %checks { - return isType(type) && !isNonNullType(type); -} - -export function assertNullableType(type: mixed): GraphQLNullableType { - if (!isNullableType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`); - } - return type; -} - -/* eslint-disable no-redeclare */ -declare function getNullableType(type: void | null): void; -declare function getNullableType(type: T): T; -declare function getNullableType(type: GraphQLNonNull): T; -export function getNullableType(type) { - /* eslint-enable no-redeclare */ - if (type) { - return isNonNullType(type) ? type.ofType : type; - } -} - -/** - * These named types do not include modifiers like List or NonNull. - */ -export type GraphQLNamedType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType; - -export function isNamedType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isObjectType(type) || - isInterfaceType(type) || - isUnionType(type) || - isEnumType(type) || - isInputObjectType(type) - ); -} - -export function assertNamedType(type: mixed): GraphQLNamedType { - if (!isNamedType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`); - } - return type; -} - -/* eslint-disable no-redeclare */ -declare function getNamedType(type: void | null): void; -declare function getNamedType(type: GraphQLType): GraphQLNamedType; -export function getNamedType(type) { - /* eslint-enable no-redeclare */ - if (type) { - let unwrappedType = type; - while (isWrappingType(unwrappedType)) { - unwrappedType = unwrappedType.ofType; - } - return unwrappedType; - } -} - -/** - * Used while defining GraphQL types to allow for circular references in - * otherwise immutable type definitions. - */ -export type Thunk<+T> = (() => T) | T; - -function resolveThunk<+T>(thunk: Thunk): T { - // $FlowFixMe[incompatible-use] - return typeof thunk === 'function' ? thunk() : thunk; -} - -function undefineIfEmpty(arr: ?$ReadOnlyArray): ?$ReadOnlyArray { - return arr && arr.length > 0 ? arr : undefined; -} - -/** - * Scalar Type Definition - * - * The leaf values of any request and input values to arguments are - * Scalars (or Enums) and are defined with a name and a series of functions - * used to parse input from ast or variables and to ensure validity. - * - * If a type's serialize function does not return a value (i.e. it returns - * `undefined`) then an error will be raised and a `null` value will be returned - * in the response. If the serialize function returns `null`, then no error will - * be included in the response. - * - * Example: - * - * const OddType = new GraphQLScalarType({ - * name: 'Odd', - * serialize(value) { - * if (value % 2 === 1) { - * return value; - * } - * } - * }); - * - */ -export class GraphQLScalarType { - name: string; - description: ?string; - specifiedByUrl: ?string; - serialize: GraphQLScalarSerializer; - parseValue: GraphQLScalarValueParser; - parseLiteral: GraphQLScalarLiteralParser; - extensions: ?ReadOnlyObjMap; - astNode: ?ScalarTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - constructor(config: $ReadOnly>) { - const parseValue = config.parseValue ?? identityFunc; - this.name = config.name; - this.description = config.description; - this.specifiedByUrl = config.specifiedByUrl; - this.serialize = config.serialize ?? identityFunc; - this.parseValue = parseValue; - this.parseLiteral = - config.parseLiteral ?? - ((node, variables) => parseValue(valueFromASTUntyped(node, variables))); - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - devAssert(typeof config.name === 'string', 'Must provide name.'); - - devAssert( - config.specifiedByUrl == null || - typeof config.specifiedByUrl === 'string', - `${this.name} must provide "specifiedByUrl" as a string, ` + - `but got: ${inspect(config.specifiedByUrl)}.`, - ); - - devAssert( - config.serialize == null || typeof config.serialize === 'function', - `${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`, - ); - - if (config.parseLiteral) { - devAssert( - typeof config.parseValue === 'function' && - typeof config.parseLiteral === 'function', - `${this.name} must provide both "parseValue" and "parseLiteral" functions.`, - ); - } - } - - toConfig(): GraphQLScalarTypeNormalizedConfig { - return { - name: this.name, - description: this.description, - specifiedByUrl: this.specifiedByUrl, - serialize: this.serialize, - parseValue: this.parseValue, - parseLiteral: this.parseLiteral, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLScalarType'; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLScalarType); - -export type GraphQLScalarSerializer = ( - outputValue: mixed, -) => ?TExternal; - -export type GraphQLScalarValueParser = ( - inputValue: mixed, -) => ?TInternal; - -export type GraphQLScalarLiteralParser = ( - valueNode: ValueNode, - variables: ?ObjMap, -) => ?TInternal; - -export type GraphQLScalarTypeConfig = {| - name: string, - description?: ?string, - specifiedByUrl?: ?string, - // Serializes an internal value to include in a response. - serialize?: GraphQLScalarSerializer, - // Parses an externally provided value to use as an input. - parseValue?: GraphQLScalarValueParser, - // Parses an externally provided literal value to use as an input. - parseLiteral?: GraphQLScalarLiteralParser, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?ScalarTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -type GraphQLScalarTypeNormalizedConfig = {| - ...GraphQLScalarTypeConfig, - serialize: GraphQLScalarSerializer, - parseValue: GraphQLScalarValueParser, - parseLiteral: GraphQLScalarLiteralParser, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, -|}; - -/** - * Object Type Definition - * - * Almost all of the GraphQL types you define will be object types. Object types - * have a name, but most importantly describe their fields. - * - * Example: - * - * const AddressType = new GraphQLObjectType({ - * name: 'Address', - * fields: { - * street: { type: GraphQLString }, - * number: { type: GraphQLInt }, - * formatted: { - * type: GraphQLString, - * resolve(obj) { - * return obj.number + ' ' + obj.street - * } - * } - * } - * }); - * - * When two types need to refer to each other, or a type needs to refer to - * itself in a field, you can use a function expression (aka a closure or a - * thunk) to supply the fields lazily. - * - * Example: - * - * const PersonType = new GraphQLObjectType({ - * name: 'Person', - * fields: () => ({ - * name: { type: GraphQLString }, - * bestFriend: { type: PersonType }, - * }) - * }); - * - */ -export class GraphQLObjectType { - name: string; - description: ?string; - isTypeOf: ?GraphQLIsTypeOfFn; - extensions: ?ReadOnlyObjMap; - astNode: ?ObjectTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _fields: Thunk>; - _interfaces: Thunk>; - - constructor(config: $ReadOnly>) { - this.name = config.name; - this.description = config.description; - this.isTypeOf = config.isTypeOf; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._fields = defineFieldMap.bind(undefined, config); - this._interfaces = defineInterfaces.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert( - config.isTypeOf == null || typeof config.isTypeOf === 'function', - `${this.name} must provide "isTypeOf" as a function, ` + - `but got: ${inspect(config.isTypeOf)}.`, - ); - } - - getFields(): GraphQLFieldMap { - if (typeof this._fields === 'function') { - this._fields = this._fields(); - } - return this._fields; - } - - getInterfaces(): Array { - if (typeof this._interfaces === 'function') { - this._interfaces = this._interfaces(); - } - return this._interfaces; - } - - toConfig(): GraphQLObjectTypeNormalizedConfig { - return { - name: this.name, - description: this.description, - interfaces: this.getInterfaces(), - fields: fieldsToFieldsConfig(this.getFields()), - isTypeOf: this.isTypeOf, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes || [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLObjectType'; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLObjectType); - -function defineInterfaces( - config: $ReadOnly< - | GraphQLObjectTypeConfig - | GraphQLInterfaceTypeConfig, - >, -): Array { - const interfaces = resolveThunk(config.interfaces) ?? []; - devAssert( - Array.isArray(interfaces), - `${config.name} interfaces must be an Array or a function which returns an Array.`, - ); - return interfaces; -} - -function defineFieldMap( - config: $ReadOnly< - | GraphQLObjectTypeConfig - | GraphQLInterfaceTypeConfig, - >, -): GraphQLFieldMap { - const fieldMap = resolveThunk(config.fields); - devAssert( - isPlainObj(fieldMap), - `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, - ); - - return mapValue(fieldMap, (fieldConfig, fieldName) => { - devAssert( - isPlainObj(fieldConfig), - `${config.name}.${fieldName} field config must be an object.`, - ); - devAssert( - !('isDeprecated' in fieldConfig), - `${config.name}.${fieldName} should provide "deprecationReason" instead of "isDeprecated".`, - ); - devAssert( - fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', - `${config.name}.${fieldName} field resolver must be a function if ` + - `provided, but got: ${inspect(fieldConfig.resolve)}.`, - ); - - const argsConfig = fieldConfig.args ?? {}; - devAssert( - isPlainObj(argsConfig), - `${config.name}.${fieldName} args must be an object with argument names as keys.`, - ); - - const args = objectEntries(argsConfig).map(([argName, argConfig]) => ({ - name: argName, - description: argConfig.description, - type: argConfig.type, - defaultValue: argConfig.defaultValue, - deprecationReason: argConfig.deprecationReason, - extensions: argConfig.extensions && toObjMap(argConfig.extensions), - astNode: argConfig.astNode, - })); - - return { - name: fieldName, - description: fieldConfig.description, - type: fieldConfig.type, - args, - resolve: fieldConfig.resolve, - subscribe: fieldConfig.subscribe, - isDeprecated: fieldConfig.deprecationReason != null, - deprecationReason: fieldConfig.deprecationReason, - extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), - astNode: fieldConfig.astNode, - }; - }); -} - -function isPlainObj(obj: mixed): boolean { - return isObjectLike(obj) && !Array.isArray(obj); -} - -function fieldsToFieldsConfig( - fields: GraphQLFieldMap, -): GraphQLFieldConfigMap { - return mapValue(fields, (field) => ({ - description: field.description, - type: field.type, - args: argsToArgsConfig(field.args), - resolve: field.resolve, - subscribe: field.subscribe, - deprecationReason: field.deprecationReason, - extensions: field.extensions, - astNode: field.astNode, - })); -} - -/** - * @internal - */ -export function argsToArgsConfig( - args: $ReadOnlyArray, -): GraphQLFieldConfigArgumentMap { - return keyValMap( - args, - (arg) => arg.name, - (arg) => ({ - description: arg.description, - type: arg.type, - defaultValue: arg.defaultValue, - deprecationReason: arg.deprecationReason, - extensions: arg.extensions, - astNode: arg.astNode, - }), - ); -} - -export type GraphQLObjectTypeConfig = {| - name: string, - description?: ?string, - interfaces?: Thunk>, - fields: Thunk>, - isTypeOf?: ?GraphQLIsTypeOfFn, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?ObjectTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -type GraphQLObjectTypeNormalizedConfig = {| - ...GraphQLObjectTypeConfig, - interfaces: Array, - fields: GraphQLFieldConfigMap, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, -|}; - -/** - * Note: returning GraphQLObjectType is deprecated and will be removed in v16.0.0 - */ -export type GraphQLTypeResolver = ( - value: TSource, - context: TContext, - info: GraphQLResolveInfo, - abstractType: GraphQLAbstractType, -) => PromiseOrValue; - -export type GraphQLIsTypeOfFn = ( - source: TSource, - context: TContext, - info: GraphQLResolveInfo, -) => PromiseOrValue; - -export type GraphQLFieldResolver< - TSource, - TContext, - TArgs = { [argument: string]: any, ... }, -> = ( - source: TSource, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo, -) => mixed; - -export type GraphQLResolveInfo = {| - +fieldName: string, - +fieldNodes: $ReadOnlyArray, - +returnType: GraphQLOutputType, - +parentType: GraphQLObjectType, - +path: Path, - +schema: GraphQLSchema, - +fragments: ObjMap, - +rootValue: mixed, - +operation: OperationDefinitionNode, - +variableValues: { [variable: string]: mixed, ... }, -|}; - -export type GraphQLFieldConfig< - TSource, - TContext, - TArgs = { [argument: string]: any, ... }, -> = {| - description?: ?string, - type: GraphQLOutputType, - args?: GraphQLFieldConfigArgumentMap, - resolve?: GraphQLFieldResolver, - subscribe?: GraphQLFieldResolver, - deprecationReason?: ?string, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?FieldDefinitionNode, -|}; - -export type GraphQLFieldConfigArgumentMap = ObjMap; - -export type GraphQLArgumentConfig = {| - description?: ?string, - type: GraphQLInputType, - defaultValue?: mixed, - extensions?: ?ReadOnlyObjMapLike, - deprecationReason?: ?string, - astNode?: ?InputValueDefinitionNode, -|}; - -export type GraphQLFieldConfigMap = ObjMap< - GraphQLFieldConfig, ->; - -export type GraphQLField< - TSource, - TContext, - TArgs = { [argument: string]: any, ... }, -> = {| - name: string, - description: ?string, - type: GraphQLOutputType, - args: Array, - resolve?: GraphQLFieldResolver, - subscribe?: GraphQLFieldResolver, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?FieldDefinitionNode, - - // @deprecated and will be removed in v16 - isDeprecated: boolean, -|}; - -export type GraphQLArgument = {| - name: string, - description: ?string, - type: GraphQLInputType, - defaultValue: mixed, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?InputValueDefinitionNode, -|}; - -export function isRequiredArgument(arg: GraphQLArgument): boolean %checks { - return isNonNullType(arg.type) && arg.defaultValue === undefined; -} - -export type GraphQLFieldMap = ObjMap< - GraphQLField, ->; - -/** - * Interface Type Definition - * - * When a field can return one of a heterogeneous set of types, a Interface type - * is used to describe what types are possible, what fields are in common across - * all types, as well as a function to determine which type is actually used - * when the field is resolved. - * - * Example: - * - * const EntityType = new GraphQLInterfaceType({ - * name: 'Entity', - * fields: { - * name: { type: GraphQLString } - * } - * }); - * - */ -export class GraphQLInterfaceType { - name: string; - description: ?string; - resolveType: ?GraphQLTypeResolver; - extensions: ?ReadOnlyObjMap; - astNode: ?InterfaceTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _fields: Thunk>; - _interfaces: Thunk>; - - constructor(config: $ReadOnly>) { - this.name = config.name; - this.description = config.description; - this.resolveType = config.resolveType; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._fields = defineFieldMap.bind(undefined, config); - this._interfaces = defineInterfaces.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert( - config.resolveType == null || typeof config.resolveType === 'function', - `${this.name} must provide "resolveType" as a function, ` + - `but got: ${inspect(config.resolveType)}.`, - ); - } - - getFields(): GraphQLFieldMap { - if (typeof this._fields === 'function') { - this._fields = this._fields(); - } - return this._fields; - } - - getInterfaces(): Array { - if (typeof this._interfaces === 'function') { - this._interfaces = this._interfaces(); - } - return this._interfaces; - } - - toConfig(): GraphQLInterfaceTypeNormalizedConfig { - return { - name: this.name, - description: this.description, - interfaces: this.getInterfaces(), - fields: fieldsToFieldsConfig(this.getFields()), - resolveType: this.resolveType, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLInterfaceType'; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLInterfaceType); - -export type GraphQLInterfaceTypeConfig = {| - name: string, - description?: ?string, - interfaces?: Thunk>, - fields: Thunk>, - /** - * Optionally provide a custom type resolver function. If one is not provided, - * the default implementation will call `isTypeOf` on each implementing - * Object type. - */ - resolveType?: ?GraphQLTypeResolver, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?InterfaceTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -export type GraphQLInterfaceTypeNormalizedConfig = {| - ...GraphQLInterfaceTypeConfig, - interfaces: Array, - fields: GraphQLFieldConfigMap, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, -|}; - -/** - * Union Type Definition - * - * When a field can return one of a heterogeneous set of types, a Union type - * is used to describe what types are possible as well as providing a function - * to determine which type is actually used when the field is resolved. - * - * Example: - * - * const PetType = new GraphQLUnionType({ - * name: 'Pet', - * types: [ DogType, CatType ], - * resolveType(value) { - * if (value instanceof Dog) { - * return DogType; - * } - * if (value instanceof Cat) { - * return CatType; - * } - * } - * }); - * - */ -export class GraphQLUnionType { - name: string; - description: ?string; - resolveType: ?GraphQLTypeResolver; - extensions: ?ReadOnlyObjMap; - astNode: ?UnionTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _types: Thunk>; - - constructor(config: $ReadOnly>) { - this.name = config.name; - this.description = config.description; - this.resolveType = config.resolveType; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._types = defineTypes.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert( - config.resolveType == null || typeof config.resolveType === 'function', - `${this.name} must provide "resolveType" as a function, ` + - `but got: ${inspect(config.resolveType)}.`, - ); - } - - getTypes(): Array { - if (typeof this._types === 'function') { - this._types = this._types(); - } - return this._types; - } - - toConfig(): GraphQLUnionTypeNormalizedConfig { - return { - name: this.name, - description: this.description, - types: this.getTypes(), - resolveType: this.resolveType, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLUnionType'; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLUnionType); - -function defineTypes( - config: $ReadOnly>, -): Array { - const types = resolveThunk(config.types); - devAssert( - Array.isArray(types), - `Must provide Array of types or a function which returns such an array for Union ${config.name}.`, - ); - return types; -} - -export type GraphQLUnionTypeConfig = {| - name: string, - description?: ?string, - types: Thunk>, - /** - * Optionally provide a custom type resolver function. If one is not provided, - * the default implementation will call `isTypeOf` on each implementing - * Object type. - */ - resolveType?: ?GraphQLTypeResolver, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?UnionTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -type GraphQLUnionTypeNormalizedConfig = {| - ...GraphQLUnionTypeConfig, - types: Array, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, -|}; - -/** - * Enum Type Definition - * - * Some leaf values of requests and input values are Enums. GraphQL serializes - * Enum values as strings, however internally Enums can be represented by any - * kind of type, often integers. - * - * Example: - * - * const RGBType = new GraphQLEnumType({ - * name: 'RGB', - * values: { - * RED: { value: 0 }, - * GREEN: { value: 1 }, - * BLUE: { value: 2 } - * } - * }); - * - * Note: If a value is not provided in a definition, the name of the enum value - * will be used as its internal value. - */ -export class GraphQLEnumType /* */ { - name: string; - description: ?string; - extensions: ?ReadOnlyObjMap; - astNode: ?EnumTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _values: Array */>; - _valueLookup: Map; - _nameLookup: ObjMap; - - constructor(config: $ReadOnly */>) { - this.name = config.name; - this.description = config.description; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._values = defineEnumValues(this.name, config.values); - this._valueLookup = new Map( - this._values.map((enumValue) => [enumValue.value, enumValue]), - ); - this._nameLookup = keyMap(this._values, (value) => value.name); - - devAssert(typeof config.name === 'string', 'Must provide name.'); - } - - getValues(): Array */> { - return this._values; - } - - getValue(name: string): ?GraphQLEnumValue { - return this._nameLookup[name]; - } - - serialize(outputValue: mixed /* T */): ?string { - const enumValue = this._valueLookup.get(outputValue); - if (enumValue === undefined) { - throw new GraphQLError( - `Enum "${this.name}" cannot represent value: ${inspect(outputValue)}`, - ); - } - return enumValue.name; - } - - parseValue(inputValue: mixed): ?any /* T */ { - if (typeof inputValue !== 'string') { - const valueStr = inspect(inputValue); - throw new GraphQLError( - `Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + - didYouMeanEnumValue(this, valueStr), - ); - } - - const enumValue = this.getValue(inputValue); - if (enumValue == null) { - throw new GraphQLError( - `Value "${inputValue}" does not exist in "${this.name}" enum.` + - didYouMeanEnumValue(this, inputValue), - ); - } - return enumValue.value; - } - - parseLiteral(valueNode: ValueNode, _variables: ?ObjMap): ?any /* T */ { - // Note: variables will be resolved to a value before calling this function. - if (valueNode.kind !== Kind.ENUM) { - const valueStr = print(valueNode); - throw new GraphQLError( - `Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + - didYouMeanEnumValue(this, valueStr), - valueNode, - ); - } - - const enumValue = this.getValue(valueNode.value); - if (enumValue == null) { - const valueStr = print(valueNode); - throw new GraphQLError( - `Value "${valueStr}" does not exist in "${this.name}" enum.` + - didYouMeanEnumValue(this, valueStr), - valueNode, - ); - } - return enumValue.value; - } - - toConfig(): GraphQLEnumTypeNormalizedConfig { - const values = keyValMap( - this.getValues(), - (value) => value.name, - (value) => ({ - description: value.description, - value: value.value, - deprecationReason: value.deprecationReason, - extensions: value.extensions, - astNode: value.astNode, - }), - ); - - return { - name: this.name, - description: this.description, - values, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLEnumType'; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLEnumType); - -function didYouMeanEnumValue( - enumType: GraphQLEnumType, - unknownValueStr: string, -): string { - const allNames = enumType.getValues().map((value) => value.name); - const suggestedValues = suggestionList(unknownValueStr, allNames); - - return didYouMean('the enum value', suggestedValues); -} - -function defineEnumValues( - typeName: string, - valueMap: GraphQLEnumValueConfigMap /* */, -): Array */> { - devAssert( - isPlainObj(valueMap), - `${typeName} values must be an object with value names as keys.`, - ); - return objectEntries(valueMap).map(([valueName, valueConfig]) => { - devAssert( - isPlainObj(valueConfig), - `${typeName}.${valueName} must refer to an object with a "value" key ` + - `representing an internal value but got: ${inspect(valueConfig)}.`, - ); - devAssert( - !('isDeprecated' in valueConfig), - `${typeName}.${valueName} should provide "deprecationReason" instead of "isDeprecated".`, - ); - return { - name: valueName, - description: valueConfig.description, - value: valueConfig.value !== undefined ? valueConfig.value : valueName, - isDeprecated: valueConfig.deprecationReason != null, - deprecationReason: valueConfig.deprecationReason, - extensions: valueConfig.extensions && toObjMap(valueConfig.extensions), - astNode: valueConfig.astNode, - }; - }); -} - -export type GraphQLEnumTypeConfig /* */ = {| - name: string, - description?: ?string, - values: GraphQLEnumValueConfigMap /* */, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?EnumTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -type GraphQLEnumTypeNormalizedConfig = {| - ...GraphQLEnumTypeConfig, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, -|}; - -export type GraphQLEnumValueConfigMap /* */ = ObjMap */>; - -export type GraphQLEnumValueConfig /* */ = {| - description?: ?string, - value?: any /* T */, - deprecationReason?: ?string, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?EnumValueDefinitionNode, -|}; - -export type GraphQLEnumValue /* */ = {| - name: string, - description: ?string, - value: any /* T */, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?EnumValueDefinitionNode, - - // @deprecated and will be removed in v16 - isDeprecated: boolean, -|}; - -/** - * Input Object Type Definition - * - * An input object defines a structured collection of fields which may be - * supplied to a field argument. - * - * Using `NonNull` will ensure that a value must be provided by the query - * - * Example: - * - * const GeoPoint = new GraphQLInputObjectType({ - * name: 'GeoPoint', - * fields: { - * lat: { type: new GraphQLNonNull(GraphQLFloat) }, - * lon: { type: new GraphQLNonNull(GraphQLFloat) }, - * alt: { type: GraphQLFloat, defaultValue: 0 }, - * } - * }); - * - */ -export class GraphQLInputObjectType { - name: string; - description: ?string; - extensions: ?ReadOnlyObjMap; - astNode: ?InputObjectTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _fields: Thunk; - - constructor(config: $ReadOnly) { - this.name = config.name; - this.description = config.description; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._fields = defineInputFieldMap.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - } - - getFields(): GraphQLInputFieldMap { - if (typeof this._fields === 'function') { - this._fields = this._fields(); - } - return this._fields; - } - - toConfig(): GraphQLInputObjectTypeNormalizedConfig { - const fields = mapValue(this.getFields(), (field) => ({ - description: field.description, - type: field.type, - defaultValue: field.defaultValue, - extensions: field.extensions, - astNode: field.astNode, - })); - - return { - name: this.name, - description: this.description, - fields, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLInputObjectType'; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLInputObjectType); - -function defineInputFieldMap( - config: $ReadOnly, -): GraphQLInputFieldMap { - const fieldMap = resolveThunk(config.fields); - devAssert( - isPlainObj(fieldMap), - `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, - ); - return mapValue(fieldMap, (fieldConfig, fieldName) => { - devAssert( - !('resolve' in fieldConfig), - `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`, - ); - - return { - name: fieldName, - description: fieldConfig.description, - type: fieldConfig.type, - defaultValue: fieldConfig.defaultValue, - deprecationReason: fieldConfig.deprecationReason, - extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), - astNode: fieldConfig.astNode, - }; - }); -} - -export type GraphQLInputObjectTypeConfig = {| - name: string, - description?: ?string, - fields: Thunk, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?InputObjectTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -type GraphQLInputObjectTypeNormalizedConfig = {| - ...GraphQLInputObjectTypeConfig, - fields: GraphQLInputFieldConfigMap, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, -|}; - -export type GraphQLInputFieldConfig = {| - description?: ?string, - type: GraphQLInputType, - defaultValue?: mixed, - deprecationReason?: ?string, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?InputValueDefinitionNode, -|}; - -export type GraphQLInputFieldConfigMap = ObjMap; - -export type GraphQLInputField = {| - name: string, - description: ?string, - type: GraphQLInputType, - defaultValue: mixed, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?InputValueDefinitionNode, -|}; - -export function isRequiredInputField( - field: GraphQLInputField, -): boolean %checks { - return isNonNullType(field.type) && field.defaultValue === undefined; -} - -export type GraphQLInputFieldMap = ObjMap; diff --git a/src/type/definition.ts b/src/type/definition.ts new file mode 100644 index 0000000000..7eaac560dc --- /dev/null +++ b/src/type/definition.ts @@ -0,0 +1,1767 @@ +import { devAssert } from '../jsutils/devAssert'; +import { didYouMean } from '../jsutils/didYouMean'; +import { identityFunc } from '../jsutils/identityFunc'; +import { inspect } from '../jsutils/inspect'; +import { instanceOf } from '../jsutils/instanceOf'; +import { isObjectLike } from '../jsutils/isObjectLike'; +import { keyMap } from '../jsutils/keyMap'; +import { keyValMap } from '../jsutils/keyValMap'; +import { mapValue } from '../jsutils/mapValue'; +import type { Maybe } from '../jsutils/Maybe'; +import type { ObjMap } from '../jsutils/ObjMap'; +import type { Path } from '../jsutils/Path'; +import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; +import { suggestionList } from '../jsutils/suggestionList'; +import { toObjMap } from '../jsutils/toObjMap'; + +import { GraphQLError } from '../error/GraphQLError'; + +import type { + EnumTypeDefinitionNode, + EnumTypeExtensionNode, + EnumValueDefinitionNode, + FieldDefinitionNode, + FieldNode, + FragmentDefinitionNode, + InputObjectTypeDefinitionNode, + InputObjectTypeExtensionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + InterfaceTypeExtensionNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, + OperationDefinitionNode, + ScalarTypeDefinitionNode, + ScalarTypeExtensionNode, + UnionTypeDefinitionNode, + UnionTypeExtensionNode, + ValueNode, +} from '../language/ast'; +import { Kind } from '../language/kinds'; +import { print } from '../language/printer'; + +import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped'; + +import { assertEnumValueName, assertName } from './assertName'; +import type { GraphQLSchema } from './schema'; + +// Predicates & Assertions + +/** + * These are all of the possible kinds of types. + */ +export type GraphQLType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList + | GraphQLNonNull< + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList + >; + +export function isType(type: unknown): type is GraphQLType { + return ( + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + isInputObjectType(type) || + isListType(type) || + isNonNullType(type) + ); +} + +export function assertType(type: unknown): GraphQLType { + if (!isType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`); + } + return type; +} + +/** + * There are predicates for each kind of GraphQL type. + */ +export function isScalarType(type: unknown): type is GraphQLScalarType { + return instanceOf(type, GraphQLScalarType); +} + +export function assertScalarType(type: unknown): GraphQLScalarType { + if (!isScalarType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`); + } + return type; +} + +export function isObjectType(type: unknown): type is GraphQLObjectType { + return instanceOf(type, GraphQLObjectType); +} + +export function assertObjectType(type: unknown): GraphQLObjectType { + if (!isObjectType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`); + } + return type; +} + +export function isInterfaceType(type: unknown): type is GraphQLInterfaceType { + return instanceOf(type, GraphQLInterfaceType); +} + +export function assertInterfaceType(type: unknown): GraphQLInterfaceType { + if (!isInterfaceType(type)) { + throw new Error( + `Expected ${inspect(type)} to be a GraphQL Interface type.`, + ); + } + return type; +} + +export function isUnionType(type: unknown): type is GraphQLUnionType { + return instanceOf(type, GraphQLUnionType); +} + +export function assertUnionType(type: unknown): GraphQLUnionType { + if (!isUnionType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`); + } + return type; +} + +export function isEnumType(type: unknown): type is GraphQLEnumType { + return instanceOf(type, GraphQLEnumType); +} + +export function assertEnumType(type: unknown): GraphQLEnumType { + if (!isEnumType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`); + } + return type; +} + +export function isInputObjectType( + type: unknown, +): type is GraphQLInputObjectType { + return instanceOf(type, GraphQLInputObjectType); +} + +export function assertInputObjectType(type: unknown): GraphQLInputObjectType { + if (!isInputObjectType(type)) { + throw new Error( + `Expected ${inspect(type)} to be a GraphQL Input Object type.`, + ); + } + return type; +} + +export function isListType( + type: GraphQLInputType, +): type is GraphQLList; +export function isListType( + type: GraphQLOutputType, +): type is GraphQLList; +export function isListType(type: unknown): type is GraphQLList; +export function isListType(type: unknown): type is GraphQLList { + return instanceOf(type, GraphQLList); +} + +export function assertListType(type: unknown): GraphQLList { + if (!isListType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`); + } + return type; +} + +export function isNonNullType( + type: GraphQLInputType, +): type is GraphQLNonNull; +export function isNonNullType( + type: GraphQLOutputType, +): type is GraphQLNonNull; +export function isNonNullType( + type: unknown, +): type is GraphQLNonNull; +export function isNonNullType( + type: unknown, +): type is GraphQLNonNull { + return instanceOf(type, GraphQLNonNull); +} + +export function assertNonNullType(type: unknown): GraphQLNonNull { + if (!isNonNullType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`); + } + return type; +} + +/** + * These types may be used as input types for arguments and directives. + */ +export type GraphQLInputType = + | GraphQLScalarType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList + | GraphQLNonNull< + | GraphQLScalarType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList + >; + +export function isInputType(type: unknown): type is GraphQLInputType { + return ( + isScalarType(type) || + isEnumType(type) || + isInputObjectType(type) || + (isWrappingType(type) && isInputType(type.ofType)) + ); +} + +export function assertInputType(type: unknown): GraphQLInputType { + if (!isInputType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL input type.`); + } + return type; +} + +/** + * These types may be used as output types as the result of fields. + */ +export type GraphQLOutputType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLList + | GraphQLNonNull< + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLList + >; + +export function isOutputType(type: unknown): type is GraphQLOutputType { + return ( + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + (isWrappingType(type) && isOutputType(type.ofType)) + ); +} + +export function assertOutputType(type: unknown): GraphQLOutputType { + if (!isOutputType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`); + } + return type; +} + +/** + * These types may describe types which may be leaf values. + */ +export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; + +export function isLeafType(type: unknown): type is GraphQLLeafType { + return isScalarType(type) || isEnumType(type); +} + +export function assertLeafType(type: unknown): GraphQLLeafType { + if (!isLeafType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`); + } + return type; +} + +/** + * These types may describe the parent context of a selection set. + */ +export type GraphQLCompositeType = + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType; + +export function isCompositeType(type: unknown): type is GraphQLCompositeType { + return isObjectType(type) || isInterfaceType(type) || isUnionType(type); +} + +export function assertCompositeType(type: unknown): GraphQLCompositeType { + if (!isCompositeType(type)) { + throw new Error( + `Expected ${inspect(type)} to be a GraphQL composite type.`, + ); + } + return type; +} + +/** + * These types may describe the parent context of a selection set. + */ +export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; + +export function isAbstractType(type: unknown): type is GraphQLAbstractType { + return isInterfaceType(type) || isUnionType(type); +} + +export function assertAbstractType(type: unknown): GraphQLAbstractType { + if (!isAbstractType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL abstract type.`); + } + return type; +} + +/** + * List Type Wrapper + * + * A list is a wrapping type which points to another type. + * Lists are often created within the context of defining the fields of + * an object type. + * + * Example: + * + * ```ts + * const PersonType = new GraphQLObjectType({ + * name: 'Person', + * fields: () => ({ + * parents: { type: new GraphQLList(PersonType) }, + * children: { type: new GraphQLList(PersonType) }, + * }) + * }) + * ``` + */ +export class GraphQLList { + readonly ofType: T; + + constructor(ofType: T) { + devAssert( + isType(ofType), + `Expected ${inspect(ofType)} to be a GraphQL type.`, + ); + + this.ofType = ofType; + } + + get [Symbol.toStringTag]() { + return 'GraphQLList'; + } + + toString(): string { + return '[' + String(this.ofType) + ']'; + } + + toJSON(): string { + return this.toString(); + } +} + +/** + * Non-Null Type Wrapper + * + * A non-null is a wrapping type which points to another type. + * Non-null types enforce that their values are never null and can ensure + * an error is raised if this ever occurs during a request. It is useful for + * fields which you can make a strong guarantee on non-nullability, for example + * usually the id field of a database row will never be null. + * + * Example: + * + * ```ts + * const RowType = new GraphQLObjectType({ + * name: 'Row', + * fields: () => ({ + * id: { type: new GraphQLNonNull(GraphQLString) }, + * }) + * }) + * ``` + * Note: the enforcement of non-nullability occurs within the executor. + */ +export class GraphQLNonNull { + readonly ofType: T; + + constructor(ofType: T) { + devAssert( + isNullableType(ofType), + `Expected ${inspect(ofType)} to be a GraphQL nullable type.`, + ); + + this.ofType = ofType; + } + + get [Symbol.toStringTag]() { + return 'GraphQLNonNull'; + } + + toString(): string { + return String(this.ofType) + '!'; + } + + toJSON(): string { + return this.toString(); + } +} + +/** + * These types wrap and modify other types + */ + +export type GraphQLWrappingType = + | GraphQLList + | GraphQLNonNull; + +export function isWrappingType(type: unknown): type is GraphQLWrappingType { + return isListType(type) || isNonNullType(type); +} + +export function assertWrappingType(type: unknown): GraphQLWrappingType { + if (!isWrappingType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`); + } + return type; +} + +/** + * These types can all accept null as a value. + */ +export type GraphQLNullableType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList; + +export function isNullableType(type: unknown): type is GraphQLNullableType { + return isType(type) && !isNonNullType(type); +} + +export function assertNullableType(type: unknown): GraphQLNullableType { + if (!isNullableType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`); + } + return type; +} + +export function getNullableType(type: undefined | null): void; +export function getNullableType( + type: T | GraphQLNonNull, +): T; +export function getNullableType( + type: Maybe, +): GraphQLNullableType | undefined; +export function getNullableType( + type: Maybe, +): GraphQLNullableType | undefined { + if (type) { + return isNonNullType(type) ? type.ofType : type; + } +} + +/** + * These named types do not include modifiers like List or NonNull. + */ +export type GraphQLNamedType = GraphQLNamedInputType | GraphQLNamedOutputType; + +export type GraphQLNamedInputType = + | GraphQLScalarType + | GraphQLEnumType + | GraphQLInputObjectType; + +export type GraphQLNamedOutputType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType; + +export function isNamedType(type: unknown): type is GraphQLNamedType { + return ( + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + isInputObjectType(type) + ); +} + +export function assertNamedType(type: unknown): GraphQLNamedType { + if (!isNamedType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`); + } + return type; +} + +export function getNamedType(type: undefined | null): void; +export function getNamedType(type: GraphQLInputType): GraphQLNamedInputType; +export function getNamedType(type: GraphQLOutputType): GraphQLNamedOutputType; +export function getNamedType(type: GraphQLType): GraphQLNamedType; +export function getNamedType( + type: Maybe, +): GraphQLNamedType | undefined; +export function getNamedType( + type: Maybe, +): GraphQLNamedType | undefined { + if (type) { + let unwrappedType = type; + while (isWrappingType(unwrappedType)) { + unwrappedType = unwrappedType.ofType; + } + return unwrappedType; + } +} + +/** + * Used while defining GraphQL types to allow for circular references in + * otherwise immutable type definitions. + */ +export type ThunkReadonlyArray = (() => ReadonlyArray) | ReadonlyArray; +export type ThunkObjMap = (() => ObjMap) | ObjMap; + +export function resolveReadonlyArrayThunk( + thunk: ThunkReadonlyArray, +): ReadonlyArray { + return typeof thunk === 'function' ? thunk() : thunk; +} + +export function resolveObjMapThunk(thunk: ThunkObjMap): ObjMap { + return typeof thunk === 'function' ? thunk() : thunk; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLScalarTypeExtensions { + [attributeName: string]: unknown; +} + +/** + * Scalar Type Definition + * + * The leaf values of any request and input values to arguments are + * Scalars (or Enums) and are defined with a name and a series of functions + * used to parse input from ast or variables and to ensure validity. + * + * If a type's serialize function returns `null` or does not return a value + * (i.e. it returns `undefined`) then an error will be raised and a `null` + * value will be returned in the response. It is always better to validate + * + * Example: + * + * ```ts + * const OddType = new GraphQLScalarType({ + * name: 'Odd', + * serialize(value) { + * if (!Number.isFinite(value)) { + * throw new Error( + * `Scalar "Odd" cannot represent "${value}" since it is not a finite number.`, + * ); + * } + * + * if (value % 2 === 0) { + * throw new Error(`Scalar "Odd" cannot represent "${value}" since it is even.`); + * } + * return value; + * } + * }); + * ``` + */ +export class GraphQLScalarType { + name: string; + description: Maybe; + specifiedByURL: Maybe; + serialize: GraphQLScalarSerializer; + parseValue: GraphQLScalarValueParser; + parseLiteral: GraphQLScalarLiteralParser; + extensions: Readonly; + astNode: Maybe; + extensionASTNodes: ReadonlyArray; + + constructor(config: Readonly>) { + const parseValue = + config.parseValue ?? + (identityFunc as GraphQLScalarValueParser); + + this.name = assertName(config.name); + this.description = config.description; + this.specifiedByURL = config.specifiedByURL; + this.serialize = + config.serialize ?? (identityFunc as GraphQLScalarSerializer); + this.parseValue = parseValue; + this.parseLiteral = + config.parseLiteral ?? + ((node, variables) => parseValue(valueFromASTUntyped(node, variables))); + this.extensions = toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = config.extensionASTNodes ?? []; + + devAssert( + config.specifiedByURL == null || + typeof config.specifiedByURL === 'string', + `${this.name} must provide "specifiedByURL" as a string, ` + + `but got: ${inspect(config.specifiedByURL)}.`, + ); + + devAssert( + config.serialize == null || typeof config.serialize === 'function', + `${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`, + ); + + if (config.parseLiteral) { + devAssert( + typeof config.parseValue === 'function' && + typeof config.parseLiteral === 'function', + `${this.name} must provide both "parseValue" and "parseLiteral" functions.`, + ); + } + } + + get [Symbol.toStringTag]() { + return 'GraphQLScalarType'; + } + + toConfig(): GraphQLScalarTypeNormalizedConfig { + return { + name: this.name, + description: this.description, + specifiedByURL: this.specifiedByURL, + serialize: this.serialize, + parseValue: this.parseValue, + parseLiteral: this.parseLiteral, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes, + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } +} + +export type GraphQLScalarSerializer = ( + outputValue: unknown, +) => TExternal; + +export type GraphQLScalarValueParser = ( + inputValue: unknown, +) => TInternal; + +export type GraphQLScalarLiteralParser = ( + valueNode: ValueNode, + variables?: Maybe>, +) => TInternal; + +export interface GraphQLScalarTypeConfig { + name: string; + description?: Maybe; + specifiedByURL?: Maybe; + /** Serializes an internal value to include in a response. */ + serialize?: GraphQLScalarSerializer; + /** Parses an externally provided value to use as an input. */ + parseValue?: GraphQLScalarValueParser; + /** Parses an externally provided literal value to use as an input. */ + parseLiteral?: GraphQLScalarLiteralParser; + extensions?: Maybe>; + astNode?: Maybe; + extensionASTNodes?: Maybe>; +} + +interface GraphQLScalarTypeNormalizedConfig + extends GraphQLScalarTypeConfig { + serialize: GraphQLScalarSerializer; + parseValue: GraphQLScalarValueParser; + parseLiteral: GraphQLScalarLiteralParser; + extensions: Readonly; + extensionASTNodes: ReadonlyArray; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + * + * We've provided these template arguments because this is an open type and + * you may find them useful. + */ +export interface GraphQLObjectTypeExtensions<_TSource = any, _TContext = any> { + [attributeName: string]: unknown; +} + +/** + * Object Type Definition + * + * Almost all of the GraphQL types you define will be object types. Object types + * have a name, but most importantly describe their fields. + * + * Example: + * + * ```ts + * const AddressType = new GraphQLObjectType({ + * name: 'Address', + * fields: { + * street: { type: GraphQLString }, + * number: { type: GraphQLInt }, + * formatted: { + * type: GraphQLString, + * resolve(obj) { + * return obj.number + ' ' + obj.street + * } + * } + * } + * }); + * ``` + * + * When two types need to refer to each other, or a type needs to refer to + * itself in a field, you can use a function expression (aka a closure or a + * thunk) to supply the fields lazily. + * + * Example: + * + * ```ts + * const PersonType = new GraphQLObjectType({ + * name: 'Person', + * fields: () => ({ + * name: { type: GraphQLString }, + * bestFriend: { type: PersonType }, + * }) + * }); + * ``` + */ +export class GraphQLObjectType { + name: string; + description: Maybe; + isTypeOf: Maybe>; + extensions: Readonly>; + astNode: Maybe; + extensionASTNodes: ReadonlyArray; + + private _fields: ThunkObjMap>; + private _interfaces: ThunkReadonlyArray; + + constructor(config: Readonly>) { + this.name = assertName(config.name); + this.description = config.description; + this.isTypeOf = config.isTypeOf; + this.extensions = toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = config.extensionASTNodes ?? []; + + this._fields = () => defineFieldMap(config); + this._interfaces = () => defineInterfaces(config); + devAssert( + config.isTypeOf == null || typeof config.isTypeOf === 'function', + `${this.name} must provide "isTypeOf" as a function, ` + + `but got: ${inspect(config.isTypeOf)}.`, + ); + } + + get [Symbol.toStringTag]() { + return 'GraphQLObjectType'; + } + + getFields(): GraphQLFieldMap { + if (typeof this._fields === 'function') { + this._fields = this._fields(); + } + return this._fields; + } + + getInterfaces(): ReadonlyArray { + if (typeof this._interfaces === 'function') { + this._interfaces = this._interfaces(); + } + return this._interfaces; + } + + toConfig(): GraphQLObjectTypeNormalizedConfig { + return { + name: this.name, + description: this.description, + interfaces: this.getInterfaces(), + fields: fieldsToFieldsConfig(this.getFields()), + isTypeOf: this.isTypeOf, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes, + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } +} + +function defineInterfaces( + config: Readonly< + GraphQLObjectTypeConfig | GraphQLInterfaceTypeConfig + >, +): ReadonlyArray { + const interfaces = resolveReadonlyArrayThunk(config.interfaces ?? []); + devAssert( + Array.isArray(interfaces), + `${config.name} interfaces must be an Array or a function which returns an Array.`, + ); + return interfaces; +} + +function defineFieldMap( + config: Readonly< + | GraphQLObjectTypeConfig + | GraphQLInterfaceTypeConfig + >, +): GraphQLFieldMap { + const fieldMap = resolveObjMapThunk(config.fields); + devAssert( + isPlainObj(fieldMap), + `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, + ); + + return mapValue(fieldMap, (fieldConfig, fieldName) => { + devAssert( + isPlainObj(fieldConfig), + `${config.name}.${fieldName} field config must be an object.`, + ); + devAssert( + fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', + `${config.name}.${fieldName} field resolver must be a function if ` + + `provided, but got: ${inspect(fieldConfig.resolve)}.`, + ); + + const argsConfig = fieldConfig.args ?? {}; + devAssert( + isPlainObj(argsConfig), + `${config.name}.${fieldName} args must be an object with argument names as keys.`, + ); + + return { + name: assertName(fieldName), + description: fieldConfig.description, + type: fieldConfig.type, + args: defineArguments(argsConfig), + resolve: fieldConfig.resolve, + subscribe: fieldConfig.subscribe, + deprecationReason: fieldConfig.deprecationReason, + extensions: toObjMap(fieldConfig.extensions), + astNode: fieldConfig.astNode, + }; + }); +} + +export function defineArguments( + config: GraphQLFieldConfigArgumentMap, +): ReadonlyArray { + return Object.entries(config).map(([argName, argConfig]) => ({ + name: assertName(argName), + description: argConfig.description, + type: argConfig.type, + defaultValue: argConfig.defaultValue, + deprecationReason: argConfig.deprecationReason, + extensions: toObjMap(argConfig.extensions), + astNode: argConfig.astNode, + })); +} + +function isPlainObj(obj: unknown): boolean { + return isObjectLike(obj) && !Array.isArray(obj); +} + +function fieldsToFieldsConfig( + fields: GraphQLFieldMap, +): GraphQLFieldConfigMap { + return mapValue(fields, (field) => ({ + description: field.description, + type: field.type, + args: argsToArgsConfig(field.args), + resolve: field.resolve, + subscribe: field.subscribe, + deprecationReason: field.deprecationReason, + extensions: field.extensions, + astNode: field.astNode, + })); +} + +/** + * @internal + */ +export function argsToArgsConfig( + args: ReadonlyArray, +): GraphQLFieldConfigArgumentMap { + return keyValMap( + args, + (arg) => arg.name, + (arg) => ({ + description: arg.description, + type: arg.type, + defaultValue: arg.defaultValue, + deprecationReason: arg.deprecationReason, + extensions: arg.extensions, + astNode: arg.astNode, + }), + ); +} + +export interface GraphQLObjectTypeConfig { + name: string; + description?: Maybe; + interfaces?: ThunkReadonlyArray; + fields: ThunkObjMap>; + isTypeOf?: Maybe>; + extensions?: Maybe>>; + astNode?: Maybe; + extensionASTNodes?: Maybe>; +} + +interface GraphQLObjectTypeNormalizedConfig + extends GraphQLObjectTypeConfig { + interfaces: ReadonlyArray; + fields: GraphQLFieldConfigMap; + extensions: Readonly>; + extensionASTNodes: ReadonlyArray; +} + +export type GraphQLTypeResolver = ( + value: TSource, + context: TContext, + info: GraphQLResolveInfo, + abstractType: GraphQLAbstractType, +) => PromiseOrValue; + +export type GraphQLIsTypeOfFn = ( + source: TSource, + context: TContext, + info: GraphQLResolveInfo, +) => PromiseOrValue; + +export type GraphQLFieldResolver< + TSource, + TContext, + TArgs = any, + TResult = unknown, +> = ( + source: TSource, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo, +) => TResult; + +export interface GraphQLResolveInfo { + readonly fieldName: string; + readonly fieldNodes: ReadonlyArray; + readonly returnType: GraphQLOutputType; + readonly parentType: GraphQLObjectType; + readonly path: Path; + readonly schema: GraphQLSchema; + readonly fragments: ObjMap; + readonly rootValue: unknown; + readonly operation: OperationDefinitionNode; + readonly variableValues: { [variable: string]: unknown }; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + * + * We've provided these template arguments because this is an open type and + * you may find them useful. + */ +export interface GraphQLFieldExtensions<_TSource, _TContext, _TArgs = any> { + [attributeName: string]: unknown; +} + +export interface GraphQLFieldConfig { + description?: Maybe; + type: GraphQLOutputType; + args?: GraphQLFieldConfigArgumentMap; + resolve?: GraphQLFieldResolver; + subscribe?: GraphQLFieldResolver; + deprecationReason?: Maybe; + extensions?: Maybe< + Readonly> + >; + astNode?: Maybe; +} + +export type GraphQLFieldConfigArgumentMap = ObjMap; + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLArgumentExtensions { + [attributeName: string]: unknown; +} + +export interface GraphQLArgumentConfig { + description?: Maybe; + type: GraphQLInputType; + defaultValue?: unknown; + deprecationReason?: Maybe; + extensions?: Maybe>; + astNode?: Maybe; +} + +export type GraphQLFieldConfigMap = ObjMap< + GraphQLFieldConfig +>; + +export interface GraphQLField { + name: string; + description: Maybe; + type: GraphQLOutputType; + args: ReadonlyArray; + resolve?: GraphQLFieldResolver; + subscribe?: GraphQLFieldResolver; + deprecationReason: Maybe; + extensions: Readonly>; + astNode: Maybe; +} + +export interface GraphQLArgument { + name: string; + description: Maybe; + type: GraphQLInputType; + defaultValue: unknown; + deprecationReason: Maybe; + extensions: Readonly; + astNode: Maybe; +} + +export function isRequiredArgument(arg: GraphQLArgument): boolean { + return isNonNullType(arg.type) && arg.defaultValue === undefined; +} + +export type GraphQLFieldMap = ObjMap< + GraphQLField +>; + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLInterfaceTypeExtensions { + [attributeName: string]: unknown; +} + +/** + * Interface Type Definition + * + * When a field can return one of a heterogeneous set of types, a Interface type + * is used to describe what types are possible, what fields are in common across + * all types, as well as a function to determine which type is actually used + * when the field is resolved. + * + * Example: + * + * ```ts + * const EntityType = new GraphQLInterfaceType({ + * name: 'Entity', + * fields: { + * name: { type: GraphQLString } + * } + * }); + * ``` + */ +export class GraphQLInterfaceType { + name: string; + description: Maybe; + resolveType: Maybe>; + extensions: Readonly; + astNode: Maybe; + extensionASTNodes: ReadonlyArray; + + private _fields: ThunkObjMap>; + private _interfaces: ThunkReadonlyArray; + + constructor(config: Readonly>) { + this.name = assertName(config.name); + this.description = config.description; + this.resolveType = config.resolveType; + this.extensions = toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = config.extensionASTNodes ?? []; + + this._fields = defineFieldMap.bind(undefined, config); + this._interfaces = defineInterfaces.bind(undefined, config); + devAssert( + config.resolveType == null || typeof config.resolveType === 'function', + `${this.name} must provide "resolveType" as a function, ` + + `but got: ${inspect(config.resolveType)}.`, + ); + } + + get [Symbol.toStringTag]() { + return 'GraphQLInterfaceType'; + } + + getFields(): GraphQLFieldMap { + if (typeof this._fields === 'function') { + this._fields = this._fields(); + } + return this._fields; + } + + getInterfaces(): ReadonlyArray { + if (typeof this._interfaces === 'function') { + this._interfaces = this._interfaces(); + } + return this._interfaces; + } + + toConfig(): GraphQLInterfaceTypeNormalizedConfig { + return { + name: this.name, + description: this.description, + interfaces: this.getInterfaces(), + fields: fieldsToFieldsConfig(this.getFields()), + resolveType: this.resolveType, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes, + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } +} + +export interface GraphQLInterfaceTypeConfig { + name: string; + description?: Maybe; + interfaces?: ThunkReadonlyArray; + fields: ThunkObjMap>; + /** + * Optionally provide a custom type resolver function. If one is not provided, + * the default implementation will call `isTypeOf` on each implementing + * Object type. + */ + resolveType?: Maybe>; + extensions?: Maybe>; + astNode?: Maybe; + extensionASTNodes?: Maybe>; +} + +export interface GraphQLInterfaceTypeNormalizedConfig + extends GraphQLInterfaceTypeConfig { + interfaces: ReadonlyArray; + fields: GraphQLFieldConfigMap; + extensions: Readonly; + extensionASTNodes: ReadonlyArray; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLUnionTypeExtensions { + [attributeName: string]: unknown; +} + +/** + * Union Type Definition + * + * When a field can return one of a heterogeneous set of types, a Union type + * is used to describe what types are possible as well as providing a function + * to determine which type is actually used when the field is resolved. + * + * Example: + * + * ```ts + * const PetType = new GraphQLUnionType({ + * name: 'Pet', + * types: [ DogType, CatType ], + * resolveType(value) { + * if (value instanceof Dog) { + * return DogType; + * } + * if (value instanceof Cat) { + * return CatType; + * } + * } + * }); + * ``` + */ +export class GraphQLUnionType { + name: string; + description: Maybe; + resolveType: Maybe>; + extensions: Readonly; + astNode: Maybe; + extensionASTNodes: ReadonlyArray; + + private _types: ThunkReadonlyArray; + + constructor(config: Readonly>) { + this.name = assertName(config.name); + this.description = config.description; + this.resolveType = config.resolveType; + this.extensions = toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = config.extensionASTNodes ?? []; + + this._types = defineTypes.bind(undefined, config); + devAssert( + config.resolveType == null || typeof config.resolveType === 'function', + `${this.name} must provide "resolveType" as a function, ` + + `but got: ${inspect(config.resolveType)}.`, + ); + } + + get [Symbol.toStringTag]() { + return 'GraphQLUnionType'; + } + + getTypes(): ReadonlyArray { + if (typeof this._types === 'function') { + this._types = this._types(); + } + return this._types; + } + + toConfig(): GraphQLUnionTypeNormalizedConfig { + return { + name: this.name, + description: this.description, + types: this.getTypes(), + resolveType: this.resolveType, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes, + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } +} + +function defineTypes( + config: Readonly>, +): ReadonlyArray { + const types = resolveReadonlyArrayThunk(config.types); + devAssert( + Array.isArray(types), + `Must provide Array of types or a function which returns such an array for Union ${config.name}.`, + ); + return types; +} + +export interface GraphQLUnionTypeConfig { + name: string; + description?: Maybe; + types: ThunkReadonlyArray; + /** + * Optionally provide a custom type resolver function. If one is not provided, + * the default implementation will call `isTypeOf` on each implementing + * Object type. + */ + resolveType?: Maybe>; + extensions?: Maybe>; + astNode?: Maybe; + extensionASTNodes?: Maybe>; +} + +interface GraphQLUnionTypeNormalizedConfig + extends GraphQLUnionTypeConfig { + types: ReadonlyArray; + extensions: Readonly; + extensionASTNodes: ReadonlyArray; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLEnumTypeExtensions { + [attributeName: string]: unknown; +} + +/** + * Enum Type Definition + * + * Some leaf values of requests and input values are Enums. GraphQL serializes + * Enum values as strings, however internally Enums can be represented by any + * kind of type, often integers. + * + * Example: + * + * ```ts + * const RGBType = new GraphQLEnumType({ + * name: 'RGB', + * values: { + * RED: { value: 0 }, + * GREEN: { value: 1 }, + * BLUE: { value: 2 } + * } + * }); + * ``` + * + * Note: If a value is not provided in a definition, the name of the enum value + * will be used as its internal value. + */ +export class GraphQLEnumType /* */ { + name: string; + description: Maybe; + extensions: Readonly; + astNode: Maybe; + extensionASTNodes: ReadonlyArray; + + private _values: + | ReadonlyArray */> + | (() => GraphQLEnumValueConfigMap); + + private _valueLookup: ReadonlyMap | null; + private _nameLookup: ObjMap | null; + + constructor(config: Readonly */>) { + this.name = assertName(config.name); + this.description = config.description; + this.extensions = toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = config.extensionASTNodes ?? []; + + this._values = + typeof config.values === 'function' + ? config.values + : defineEnumValues(this.name, config.values); + this._valueLookup = null; + this._nameLookup = null; + } + + get [Symbol.toStringTag]() { + return 'GraphQLEnumType'; + } + + getValues(): ReadonlyArray */> { + if (typeof this._values === 'function') { + this._values = defineEnumValues(this.name, this._values()); + } + return this._values; + } + + getValue(name: string): Maybe { + if (this._nameLookup === null) { + this._nameLookup = keyMap(this.getValues(), (value) => value.name); + } + return this._nameLookup[name]; + } + + serialize(outputValue: unknown /* T */): Maybe { + if (this._valueLookup === null) { + this._valueLookup = new Map( + this.getValues().map((enumValue) => [enumValue.value, enumValue]), + ); + } + const enumValue = this._valueLookup.get(outputValue); + if (enumValue === undefined) { + throw new GraphQLError( + `Enum "${this.name}" cannot represent value: ${inspect(outputValue)}`, + ); + } + return enumValue.name; + } + + parseValue(inputValue: unknown): Maybe /* T */ { + if (typeof inputValue !== 'string') { + const valueStr = inspect(inputValue); + throw new GraphQLError( + `Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + + didYouMeanEnumValue(this, valueStr), + ); + } + + const enumValue = this.getValue(inputValue); + if (enumValue == null) { + throw new GraphQLError( + `Value "${inputValue}" does not exist in "${this.name}" enum.` + + didYouMeanEnumValue(this, inputValue), + ); + } + return enumValue.value; + } + + parseLiteral( + valueNode: ValueNode, + _variables: Maybe>, + ): Maybe /* T */ { + // Note: variables will be resolved to a value before calling this function. + if (valueNode.kind !== Kind.ENUM) { + const valueStr = print(valueNode); + throw new GraphQLError( + `Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + + didYouMeanEnumValue(this, valueStr), + { nodes: valueNode }, + ); + } + + const enumValue = this.getValue(valueNode.value); + if (enumValue == null) { + const valueStr = print(valueNode); + throw new GraphQLError( + `Value "${valueStr}" does not exist in "${this.name}" enum.` + + didYouMeanEnumValue(this, valueStr), + { nodes: valueNode }, + ); + } + return enumValue.value; + } + + toConfig(): GraphQLEnumTypeNormalizedConfig { + const values = keyValMap( + this.getValues(), + (value) => value.name, + (value) => ({ + description: value.description, + value: value.value, + deprecationReason: value.deprecationReason, + extensions: value.extensions, + astNode: value.astNode, + }), + ); + + return { + name: this.name, + description: this.description, + values, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes, + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } +} + +function didYouMeanEnumValue( + enumType: GraphQLEnumType, + unknownValueStr: string, +): string { + const allNames = enumType.getValues().map((value) => value.name); + const suggestedValues = suggestionList(unknownValueStr, allNames); + + return didYouMean('the enum value', suggestedValues); +} + +function defineEnumValues( + typeName: string, + valueMap: GraphQLEnumValueConfigMap /* */, +): ReadonlyArray */> { + devAssert( + isPlainObj(valueMap), + `${typeName} values must be an object with value names as keys.`, + ); + return Object.entries(valueMap).map(([valueName, valueConfig]) => { + devAssert( + isPlainObj(valueConfig), + `${typeName}.${valueName} must refer to an object with a "value" key ` + + `representing an internal value but got: ${inspect(valueConfig)}.`, + ); + return { + name: assertEnumValueName(valueName), + description: valueConfig.description, + value: valueConfig.value !== undefined ? valueConfig.value : valueName, + deprecationReason: valueConfig.deprecationReason, + extensions: toObjMap(valueConfig.extensions), + astNode: valueConfig.astNode, + }; + }); +} + +export interface GraphQLEnumTypeConfig { + name: string; + description?: Maybe; + values: ThunkObjMap */>; + extensions?: Maybe>; + astNode?: Maybe; + extensionASTNodes?: Maybe>; +} + +interface GraphQLEnumTypeNormalizedConfig extends GraphQLEnumTypeConfig { + values: ObjMap */>; + extensions: Readonly; + extensionASTNodes: ReadonlyArray; +} + +export type GraphQLEnumValueConfigMap /* */ = + ObjMap */>; + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLEnumValueExtensions { + [attributeName: string]: unknown; +} + +export interface GraphQLEnumValueConfig { + description?: Maybe; + value?: any /* T */; + deprecationReason?: Maybe; + extensions?: Maybe>; + astNode?: Maybe; +} + +export interface GraphQLEnumValue { + name: string; + description: Maybe; + value: any /* T */; + deprecationReason: Maybe; + extensions: Readonly; + astNode: Maybe; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLInputObjectTypeExtensions { + [attributeName: string]: unknown; +} + +/** + * Input Object Type Definition + * + * An input object defines a structured collection of fields which may be + * supplied to a field argument. + * + * Using `NonNull` will ensure that a value must be provided by the query + * + * Example: + * + * ```ts + * const GeoPoint = new GraphQLInputObjectType({ + * name: 'GeoPoint', + * fields: { + * lat: { type: new GraphQLNonNull(GraphQLFloat) }, + * lon: { type: new GraphQLNonNull(GraphQLFloat) }, + * alt: { type: GraphQLFloat, defaultValue: 0 }, + * } + * }); + * ``` + */ +export class GraphQLInputObjectType { + name: string; + description: Maybe; + extensions: Readonly; + astNode: Maybe; + extensionASTNodes: ReadonlyArray; + isOneOf: boolean; + + private _fields: ThunkObjMap; + + constructor(config: Readonly) { + this.name = assertName(config.name); + this.description = config.description; + this.extensions = toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = config.extensionASTNodes ?? []; + this.isOneOf = config.isOneOf ?? false; + + this._fields = defineInputFieldMap.bind(undefined, config); + } + + get [Symbol.toStringTag]() { + return 'GraphQLInputObjectType'; + } + + getFields(): GraphQLInputFieldMap { + if (typeof this._fields === 'function') { + this._fields = this._fields(); + } + return this._fields; + } + + toConfig(): GraphQLInputObjectTypeNormalizedConfig { + const fields = mapValue(this.getFields(), (field) => ({ + description: field.description, + type: field.type, + defaultValue: field.defaultValue, + deprecationReason: field.deprecationReason, + extensions: field.extensions, + astNode: field.astNode, + })); + + return { + name: this.name, + description: this.description, + fields, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes, + isOneOf: this.isOneOf, + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } +} + +function defineInputFieldMap( + config: Readonly, +): GraphQLInputFieldMap { + const fieldMap = resolveObjMapThunk(config.fields); + devAssert( + isPlainObj(fieldMap), + `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, + ); + return mapValue(fieldMap, (fieldConfig, fieldName) => { + devAssert( + !('resolve' in fieldConfig), + `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`, + ); + + return { + name: assertName(fieldName), + description: fieldConfig.description, + type: fieldConfig.type, + defaultValue: fieldConfig.defaultValue, + deprecationReason: fieldConfig.deprecationReason, + extensions: toObjMap(fieldConfig.extensions), + astNode: fieldConfig.astNode, + }; + }); +} + +export interface GraphQLInputObjectTypeConfig { + name: string; + description?: Maybe; + fields: ThunkObjMap; + extensions?: Maybe>; + astNode?: Maybe; + extensionASTNodes?: Maybe>; + isOneOf?: boolean; +} + +interface GraphQLInputObjectTypeNormalizedConfig + extends GraphQLInputObjectTypeConfig { + fields: GraphQLInputFieldConfigMap; + extensions: Readonly; + extensionASTNodes: ReadonlyArray; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLInputFieldExtensions { + [attributeName: string]: unknown; +} + +export interface GraphQLInputFieldConfig { + description?: Maybe; + type: GraphQLInputType; + defaultValue?: unknown; + deprecationReason?: Maybe; + extensions?: Maybe>; + astNode?: Maybe; +} + +export type GraphQLInputFieldConfigMap = ObjMap; + +export interface GraphQLInputField { + name: string; + description: Maybe; + type: GraphQLInputType; + defaultValue: unknown; + deprecationReason: Maybe; + extensions: Readonly; + astNode: Maybe; +} + +export function isRequiredInputField(field: GraphQLInputField): boolean { + return isNonNullType(field.type) && field.defaultValue === undefined; +} + +export type GraphQLInputFieldMap = ObjMap; diff --git a/src/type/directives.d.ts b/src/type/directives.d.ts deleted file mode 100644 index 2c6de77b1d..0000000000 --- a/src/type/directives.d.ts +++ /dev/null @@ -1,96 +0,0 @@ -// FIXME -/* eslint-disable import/no-cycle */ - -import { Maybe } from '../jsutils/Maybe'; - -import { DirectiveDefinitionNode } from '../language/ast'; -import { DirectiveLocationEnum } from '../language/directiveLocation'; - -import { GraphQLFieldConfigArgumentMap, GraphQLArgument } from './definition'; - -/** - * Test if the given value is a GraphQL directive. - */ -export function isDirective(directive: any): directive is GraphQLDirective; -export function assertDirective(directive: any): GraphQLDirective; - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLDirectiveExtensions { - [attributeName: string]: any; -} - -/** - * Directives are used by the GraphQL runtime as a way of modifying execution - * behavior. Type system creators will usually not create these directly. - */ -export class GraphQLDirective { - name: string; - description: Maybe; - locations: Array; - isRepeatable: boolean; - args: Array; - extensions: Maybe>; - astNode: Maybe; - - constructor(config: Readonly); - - toConfig(): GraphQLDirectiveConfig & { - args: GraphQLFieldConfigArgumentMap; - isRepeatable: boolean; - extensions: Maybe>; - }; - - toString(): string; - toJSON(): string; - inspect(): string; -} - -export interface GraphQLDirectiveConfig { - name: string; - description?: Maybe; - locations: Array; - args?: Maybe; - isRepeatable?: Maybe; - extensions?: Maybe>; - astNode?: Maybe; -} - -/** - * Used to conditionally include fields or fragments. - */ -export const GraphQLIncludeDirective: GraphQLDirective; - -/** - * Used to conditionally skip (exclude) fields or fragments. - */ -export const GraphQLSkipDirective: GraphQLDirective; - -/** - * Used to provide a URL for specifying the behavior of custom scalar definitions. - */ -export const GraphQLSpecifiedByDirective: GraphQLDirective; - -/** - * Constant string used for default reason for a deprecation. - */ -export const DEFAULT_DEPRECATION_REASON: 'No longer supported'; - -/** - * Used to declare element of a GraphQL schema as deprecated. - */ -export const GraphQLDeprecatedDirective: GraphQLDirective; - -/** - * The full list of specified directives. - */ -export const specifiedDirectives: ReadonlyArray; - -export function isSpecifiedDirective(directive: GraphQLDirective): boolean; diff --git a/src/type/directives.js b/src/type/directives.js deleted file mode 100644 index d35069f691..0000000000 --- a/src/type/directives.js +++ /dev/null @@ -1,229 +0,0 @@ -import objectEntries from '../polyfills/objectEntries'; -import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols'; - -import type { ReadOnlyObjMap, ReadOnlyObjMapLike } from '../jsutils/ObjMap'; -import inspect from '../jsutils/inspect'; -import toObjMap from '../jsutils/toObjMap'; -import devAssert from '../jsutils/devAssert'; -import instanceOf from '../jsutils/instanceOf'; -import isObjectLike from '../jsutils/isObjectLike'; -import defineInspect from '../jsutils/defineInspect'; - -import type { DirectiveDefinitionNode } from '../language/ast'; -import type { DirectiveLocationEnum } from '../language/directiveLocation'; -import { DirectiveLocation } from '../language/directiveLocation'; - -import type { - GraphQLArgument, - GraphQLFieldConfigArgumentMap, -} from './definition'; -import { GraphQLString, GraphQLBoolean } from './scalars'; -import { argsToArgsConfig, GraphQLNonNull } from './definition'; - -/** - * Test if the given value is a GraphQL directive. - */ -declare function isDirective( - directive: mixed, -): boolean %checks(directive instanceof GraphQLDirective); -// eslint-disable-next-line no-redeclare -export function isDirective(directive) { - return instanceOf(directive, GraphQLDirective); -} - -export function assertDirective(directive: mixed): GraphQLDirective { - if (!isDirective(directive)) { - throw new Error( - `Expected ${inspect(directive)} to be a GraphQL directive.`, - ); - } - return directive; -} - -/** - * Directives are used by the GraphQL runtime as a way of modifying execution - * behavior. Type system creators will usually not create these directly. - */ -export class GraphQLDirective { - name: string; - description: ?string; - locations: Array; - args: Array; - isRepeatable: boolean; - extensions: ?ReadOnlyObjMap; - astNode: ?DirectiveDefinitionNode; - - constructor(config: $ReadOnly) { - this.name = config.name; - this.description = config.description; - this.locations = config.locations; - this.isRepeatable = config.isRepeatable ?? false; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - - devAssert(config.name, 'Directive must be named.'); - devAssert( - Array.isArray(config.locations), - `@${config.name} locations must be an Array.`, - ); - - const args = config.args ?? {}; - devAssert( - isObjectLike(args) && !Array.isArray(args), - `@${config.name} args must be an object with argument names as keys.`, - ); - - this.args = objectEntries(args).map(([argName, argConfig]) => ({ - name: argName, - description: argConfig.description, - type: argConfig.type, - defaultValue: argConfig.defaultValue, - deprecationReason: argConfig.deprecationReason, - extensions: argConfig.extensions && toObjMap(argConfig.extensions), - astNode: argConfig.astNode, - })); - } - - toConfig(): GraphQLDirectiveNormalizedConfig { - return { - name: this.name, - description: this.description, - locations: this.locations, - args: argsToArgsConfig(this.args), - isRepeatable: this.isRepeatable, - extensions: this.extensions, - astNode: this.astNode, - }; - } - - toString(): string { - return '@' + this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLDirective'; - } -} - -// Print a simplified form when appearing in `inspect` and `util.inspect`. -defineInspect(GraphQLDirective); - -export type GraphQLDirectiveConfig = {| - name: string, - description?: ?string, - locations: Array, - args?: ?GraphQLFieldConfigArgumentMap, - isRepeatable?: ?boolean, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?DirectiveDefinitionNode, -|}; - -type GraphQLDirectiveNormalizedConfig = {| - ...GraphQLDirectiveConfig, - args: GraphQLFieldConfigArgumentMap, - isRepeatable: boolean, - extensions: ?ReadOnlyObjMap, -|}; - -/** - * Used to conditionally include fields or fragments. - */ -export const GraphQLIncludeDirective = new GraphQLDirective({ - name: 'include', - description: - 'Directs the executor to include this field or fragment only when the `if` argument is true.', - locations: [ - DirectiveLocation.FIELD, - DirectiveLocation.FRAGMENT_SPREAD, - DirectiveLocation.INLINE_FRAGMENT, - ], - args: { - if: { - type: new GraphQLNonNull(GraphQLBoolean), - description: 'Included when true.', - }, - }, -}); - -/** - * Used to conditionally skip (exclude) fields or fragments. - */ -export const GraphQLSkipDirective = new GraphQLDirective({ - name: 'skip', - description: - 'Directs the executor to skip this field or fragment when the `if` argument is true.', - locations: [ - DirectiveLocation.FIELD, - DirectiveLocation.FRAGMENT_SPREAD, - DirectiveLocation.INLINE_FRAGMENT, - ], - args: { - if: { - type: new GraphQLNonNull(GraphQLBoolean), - description: 'Skipped when true.', - }, - }, -}); - -/** - * Constant string used for default reason for a deprecation. - */ -export const DEFAULT_DEPRECATION_REASON = 'No longer supported'; - -/** - * Used to declare element of a GraphQL schema as deprecated. - */ -export const GraphQLDeprecatedDirective = new GraphQLDirective({ - name: 'deprecated', - description: 'Marks an element of a GraphQL schema as no longer supported.', - locations: [ - DirectiveLocation.FIELD_DEFINITION, - DirectiveLocation.ARGUMENT_DEFINITION, - DirectiveLocation.INPUT_FIELD_DEFINITION, - DirectiveLocation.ENUM_VALUE, - ], - args: { - reason: { - type: GraphQLString, - description: - 'Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).', - defaultValue: DEFAULT_DEPRECATION_REASON, - }, - }, -}); - -/** - * Used to provide a URL for specifying the behaviour of custom scalar definitions. - */ -export const GraphQLSpecifiedByDirective = new GraphQLDirective({ - name: 'specifiedBy', - description: 'Exposes a URL that specifies the behaviour of this scalar.', - locations: [DirectiveLocation.SCALAR], - args: { - url: { - type: new GraphQLNonNull(GraphQLString), - description: 'The URL that specifies the behaviour of this scalar.', - }, - }, -}); - -/** - * The full list of specified directives. - */ -export const specifiedDirectives = Object.freeze([ - GraphQLIncludeDirective, - GraphQLSkipDirective, - GraphQLDeprecatedDirective, - GraphQLSpecifiedByDirective, -]); - -export function isSpecifiedDirective( - directive: GraphQLDirective, -): boolean %checks { - return specifiedDirectives.some(({ name }) => name === directive.name); -} diff --git a/src/type/directives.ts b/src/type/directives.ts new file mode 100644 index 0000000000..6881f20532 --- /dev/null +++ b/src/type/directives.ts @@ -0,0 +1,237 @@ +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; +import { instanceOf } from '../jsutils/instanceOf'; +import { isObjectLike } from '../jsutils/isObjectLike'; +import type { Maybe } from '../jsutils/Maybe'; +import { toObjMap } from '../jsutils/toObjMap'; + +import type { DirectiveDefinitionNode } from '../language/ast'; +import { DirectiveLocation } from '../language/directiveLocation'; + +import { assertName } from './assertName'; +import type { + GraphQLArgument, + GraphQLFieldConfigArgumentMap, +} from './definition'; +import { + argsToArgsConfig, + defineArguments, + GraphQLNonNull, +} from './definition'; +import { GraphQLBoolean, GraphQLString } from './scalars'; + +/** + * Test if the given value is a GraphQL directive. + */ +export function isDirective(directive: unknown): directive is GraphQLDirective { + return instanceOf(directive, GraphQLDirective); +} + +export function assertDirective(directive: unknown): GraphQLDirective { + if (!isDirective(directive)) { + throw new Error( + `Expected ${inspect(directive)} to be a GraphQL directive.`, + ); + } + return directive; +} + +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLDirectiveExtensions { + [attributeName: string]: unknown; +} + +/** + * Directives are used by the GraphQL runtime as a way of modifying execution + * behavior. Type system creators will usually not create these directly. + */ +export class GraphQLDirective { + name: string; + description: Maybe; + locations: ReadonlyArray; + args: ReadonlyArray; + isRepeatable: boolean; + extensions: Readonly; + astNode: Maybe; + + constructor(config: Readonly) { + this.name = assertName(config.name); + this.description = config.description; + this.locations = config.locations; + this.isRepeatable = config.isRepeatable ?? false; + this.extensions = toObjMap(config.extensions); + this.astNode = config.astNode; + + devAssert( + Array.isArray(config.locations), + `@${config.name} locations must be an Array.`, + ); + + const args = config.args ?? {}; + devAssert( + isObjectLike(args) && !Array.isArray(args), + `@${config.name} args must be an object with argument names as keys.`, + ); + + this.args = defineArguments(args); + } + + get [Symbol.toStringTag]() { + return 'GraphQLDirective'; + } + + toConfig(): GraphQLDirectiveNormalizedConfig { + return { + name: this.name, + description: this.description, + locations: this.locations, + args: argsToArgsConfig(this.args), + isRepeatable: this.isRepeatable, + extensions: this.extensions, + astNode: this.astNode, + }; + } + + toString(): string { + return '@' + this.name; + } + + toJSON(): string { + return this.toString(); + } +} + +export interface GraphQLDirectiveConfig { + name: string; + description?: Maybe; + locations: ReadonlyArray; + args?: Maybe; + isRepeatable?: Maybe; + extensions?: Maybe>; + astNode?: Maybe; +} + +interface GraphQLDirectiveNormalizedConfig extends GraphQLDirectiveConfig { + args: GraphQLFieldConfigArgumentMap; + isRepeatable: boolean; + extensions: Readonly; +} + +/** + * Used to conditionally include fields or fragments. + */ +export const GraphQLIncludeDirective: GraphQLDirective = new GraphQLDirective({ + name: 'include', + description: + 'Directs the executor to include this field or fragment only when the `if` argument is true.', + locations: [ + DirectiveLocation.FIELD, + DirectiveLocation.FRAGMENT_SPREAD, + DirectiveLocation.INLINE_FRAGMENT, + ], + args: { + if: { + type: new GraphQLNonNull(GraphQLBoolean), + description: 'Included when true.', + }, + }, +}); + +/** + * Used to conditionally skip (exclude) fields or fragments. + */ +export const GraphQLSkipDirective: GraphQLDirective = new GraphQLDirective({ + name: 'skip', + description: + 'Directs the executor to skip this field or fragment when the `if` argument is true.', + locations: [ + DirectiveLocation.FIELD, + DirectiveLocation.FRAGMENT_SPREAD, + DirectiveLocation.INLINE_FRAGMENT, + ], + args: { + if: { + type: new GraphQLNonNull(GraphQLBoolean), + description: 'Skipped when true.', + }, + }, +}); + +/** + * Constant string used for default reason for a deprecation. + */ +export const DEFAULT_DEPRECATION_REASON = 'No longer supported'; + +/** + * Used to declare element of a GraphQL schema as deprecated. + */ +export const GraphQLDeprecatedDirective: GraphQLDirective = + new GraphQLDirective({ + name: 'deprecated', + description: 'Marks an element of a GraphQL schema as no longer supported.', + locations: [ + DirectiveLocation.FIELD_DEFINITION, + DirectiveLocation.ARGUMENT_DEFINITION, + DirectiveLocation.INPUT_FIELD_DEFINITION, + DirectiveLocation.ENUM_VALUE, + ], + args: { + reason: { + type: GraphQLString, + description: + 'Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).', + defaultValue: DEFAULT_DEPRECATION_REASON, + }, + }, + }); + +/** + * Used to provide a URL for specifying the behavior of custom scalar definitions. + */ +export const GraphQLSpecifiedByDirective: GraphQLDirective = + new GraphQLDirective({ + name: 'specifiedBy', + description: 'Exposes a URL that specifies the behavior of this scalar.', + locations: [DirectiveLocation.SCALAR], + args: { + url: { + type: new GraphQLNonNull(GraphQLString), + description: 'The URL that specifies the behavior of this scalar.', + }, + }, + }); + +/** + * Used to indicate an Input Object is a OneOf Input Object. + */ +export const GraphQLOneOfDirective: GraphQLDirective = new GraphQLDirective({ + name: 'oneOf', + description: + 'Indicates exactly one field must be supplied and this field must not be `null`.', + locations: [DirectiveLocation.INPUT_OBJECT], + args: {}, +}); + +/** + * The full list of specified directives. + */ +export const specifiedDirectives: ReadonlyArray = + Object.freeze([ + GraphQLIncludeDirective, + GraphQLSkipDirective, + GraphQLDeprecatedDirective, + GraphQLSpecifiedByDirective, + GraphQLOneOfDirective, + ]); + +export function isSpecifiedDirective(directive: GraphQLDirective): boolean { + return specifiedDirectives.some(({ name }) => name === directive.name); +} diff --git a/src/type/index.js b/src/type/index.js deleted file mode 100644 index 811d50247a..0000000000 --- a/src/type/index.js +++ /dev/null @@ -1,162 +0,0 @@ -export type { Path as ResponsePath } from '../jsutils/Path'; - -export { - // Predicate - isSchema, - // Assertion - assertSchema, - // GraphQL Schema definition - GraphQLSchema, -} from './schema'; -export type { GraphQLSchemaConfig } from './schema'; - -export { - // Predicates - isType, - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, - isEnumType, - isInputObjectType, - isListType, - isNonNullType, - isInputType, - isOutputType, - isLeafType, - isCompositeType, - isAbstractType, - isWrappingType, - isNullableType, - isNamedType, - isRequiredArgument, - isRequiredInputField, - // Assertions - assertType, - assertScalarType, - assertObjectType, - assertInterfaceType, - assertUnionType, - assertEnumType, - assertInputObjectType, - assertListType, - assertNonNullType, - assertInputType, - assertOutputType, - assertLeafType, - assertCompositeType, - assertAbstractType, - assertWrappingType, - assertNullableType, - assertNamedType, - // Un-modifiers - getNullableType, - getNamedType, - // Definitions - GraphQLScalarType, - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, - // Type Wrappers - GraphQLList, - GraphQLNonNull, -} from './definition'; - -export { - // Predicate - isDirective, - // Assertion - assertDirective, - // Directives Definition - GraphQLDirective, - // Built-in Directives defined by the Spec - isSpecifiedDirective, - specifiedDirectives, - GraphQLIncludeDirective, - GraphQLSkipDirective, - GraphQLDeprecatedDirective, - GraphQLSpecifiedByDirective, - // Constant Deprecation Reason - DEFAULT_DEPRECATION_REASON, -} from './directives'; - -export type { GraphQLDirectiveConfig } from './directives'; - -// Common built-in scalar instances. -export { - // Predicate - isSpecifiedScalarType, - // Standard GraphQL Scalars - specifiedScalarTypes, - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, - GraphQLID, -} from './scalars'; - -export { - // Predicate - isIntrospectionType, - // GraphQL Types for introspection. - introspectionTypes, - __Schema, - __Directive, - __DirectiveLocation, - __Type, - __Field, - __InputValue, - __EnumValue, - __TypeKind, - // "Enum" of Type Kinds - TypeKind, - // Meta-field definitions. - SchemaMetaFieldDef, - TypeMetaFieldDef, - TypeNameMetaFieldDef, -} from './introspection'; - -export type { - GraphQLType, - GraphQLInputType, - GraphQLOutputType, - GraphQLLeafType, - GraphQLCompositeType, - GraphQLAbstractType, - GraphQLWrappingType, - GraphQLNullableType, - GraphQLNamedType, - Thunk, - GraphQLArgument, - GraphQLArgumentConfig, - GraphQLEnumTypeConfig, - GraphQLEnumValue, - GraphQLEnumValueConfig, - GraphQLEnumValueConfigMap, - GraphQLField, - GraphQLFieldConfig, - GraphQLFieldConfigArgumentMap, - GraphQLFieldConfigMap, - GraphQLFieldMap, - GraphQLFieldResolver, - GraphQLInputField, - GraphQLInputFieldConfig, - GraphQLInputFieldConfigMap, - GraphQLInputFieldMap, - GraphQLInputObjectTypeConfig, - GraphQLInterfaceTypeConfig, - GraphQLIsTypeOfFn, - GraphQLObjectTypeConfig, - GraphQLResolveInfo, - GraphQLScalarTypeConfig, - GraphQLTypeResolver, - GraphQLUnionTypeConfig, - GraphQLScalarSerializer, - GraphQLScalarValueParser, - GraphQLScalarLiteralParser, -} from './definition'; - -// Validate GraphQL schema. -export { validateSchema, assertValidSchema } from './validate'; diff --git a/src/type/index.d.ts b/src/type/index.ts similarity index 84% rename from src/type/index.d.ts rename to src/type/index.ts index 9686f413b7..cf276d1e02 100644 --- a/src/type/index.d.ts +++ b/src/type/index.ts @@ -1,4 +1,4 @@ -export { Path as ResponsePath } from '../jsutils/Path'; +export type { Path as ResponsePath } from '../jsutils/Path'; export { // Predicate @@ -7,11 +7,12 @@ export { assertSchema, // GraphQL Schema definition GraphQLSchema, - GraphQLSchemaConfig, - GraphQLSchemaExtensions, } from './schema'; +export type { GraphQLSchemaConfig, GraphQLSchemaExtensions } from './schema'; export { + resolveObjMapThunk, + resolveReadonlyArrayThunk, // Predicates isType, isScalarType, @@ -63,7 +64,9 @@ export { // Type Wrappers GraphQLList, GraphQLNonNull, - // type +} from './definition'; + +export type { GraphQLType, GraphQLInputType, GraphQLOutputType, @@ -73,7 +76,10 @@ export { GraphQLWrappingType, GraphQLNullableType, GraphQLNamedType, - Thunk, + GraphQLNamedInputType, + GraphQLNamedOutputType, + ThunkReadonlyArray, + ThunkObjMap, GraphQLArgument, GraphQLArgumentConfig, GraphQLArgumentExtensions, @@ -127,29 +133,36 @@ export { GraphQLSkipDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective, + GraphQLOneOfDirective, // Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, - // type +} from './directives'; + +export type { GraphQLDirectiveConfig, GraphQLDirectiveExtensions, } from './directives'; // Common built-in scalar instances. export { + // Predicate isSpecifiedScalarType, + // Standard GraphQL Scalars specifiedScalarTypes, GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean, GraphQLID, + // Int boundaries constants + GRAPHQL_MAX_INT, + GRAPHQL_MIN_INT, } from './scalars'; export { - // "Enum" of Type Kinds - TypeKind, - // GraphQL Types for introspection. + // Predicate isIntrospectionType, + // GraphQL Types for introspection. introspectionTypes, __Schema, __Directive, @@ -159,10 +172,16 @@ export { __InputValue, __EnumValue, __TypeKind, + // "Enum" of Type Kinds + TypeKind, // Meta-field definitions. SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, } from './introspection'; +// Validate GraphQL schema. export { validateSchema, assertValidSchema } from './validate'; + +// Upholds the spec rules about naming. +export { assertName, assertEnumValueName } from './assertName'; diff --git a/src/type/introspection.d.ts b/src/type/introspection.d.ts deleted file mode 100644 index 34cefa72fb..0000000000 --- a/src/type/introspection.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - GraphQLObjectType, - GraphQLField, - GraphQLEnumType, - GraphQLNamedType, -} from './definition'; - -export const __Schema: GraphQLObjectType; -export const __Directive: GraphQLObjectType; -export const __DirectiveLocation: GraphQLEnumType; -export const __Type: GraphQLObjectType; -export const __Field: GraphQLObjectType; -export const __InputValue: GraphQLObjectType; -export const __EnumValue: GraphQLObjectType; - -export const TypeKind: { - SCALAR: 'SCALAR'; - OBJECT: 'OBJECT'; - INTERFACE: 'INTERFACE'; - UNION: 'UNION'; - ENUM: 'ENUM'; - INPUT_OBJECT: 'INPUT_OBJECT'; - LIST: 'LIST'; - NON_NULL: 'NON_NULL'; -}; - -export const __TypeKind: GraphQLEnumType; - -/** - * Note that these are GraphQLField and not GraphQLFieldConfig, - * so the format for args is different. - */ - -export const SchemaMetaFieldDef: GraphQLField; -export const TypeMetaFieldDef: GraphQLField; -export const TypeNameMetaFieldDef: GraphQLField; - -export const introspectionTypes: ReadonlyArray; - -export function isIntrospectionType(type: GraphQLNamedType): boolean; diff --git a/src/type/introspection.js b/src/type/introspection.ts similarity index 83% rename from src/type/introspection.js rename to src/type/introspection.ts index 77362ed02d..2c66ca5098 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.ts @@ -1,40 +1,39 @@ -import objectValues from '../polyfills/objectValues'; +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; - -import { print } from '../language/printer'; import { DirectiveLocation } from '../language/directiveLocation'; +import { print } from '../language/printer'; + import { astFromValue } from '../utilities/astFromValue'; -import type { GraphQLSchema } from './schema'; -import type { GraphQLDirective } from './directives'; import type { - GraphQLType, - GraphQLNamedType, - GraphQLInputField, GraphQLEnumValue, GraphQLField, GraphQLFieldConfigMap, + GraphQLInputField, + GraphQLNamedType, + GraphQLType, } from './definition'; -import { GraphQLString, GraphQLBoolean } from './scalars'; import { + GraphQLEnumType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLEnumType, - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, + isAbstractType, isEnumType, isInputObjectType, + isInterfaceType, isListType, isNonNullType, - isAbstractType, + isObjectType, + isScalarType, + isUnionType, } from './definition'; +import type { GraphQLDirective } from './directives'; +import { GraphQLBoolean, GraphQLString } from './scalars'; +import type { GraphQLSchema } from './schema'; -export const __Schema = new GraphQLObjectType({ +export const __Schema: GraphQLObjectType = new GraphQLObjectType({ name: '__Schema', description: 'A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.', @@ -48,7 +47,7 @@ export const __Schema = new GraphQLObjectType({ description: 'A list of all types supported by this server.', type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__Type))), resolve(schema) { - return objectValues(schema.getTypeMap()); + return Object.values(schema.getTypeMap()); }, }, queryType: { @@ -75,10 +74,10 @@ export const __Schema = new GraphQLObjectType({ ), resolve: (schema) => schema.getDirectives(), }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); -export const __Directive = new GraphQLObjectType({ +export const __Directive: GraphQLObjectType = new GraphQLObjectType({ name: '__Directive', description: "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", @@ -106,12 +105,22 @@ export const __Directive = new GraphQLObjectType({ type: new GraphQLNonNull( new GraphQLList(new GraphQLNonNull(__InputValue)), ), - resolve: (directive) => directive.args, + args: { + includeDeprecated: { + type: GraphQLBoolean, + defaultValue: false, + }, + }, + resolve(field, { includeDeprecated }) { + return includeDeprecated + ? field.args + : field.args.filter((arg) => arg.deprecationReason == null); + }, }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); -export const __DirectiveLocation = new GraphQLEnumType({ +export const __DirectiveLocation: GraphQLEnumType = new GraphQLEnumType({ name: '__DirectiveLocation', description: 'A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.', @@ -195,10 +204,10 @@ export const __DirectiveLocation = new GraphQLEnumType({ }, }); -export const __Type = new GraphQLObjectType({ +export const __Type: GraphQLObjectType = new GraphQLObjectType({ name: '__Type', description: - 'The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByUrl`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.', + 'The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByURL`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.', fields: () => ({ kind: { @@ -225,28 +234,29 @@ export const __Type = new GraphQLObjectType({ if (isListType(type)) { return TypeKind.LIST; } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isNonNullType(type)) { return TypeKind.NON_NULL; } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, `Unexpected type: "${inspect((type: empty))}".`); + /* c8 ignore next 3 */ + // Not reachable, all possible types have been considered) + invariant(false, `Unexpected type: "${inspect(type)}".`); }, }, name: { type: GraphQLString, - resolve: (type) => (type.name !== undefined ? type.name : undefined), + resolve: (type) => ('name' in type ? type.name : undefined), }, description: { type: GraphQLString, resolve: (type) => - type.description !== undefined ? type.description : undefined, + // FIXME: add test case + /* c8 ignore next */ + 'description' in type ? type.description : undefined, }, - specifiedByUrl: { + specifiedByURL: { type: GraphQLString, resolve: (obj) => - obj.specifiedByUrl !== undefined ? obj.specifiedByUrl : undefined, + 'specifiedByURL' in obj ? obj.specifiedByURL : undefined, }, fields: { type: new GraphQLList(new GraphQLNonNull(__Field)), @@ -255,7 +265,7 @@ export const __Type = new GraphQLObjectType({ }, resolve(type, { includeDeprecated }) { if (isObjectType(type) || isInterfaceType(type)) { - const fields = objectValues(type.getFields()); + const fields = Object.values(type.getFields()); return includeDeprecated ? fields : fields.filter((field) => field.deprecationReason == null); @@ -302,7 +312,7 @@ export const __Type = new GraphQLObjectType({ }, resolve(type, { includeDeprecated }) { if (isInputObjectType(type)) { - const values = objectValues(type.getFields()); + const values = Object.values(type.getFields()); return includeDeprecated ? values : values.filter((field) => field.deprecationReason == null); @@ -311,13 +321,20 @@ export const __Type = new GraphQLObjectType({ }, ofType: { type: __Type, - resolve: (type) => - type.ofType !== undefined ? type.ofType : undefined, + resolve: (type) => ('ofType' in type ? type.ofType : undefined), }, - }: GraphQLFieldConfigMap), + isOneOf: { + type: GraphQLBoolean, + resolve: (type) => { + if (isInputObjectType(type)) { + return type.isOneOf; + } + }, + }, + } as GraphQLFieldConfigMap), }); -export const __Field = new GraphQLObjectType({ +export const __Field: GraphQLObjectType = new GraphQLObjectType({ name: '__Field', description: 'Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.', @@ -359,10 +376,10 @@ export const __Field = new GraphQLObjectType({ type: GraphQLString, resolve: (field) => field.deprecationReason, }, - }: GraphQLFieldConfigMap, mixed>), + } as GraphQLFieldConfigMap, unknown>), }); -export const __InputValue = new GraphQLObjectType({ +export const __InputValue: GraphQLObjectType = new GraphQLObjectType({ name: '__InputValue', description: 'Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.', @@ -398,10 +415,10 @@ export const __InputValue = new GraphQLObjectType({ type: GraphQLString, resolve: (obj) => obj.deprecationReason, }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); -export const __EnumValue = new GraphQLObjectType({ +export const __EnumValue: GraphQLObjectType = new GraphQLObjectType({ name: '__EnumValue', description: 'One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.', @@ -423,21 +440,22 @@ export const __EnumValue = new GraphQLObjectType({ type: GraphQLString, resolve: (enumValue) => enumValue.deprecationReason, }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); -export const TypeKind = Object.freeze({ - SCALAR: 'SCALAR', - OBJECT: 'OBJECT', - INTERFACE: 'INTERFACE', - UNION: 'UNION', - ENUM: 'ENUM', - INPUT_OBJECT: 'INPUT_OBJECT', - LIST: 'LIST', - NON_NULL: 'NON_NULL', -}); +enum TypeKind { + SCALAR = 'SCALAR', + OBJECT = 'OBJECT', + INTERFACE = 'INTERFACE', + UNION = 'UNION', + ENUM = 'ENUM', + INPUT_OBJECT = 'INPUT_OBJECT', + LIST = 'LIST', + NON_NULL = 'NON_NULL', +} +export { TypeKind }; -export const __TypeKind = new GraphQLEnumType({ +export const __TypeKind: GraphQLEnumType = new GraphQLEnumType({ name: '__TypeKind', description: 'An enum describing what kind of type a given `__Type` is.', values: { @@ -487,19 +505,18 @@ export const __TypeKind = new GraphQLEnumType({ * so the format for args is different. */ -export const SchemaMetaFieldDef: GraphQLField = { +export const SchemaMetaFieldDef: GraphQLField = { name: '__schema', type: new GraphQLNonNull(__Schema), description: 'Access the current type schema of this server.', args: [], resolve: (_source, _args, _context, { schema }) => schema, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: Object.create(null), astNode: undefined, }; -export const TypeMetaFieldDef: GraphQLField = { +export const TypeMetaFieldDef: GraphQLField = { name: '__type', type: __Type, description: 'Request the type information of a single type.', @@ -510,40 +527,39 @@ export const TypeMetaFieldDef: GraphQLField = { type: new GraphQLNonNull(GraphQLString), defaultValue: undefined, deprecationReason: undefined, - extensions: undefined, + extensions: Object.create(null), astNode: undefined, }, ], resolve: (_source, { name }, _context, { schema }) => schema.getType(name), - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: Object.create(null), astNode: undefined, }; -export const TypeNameMetaFieldDef: GraphQLField = { +export const TypeNameMetaFieldDef: GraphQLField = { name: '__typename', type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', args: [], resolve: (_source, _args, _context, { parentType }) => parentType.name, - isDeprecated: false, deprecationReason: undefined, - extensions: undefined, + extensions: Object.create(null), astNode: undefined, }; -export const introspectionTypes = Object.freeze([ - __Schema, - __Directive, - __DirectiveLocation, - __Type, - __Field, - __InputValue, - __EnumValue, - __TypeKind, -]); +export const introspectionTypes: ReadonlyArray = + Object.freeze([ + __Schema, + __Directive, + __DirectiveLocation, + __Type, + __Field, + __InputValue, + __EnumValue, + __TypeKind, + ]); -export function isIntrospectionType(type: GraphQLNamedType): boolean %checks { +export function isIntrospectionType(type: GraphQLNamedType): boolean { return introspectionTypes.some(({ name }) => type.name === name); } diff --git a/src/type/scalars.d.ts b/src/type/scalars.d.ts deleted file mode 100644 index 71593d10c2..0000000000 --- a/src/type/scalars.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { GraphQLScalarType, GraphQLNamedType } from './definition'; - -export const GraphQLInt: GraphQLScalarType; -export const GraphQLFloat: GraphQLScalarType; -export const GraphQLString: GraphQLScalarType; -export const GraphQLBoolean: GraphQLScalarType; -export const GraphQLID: GraphQLScalarType; - -export const specifiedScalarTypes: ReadonlyArray; - -export function isSpecifiedScalarType(type: GraphQLNamedType): boolean; diff --git a/src/type/scalars.js b/src/type/scalars.js deleted file mode 100644 index ceca14b5c3..0000000000 --- a/src/type/scalars.js +++ /dev/null @@ -1,286 +0,0 @@ -import isFinite from '../polyfills/isFinite'; -import isInteger from '../polyfills/isInteger'; - -import inspect from '../jsutils/inspect'; -import isObjectLike from '../jsutils/isObjectLike'; - -import { Kind } from '../language/kinds'; -import { print } from '../language/printer'; - -import { GraphQLError } from '../error/GraphQLError'; - -import type { GraphQLNamedType } from './definition'; -import { GraphQLScalarType } from './definition'; - -// As per the GraphQL Spec, Integers are only treated as valid when a valid -// 32-bit signed integer, providing the broadest support across platforms. -// -// n.b. JavaScript's integers are safe between -(2^53 - 1) and 2^53 - 1 because -// they are internally represented as IEEE 754 doubles. -const MAX_INT = 2147483647; -const MIN_INT = -2147483648; - -function serializeInt(outputValue: mixed): number { - const coercedValue = serializeObject(outputValue); - - if (typeof coercedValue === 'boolean') { - return coercedValue ? 1 : 0; - } - - let num = coercedValue; - if (typeof coercedValue === 'string' && coercedValue !== '') { - num = Number(coercedValue); - } - - if (!isInteger(num)) { - throw new GraphQLError( - `Int cannot represent non-integer value: ${inspect(coercedValue)}`, - ); - } - if (num > MAX_INT || num < MIN_INT) { - throw new GraphQLError( - 'Int cannot represent non 32-bit signed integer value: ' + - inspect(coercedValue), - ); - } - return num; -} - -function coerceInt(inputValue: mixed): number { - if (!isInteger(inputValue)) { - throw new GraphQLError( - `Int cannot represent non-integer value: ${inspect(inputValue)}`, - ); - } - if (inputValue > MAX_INT || inputValue < MIN_INT) { - throw new GraphQLError( - `Int cannot represent non 32-bit signed integer value: ${inputValue}`, - ); - } - return inputValue; -} - -export const GraphQLInt = new GraphQLScalarType({ - name: 'Int', - description: - 'The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.', - serialize: serializeInt, - parseValue: coerceInt, - parseLiteral(valueNode) { - if (valueNode.kind !== Kind.INT) { - throw new GraphQLError( - `Int cannot represent non-integer value: ${print(valueNode)}`, - valueNode, - ); - } - const num = parseInt(valueNode.value, 10); - if (num > MAX_INT || num < MIN_INT) { - throw new GraphQLError( - `Int cannot represent non 32-bit signed integer value: ${valueNode.value}`, - valueNode, - ); - } - return num; - }, -}); - -function serializeFloat(outputValue: mixed): number { - const coercedValue = serializeObject(outputValue); - - if (typeof coercedValue === 'boolean') { - return coercedValue ? 1 : 0; - } - - let num = coercedValue; - if (typeof coercedValue === 'string' && coercedValue !== '') { - num = Number(coercedValue); - } - - if (!isFinite(num)) { - throw new GraphQLError( - `Float cannot represent non numeric value: ${inspect(coercedValue)}`, - ); - } - return num; -} - -function coerceFloat(inputValue: mixed): number { - if (!isFinite(inputValue)) { - throw new GraphQLError( - `Float cannot represent non numeric value: ${inspect(inputValue)}`, - ); - } - return inputValue; -} - -export const GraphQLFloat = new GraphQLScalarType({ - name: 'Float', - description: - 'The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).', - serialize: serializeFloat, - parseValue: coerceFloat, - parseLiteral(valueNode) { - if (valueNode.kind !== Kind.FLOAT && valueNode.kind !== Kind.INT) { - throw new GraphQLError( - `Float cannot represent non numeric value: ${print(valueNode)}`, - valueNode, - ); - } - return parseFloat(valueNode.value); - }, -}); - -// Support serializing objects with custom valueOf() or toJSON() functions - -// a common way to represent a complex value which can be represented as -// a string (ex: MongoDB id objects). -function serializeObject(outputValue: mixed): mixed { - if (isObjectLike(outputValue)) { - if (typeof outputValue.valueOf === 'function') { - const valueOfResult = outputValue.valueOf(); - if (!isObjectLike(valueOfResult)) { - return valueOfResult; - } - } - if (typeof outputValue.toJSON === 'function') { - // $FlowFixMe[incompatible-use] - return outputValue.toJSON(); - } - } - return outputValue; -} - -function serializeString(outputValue: mixed): string { - const coercedValue = serializeObject(outputValue); - - // Serialize string, boolean and number values to a string, but do not - // attempt to coerce object, function, symbol, or other types as strings. - if (typeof coercedValue === 'string') { - return coercedValue; - } - if (typeof coercedValue === 'boolean') { - return coercedValue ? 'true' : 'false'; - } - if (isFinite(coercedValue)) { - return coercedValue.toString(); - } - throw new GraphQLError( - `String cannot represent value: ${inspect(outputValue)}`, - ); -} - -function coerceString(inputValue: mixed): string { - if (typeof inputValue !== 'string') { - throw new GraphQLError( - `String cannot represent a non string value: ${inspect(inputValue)}`, - ); - } - return inputValue; -} - -export const GraphQLString = new GraphQLScalarType({ - name: 'String', - description: - 'The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.', - serialize: serializeString, - parseValue: coerceString, - parseLiteral(valueNode) { - if (valueNode.kind !== Kind.STRING) { - throw new GraphQLError( - `String cannot represent a non string value: ${print(valueNode)}`, - valueNode, - ); - } - return valueNode.value; - }, -}); - -function serializeBoolean(outputValue: mixed): boolean { - const coercedValue = serializeObject(outputValue); - - if (typeof coercedValue === 'boolean') { - return coercedValue; - } - if (isFinite(coercedValue)) { - return coercedValue !== 0; - } - throw new GraphQLError( - `Boolean cannot represent a non boolean value: ${inspect(coercedValue)}`, - ); -} - -function coerceBoolean(inputValue: mixed): boolean { - if (typeof inputValue !== 'boolean') { - throw new GraphQLError( - `Boolean cannot represent a non boolean value: ${inspect(inputValue)}`, - ); - } - return inputValue; -} - -export const GraphQLBoolean = new GraphQLScalarType({ - name: 'Boolean', - description: 'The `Boolean` scalar type represents `true` or `false`.', - serialize: serializeBoolean, - parseValue: coerceBoolean, - parseLiteral(valueNode) { - if (valueNode.kind !== Kind.BOOLEAN) { - throw new GraphQLError( - `Boolean cannot represent a non boolean value: ${print(valueNode)}`, - valueNode, - ); - } - return valueNode.value; - }, -}); - -function serializeID(outputValue: mixed): string { - const coercedValue = serializeObject(outputValue); - - if (typeof coercedValue === 'string') { - return coercedValue; - } - if (isInteger(coercedValue)) { - return String(coercedValue); - } - throw new GraphQLError(`ID cannot represent value: ${inspect(outputValue)}`); -} - -function coerceID(inputValue: mixed): string { - if (typeof inputValue === 'string') { - return inputValue; - } - if (isInteger(inputValue)) { - return inputValue.toString(); - } - throw new GraphQLError(`ID cannot represent value: ${inspect(inputValue)}`); -} - -export const GraphQLID = new GraphQLScalarType({ - name: 'ID', - description: - 'The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.', - serialize: serializeID, - parseValue: coerceID, - parseLiteral(valueNode) { - if (valueNode.kind !== Kind.STRING && valueNode.kind !== Kind.INT) { - throw new GraphQLError( - 'ID cannot represent a non-string and non-integer value: ' + - print(valueNode), - valueNode, - ); - } - return valueNode.value; - }, -}); - -export const specifiedScalarTypes = Object.freeze([ - GraphQLString, - GraphQLInt, - GraphQLFloat, - GraphQLBoolean, - GraphQLID, -]); - -export function isSpecifiedScalarType(type: GraphQLNamedType): boolean %checks { - return specifiedScalarTypes.some(({ name }) => type.name === name); -} diff --git a/src/type/scalars.ts b/src/type/scalars.ts new file mode 100644 index 0000000000..4990347887 --- /dev/null +++ b/src/type/scalars.ts @@ -0,0 +1,284 @@ +import { inspect } from '../jsutils/inspect'; +import { isObjectLike } from '../jsutils/isObjectLike'; + +import { GraphQLError } from '../error/GraphQLError'; + +import { Kind } from '../language/kinds'; +import { print } from '../language/printer'; + +import type { GraphQLNamedType } from './definition'; +import { GraphQLScalarType } from './definition'; + +/** + * Maximum possible Int value as per GraphQL Spec (32-bit signed integer). + * n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe up-to 2^53 - 1 + * */ +export const GRAPHQL_MAX_INT = 2147483647; + +/** + * Minimum possible Int value as per GraphQL Spec (32-bit signed integer). + * n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe starting at -(2^53 - 1) + * */ +export const GRAPHQL_MIN_INT = -2147483648; + +export const GraphQLInt = new GraphQLScalarType({ + name: 'Int', + description: + 'The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.', + + serialize(outputValue) { + const coercedValue = serializeObject(outputValue); + + if (typeof coercedValue === 'boolean') { + return coercedValue ? 1 : 0; + } + + let num = coercedValue; + if (typeof coercedValue === 'string' && coercedValue !== '') { + num = Number(coercedValue); + } + + if (typeof num !== 'number' || !Number.isInteger(num)) { + throw new GraphQLError( + `Int cannot represent non-integer value: ${inspect(coercedValue)}`, + ); + } + if (num > GRAPHQL_MAX_INT || num < GRAPHQL_MIN_INT) { + throw new GraphQLError( + 'Int cannot represent non 32-bit signed integer value: ' + + inspect(coercedValue), + ); + } + return num; + }, + + parseValue(inputValue) { + if (typeof inputValue !== 'number' || !Number.isInteger(inputValue)) { + throw new GraphQLError( + `Int cannot represent non-integer value: ${inspect(inputValue)}`, + ); + } + if (inputValue > GRAPHQL_MAX_INT || inputValue < GRAPHQL_MIN_INT) { + throw new GraphQLError( + `Int cannot represent non 32-bit signed integer value: ${inputValue}`, + ); + } + return inputValue; + }, + + parseLiteral(valueNode) { + if (valueNode.kind !== Kind.INT) { + throw new GraphQLError( + `Int cannot represent non-integer value: ${print(valueNode)}`, + { nodes: valueNode }, + ); + } + const num = parseInt(valueNode.value, 10); + if (num > GRAPHQL_MAX_INT || num < GRAPHQL_MIN_INT) { + throw new GraphQLError( + `Int cannot represent non 32-bit signed integer value: ${valueNode.value}`, + { nodes: valueNode }, + ); + } + return num; + }, +}); + +export const GraphQLFloat = new GraphQLScalarType({ + name: 'Float', + description: + 'The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).', + + serialize(outputValue) { + const coercedValue = serializeObject(outputValue); + + if (typeof coercedValue === 'boolean') { + return coercedValue ? 1 : 0; + } + + let num = coercedValue; + if (typeof coercedValue === 'string' && coercedValue !== '') { + num = Number(coercedValue); + } + + if (typeof num !== 'number' || !Number.isFinite(num)) { + throw new GraphQLError( + `Float cannot represent non numeric value: ${inspect(coercedValue)}`, + ); + } + return num; + }, + + parseValue(inputValue) { + if (typeof inputValue !== 'number' || !Number.isFinite(inputValue)) { + throw new GraphQLError( + `Float cannot represent non numeric value: ${inspect(inputValue)}`, + ); + } + return inputValue; + }, + + parseLiteral(valueNode) { + if (valueNode.kind !== Kind.FLOAT && valueNode.kind !== Kind.INT) { + throw new GraphQLError( + `Float cannot represent non numeric value: ${print(valueNode)}`, + valueNode, + ); + } + return parseFloat(valueNode.value); + }, +}); + +export const GraphQLString = new GraphQLScalarType({ + name: 'String', + description: + 'The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.', + + serialize(outputValue) { + const coercedValue = serializeObject(outputValue); + + // Serialize string, boolean and number values to a string, but do not + // attempt to coerce object, function, symbol, or other types as strings. + if (typeof coercedValue === 'string') { + return coercedValue; + } + if (typeof coercedValue === 'boolean') { + return coercedValue ? 'true' : 'false'; + } + if (typeof coercedValue === 'number' && Number.isFinite(coercedValue)) { + return coercedValue.toString(); + } + throw new GraphQLError( + `String cannot represent value: ${inspect(outputValue)}`, + ); + }, + + parseValue(inputValue) { + if (typeof inputValue !== 'string') { + throw new GraphQLError( + `String cannot represent a non string value: ${inspect(inputValue)}`, + ); + } + return inputValue; + }, + + parseLiteral(valueNode) { + if (valueNode.kind !== Kind.STRING) { + throw new GraphQLError( + `String cannot represent a non string value: ${print(valueNode)}`, + { nodes: valueNode }, + ); + } + return valueNode.value; + }, +}); + +export const GraphQLBoolean = new GraphQLScalarType({ + name: 'Boolean', + description: 'The `Boolean` scalar type represents `true` or `false`.', + + serialize(outputValue) { + const coercedValue = serializeObject(outputValue); + + if (typeof coercedValue === 'boolean') { + return coercedValue; + } + if (Number.isFinite(coercedValue)) { + return coercedValue !== 0; + } + throw new GraphQLError( + `Boolean cannot represent a non boolean value: ${inspect(coercedValue)}`, + ); + }, + + parseValue(inputValue) { + if (typeof inputValue !== 'boolean') { + throw new GraphQLError( + `Boolean cannot represent a non boolean value: ${inspect(inputValue)}`, + ); + } + return inputValue; + }, + + parseLiteral(valueNode) { + if (valueNode.kind !== Kind.BOOLEAN) { + throw new GraphQLError( + `Boolean cannot represent a non boolean value: ${print(valueNode)}`, + { nodes: valueNode }, + ); + } + return valueNode.value; + }, +}); + +export const GraphQLID = new GraphQLScalarType({ + name: 'ID', + description: + 'The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.', + + serialize(outputValue) { + const coercedValue = serializeObject(outputValue); + + if (typeof coercedValue === 'string') { + return coercedValue; + } + if (Number.isInteger(coercedValue)) { + return String(coercedValue); + } + throw new GraphQLError( + `ID cannot represent value: ${inspect(outputValue)}`, + ); + }, + + parseValue(inputValue) { + if (typeof inputValue === 'string') { + return inputValue; + } + if (typeof inputValue === 'number' && Number.isInteger(inputValue)) { + return inputValue.toString(); + } + throw new GraphQLError(`ID cannot represent value: ${inspect(inputValue)}`); + }, + + parseLiteral(valueNode) { + if (valueNode.kind !== Kind.STRING && valueNode.kind !== Kind.INT) { + throw new GraphQLError( + 'ID cannot represent a non-string and non-integer value: ' + + print(valueNode), + { nodes: valueNode }, + ); + } + return valueNode.value; + }, +}); + +export const specifiedScalarTypes: ReadonlyArray = + Object.freeze([ + GraphQLString, + GraphQLInt, + GraphQLFloat, + GraphQLBoolean, + GraphQLID, + ]); + +export function isSpecifiedScalarType(type: GraphQLNamedType): boolean { + return specifiedScalarTypes.some(({ name }) => type.name === name); +} + +// Support serializing objects with custom valueOf() or toJSON() functions - +// a common way to represent a complex value which can be represented as +// a string (ex: MongoDB id objects). +function serializeObject(outputValue: unknown): unknown { + if (isObjectLike(outputValue)) { + if (typeof outputValue.valueOf === 'function') { + const valueOfResult = outputValue.valueOf(); + if (!isObjectLike(valueOfResult)) { + return valueOfResult; + } + } + if (typeof outputValue.toJSON === 'function') { + return outputValue.toJSON(); + } + } + return outputValue; +} diff --git a/src/type/schema.d.ts b/src/type/schema.d.ts deleted file mode 100644 index 4f759f9f27..0000000000 --- a/src/type/schema.d.ts +++ /dev/null @@ -1,147 +0,0 @@ -// FIXME -/* eslint-disable import/no-cycle */ - -import { Maybe } from '../jsutils/Maybe'; - -import { SchemaDefinitionNode, SchemaExtensionNode } from '../language/ast'; - -import { GraphQLDirective } from './directives'; -import { - GraphQLNamedType, - GraphQLAbstractType, - GraphQLObjectType, - GraphQLInterfaceType, -} from './definition'; - -/** - * Test if the given value is a GraphQL schema. - */ -export function isSchema(schema: any): schema is GraphQLSchema; -export function assertSchema(schema: any): GraphQLSchema; - -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ -export interface GraphQLSchemaExtensions { - [attributeName: string]: any; -} - -/** - * Schema Definition - * - * A Schema is created by supplying the root types of each type of operation, - * query and mutation (optional). A schema definition is then supplied to the - * validator and executor. - * - * Example: - * - * const MyAppSchema = new GraphQLSchema({ - * query: MyAppQueryRootType, - * mutation: MyAppMutationRootType, - * }) - * - * Note: If an array of `directives` are provided to GraphQLSchema, that will be - * the exact list of directives represented and allowed. If `directives` is not - * provided then a default set of the specified directives (e.g. @include and - * @skip) will be used. If you wish to provide *additional* directives to these - * specified directives, you must explicitly declare them. Example: - * - * const MyAppSchema = new GraphQLSchema({ - * ... - * directives: specifiedDirectives.concat([ myCustomDirective ]), - * }) - * - */ -export class GraphQLSchema { - description: Maybe; - extensions: Maybe>; - astNode: Maybe; - extensionASTNodes: Maybe>; - - constructor(config: Readonly); - getQueryType(): Maybe; - getMutationType(): Maybe; - getSubscriptionType(): Maybe; - getTypeMap(): TypeMap; - getType(name: string): Maybe; - - getPossibleTypes( - abstractType: GraphQLAbstractType, - ): ReadonlyArray; - - getImplementations( - interfaceType: GraphQLInterfaceType, - ): InterfaceImplementations; - - // @deprecated: use isSubType instead - will be removed in v16. - isPossibleType( - abstractType: GraphQLAbstractType, - possibleType: GraphQLObjectType, - ): boolean; - - isSubType( - abstractType: GraphQLAbstractType, - maybeSubType: GraphQLNamedType, - ): boolean; - - getDirectives(): ReadonlyArray; - getDirective(name: string): Maybe; - - toConfig(): GraphQLSchemaConfig & { - types: Array; - directives: Array; - extensions: Maybe>; - extensionASTNodes: ReadonlyArray; - assumeValid: boolean; - }; -} - -interface TypeMap { - [key: string]: GraphQLNamedType; -} - -interface InterfaceImplementations { - objects: ReadonlyArray; - interfaces: ReadonlyArray; -} - -export interface GraphQLSchemaValidationOptions { - /** - * When building a schema from a GraphQL service's introspection result, it - * might be safe to assume the schema is valid. Set to true to assume the - * produced schema is valid. - * - * Default: false - */ - assumeValid?: boolean; -} - -export interface GraphQLSchemaConfig extends GraphQLSchemaValidationOptions { - description?: Maybe; - query?: Maybe; - mutation?: Maybe; - subscription?: Maybe; - types?: Maybe>; - directives?: Maybe>; - extensions?: Maybe>; - astNode?: Maybe; - extensionASTNodes?: Maybe>; -} - -/** - * @internal - */ -export interface GraphQLSchemaNormalizedConfig extends GraphQLSchemaConfig { - description: Maybe; - types: Array; - directives: Array; - extensions: Maybe>; - extensionASTNodes: Maybe>; - assumeValid: boolean; -} diff --git a/src/type/schema.js b/src/type/schema.ts similarity index 62% rename from src/type/schema.js rename to src/type/schema.ts index 4b0a6e3b12..97c2782145 100644 --- a/src/type/schema.js +++ b/src/type/schema.ts @@ -1,18 +1,10 @@ -import find from '../polyfills/find'; -import arrayFrom from '../polyfills/arrayFrom'; -import objectValues from '../polyfills/objectValues'; -import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols'; - -import type { - ObjMap, - ReadOnlyObjMap, - ReadOnlyObjMapLike, -} from '../jsutils/ObjMap'; -import inspect from '../jsutils/inspect'; -import toObjMap from '../jsutils/toObjMap'; -import devAssert from '../jsutils/devAssert'; -import instanceOf from '../jsutils/instanceOf'; -import isObjectLike from '../jsutils/isObjectLike'; +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; +import { instanceOf } from '../jsutils/instanceOf'; +import { isObjectLike } from '../jsutils/isObjectLike'; +import type { Maybe } from '../jsutils/Maybe'; +import type { ObjMap } from '../jsutils/ObjMap'; +import { toObjMap } from '../jsutils/toObjMap'; import type { GraphQLError } from '../error/GraphQLError'; @@ -20,45 +12,53 @@ import type { SchemaDefinitionNode, SchemaExtensionNode, } from '../language/ast'; +import { OperationTypeNode } from '../language/ast'; import type { - GraphQLType, - GraphQLNamedType, GraphQLAbstractType, - GraphQLObjectType, GraphQLInterfaceType, + GraphQLNamedType, + GraphQLObjectType, + GraphQLType, } from './definition'; -import { __Schema } from './introspection'; import { - GraphQLDirective, - isDirective, - specifiedDirectives, -} from './directives'; -import { - isObjectType, + getNamedType, + isInputObjectType, isInterfaceType, + isObjectType, isUnionType, - isInputObjectType, - getNamedType, } from './definition'; +import type { GraphQLDirective } from './directives'; +import { isDirective, specifiedDirectives } from './directives'; +import { __Schema } from './introspection'; /** * Test if the given value is a GraphQL schema. */ -declare function isSchema(schema: mixed): boolean %checks(schema instanceof - GraphQLSchema); -// eslint-disable-next-line no-redeclare -export function isSchema(schema) { +export function isSchema(schema: unknown): schema is GraphQLSchema { return instanceOf(schema, GraphQLSchema); } -export function assertSchema(schema: mixed): GraphQLSchema { +export function assertSchema(schema: unknown): GraphQLSchema { if (!isSchema(schema)) { throw new Error(`Expected ${inspect(schema)} to be a GraphQL schema.`); } return schema; } +/** + * Custom extensions + * + * @remarks + * Use a unique identifier name for your extension, for example the name of + * your library or project. Do not use a shortened identifier as this increases + * the risk of conflicts. We recommend you add at most one extension field, + * an object which can contain all the values you need. + */ +export interface GraphQLSchemaExtensions { + [attributeName: string]: unknown; +} + /** * Schema Definition * @@ -68,10 +68,12 @@ export function assertSchema(schema: mixed): GraphQLSchema { * * Example: * - * const MyAppSchema = new GraphQLSchema({ - * query: MyAppQueryRootType, - * mutation: MyAppMutationRootType, - * }) + * ```ts + * const MyAppSchema = new GraphQLSchema({ + * query: MyAppQueryRootType, + * mutation: MyAppMutationRootType, + * }) + * ``` * * Note: When the schema is constructed, by default only the types that are * reachable by traversing the root types are included, other types must be @@ -79,70 +81,73 @@ export function assertSchema(schema: mixed): GraphQLSchema { * * Example: * - * const characterInterface = new GraphQLInterfaceType({ - * name: 'Character', - * ... - * }); + * ```ts + * const characterInterface = new GraphQLInterfaceType({ + * name: 'Character', + * ... + * }); * - * const humanType = new GraphQLObjectType({ - * name: 'Human', - * interfaces: [characterInterface], - * ... - * }); + * const humanType = new GraphQLObjectType({ + * name: 'Human', + * interfaces: [characterInterface], + * ... + * }); * - * const droidType = new GraphQLObjectType({ - * name: 'Droid', - * interfaces: [characterInterface], - * ... - * }); + * const droidType = new GraphQLObjectType({ + * name: 'Droid', + * interfaces: [characterInterface], + * ... + * }); * - * const schema = new GraphQLSchema({ - * query: new GraphQLObjectType({ - * name: 'Query', - * fields: { - * hero: { type: characterInterface, ... }, - * } - * }), - * ... - * // Since this schema references only the `Character` interface it's - * // necessary to explicitly list the types that implement it if - * // you want them to be included in the final schema. - * types: [humanType, droidType], - * }) + * const schema = new GraphQLSchema({ + * query: new GraphQLObjectType({ + * name: 'Query', + * fields: { + * hero: { type: characterInterface, ... }, + * } + * }), + * ... + * // Since this schema references only the `Character` interface it's + * // necessary to explicitly list the types that implement it if + * // you want them to be included in the final schema. + * types: [humanType, droidType], + * }) + * ``` * * Note: If an array of `directives` are provided to GraphQLSchema, that will be * the exact list of directives represented and allowed. If `directives` is not - * provided then a default set of the specified directives (e.g. @include and - * @skip) will be used. If you wish to provide *additional* directives to these + * provided then a default set of the specified directives (e.g. `@include` and + * `@skip`) will be used. If you wish to provide *additional* directives to these * specified directives, you must explicitly declare them. Example: * - * const MyAppSchema = new GraphQLSchema({ - * ... - * directives: specifiedDirectives.concat([ myCustomDirective ]), - * }) - * + * ```ts + * const MyAppSchema = new GraphQLSchema({ + * ... + * directives: specifiedDirectives.concat([ myCustomDirective ]), + * }) + * ``` */ export class GraphQLSchema { - description: ?string; - extensions: ?ReadOnlyObjMap; - astNode: ?SchemaDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _queryType: ?GraphQLObjectType; - _mutationType: ?GraphQLObjectType; - _subscriptionType: ?GraphQLObjectType; - _directives: $ReadOnlyArray; - _typeMap: TypeMap; - _subTypeMap: ObjMap>; - _implementationsMap: ObjMap<{| - objects: Array, - interfaces: Array, - |}>; + description: Maybe; + extensions: Readonly; + astNode: Maybe; + extensionASTNodes: ReadonlyArray; // Used as a cache for validateSchema(). - __validationErrors: ?$ReadOnlyArray; - - constructor(config: $ReadOnly) { + __validationErrors: Maybe>; + + private _queryType: Maybe; + private _mutationType: Maybe; + private _subscriptionType: Maybe; + private _directives: ReadonlyArray; + private _typeMap: TypeMap; + private _subTypeMap: ObjMap>; + private _implementationsMap: ObjMap<{ + objects: Array; + interfaces: Array; + }>; + + constructor(config: Readonly) { // If this schema was built from a source known to be valid, then it may be // marked with assumeValid to avoid an additional type system validation. this.__validationErrors = config.assumeValid === true ? [] : undefined; @@ -160,9 +165,9 @@ export class GraphQLSchema { ); this.description = config.description; - this.extensions = config.extensions && toObjMap(config.extensions); + this.extensions = toObjMap(config.extensions); this.astNode = config.astNode; - this.extensionASTNodes = config.extensionASTNodes; + this.extensionASTNodes = config.extensionASTNodes ?? []; this._queryType = config.query; this._mutationType = config.mutation; @@ -208,7 +213,7 @@ export class GraphQLSchema { // Keep track of all implementations by interface name. this._implementationsMap = Object.create(null); - for (const namedType of arrayFrom(allReferencedTypes)) { + for (const namedType of allReferencedTypes) { if (namedType == null) { continue; } @@ -259,52 +264,57 @@ export class GraphQLSchema { } } - getQueryType(): ?GraphQLObjectType { + get [Symbol.toStringTag]() { + return 'GraphQLSchema'; + } + + getQueryType(): Maybe { return this._queryType; } - getMutationType(): ?GraphQLObjectType { + getMutationType(): Maybe { return this._mutationType; } - getSubscriptionType(): ?GraphQLObjectType { + getSubscriptionType(): Maybe { return this._subscriptionType; } + getRootType(operation: OperationTypeNode): Maybe { + switch (operation) { + case OperationTypeNode.QUERY: + return this.getQueryType(); + case OperationTypeNode.MUTATION: + return this.getMutationType(); + case OperationTypeNode.SUBSCRIPTION: + return this.getSubscriptionType(); + } + } + getTypeMap(): TypeMap { return this._typeMap; } - getType(name: string): ?GraphQLNamedType { + getType(name: string): GraphQLNamedType | undefined { return this.getTypeMap()[name]; } getPossibleTypes( abstractType: GraphQLAbstractType, - ): $ReadOnlyArray { + ): ReadonlyArray { return isUnionType(abstractType) ? abstractType.getTypes() : this.getImplementations(abstractType).objects; } - getImplementations( - interfaceType: GraphQLInterfaceType, - ): {| - objects: /* $ReadOnly */ Array, - interfaces: /* $ReadOnly */ Array, - |} { + getImplementations(interfaceType: GraphQLInterfaceType): { + objects: ReadonlyArray; + interfaces: ReadonlyArray; + } { const implementations = this._implementationsMap[interfaceType.name]; return implementations ?? { objects: [], interfaces: [] }; } - // @deprecated: use isSubType instead - will be removed in v16. - isPossibleType( - abstractType: GraphQLAbstractType, - possibleType: GraphQLObjectType, - ): boolean { - return this.isSubType(abstractType, possibleType); - } - isSubType( abstractType: GraphQLAbstractType, maybeSubType: GraphQLObjectType | GraphQLInterfaceType, @@ -332,12 +342,12 @@ export class GraphQLSchema { return map[maybeSubType.name] !== undefined; } - getDirectives(): $ReadOnlyArray { + getDirectives(): ReadonlyArray { return this._directives; } - getDirective(name: string): ?GraphQLDirective { - return find(this.getDirectives(), (directive) => directive.name === name); + getDirective(name: string): Maybe { + return this.getDirectives().find((directive) => directive.name === name); } toConfig(): GraphQLSchemaNormalizedConfig { @@ -346,24 +356,19 @@ export class GraphQLSchema { query: this.getQueryType(), mutation: this.getMutationType(), subscription: this.getSubscriptionType(), - types: objectValues(this.getTypeMap()), - directives: this.getDirectives().slice(), + types: Object.values(this.getTypeMap()), + directives: this.getDirectives(), extensions: this.extensions, astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], + extensionASTNodes: this.extensionASTNodes, assumeValid: this.__validationErrors !== undefined, }; } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [SYMBOL_TO_STRING_TAG]() { - return 'GraphQLSchema'; - } } type TypeMap = ObjMap; -export type GraphQLSchemaValidationOptions = {| +export interface GraphQLSchemaValidationOptions { /** * When building a schema from a GraphQL service's introspection result, it * might be safe to assume the schema is valid. Set to true to assume the @@ -371,34 +376,32 @@ export type GraphQLSchemaValidationOptions = {| * * Default: false */ - assumeValid?: boolean, -|}; - -export type GraphQLSchemaConfig = {| - description?: ?string, - query?: ?GraphQLObjectType, - mutation?: ?GraphQLObjectType, - subscription?: ?GraphQLObjectType, - types?: ?Array, - directives?: ?Array, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?SchemaDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, - ...GraphQLSchemaValidationOptions, -|}; + assumeValid?: boolean; +} + +export interface GraphQLSchemaConfig extends GraphQLSchemaValidationOptions { + description?: Maybe; + query?: Maybe; + mutation?: Maybe; + subscription?: Maybe; + types?: Maybe>; + directives?: Maybe>; + extensions?: Maybe>; + astNode?: Maybe; + extensionASTNodes?: Maybe>; +} /** * @internal */ -export type GraphQLSchemaNormalizedConfig = {| - ...GraphQLSchemaConfig, - description: ?string, - types: Array, - directives: Array, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - assumeValid: boolean, -|}; +export interface GraphQLSchemaNormalizedConfig extends GraphQLSchemaConfig { + description: Maybe; + types: ReadonlyArray; + directives: ReadonlyArray; + extensions: Readonly; + extensionASTNodes: ReadonlyArray; + assumeValid: boolean; +} function collectReferencedTypes( type: GraphQLType, @@ -417,14 +420,14 @@ function collectReferencedTypes( collectReferencedTypes(interfaceType, typeSet); } - for (const field of objectValues(namedType.getFields())) { + for (const field of Object.values(namedType.getFields())) { collectReferencedTypes(field.type, typeSet); for (const arg of field.args) { collectReferencedTypes(arg.type, typeSet); } } } else if (isInputObjectType(namedType)) { - for (const field of objectValues(namedType.getFields())) { + for (const field of Object.values(namedType.getFields())) { collectReferencedTypes(field.type, typeSet); } } diff --git a/src/type/validate.d.ts b/src/type/validate.d.ts deleted file mode 100644 index 98400a2363..0000000000 --- a/src/type/validate.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { GraphQLError } from '../error/GraphQLError'; - -import { GraphQLSchema } from './schema'; - -/** - * Implements the "Type Validation" sub-sections of the specification's - * "Type System" section. - * - * Validation runs synchronously, returning an array of encountered errors, or - * an empty array if no errors were encountered and the Schema is valid. - */ -export function validateSchema( - schema: GraphQLSchema, -): ReadonlyArray; - -/** - * Utility function which asserts a schema is valid by throwing an error if - * it is invalid. - */ -export function assertValidSchema(schema: GraphQLSchema): void; diff --git a/src/type/validate.js b/src/type/validate.ts similarity index 76% rename from src/type/validate.js rename to src/type/validate.ts index a2ddfe4a43..56ad63fc64 100644 --- a/src/type/validate.js +++ b/src/type/validate.ts @@ -1,45 +1,48 @@ -import find from '../polyfills/find'; -import objectValues from '../polyfills/objectValues'; - -import inspect from '../jsutils/inspect'; +import { inspect } from '../jsutils/inspect'; +import type { Maybe } from '../jsutils/Maybe'; import { GraphQLError } from '../error/GraphQLError'; -import { locatedError } from '../error/locatedError'; import type { ASTNode, - NamedTypeNode, DirectiveNode, - OperationTypeNode, + InterfaceTypeDefinitionNode, + InterfaceTypeExtensionNode, + NamedTypeNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, + UnionTypeDefinitionNode, + UnionTypeExtensionNode, } from '../language/ast'; +import { OperationTypeNode } from '../language/ast'; -import { isValidNameError } from '../utilities/assertValidName'; import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators'; -import type { GraphQLSchema } from './schema'; import type { - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType, + GraphQLInputField, GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLUnionType, } from './definition'; -import { assertSchema } from './schema'; -import { isIntrospectionType } from './introspection'; -import { isDirective, GraphQLDeprecatedDirective } from './directives'; import { - isObjectType, - isInterfaceType, - isUnionType, isEnumType, isInputObjectType, + isInputType, + isInterfaceType, isNamedType, isNonNullType, - isInputType, + isObjectType, isOutputType, isRequiredArgument, isRequiredInputField, + isUnionType, } from './definition'; +import { GraphQLDeprecatedDirective, isDirective } from './directives'; +import { isIntrospectionType } from './introspection'; +import type { GraphQLSchema } from './schema'; +import { assertSchema } from './schema'; /** * Implements the "Type Validation" sub-sections of the specification's @@ -50,7 +53,7 @@ import { */ export function validateSchema( schema: GraphQLSchema, -): $ReadOnlyArray { +): ReadonlyArray { // First check to ensure the provided value is in fact a GraphQLSchema. assertSchema(schema); @@ -84,27 +87,25 @@ export function assertValidSchema(schema: GraphQLSchema): void { } class SchemaValidationContext { - +_errors: Array; - +schema: GraphQLSchema; + readonly _errors: Array; + readonly schema: GraphQLSchema; - constructor(schema) { + constructor(schema: GraphQLSchema) { this._errors = []; this.schema = schema; } reportError( message: string, - nodes?: $ReadOnlyArray | ?ASTNode, + nodes?: ReadonlyArray> | Maybe, ): void { - const _nodes = Array.isArray(nodes) ? nodes.filter(Boolean) : nodes; - this.addError(new GraphQLError(message, _nodes)); - } - - addError(error: GraphQLError): void { - this._errors.push(error); + const _nodes = Array.isArray(nodes) + ? (nodes.filter(Boolean) as ReadonlyArray) + : (nodes as Maybe); + this._errors.push(new GraphQLError(message, { nodes: _nodes })); } - getErrors(): $ReadOnlyArray { + getErrors(): ReadonlyArray { return this._errors; } } @@ -119,7 +120,8 @@ function validateRootTypes(context: SchemaValidationContext): void { `Query root type must be Object type, it cannot be ${inspect( queryType, )}.`, - getOperationTypeNode(schema, 'query') ?? queryType.astNode, + getOperationTypeNode(schema, OperationTypeNode.QUERY) ?? + (queryType as any).astNode, ); } @@ -128,7 +130,8 @@ function validateRootTypes(context: SchemaValidationContext): void { context.reportError( 'Mutation root type must be Object type if provided, it cannot be ' + `${inspect(mutationType)}.`, - getOperationTypeNode(schema, 'mutation') ?? mutationType.astNode, + getOperationTypeNode(schema, OperationTypeNode.MUTATION) ?? + (mutationType as any).astNode, ); } @@ -137,7 +140,8 @@ function validateRootTypes(context: SchemaValidationContext): void { context.reportError( 'Subscription root type must be Object type if provided, it cannot be ' + `${inspect(subscriptionType)}.`, - getOperationTypeNode(schema, 'subscription') ?? subscriptionType.astNode, + getOperationTypeNode(schema, OperationTypeNode.SUBSCRIPTION) ?? + (subscriptionType as any).astNode, ); } } @@ -145,14 +149,13 @@ function validateRootTypes(context: SchemaValidationContext): void { function getOperationTypeNode( schema: GraphQLSchema, operation: OperationTypeNode, -): ?ASTNode { - const operationNodes = getAllSubNodes(schema, (node) => node.operationTypes); - for (const node of operationNodes) { - if (node.operation === operation) { - return node.type; - } - } - return undefined; +): Maybe { + return [schema.astNode, ...schema.extensionASTNodes] + .flatMap( + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + (schemaNode) => /* c8 ignore next */ schemaNode?.operationTypes ?? [], + ) + .find((operationNode) => operationNode.operation === operation)?.type; } function validateDirectives(context: SchemaValidationContext): void { @@ -161,7 +164,7 @@ function validateDirectives(context: SchemaValidationContext): void { if (!isDirective(directive)) { context.reportError( `Expected directive but got: ${inspect(directive)}.`, - directive?.astNode, + (directive as any)?.astNode, ); continue; } @@ -169,7 +172,12 @@ function validateDirectives(context: SchemaValidationContext): void { // Ensure they are named correctly. validateName(context, directive); - // TODO: Ensure proper locations. + if (directive.locations.length === 0) { + context.reportError( + `Directive @${directive.name} must include 1 or more locations.`, + directive.astNode, + ); + } // Ensure the arguments are valid. for (const arg of directive.args) { @@ -188,11 +196,7 @@ function validateDirectives(context: SchemaValidationContext): void { if (isRequiredArgument(arg) && arg.deprecationReason != null) { context.reportError( `Required argument @${directive.name}(${arg.name}:) cannot be deprecated.`, - [ - getDeprecatedDirectiveNode(arg.astNode), - // istanbul ignore next (TODO need to write coverage tests) - arg.astNode?.type, - ], + [getDeprecatedDirectiveNode(arg.astNode), arg.astNode?.type], ); } } @@ -201,26 +205,27 @@ function validateDirectives(context: SchemaValidationContext): void { function validateName( context: SchemaValidationContext, - node: { +name: string, +astNode: ?ASTNode, ... }, + node: { readonly name: string; readonly astNode: Maybe }, ): void { // Ensure names are valid, however introspection types opt out. - const error = isValidNameError(node.name); - if (error) { - context.addError(locatedError(error, node.astNode)); + if (node.name.startsWith('__')) { + context.reportError( + `Name "${node.name}" must not begin with "__", which is reserved by GraphQL introspection.`, + node.astNode, + ); } } function validateTypes(context: SchemaValidationContext): void { - const validateInputObjectCircularRefs = createInputObjectCircularRefsValidator( - context, - ); + const validateInputObjectCircularRefs = + createInputObjectCircularRefsValidator(context); const typeMap = context.schema.getTypeMap(); - for (const type of objectValues(typeMap)) { + for (const type of Object.values(typeMap)) { // Ensure all provided types are in fact GraphQL type. if (!isNamedType(type)) { context.reportError( `Expected GraphQL named type but got: ${inspect(type)}.`, - type.astNode, + (type as any).astNode, ); continue; } @@ -262,14 +267,14 @@ function validateFields( context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType, ): void { - const fields = objectValues(type.getFields()); + const fields = Object.values(type.getFields()); // Objects and Interfaces both must define one or more fields. if (fields.length === 0) { - context.reportError( - `Type ${type.name} must define one or more fields.`, - getAllNodes(type), - ); + context.reportError(`Type ${type.name} must define one or more fields.`, [ + type.astNode, + ...type.extensionASTNodes, + ]); } for (const field of fields) { @@ -304,11 +309,7 @@ function validateFields( if (isRequiredArgument(arg) && arg.deprecationReason != null) { context.reportError( `Required argument ${type.name}.${field.name}(${argName}:) cannot be deprecated.`, - [ - getDeprecatedDirectiveNode(arg.astNode), - // istanbul ignore next (TODO need to write coverage tests) - arg.astNode?.type, - ], + [getDeprecatedDirectiveNode(arg.astNode), arg.astNode?.type], ); } } @@ -361,7 +362,7 @@ function validateTypeImplementsInterface( const typeFieldMap = type.getFields(); // Assert each interface field is implemented. - for (const ifaceField of objectValues(iface.getFields())) { + for (const ifaceField of Object.values(iface.getFields())) { const fieldName = ifaceField.name; const typeField = typeFieldMap[fieldName]; @@ -369,7 +370,7 @@ function validateTypeImplementsInterface( if (!typeField) { context.reportError( `Interface field ${iface.name}.${fieldName} expected but ${type.name} does not provide it.`, - [ifaceField.astNode, ...getAllNodes(type)], + [ifaceField.astNode, type.astNode, ...type.extensionASTNodes], ); continue; } @@ -381,19 +382,14 @@ function validateTypeImplementsInterface( `Interface field ${iface.name}.${fieldName} expects type ` + `${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` + `is type ${inspect(typeField.type)}.`, - [ - // istanbul ignore next (TODO need to write coverage tests) - ifaceField.astNode?.type, - // istanbul ignore next (TODO need to write coverage tests) - typeField.astNode?.type, - ], + [ifaceField.astNode?.type, typeField.astNode?.type], ); } // Assert each interface field arg is implemented. for (const ifaceArg of ifaceField.args) { const argName = ifaceArg.name; - const typeArg = find(typeField.args, (arg) => arg.name === argName); + const typeArg = typeField.args.find((arg) => arg.name === argName); // Assert interface field arg exists on object field. if (!typeArg) { @@ -413,12 +409,7 @@ function validateTypeImplementsInterface( `expects type ${inspect(ifaceArg.type)} but ` + `${type.name}.${fieldName}(${argName}:) is type ` + `${inspect(typeArg.type)}.`, - [ - // istanbul ignore next (TODO need to write coverage tests) - ifaceArg.astNode?.type, - // istanbul ignore next (TODO need to write coverage tests) - typeArg.astNode?.type, - ], + [ifaceArg.astNode?.type, typeArg.astNode?.type], ); } @@ -428,7 +419,7 @@ function validateTypeImplementsInterface( // Assert additional arguments must not be required. for (const typeArg of typeField.args) { const argName = typeArg.name; - const ifaceArg = find(ifaceField.args, (arg) => arg.name === argName); + const ifaceArg = ifaceField.args.find((arg) => arg.name === argName); if (!ifaceArg && isRequiredArgument(typeArg)) { context.reportError( `Object field ${type.name}.${fieldName} includes required argument ${argName} that is missing from the Interface field ${iface.name}.${fieldName}.`, @@ -446,7 +437,7 @@ function validateTypeImplementsAncestors( ): void { const ifaceInterfaces = type.getInterfaces(); for (const transitive of iface.getInterfaces()) { - if (ifaceInterfaces.indexOf(transitive) === -1) { + if (!ifaceInterfaces.includes(transitive)) { context.reportError( transitive === type ? `Type ${type.name} cannot implement ${iface.name} because it would create a circular reference.` @@ -469,7 +460,7 @@ function validateUnionMembers( if (memberTypes.length === 0) { context.reportError( `Union type ${union.name} must define one or more member types.`, - getAllNodes(union), + [union.astNode, ...union.extensionASTNodes], ); } @@ -502,21 +493,13 @@ function validateEnumValues( if (enumValues.length === 0) { context.reportError( `Enum type ${enumType.name} must define one or more values.`, - getAllNodes(enumType), + [enumType.astNode, ...enumType.extensionASTNodes], ); } for (const enumValue of enumValues) { - const valueName = enumValue.name; - // Ensure valid name. validateName(context, enumValue); - if (valueName === 'true' || valueName === 'false' || valueName === 'null') { - context.reportError( - `Enum type ${enumType.name} cannot include value: ${valueName}.`, - enumValue.astNode, - ); - } } } @@ -524,12 +507,12 @@ function validateInputFields( context: SchemaValidationContext, inputObj: GraphQLInputObjectType, ): void { - const fields = objectValues(inputObj.getFields()); + const fields = Object.values(inputObj.getFields()); if (fields.length === 0) { context.reportError( `Input Object type ${inputObj.name} must define one or more fields.`, - getAllNodes(inputObj), + [inputObj.astNode, ...inputObj.extensionASTNodes], ); } @@ -550,26 +533,46 @@ function validateInputFields( if (isRequiredInputField(field) && field.deprecationReason != null) { context.reportError( `Required input field ${inputObj.name}.${field.name} cannot be deprecated.`, - [ - getDeprecatedDirectiveNode(field.astNode), - // istanbul ignore next (TODO need to write coverage tests) - field.astNode?.type, - ], + [getDeprecatedDirectiveNode(field.astNode), field.astNode?.type], ); } + + if (inputObj.isOneOf) { + validateOneOfInputObjectField(inputObj, field, context); + } + } +} + +function validateOneOfInputObjectField( + type: GraphQLInputObjectType, + field: GraphQLInputField, + context: SchemaValidationContext, +): void { + if (isNonNullType(field.type)) { + context.reportError( + `OneOf input field ${type.name}.${field.name} must be nullable.`, + field.astNode?.type, + ); + } + + if (field.defaultValue !== undefined) { + context.reportError( + `OneOf input field ${type.name}.${field.name} cannot have a default value.`, + field.astNode, + ); } } function createInputObjectCircularRefsValidator( context: SchemaValidationContext, -): (GraphQLInputObjectType) => void { +): (inputObj: GraphQLInputObjectType) => void { // Modified copy of algorithm from 'src/validation/rules/NoFragmentCycles.js'. // Tracks already visited types to maintain O(N) and to ensure that cycles // are not redundantly reported. const visitedTypes = Object.create(null); // Array of types nodes used to produce meaningful errors - const fieldPath = []; + const fieldPath: Array = []; // Position in the type path const fieldPathIndexByTypeName = Object.create(null); @@ -587,7 +590,7 @@ function createInputObjectCircularRefsValidator( visitedTypes[inputObj.name] = true; fieldPathIndexByTypeName[inputObj.name] = fieldPath.length; - const fields = objectValues(inputObj.getFields()); + const fields = Object.values(inputObj.getFields()); for (const field of fields) { if (isNonNullType(field.type) && isInputObjectType(field.type.ofType)) { const fieldType = field.type.ofType; @@ -612,57 +615,41 @@ function createInputObjectCircularRefsValidator( } } -type SDLDefinedObject = { - +astNode: ?T, - +extensionASTNodes?: ?$ReadOnlyArray, - ... -}; - -function getAllNodes( - object: SDLDefinedObject, -): $ReadOnlyArray { - const { astNode, extensionASTNodes } = object; - return astNode - ? extensionASTNodes - ? [astNode].concat(extensionASTNodes) - : [astNode] - : extensionASTNodes ?? []; -} - -function getAllSubNodes( - object: SDLDefinedObject, - getter: (T | K) => ?(L | $ReadOnlyArray), -): $ReadOnlyArray { - let subNodes = []; - for (const node of getAllNodes(object)) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - subNodes = subNodes.concat(getter(node) ?? []); - } - return subNodes; -} - function getAllImplementsInterfaceNodes( type: GraphQLObjectType | GraphQLInterfaceType, iface: GraphQLInterfaceType, -): $ReadOnlyArray { - return getAllSubNodes(type, (typeNode) => typeNode.interfaces).filter( - (ifaceNode) => ifaceNode.name.value === iface.name, - ); +): ReadonlyArray { + const { astNode, extensionASTNodes } = type; + const nodes: ReadonlyArray< + | ObjectTypeDefinitionNode + | ObjectTypeExtensionNode + | InterfaceTypeDefinitionNode + | InterfaceTypeExtensionNode + > = astNode != null ? [astNode, ...extensionASTNodes] : extensionASTNodes; + + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + return nodes + .flatMap((typeNode) => /* c8 ignore next */ typeNode.interfaces ?? []) + .filter((ifaceNode) => ifaceNode.name.value === iface.name); } function getUnionMemberTypeNodes( union: GraphQLUnionType, typeName: string, -): ?$ReadOnlyArray { - return getAllSubNodes(union, (unionNode) => unionNode.types).filter( - (typeNode) => typeNode.name.value === typeName, - ); +): Maybe> { + const { astNode, extensionASTNodes } = union; + const nodes: ReadonlyArray = + astNode != null ? [astNode, ...extensionASTNodes] : extensionASTNodes; + + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + return nodes + .flatMap((unionNode) => /* c8 ignore next */ unionNode.types ?? []) + .filter((typeNode) => typeNode.name.value === typeName); } function getDeprecatedDirectiveNode( - definitionNode: ?{ +directives?: $ReadOnlyArray, ... }, -): ?DirectiveNode { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + definitionNode: Maybe<{ readonly directives?: ReadonlyArray }>, +): Maybe { return definitionNode?.directives?.find( (node) => node.name.value === GraphQLDeprecatedDirective.name, ); diff --git a/src/utilities/TypeInfo.d.ts b/src/utilities/TypeInfo.d.ts deleted file mode 100644 index 499fb02978..0000000000 --- a/src/utilities/TypeInfo.d.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { Visitor } from '../language/visitor'; -import { ASTNode, ASTKindToNode, FieldNode } from '../language/ast'; -import { GraphQLSchema } from '../type/schema'; -import { GraphQLDirective } from '../type/directives'; -import { - GraphQLType, - GraphQLInputType, - GraphQLOutputType, - GraphQLCompositeType, - GraphQLField, - GraphQLArgument, - GraphQLEnumValue, -} from '../type/definition'; - -/** - * TypeInfo is a utility class which, given a GraphQL schema, can keep track - * of the current field and type definitions at any point in a GraphQL document - * AST during a recursive descent by calling `enter(node)` and `leave(node)`. - */ -export class TypeInfo { - constructor( - schema: GraphQLSchema, - // NOTE: this experimental optional second parameter is only needed in order - // to support non-spec-compliant code bases. You should never need to use it. - // It may disappear in the future. - getFieldDefFn?: getFieldDef, - // Initial type may be provided in rare cases to facilitate traversals - // beginning somewhere other than documents. - initialType?: GraphQLType, - ); - - getType(): Maybe; - getParentType(): Maybe; - getInputType(): Maybe; - getParentInputType(): Maybe; - getFieldDef(): GraphQLField>; - getDefaultValue(): Maybe; - getDirective(): Maybe; - getArgument(): Maybe; - getEnumValue(): Maybe; - enter(node: ASTNode): any; - leave(node: ASTNode): any; -} - -type getFieldDef = ( - schema: GraphQLSchema, - parentType: GraphQLType, - fieldNode: FieldNode, -) => Maybe>; - -/** - * Creates a new visitor instance which maintains a provided TypeInfo instance - * along with visiting visitor. - */ -export function visitWithTypeInfo( - typeInfo: TypeInfo, - visitor: Visitor, -): Visitor; diff --git a/src/utilities/TypeInfo.js b/src/utilities/TypeInfo.ts similarity index 72% rename from src/utilities/TypeInfo.js rename to src/utilities/TypeInfo.ts index f18b03d68e..e72dfb01fb 100644 --- a/src/utilities/TypeInfo.js +++ b/src/utilities/TypeInfo.ts @@ -1,40 +1,40 @@ -import find from '../polyfills/find'; +import type { Maybe } from '../jsutils/Maybe'; -import type { Visitor } from '../language/visitor'; -import type { ASTNode, ASTKindToNode, FieldNode } from '../language/ast'; -import { Kind } from '../language/kinds'; +import type { ASTNode, FieldNode } from '../language/ast'; import { isNode } from '../language/ast'; -import { getVisitFn } from '../language/visitor'; +import { Kind } from '../language/kinds'; +import type { ASTVisitor } from '../language/visitor'; +import { getEnterLeaveForKind } from '../language/visitor'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLDirective } from '../type/directives'; import type { - GraphQLType, - GraphQLInputType, - GraphQLOutputType, + GraphQLArgument, GraphQLCompositeType, + GraphQLEnumValue, GraphQLField, - GraphQLArgument, GraphQLInputField, - GraphQLEnumValue, + GraphQLInputType, + GraphQLOutputType, + GraphQLType, } from '../type/definition'; import { - isObjectType, - isInterfaceType, + getNamedType, + getNullableType, + isCompositeType, isEnumType, isInputObjectType, - isListType, - isCompositeType, isInputType, + isInterfaceType, + isListType, + isObjectType, isOutputType, - getNullableType, - getNamedType, } from '../type/definition'; +import type { GraphQLDirective } from '../type/directives'; import { SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, } from '../type/introspection'; +import type { GraphQLSchema } from '../type/schema'; import { typeFromAST } from './typeFromAST'; @@ -44,26 +44,27 @@ import { typeFromAST } from './typeFromAST'; * AST during a recursive descent by calling `enter(node)` and `leave(node)`. */ export class TypeInfo { - _schema: GraphQLSchema; - _typeStack: Array; - _parentTypeStack: Array; - _inputTypeStack: Array; - _fieldDefStack: Array>; - _defaultValueStack: Array; - _directive: ?GraphQLDirective; - _argument: ?GraphQLArgument; - _enumValue: ?GraphQLEnumValue; - _getFieldDef: typeof getFieldDef; + private _schema: GraphQLSchema; + private _typeStack: Array>; + private _parentTypeStack: Array>; + private _inputTypeStack: Array>; + private _fieldDefStack: Array>>; + private _defaultValueStack: Array>; + private _directive: Maybe; + private _argument: Maybe; + private _enumValue: Maybe; + private _getFieldDef: GetFieldDefFn; constructor( schema: GraphQLSchema, - // NOTE: this experimental optional second parameter is only needed in order - // to support non-spec-compliant code bases. You should never need to use it. - // It may disappear in the future. - getFieldDefFn?: typeof getFieldDef, - // Initial type may be provided in rare cases to facilitate traversals - // beginning somewhere other than documents. - initialType?: GraphQLType, + /** + * Initial type may be provided in rare cases to facilitate traversals + * beginning somewhere other than documents. + */ + initialType?: Maybe, + + /** @deprecated will be removed in 17.0.0 */ + getFieldDefFn?: GetFieldDefFn, ) { this._schema = schema; this._typeStack = []; @@ -88,63 +89,67 @@ export class TypeInfo { } } - getType(): ?GraphQLOutputType { + get [Symbol.toStringTag]() { + return 'TypeInfo'; + } + + getType(): Maybe { if (this._typeStack.length > 0) { return this._typeStack[this._typeStack.length - 1]; } } - getParentType(): ?GraphQLCompositeType { + getParentType(): Maybe { if (this._parentTypeStack.length > 0) { return this._parentTypeStack[this._parentTypeStack.length - 1]; } } - getInputType(): ?GraphQLInputType { + getInputType(): Maybe { if (this._inputTypeStack.length > 0) { return this._inputTypeStack[this._inputTypeStack.length - 1]; } } - getParentInputType(): ?GraphQLInputType { + getParentInputType(): Maybe { if (this._inputTypeStack.length > 1) { return this._inputTypeStack[this._inputTypeStack.length - 2]; } } - getFieldDef(): ?GraphQLField { + getFieldDef(): Maybe> { if (this._fieldDefStack.length > 0) { return this._fieldDefStack[this._fieldDefStack.length - 1]; } } - getDefaultValue(): ?mixed { + getDefaultValue(): Maybe { if (this._defaultValueStack.length > 0) { return this._defaultValueStack[this._defaultValueStack.length - 1]; } } - getDirective(): ?GraphQLDirective { + getDirective(): Maybe { return this._directive; } - getArgument(): ?GraphQLArgument { + getArgument(): Maybe { return this._argument; } - getEnumValue(): ?GraphQLEnumValue { + getEnumValue(): Maybe { return this._enumValue; } enter(node: ASTNode) { const schema = this._schema; - // Note: many of the types below are explicitly typed as "mixed" to drop + // Note: many of the types below are explicitly typed as "unknown" to drop // any assumptions of a valid schema to ensure runtime types are properly // checked before continuing since TypeInfo is used as part of validation // which occurs before guarantees of schema and document validity. switch (node.kind) { case Kind.SELECTION_SET: { - const namedType: mixed = getNamedType(this.getType()); + const namedType: unknown = getNamedType(this.getType()); this._parentTypeStack.push( isCompositeType(namedType) ? namedType : undefined, ); @@ -153,7 +158,7 @@ export class TypeInfo { case Kind.FIELD: { const parentType = this.getParentType(); let fieldDef; - let fieldType: mixed; + let fieldType: unknown; if (parentType) { fieldDef = this._getFieldDef(schema, parentType, node); if (fieldDef) { @@ -168,32 +173,21 @@ export class TypeInfo { this._directive = schema.getDirective(node.name.value); break; case Kind.OPERATION_DEFINITION: { - let type: mixed; - switch (node.operation) { - case 'query': - type = schema.getQueryType(); - break; - case 'mutation': - type = schema.getMutationType(); - break; - case 'subscription': - type = schema.getSubscriptionType(); - break; - } - this._typeStack.push(isObjectType(type) ? type : undefined); + const rootType = schema.getRootType(node.operation); + this._typeStack.push(isObjectType(rootType) ? rootType : undefined); break; } case Kind.INLINE_FRAGMENT: case Kind.FRAGMENT_DEFINITION: { const typeConditionAST = node.typeCondition; - const outputType: mixed = typeConditionAST + const outputType: unknown = typeConditionAST ? typeFromAST(schema, typeConditionAST) : getNamedType(this.getType()); this._typeStack.push(isOutputType(outputType) ? outputType : undefined); break; } case Kind.VARIABLE_DEFINITION: { - const inputType: mixed = typeFromAST(schema, node.type); + const inputType: unknown = typeFromAST(schema, node.type); this._inputTypeStack.push( isInputType(inputType) ? inputType : undefined, ); @@ -201,11 +195,10 @@ export class TypeInfo { } case Kind.ARGUMENT: { let argDef; - let argType: mixed; + let argType: unknown; const fieldOrDirective = this.getDirective() ?? this.getFieldDef(); if (fieldOrDirective) { - argDef = find( - fieldOrDirective.args, + argDef = fieldOrDirective.args.find( (arg) => arg.name === node.name.value, ); if (argDef) { @@ -218,8 +211,8 @@ export class TypeInfo { break; } case Kind.LIST: { - const listType: mixed = getNullableType(this.getInputType()); - const itemType: mixed = isListType(listType) + const listType: unknown = getNullableType(this.getInputType()); + const itemType: unknown = isListType(listType) ? listType.ofType : listType; // List positions never have a default value. @@ -228,9 +221,9 @@ export class TypeInfo { break; } case Kind.OBJECT_FIELD: { - const objectType: mixed = getNamedType(this.getInputType()); - let inputFieldType: GraphQLInputType | void; - let inputField: GraphQLInputField | void; + const objectType: unknown = getNamedType(this.getInputType()); + let inputFieldType: GraphQLInputType | undefined; + let inputField: GraphQLInputField | undefined; if (isInputObjectType(objectType)) { inputField = objectType.getFields()[node.name.value]; if (inputField) { @@ -246,7 +239,7 @@ export class TypeInfo { break; } case Kind.ENUM: { - const enumType: mixed = getNamedType(this.getInputType()); + const enumType: unknown = getNamedType(this.getInputType()); let enumValue; if (isEnumType(enumType)) { enumValue = enumType.getValue(node.value); @@ -254,6 +247,8 @@ export class TypeInfo { this._enumValue = enumValue; break; } + default: + // Ignore other nodes } } @@ -290,10 +285,18 @@ export class TypeInfo { case Kind.ENUM: this._enumValue = null; break; + default: + // Ignore other nodes } } } +type GetFieldDefFn = ( + schema: GraphQLSchema, + parentType: GraphQLType, + fieldNode: FieldNode, +) => Maybe>; + /** * Not exactly the same as the executor's definition of getFieldDef, in this * statically evaluated environment we do not always have an Object type, @@ -303,7 +306,7 @@ function getFieldDef( schema: GraphQLSchema, parentType: GraphQLType, fieldNode: FieldNode, -): ?GraphQLField { +): Maybe> { const name = fieldNode.name.value; if ( name === SchemaMetaFieldDef.name && @@ -328,14 +331,15 @@ function getFieldDef( */ export function visitWithTypeInfo( typeInfo: TypeInfo, - visitor: Visitor, -): Visitor { + visitor: ASTVisitor, +): ASTVisitor { return { - enter(node) { + enter(...args) { + const node = args[0]; typeInfo.enter(node); - const fn = getVisitFn(visitor, node.kind, /* isLeaving */ false); + const fn = getEnterLeaveForKind(visitor, node.kind).enter; if (fn) { - const result = fn.apply(visitor, arguments); + const result = fn.apply(visitor, args); if (result !== undefined) { typeInfo.leave(node); if (isNode(result)) { @@ -345,11 +349,12 @@ export function visitWithTypeInfo( return result; } }, - leave(node) { - const fn = getVisitFn(visitor, node.kind, /* isLeaving */ true); + leave(...args) { + const node = args[0]; + const fn = getEnterLeaveForKind(visitor, node.kind).leave; let result; if (fn) { - result = fn.apply(visitor, arguments); + result = fn.apply(visitor, args); } typeInfo.leave(node); return result; diff --git a/src/utilities/__tests__/TypeInfo-test.js b/src/utilities/__tests__/TypeInfo-test.ts similarity index 91% rename from src/utilities/__tests__/TypeInfo-test.js rename to src/utilities/__tests__/TypeInfo-test.ts index 73ca3d5090..5c04458c51 100644 --- a/src/utilities/__tests__/TypeInfo-test.js +++ b/src/utilities/__tests__/TypeInfo-test.ts @@ -1,22 +1,63 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; +import { invariant } from '../../jsutils/invariant'; import { parse, parseValue } from '../../language/parser'; import { print } from '../../language/printer'; import { visit } from '../../language/visitor'; import { getNamedType, isCompositeType } from '../../type/definition'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../buildASTSchema'; import { TypeInfo, visitWithTypeInfo } from '../TypeInfo'; -import { testSchema } from '../../validation/__tests__/harness'; +const testSchema = buildSchema(` + interface Pet { + name: String + } + + type Dog implements Pet { + name: String + } + + type Cat implements Pet { + name: String + } + + type Human { + name: String + pets: [Pet] + } + + type Alien { + name(surname: Boolean): String + } + + type QueryRoot { + human(id: ID): Human + alien: Alien + } + + schema { + query: QueryRoot + } +`); describe('TypeInfo', () => { + const schema = new GraphQLSchema({}); + + it('can be Object.toStringified', () => { + const typeInfo = new TypeInfo(schema); + + expect(Object.prototype.toString.call(typeInfo)).to.equal( + '[object TypeInfo]', + ); + }); + it('allow all methods to be called before entering any node', () => { - const typeInfo = new TypeInfo(testSchema); + const typeInfo = new TypeInfo(schema); expect(typeInfo.getType()).to.equal(undefined); expect(typeInfo.getParentType()).to.equal(undefined); @@ -58,7 +99,7 @@ describe('visitWithTypeInfo', () => { `); const typeInfo = new TypeInfo(schema); - const rootTypes = {}; + const rootTypes: any = {}; visit( ast, visitWithTypeInfo(typeInfo, { @@ -80,7 +121,7 @@ describe('visitWithTypeInfo', () => { '{ human(id: 4) { name, pets { ... { name } }, unknown } }', ); - const visitorArgs = []; + const visitorArgs: Array = []; visit(ast, { enter(...args) { visitorArgs.push(['enter', ...args]); @@ -90,7 +131,7 @@ describe('visitWithTypeInfo', () => { }, }); - const wrappedVisitorArgs = []; + const wrappedVisitorArgs: Array = []; const typeInfo = new TypeInfo(testSchema); visit( ast, @@ -108,7 +149,7 @@ describe('visitWithTypeInfo', () => { }); it('maintains type info during visit', () => { - const visited = []; + const visited: Array = []; const typeInfo = new TypeInfo(testSchema); @@ -193,7 +234,7 @@ describe('visitWithTypeInfo', () => { }); it('maintains type info during edit', () => { - const visited = []; + const visited: Array = []; const typeInfo = new TypeInfo(testSchema); const ast = parse('{ human(id: 4) { name, pets }, alien }'); @@ -308,13 +349,18 @@ describe('visitWithTypeInfo', () => { }); it('supports traversals of input values', () => { + const schema = buildSchema(` + input ComplexInput { + stringListField: [String] + } + `); const ast = parseValue('{ stringListField: ["foo"] }'); - const complexInputType = testSchema.getType('ComplexInput'); + const complexInputType = schema.getType('ComplexInput'); invariant(complexInputType != null); - const typeInfo = new TypeInfo(testSchema, undefined, complexInputType); + const typeInfo = new TypeInfo(schema, complexInputType); - const visited = []; + const visited: Array = []; visit( ast, visitWithTypeInfo(typeInfo, { @@ -357,13 +403,13 @@ describe('visitWithTypeInfo', () => { const humanType = testSchema.getType('Human'); invariant(humanType != null); - const typeInfo = new TypeInfo(testSchema, undefined, humanType); + const typeInfo = new TypeInfo(testSchema, humanType); const ast = parse('{ name, pets { name } }'); const operationNode = ast.definitions[0]; invariant(operationNode.kind === 'OperationDefinition'); - const visited = []; + const visited: Array = []; visit( operationNode.selectionSet, visitWithTypeInfo(typeInfo, { diff --git a/src/utilities/__tests__/assertValidName-test.js b/src/utilities/__tests__/assertValidName-test.js deleted file mode 100644 index 40f9d2e398..0000000000 --- a/src/utilities/__tests__/assertValidName-test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { assertValidName } from '../assertValidName'; - -describe('assertValidName()', () => { - it('passthrough valid name', () => { - expect(assertValidName('_ValidName123')).to.equal('_ValidName123'); - }); - - it('throws for use of leading double underscores', () => { - expect(() => assertValidName('__bad')).to.throw( - '"__bad" must not begin with "__", which is reserved by GraphQL introspection.', - ); - }); - - it('throws for non-strings', () => { - // $FlowExpectedError[incompatible-call] - expect(() => assertValidName({})).to.throw('Expected name to be a string.'); - }); - - it('throws for names with invalid characters', () => { - expect(() => assertValidName('>--()-->')).to.throw(/Names must match/); - }); -}); diff --git a/src/utilities/__tests__/astFromValue-test.js b/src/utilities/__tests__/astFromValue-test.ts similarity index 100% rename from src/utilities/__tests__/astFromValue-test.js rename to src/utilities/__tests__/astFromValue-test.ts index 3641f00227..b8f2361bd7 100644 --- a/src/utilities/__tests__/astFromValue-test.js +++ b/src/utilities/__tests__/astFromValue-test.ts @@ -2,19 +2,19 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import { - GraphQLID, - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, -} from '../../type/scalars'; -import { + GraphQLEnumType, + GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, - GraphQLEnumType, - GraphQLInputObjectType, } from '../../type/definition'; +import { + GraphQLBoolean, + GraphQLFloat, + GraphQLID, + GraphQLInt, + GraphQLString, +} from '../../type/scalars'; import { astFromValue } from '../astFromValue'; diff --git a/src/utilities/__tests__/buildASTSchema-test.js b/src/utilities/__tests__/buildASTSchema-test.ts similarity index 85% rename from src/utilities/__tests__/buildASTSchema-test.js rename to src/utilities/__tests__/buildASTSchema-test.ts index f364e311dd..29280474ec 100644 --- a/src/utilities/__tests__/buildASTSchema-test.js +++ b/src/utilities/__tests__/buildASTSchema-test.ts @@ -1,71 +1,66 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; -import invariant from '../../jsutils/invariant'; +import { invariant } from '../../jsutils/invariant'; +import type { Maybe } from '../../jsutils/Maybe'; import type { ASTNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; import { print } from '../../language/printer'; -import type { GraphQLNamedType } from '../../type/definition'; -import { GraphQLSchema } from '../../type/schema'; -import { validateSchema } from '../../type/validate'; -import { __Schema, __EnumValue } from '../../type/introspection'; +import { + assertEnumType, + assertInputObjectType, + assertInterfaceType, + assertObjectType, + assertScalarType, + assertUnionType, +} from '../../type/definition'; import { assertDirective, - GraphQLSkipDirective, - GraphQLIncludeDirective, GraphQLDeprecatedDirective, + GraphQLIncludeDirective, + GraphQLOneOfDirective, + GraphQLSkipDirective, GraphQLSpecifiedByDirective, } from '../../type/directives'; +import { __EnumValue, __Schema } from '../../type/introspection'; import { + GraphQLBoolean, + GraphQLFloat, GraphQLID, GraphQLInt, - GraphQLFloat, GraphQLString, - GraphQLBoolean, } from '../../type/scalars'; -import { - assertObjectType, - assertInputObjectType, - assertEnumType, - assertUnionType, - assertInterfaceType, - assertScalarType, -} from '../../type/definition'; +import { GraphQLSchema } from '../../type/schema'; +import { validateSchema } from '../../type/validate'; import { graphqlSync } from '../../graphql'; -import { printType, printSchema } from '../printSchema'; import { buildASTSchema, buildSchema } from '../buildASTSchema'; +import { printSchema, printType } from '../printSchema'; /** * This function does a full cycle of going from a string with the contents of * the SDL, parsed in a schema AST, materializing that schema AST into an * in-memory GraphQLSchema, and then finally printing that object into the SDL */ -function cycleSDL(sdl: string, options): string { - const ast = parse(sdl); - const schema = buildASTSchema(ast, options); - - const commentDescriptions = options?.commentDescriptions; - return printSchema(schema, { commentDescriptions }); +function cycleSDL(sdl: string): string { + return printSchema(buildSchema(sdl)); } -function printASTNode(obj: ?{ +astNode: ?ASTNode, ... }): string { +function expectASTNode(obj: Maybe<{ readonly astNode: Maybe }>) { invariant(obj?.astNode != null); - return print(obj.astNode); + return expect(print(obj.astNode)); } -function printAllASTNodes(obj: GraphQLNamedType): string { - invariant(obj.astNode != null && obj.extensionASTNodes != null); - return print({ - kind: Kind.DOCUMENT, - definitions: [obj.astNode, ...obj.extensionASTNodes], - }); +function expectExtensionASTNodes(obj: { + readonly extensionASTNodes: ReadonlyArray; +}) { + return expect(obj.extensionASTNodes.map(print).join('\n\n')); } describe('Schema Builder', () => { @@ -95,7 +90,7 @@ describe('Schema Builder', () => { const source = '{ add(x: 34, y: 55) }'; const rootValue = { - add: ({ x, y }) => x + y, + add: ({ x, y }: { x: number; y: number }) => x + y, }; expect(graphqlSync({ schema, source, rootValue })).to.deep.equal({ data: { add: 89 }, @@ -225,36 +220,10 @@ describe('Schema Builder', () => { expect(cycleSDL(sdl)).to.equal(sdl); }); - it('Supports option for comment descriptions', () => { - const sdl = dedent` - # This is a directive - directive @foo( - # It has an argument - arg: Int - ) on FIELD - - # With an enum - enum Color { - RED - - # Not a creative color - GREEN - BLUE - } - - # What a great type - type Query { - # And a field to boot - str: String - } - `; - expect(cycleSDL(sdl, { commentDescriptions: true })).to.equal(sdl); - }); - it('Maintains @include, @skip & @specifiedBy', () => { const schema = buildSchema('type Query'); - expect(schema.getDirectives()).to.have.lengthOf(4); + expect(schema.getDirectives()).to.have.lengthOf(5); expect(schema.getDirective('skip')).to.equal(GraphQLSkipDirective); expect(schema.getDirective('include')).to.equal(GraphQLIncludeDirective); expect(schema.getDirective('deprecated')).to.equal( @@ -263,6 +232,7 @@ describe('Schema Builder', () => { expect(schema.getDirective('specifiedBy')).to.equal( GraphQLSpecifiedByDirective, ); + expect(schema.getDirective('oneOf')).to.equal(GraphQLOneOfDirective); }); it('Overriding directives excludes specified', () => { @@ -271,9 +241,10 @@ describe('Schema Builder', () => { directive @include on FIELD directive @deprecated on FIELD_DEFINITION directive @specifiedBy on FIELD_DEFINITION + directive @oneOf on OBJECT `); - expect(schema.getDirectives()).to.have.lengthOf(4); + expect(schema.getDirectives()).to.have.lengthOf(5); expect(schema.getDirective('skip')).to.not.equal(GraphQLSkipDirective); expect(schema.getDirective('include')).to.not.equal( GraphQLIncludeDirective, @@ -284,18 +255,20 @@ describe('Schema Builder', () => { expect(schema.getDirective('specifiedBy')).to.not.equal( GraphQLSpecifiedByDirective, ); + expect(schema.getDirective('oneOf')).to.not.equal(GraphQLOneOfDirective); }); - it('Adding directives maintains @include, @skip & @specifiedBy', () => { + it('Adding directives maintains @include, @skip, @deprecated, @specifiedBy, and @oneOf', () => { const schema = buildSchema(` directive @foo(arg: Int) on FIELD `); - expect(schema.getDirectives()).to.have.lengthOf(5); + expect(schema.getDirectives()).to.have.lengthOf(6); expect(schema.getDirective('skip')).to.not.equal(undefined); expect(schema.getDirective('include')).to.not.equal(undefined); expect(schema.getDirective('deprecated')).to.not.equal(undefined); expect(schema.getDirective('specifiedBy')).to.not.equal(undefined); + expect(schema.getDirective('oneOf')).to.not.equal(undefined); }); it('Type modifiers', () => { @@ -675,27 +648,23 @@ describe('Schema Builder', () => { const myEnum = assertEnumType(schema.getType('MyEnum')); const value = myEnum.getValue('VALUE'); - expect(value).to.include({ isDeprecated: false }); + expect(value).to.include({ deprecationReason: undefined }); const oldValue = myEnum.getValue('OLD_VALUE'); expect(oldValue).to.include({ - isDeprecated: true, deprecationReason: 'No longer supported', }); const otherValue = myEnum.getValue('OTHER_VALUE'); expect(otherValue).to.include({ - isDeprecated: true, deprecationReason: 'Terrible reasons', }); const rootFields = assertObjectType(schema.getType('Query')).getFields(); expect(rootFields.field1).to.include({ - isDeprecated: true, deprecationReason: 'No longer supported', }); expect(rootFields.field2).to.include({ - isDeprecated: true, deprecationReason: 'Because I said so', }); @@ -742,34 +711,35 @@ describe('Schema Builder', () => { const schema = buildSchema(sdl); expect(schema.getType('Foo')).to.include({ - specifiedByUrl: 'https://example.com/foo_spec', + specifiedByURL: 'https://example.com/foo_spec', }); }); it('Correctly extend scalar type', () => { - const scalarSDL = dedent` + const schema = buildSchema(` scalar SomeScalar - extend scalar SomeScalar @foo - extend scalar SomeScalar @bar - `; - const schema = buildSchema(` - ${scalarSDL} + directive @foo on SCALAR directive @bar on SCALAR `); const someScalar = assertScalarType(schema.getType('SomeScalar')); - expect(printType(someScalar) + '\n').to.equal(dedent` + expect(printType(someScalar)).to.equal(dedent` scalar SomeScalar `); - expect(printAllASTNodes(someScalar)).to.equal(scalarSDL); + expectASTNode(someScalar).to.equal('scalar SomeScalar'); + expectExtensionASTNodes(someScalar).to.equal(dedent` + extend scalar SomeScalar @foo + + extend scalar SomeScalar @bar + `); }); it('Correctly extend object type', () => { - const objectSDL = dedent` + const schema = buildSchema(` type SomeObject implements Foo { first: String } @@ -781,16 +751,14 @@ describe('Schema Builder', () => { extend type SomeObject implements Baz { third: Float } - `; - const schema = buildSchema(` - ${objectSDL} + interface Foo interface Bar interface Baz `); const someObject = assertObjectType(schema.getType('SomeObject')); - expect(printType(someObject) + '\n').to.equal(dedent` + expect(printType(someObject)).to.equal(dedent` type SomeObject implements Foo & Bar & Baz { first: String second: Int @@ -798,11 +766,24 @@ describe('Schema Builder', () => { } `); - expect(printAllASTNodes(someObject)).to.equal(objectSDL); + expectASTNode(someObject).to.equal(dedent` + type SomeObject implements Foo { + first: String + } + `); + expectExtensionASTNodes(someObject).to.equal(dedent` + extend type SomeObject implements Bar { + second: Int + } + + extend type SomeObject implements Baz { + third: Float + } + `); }); it('Correctly extend interface type', () => { - const interfaceSDL = dedent` + const schema = buildSchema(dedent` interface SomeInterface { first: String } @@ -814,11 +795,10 @@ describe('Schema Builder', () => { extend interface SomeInterface { third: Float } - `; - const schema = buildSchema(interfaceSDL); + `); const someInterface = assertInterfaceType(schema.getType('SomeInterface')); - expect(printType(someInterface) + '\n').to.equal(dedent` + expect(printType(someInterface)).to.equal(dedent` interface SomeInterface { first: String second: Int @@ -826,34 +806,48 @@ describe('Schema Builder', () => { } `); - expect(printAllASTNodes(someInterface)).to.equal(interfaceSDL); + expectASTNode(someInterface).to.equal(dedent` + interface SomeInterface { + first: String + } + `); + expectExtensionASTNodes(someInterface).to.equal(dedent` + extend interface SomeInterface { + second: Int + } + + extend interface SomeInterface { + third: Float + } + `); }); it('Correctly extend union type', () => { - const unionSDL = dedent` + const schema = buildSchema(` union SomeUnion = FirstType - extend union SomeUnion = SecondType - extend union SomeUnion = ThirdType - `; - const schema = buildSchema(` - ${unionSDL} + type FirstType type SecondType type ThirdType `); const someUnion = assertUnionType(schema.getType('SomeUnion')); - expect(printType(someUnion) + '\n').to.equal(dedent` + expect(printType(someUnion)).to.equal(dedent` union SomeUnion = FirstType | SecondType | ThirdType `); - expect(printAllASTNodes(someUnion)).to.equal(unionSDL); + expectASTNode(someUnion).to.equal('union SomeUnion = FirstType'); + expectExtensionASTNodes(someUnion).to.equal(dedent` + extend union SomeUnion = SecondType + + extend union SomeUnion = ThirdType + `); }); it('Correctly extend enum type', () => { - const enumSDL = dedent` + const schema = buildSchema(dedent` enum SomeEnum { FIRST } @@ -865,11 +859,10 @@ describe('Schema Builder', () => { extend enum SomeEnum { THIRD } - `; - const schema = buildSchema(enumSDL); + `); const someEnum = assertEnumType(schema.getType('SomeEnum')); - expect(printType(someEnum) + '\n').to.equal(dedent` + expect(printType(someEnum)).to.equal(dedent` enum SomeEnum { FIRST SECOND @@ -877,11 +870,24 @@ describe('Schema Builder', () => { } `); - expect(printAllASTNodes(someEnum)).to.equal(enumSDL); + expectASTNode(someEnum).to.equal(dedent` + enum SomeEnum { + FIRST + } + `); + expectExtensionASTNodes(someEnum).to.equal(dedent` + extend enum SomeEnum { + SECOND + } + + extend enum SomeEnum { + THIRD + } + `); }); it('Correctly extend input object type', () => { - const inputSDL = dedent` + const schema = buildSchema(dedent` input SomeInput { first: String } @@ -893,11 +899,10 @@ describe('Schema Builder', () => { extend input SomeInput { third: Float } - `; - const schema = buildSchema(inputSDL); + `); const someInput = assertInputObjectType(schema.getType('SomeInput')); - expect(printType(someInput) + '\n').to.equal(dedent` + expect(printType(someInput)).to.equal(dedent` input SomeInput { first: String second: Int @@ -905,7 +910,20 @@ describe('Schema Builder', () => { } `); - expect(printAllASTNodes(someInput)).to.equal(inputSDL); + expectASTNode(someInput).to.equal(dedent` + input SomeInput { + first: String + } + `); + expectExtensionASTNodes(someInput).to.equal(dedent` + extend input SomeInput { + second: Int + } + + extend input SomeInput { + third: Float + } + `); }); it('Correctly assign AST nodes', () => { @@ -965,25 +983,23 @@ describe('Schema Builder', () => { ]).to.be.deep.equal(ast.definitions); const testField = query.getFields().testField; - expect(printASTNode(testField)).to.equal( + expectASTNode(testField).to.equal( 'testField(testArg: TestInput): TestUnion', ); - expect(printASTNode(testField.args[0])).to.equal('testArg: TestInput'); - expect(printASTNode(testInput.getFields().testInputField)).to.equal( + expectASTNode(testField.args[0]).to.equal('testArg: TestInput'); + expectASTNode(testInput.getFields().testInputField).to.equal( 'testInputField: TestEnum', ); - expect(printASTNode(testEnum.getValue('TEST_VALUE'))).to.equal( - 'TEST_VALUE', - ); + expectASTNode(testEnum.getValue('TEST_VALUE')).to.equal('TEST_VALUE'); - expect(printASTNode(testInterface.getFields().interfaceField)).to.equal( + expectASTNode(testInterface.getFields().interfaceField).to.equal( 'interfaceField: String', ); - expect(printASTNode(testType.getFields().interfaceField)).to.equal( + expectASTNode(testType.getFields().interfaceField).to.equal( 'interfaceField: String', ); - expect(printASTNode(testDirective.args[0])).to.equal('arg: TestScalar'); + expectASTNode(testDirective.args[0]).to.equal('arg: TestScalar'); }); it('Root operation types with custom names', () => { @@ -1025,7 +1041,7 @@ describe('Schema Builder', () => { }); it('Do not override standard types', () => { - // NOTE: not sure it's desired behaviour to just silently ignore override + // NOTE: not sure it's desired behavior to just silently ignore override // attempts so just documenting it here. const schema = buildSchema(` @@ -1084,12 +1100,12 @@ describe('Schema Builder', () => { }); it('Rejects invalid AST', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (First parameter expected to be DocumentNode) expect(() => buildASTSchema(null)).to.throw( 'Must provide valid Document AST', ); - // $FlowExpectedError[prop-missing] + // @ts-expect-error expect(() => buildASTSchema({})).to.throw( 'Must provide valid Document AST', ); diff --git a/src/utilities/__tests__/buildClientSchema-test.js b/src/utilities/__tests__/buildClientSchema-test.ts similarity index 88% rename from src/utilities/__tests__/buildClientSchema-test.js rename to src/utilities/__tests__/buildClientSchema-test.ts index 33a4fe3a61..e8cf046921 100644 --- a/src/utilities/__tests__/buildClientSchema-test.js +++ b/src/utilities/__tests__/buildClientSchema-test.ts @@ -1,28 +1,30 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; -import { graphqlSync } from '../../graphql'; +import { invariant } from '../../jsutils/invariant'; -import { GraphQLSchema } from '../../type/schema'; import { assertEnumType, - GraphQLObjectType, GraphQLEnumType, + GraphQLObjectType, } from '../../type/definition'; import { - GraphQLInt, - GraphQLFloat, - GraphQLString, GraphQLBoolean, + GraphQLFloat, GraphQLID, + GraphQLInt, + GraphQLString, } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; + +import { graphqlSync } from '../../graphql'; -import { printSchema } from '../printSchema'; import { buildSchema } from '../buildASTSchema'; import { buildClientSchema } from '../buildClientSchema'; import { introspectionFromSchema } from '../introspectionFromSchema'; +import { printSchema } from '../printSchema'; /** * This function does a full cycle of going from a string with the contents of @@ -72,7 +74,8 @@ describe('Type System: build schema from introspection', () => { const schema = buildSchema(sdl); const introspection = introspectionFromSchema(schema); - delete (introspection: any).__schema.queryType; + // @ts-expect-error + delete introspection.__schema.queryType; const clientSchema = buildClientSchema(introspection); expect(clientSchema.getQueryType()).to.equal(null); @@ -381,27 +384,24 @@ describe('Type System: build schema from introspection', () => { name: 'VEGETABLES', description: 'Foods that are vegetables.', value: 'VEGETABLES', - isDeprecated: false, deprecationReason: null, - extensions: undefined, + extensions: {}, astNode: undefined, }, { name: 'FRUITS', description: null, value: 'FRUITS', - isDeprecated: false, deprecationReason: null, - extensions: undefined, + extensions: {}, astNode: undefined, }, { name: 'OILS', description: null, value: 'OILS', - isDeprecated: true, deprecationReason: 'Too fatty', - extensions: undefined, + extensions: {}, astNode: undefined, }, ]); @@ -475,7 +475,8 @@ describe('Type System: build schema from introspection', () => { const schema = buildSchema(sdl); const introspection = introspectionFromSchema(schema); - delete (introspection: any).__schema.directives; + // @ts-expect-error + delete introspection.__schema.directives; const clientSchema = buildClientSchema(introspection); @@ -572,6 +573,21 @@ describe('Type System: build schema from introspection', () => { expect(cycleIntrospection(sdl)).to.equal(sdl); }); + it('builds a schema with @oneOf directive', () => { + const sdl = dedent` + type Query { + someField(someArg: SomeInputObject): String + } + + input SomeInputObject @oneOf { + someInputField1: String + someInputField2: String + } + `; + + expect(cycleIntrospection(sdl)).to.equal(sdl); + }); + it('can use client schema for limited execution', () => { const schema = buildSchema(` scalar CustomScalar @@ -595,7 +611,7 @@ describe('Type System: build schema from introspection', () => { expect(result.data).to.deep.equal({ foo: 'bar' }); }); - describe('can build invalid schema', () => { + it('can build invalid schema', () => { const schema = buildSchema('type Query', { assumeValid: true }); const introspection = introspectionFromSchema(schema); @@ -628,12 +644,12 @@ describe('Type System: build schema from introspection', () => { `); it('throws when introspection is missing __schema property', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (First parameter expected to be introspection results) expect(() => buildClientSchema(null)).to.throw( 'Invalid or incomplete introspection result. Ensure that you are passing "data" property of introspection response and no "errors" was returned alongside: null.', ); - // $FlowExpectedError[prop-missing] + // @ts-expect-error expect(() => buildClientSchema({})).to.throw( 'Invalid or incomplete introspection result. Ensure that you are passing "data" property of introspection response and no "errors" was returned alongside: {}.', ); @@ -642,7 +658,8 @@ describe('Type System: build schema from introspection', () => { it('throws when referenced unknown type', () => { const introspection = introspectionFromSchema(dummySchema); - (introspection: any).__schema.types = introspection.__schema.types.filter( + // @ts-expect-error + introspection.__schema.types = introspection.__schema.types.filter( ({ name }) => name !== 'Query', ); @@ -659,7 +676,8 @@ describe('Type System: build schema from introspection', () => { `); const introspection = introspectionFromSchema(schema); - (introspection: any).__schema.types = introspection.__schema.types.filter( + // @ts-expect-error + introspection.__schema.types = introspection.__schema.types.filter( ({ name }) => name !== 'Float', ); @@ -673,10 +691,11 @@ describe('Type System: build schema from introspection', () => { expect(introspection).to.have.nested.property('__schema.queryType.name'); - delete (introspection: any).__schema.queryType.name; + // @ts-expect-error + delete introspection.__schema.queryType.name; expect(() => buildClientSchema(introspection)).to.throw( - 'Unknown type reference: {}.', + 'Unknown type reference: { kind: "OBJECT" }.', ); }); @@ -686,9 +705,9 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'Query', ); - expect(queryTypeIntrospection).to.have.property('kind'); - - delete (queryTypeIntrospection: any).kind; + invariant(queryTypeIntrospection?.kind === 'OBJECT'); + // @ts-expect-error + delete queryTypeIntrospection.kind; expect(() => buildClientSchema(introspection)).to.throw( /Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: { name: "Query", .* }\./, @@ -703,7 +722,9 @@ describe('Type System: build schema from introspection', () => { expect(queryTypeIntrospection).to.have.property('interfaces'); - delete (queryTypeIntrospection: any).interfaces; + invariant(queryTypeIntrospection?.kind === 'OBJECT'); + // @ts-expect-error + delete queryTypeIntrospection.interfaces; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing interfaces: { kind: "OBJECT", name: "Query", .* }\./, @@ -716,8 +737,9 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'SomeInterface', ); - expect(someInterfaceIntrospection).to.have.property('interfaces'); - (someInterfaceIntrospection: any).interfaces = null; + invariant(someInterfaceIntrospection?.kind === 'INTERFACE'); + // @ts-expect-error + someInterfaceIntrospection.interfaces = null; const clientSchema = buildClientSchema(introspection); expect(printSchema(clientSchema)).to.equal(printSchema(dummySchema)); @@ -729,8 +751,9 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'Query', ); - expect(queryTypeIntrospection).to.have.property('fields'); - delete (queryTypeIntrospection: any).fields; + invariant(queryTypeIntrospection?.kind === 'OBJECT'); + // @ts-expect-error + delete queryTypeIntrospection.fields; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing fields: { kind: "OBJECT", name: "Query", .* }\./, @@ -743,8 +766,9 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'Query', ); - expect(queryTypeIntrospection).to.have.nested.property('fields[0].args'); - delete (queryTypeIntrospection: any).fields[0].args; + invariant(queryTypeIntrospection?.kind === 'OBJECT'); + // @ts-expect-error + delete queryTypeIntrospection.fields[0].args; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing field args: { name: "foo", .* }\./, @@ -757,11 +781,13 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'Query', ); - expect(queryTypeIntrospection).to.have.nested.property( - 'fields[0].args[0].type.name', - 'String', - ); - (queryTypeIntrospection: any).fields[0].args[0].type.name = 'SomeUnion'; + invariant(queryTypeIntrospection?.kind === 'OBJECT'); + const argType = queryTypeIntrospection.fields[0].args[0].type; + invariant(argType.kind === 'SCALAR'); + + expect(argType).to.have.property('name', 'String'); + // @ts-expect-error + argType.name = 'SomeUnion'; expect(() => buildClientSchema(introspection)).to.throw( 'Introspection must provide input type for arguments, but received: SomeUnion.', @@ -774,11 +800,13 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'Query', ); - expect(queryTypeIntrospection).to.have.nested.property( - 'fields[0].type.name', - 'String', - ); - (queryTypeIntrospection: any).fields[0].type.name = 'SomeInputObject'; + invariant(queryTypeIntrospection?.kind === 'OBJECT'); + const fieldType = queryTypeIntrospection.fields[0].type; + invariant(fieldType.kind === 'SCALAR'); + + expect(fieldType).to.have.property('name', 'String'); + // @ts-expect-error + fieldType.name = 'SomeInputObject'; expect(() => buildClientSchema(introspection)).to.throw( 'Introspection must provide output type for fields, but received: SomeInputObject.', @@ -791,8 +819,9 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'SomeUnion', ); - expect(someUnionIntrospection).to.have.property('possibleTypes'); - delete (someUnionIntrospection: any).possibleTypes; + invariant(someUnionIntrospection?.kind === 'UNION'); + // @ts-expect-error + delete someUnionIntrospection.possibleTypes; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing possibleTypes: { kind: "UNION", name: "SomeUnion",.* }\./, @@ -805,8 +834,9 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'SomeEnum', ); - expect(someEnumIntrospection).to.have.property('enumValues'); - delete (someEnumIntrospection: any).enumValues; + invariant(someEnumIntrospection?.kind === 'ENUM'); + // @ts-expect-error + delete someEnumIntrospection.enumValues; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing enumValues: { kind: "ENUM", name: "SomeEnum", .* }\./, @@ -819,8 +849,9 @@ describe('Type System: build schema from introspection', () => { ({ name }) => name === 'SomeInputObject', ); - expect(someInputObjectIntrospection).to.have.property('inputFields'); - delete (someInputObjectIntrospection: any).inputFields; + invariant(someInputObjectIntrospection?.kind === 'INPUT_OBJECT'); + // @ts-expect-error + delete someInputObjectIntrospection.inputFields; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing inputFields: { kind: "INPUT_OBJECT", name: "SomeInputObject", .* }\./, @@ -835,7 +866,9 @@ describe('Type System: build schema from introspection', () => { name: 'SomeDirective', locations: ['QUERY'], }); - delete (someDirectiveIntrospection: any).locations; + + // @ts-expect-error + delete someDirectiveIntrospection.locations; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing directive locations: { name: "SomeDirective", .* }\./, @@ -850,7 +883,9 @@ describe('Type System: build schema from introspection', () => { name: 'SomeDirective', args: [], }); - delete (someDirectiveIntrospection: any).args; + + // @ts-expect-error + delete someDirectiveIntrospection.args; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing directive args: { name: "SomeDirective", .* }\./, @@ -859,10 +894,10 @@ describe('Type System: build schema from introspection', () => { }); describe('very deep decorators are not supported', () => { - it('fails on very deep (> 7 levels) lists', () => { + it('fails on very deep (> 8 levels) lists', () => { const schema = buildSchema(` type Query { - foo: [[[[[[[[String]]]]]]]] + foo: [[[[[[[[[[String]]]]]]]]]] } `); @@ -872,10 +907,10 @@ describe('Type System: build schema from introspection', () => { ); }); - it('fails on a very deep (> 7 levels) non-null', () => { + it('fails on a very deep (> 8 levels) non-null', () => { const schema = buildSchema(` type Query { - foo: [[[[String!]!]!]!] + foo: [[[[[String!]!]!]!]!] } `); @@ -885,11 +920,11 @@ describe('Type System: build schema from introspection', () => { ); }); - it('succeeds on deep (<= 7 levels) types', () => { - // e.g., fully non-null 3D matrix + it('succeeds on deep (<= 8 levels) types', () => { + // e.g., fully non-null 4D matrix const sdl = dedent` type Query { - foo: [[[String!]!]!]! + foo: [[[[String!]!]!]!]! } `; diff --git a/src/utilities/__tests__/coerceInputValue-test.js b/src/utilities/__tests__/coerceInputValue-test.ts similarity index 72% rename from src/utilities/__tests__/coerceInputValue-test.js rename to src/utilities/__tests__/coerceInputValue-test.ts index 05f7ca12c2..3692ce26b7 100644 --- a/src/utilities/__tests__/coerceInputValue-test.js +++ b/src/utilities/__tests__/coerceInputValue-test.ts @@ -1,43 +1,55 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; - import type { GraphQLInputType } from '../../type/definition'; -import { GraphQLInt } from '../../type/scalars'; import { + GraphQLEnumType, + GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, - GraphQLEnumType, - GraphQLInputObjectType, } from '../../type/definition'; +import { GraphQLInt } from '../../type/scalars'; import { coerceInputValue } from '../coerceInputValue'; -function expectValue(result: any) { +interface CoerceResult { + value: unknown; + errors: ReadonlyArray; +} + +interface CoerceError { + path: ReadonlyArray; + value: unknown; + error: string; +} + +function coerceValue( + inputValue: unknown, + type: GraphQLInputType, +): CoerceResult { + const errors: Array = []; + const value = coerceInputValue( + inputValue, + type, + (path, invalidValue, error) => { + errors.push({ path, value: invalidValue, error: error.message }); + }, + ); + + return { errors, value }; +} + +function expectValue(result: CoerceResult) { expect(result.errors).to.deep.equal([]); return expect(result.value); } -function expectErrors(result: any) { +function expectErrors(result: CoerceResult) { return expect(result.errors); } describe('coerceInputValue', () => { - function coerceValue(inputValue: mixed, type: GraphQLInputType) { - const errors = []; - const value = coerceInputValue( - inputValue, - type, - (path, invalidValue, error) => { - errors.push({ path, value: invalidValue, error: error.message }); - }, - ); - - return { errors, value }; - } - describe('for GraphQLNonNull', () => { const TestNonNull = new GraphQLNonNull(GraphQLInt); @@ -72,8 +84,7 @@ describe('coerceInputValue', () => { describe('for GraphQLScalar', () => { const TestScalar = new GraphQLScalarType({ name: 'TestScalar', - parseValue(input) { - invariant(typeof input === 'object' && input !== null); + parseValue(input: any) { if (input.error != null) { throw new Error(input.error); } @@ -262,8 +273,113 @@ describe('coerceInputValue', () => { }); }); + describe('for GraphQLInputObject that isOneOf', () => { + const TestInputObject = new GraphQLInputObjectType({ + name: 'TestInputObject', + fields: { + foo: { type: GraphQLInt }, + bar: { type: GraphQLInt }, + }, + isOneOf: true, + }); + + it('returns no error for a valid input', () => { + const result = coerceValue({ foo: 123 }, TestInputObject); + expectValue(result).to.deep.equal({ foo: 123 }); + }); + + it('returns an error if more than one field is specified', () => { + const result = coerceValue({ foo: 123, bar: null }, TestInputObject); + expectErrors(result).to.deep.equal([ + { + error: + 'Exactly one key must be specified for OneOf type "TestInputObject".', + path: [], + value: { foo: 123, bar: null }, + }, + ]); + }); + + it('returns an error the one field is null', () => { + const result = coerceValue({ bar: null }, TestInputObject); + expectErrors(result).to.deep.equal([ + { + error: 'Field "bar" must be non-null.', + path: ['bar'], + value: null, + }, + ]); + }); + + it('returns an error for an invalid field', () => { + const result = coerceValue({ foo: NaN }, TestInputObject); + expectErrors(result).to.deep.equal([ + { + error: 'Int cannot represent non-integer value: NaN', + path: ['foo'], + value: NaN, + }, + ]); + }); + + it('returns multiple errors for multiple invalid fields', () => { + const result = coerceValue({ foo: 'abc', bar: 'def' }, TestInputObject); + expectErrors(result).to.deep.equal([ + { + error: 'Int cannot represent non-integer value: "abc"', + path: ['foo'], + value: 'abc', + }, + { + error: 'Int cannot represent non-integer value: "def"', + path: ['bar'], + value: 'def', + }, + { + error: + 'Exactly one key must be specified for OneOf type "TestInputObject".', + path: [], + value: { foo: 'abc', bar: 'def' }, + }, + ]); + }); + + it('returns error for an unknown field', () => { + const result = coerceValue( + { foo: 123, unknownField: 123 }, + TestInputObject, + ); + expectErrors(result).to.deep.equal([ + { + error: + 'Field "unknownField" is not defined by type "TestInputObject".', + path: [], + value: { foo: 123, unknownField: 123 }, + }, + ]); + }); + + it('returns error for a misspelled field', () => { + const result = coerceValue({ bart: 123 }, TestInputObject); + expectErrors(result).to.deep.equal([ + { + error: + 'Field "bart" is not defined by type "TestInputObject". Did you mean "bar"?', + path: [], + value: { bart: 123 }, + }, + { + error: + 'Exactly one key must be specified for OneOf type "TestInputObject".', + path: [], + value: { bart: 123 }, + }, + ]); + }); + }); + describe('for GraphQLInputObject with default value', () => { - const makeTestInputObject = (defaultValue) => + const makeTestInputObject = (defaultValue: any) => new GraphQLInputObjectType({ name: 'TestInputObject', fields: { @@ -335,6 +451,20 @@ describe('coerceInputValue', () => { expectValue(result).to.deep.equal([42]); }); + it('returns a list for a non-list object value', () => { + const TestListOfObjects = new GraphQLList( + new GraphQLInputObjectType({ + name: 'TestObject', + fields: { + length: { type: GraphQLInt }, + }, + }), + ); + + const result = coerceValue({ length: 100500 }, TestListOfObjects); + expectValue(result).to.deep.equal([{ length: 100500 }]); + }); + it('returns an error for a non-list invalid value', () => { const result = coerceValue('INVALID', TestList); expectErrors(result).to.deep.equal([ diff --git a/src/utilities/__tests__/concatAST-test.js b/src/utilities/__tests__/concatAST-test.ts similarity index 93% rename from src/utilities/__tests__/concatAST-test.js rename to src/utilities/__tests__/concatAST-test.ts index 089b36e9dd..622abd6b38 100644 --- a/src/utilities/__tests__/concatAST-test.js +++ b/src/utilities/__tests__/concatAST-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; import { parse } from '../../language/parser'; import { print } from '../../language/printer'; diff --git a/src/utilities/__tests__/extendSchema-test.js b/src/utilities/__tests__/extendSchema-test.ts similarity index 82% rename from src/utilities/__tests__/extendSchema-test.js rename to src/utilities/__tests__/extendSchema-test.ts index e898363a7c..86baf0e699 100644 --- a/src/utilities/__tests__/extendSchema-test.js +++ b/src/utilities/__tests__/extendSchema-test.ts @@ -1,67 +1,63 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; -import invariant from '../../jsutils/invariant'; +import { invariant } from '../../jsutils/invariant'; +import type { Maybe } from '../../jsutils/Maybe'; import type { ASTNode } from '../../language/ast'; -import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; import { print } from '../../language/printer'; -import { graphqlSync } from '../../graphql'; - -import type { GraphQLNamedType } from '../../type/definition'; -import { GraphQLSchema } from '../../type/schema'; -import { validateSchema } from '../../type/validate'; +import { + assertEnumType, + assertInputObjectType, + assertInterfaceType, + assertObjectType, + assertScalarType, + assertUnionType, +} from '../../type/definition'; import { assertDirective } from '../../type/directives'; import { + GraphQLBoolean, + GraphQLFloat, GraphQLID, GraphQLInt, - GraphQLFloat, GraphQLString, - GraphQLBoolean, } from '../../type/scalars'; -import { - assertObjectType, - assertInputObjectType, - assertEnumType, - assertUnionType, - assertInterfaceType, - assertScalarType, -} from '../../type/definition'; +import { GraphQLSchema } from '../../type/schema'; +import { validateSchema } from '../../type/validate'; +import { graphqlSync } from '../../graphql'; + +import { buildSchema } from '../buildASTSchema'; import { concatAST } from '../concatAST'; -import { printSchema } from '../printSchema'; import { extendSchema } from '../extendSchema'; -import { buildSchema } from '../buildASTSchema'; +import { printSchema } from '../printSchema'; -function printExtensionNodes(obj: ?GraphQLNamedType | GraphQLSchema): string { - invariant(obj?.extensionASTNodes != null); - return print({ - kind: Kind.DOCUMENT, - definitions: obj.extensionASTNodes, - }); +function expectExtensionASTNodes(obj: { + readonly extensionASTNodes: ReadonlyArray; +}) { + return expect(obj.extensionASTNodes.map(print).join('\n\n')); } -function printSchemaChanges( +function expectASTNode(obj: Maybe<{ readonly astNode: Maybe }>) { + invariant(obj?.astNode != null); + return expect(print(obj.astNode)); +} + +function expectSchemaChanges( schema: GraphQLSchema, extendedSchema: GraphQLSchema, -): string { +) { const schemaDefinitions = parse(printSchema(schema)).definitions.map(print); - const ast = parse(printSchema(extendedSchema)); - return print({ - kind: Kind.DOCUMENT, - definitions: ast.definitions.filter( - (node) => !schemaDefinitions.includes(print(node)), - ), - }); -} - -function printASTNode(obj: ?{ +astNode: ?ASTNode, ... }): string { - invariant(obj?.astNode != null); - return print(obj.astNode); + return expect( + parse(printSchema(extendedSchema)) + .definitions.map(print) + .filter((def) => !schemaDefinitions.includes(def)) + .join('\n\n'), + ); } describe('extendSchema', () => { @@ -120,7 +116,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, parse(extensionSDL)); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` type SomeObject implements AnotherInterface & SomeInterface { self: SomeObject tree: [SomeObject]! @@ -132,70 +128,6 @@ describe('extendSchema', () => { `); }); - it('can describe the extended fields with legacy comments', () => { - const schema = buildSchema('type Query'); - const extendAST = parse(` - extend type Query { - # New field description. - newField: String - } - `); - const extendedSchema = extendSchema(schema, extendAST, { - commentDescriptions: true, - }); - - expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` - type Query { - """New field description.""" - newField: String - } - `); - }); - - it('describes extended fields with strings when present', () => { - const schema = buildSchema('type Query'); - const extendAST = parse(` - extend type Query { - # New field description. - "Actually use this description." - newField: String - } - `); - const extendedSchema = extendSchema(schema, extendAST, { - commentDescriptions: true, - }); - - expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` - type Query { - """Actually use this description.""" - newField: String - } - `); - }); - - it('ignores comment description on extended fields if location is not provided', () => { - const schema = buildSchema('type Query'); - const extendSDL = ` - extend type Query { - # New field description. - newField: String - } - `; - const extendAST = parse(extendSDL, { noLocation: true }); - const extendedSchema = extendSchema(schema, extendAST, { - commentDescriptions: true, - }); - - expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` - type Query { - newField: String - } - `); - }); - it('extends objects with standard type fields', () => { const schema = buildSchema('type Query'); @@ -259,7 +191,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` enum SomeEnum { """Old value description.""" OLD_VALUE @@ -287,7 +219,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` union SomeUnion = Foo | Biz | Bar `); }); @@ -302,7 +234,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.have.lengthOf.above(0); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` union SomeUnion = SomeUnion `); }); @@ -329,7 +261,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` input SomeInput { """Old field description.""" oldField: String @@ -357,10 +289,10 @@ describe('extendSchema', () => { extend scalar SomeScalar @foo `; const extendedSchema = extendSchema(schema, parse(extensionSDL)); - const someScalar = extendedSchema.getType('SomeScalar'); + const someScalar = assertScalarType(extendedSchema.getType('SomeScalar')); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printExtensionNodes(someScalar)).to.deep.equal(extensionSDL); + expectExtensionASTNodes(someScalar).to.equal(extensionSDL); }); it('extends scalars by adding specifiedBy directive', () => { @@ -382,10 +314,10 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, parse(extensionSDL)); const foo = assertScalarType(extendedSchema.getType('Foo')); - expect(foo.specifiedByUrl).to.equal('https://example.com/foo_spec'); + expect(foo.specifiedByURL).to.equal('https://example.com/foo_spec'); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printExtensionNodes(foo)).to.deep.equal(extensionSDL); + expectExtensionASTNodes(foo).to.equal(extensionSDL); }); it('correctly assign AST nodes to new and extended types', () => { @@ -504,18 +436,11 @@ describe('extendSchema', () => { extendedTwiceSchema.getDirective('test'), ); - expect(testType).to.include({ extensionASTNodes: undefined }); - expect(testEnum).to.include({ extensionASTNodes: undefined }); - expect(testUnion).to.include({ extensionASTNodes: undefined }); - expect(testInput).to.include({ extensionASTNodes: undefined }); - expect(testInterface).to.include({ extensionASTNodes: undefined }); - - invariant(query.extensionASTNodes); - invariant(someScalar.extensionASTNodes); - invariant(someEnum.extensionASTNodes); - invariant(someUnion.extensionASTNodes); - invariant(someInput.extensionASTNodes); - invariant(someInterface.extensionASTNodes); + expect(testType.extensionASTNodes).to.deep.equal([]); + expect(testEnum.extensionASTNodes).to.deep.equal([]); + expect(testUnion.extensionASTNodes).to.deep.equal([]); + expect(testInput.extensionASTNodes).to.deep.equal([]); + expect(testInterface.extensionASTNodes).to.deep.equal([]); expect([ testInput.astNode, @@ -536,47 +461,41 @@ describe('extendSchema', () => { ]); const newField = query.getFields().newField; - expect(printASTNode(newField)).to.equal( - 'newField(testArg: TestInput): TestEnum', - ); - expect(printASTNode(newField.args[0])).to.equal('testArg: TestInput'); - expect(printASTNode(query.getFields().oneMoreNewField)).to.equal( + expectASTNode(newField).to.equal('newField(testArg: TestInput): TestEnum'); + expectASTNode(newField.args[0]).to.equal('testArg: TestInput'); + expectASTNode(query.getFields().oneMoreNewField).to.equal( 'oneMoreNewField: TestUnion', ); - expect(printASTNode(someEnum.getValue('NEW_VALUE'))).to.equal('NEW_VALUE'); - expect(printASTNode(someEnum.getValue('ONE_MORE_NEW_VALUE'))).to.equal( + expectASTNode(someEnum.getValue('NEW_VALUE')).to.equal('NEW_VALUE'); + expectASTNode(someEnum.getValue('ONE_MORE_NEW_VALUE')).to.equal( 'ONE_MORE_NEW_VALUE', ); - expect(printASTNode(someInput.getFields().newField)).to.equal( - 'newField: String', - ); - expect(printASTNode(someInput.getFields().oneMoreNewField)).to.equal( + expectASTNode(someInput.getFields().newField).to.equal('newField: String'); + expectASTNode(someInput.getFields().oneMoreNewField).to.equal( 'oneMoreNewField: String', ); - expect(printASTNode(someInterface.getFields().newField)).to.equal( + expectASTNode(someInterface.getFields().newField).to.equal( 'newField: String', ); - expect(printASTNode(someInterface.getFields().oneMoreNewField)).to.equal( + expectASTNode(someInterface.getFields().oneMoreNewField).to.equal( 'oneMoreNewField: String', ); - expect(printASTNode(testInput.getFields().testInputField)).to.equal( + expectASTNode(testInput.getFields().testInputField).to.equal( 'testInputField: TestEnum', ); - expect(printASTNode(testEnum.getValue('TEST_VALUE'))).to.equal( - 'TEST_VALUE', - ); + expectASTNode(testEnum.getValue('TEST_VALUE')).to.equal('TEST_VALUE'); - expect(printASTNode(testInterface.getFields().interfaceField)).to.equal( + expectASTNode(testInterface.getFields().interfaceField).to.equal( 'interfaceField: String', ); - expect(printASTNode(testType.getFields().interfaceField)).to.equal( + expectASTNode(testType.getFields().interfaceField).to.equal( 'interfaceField: String', ); - expect(printASTNode(testDirective.args[0])).to.equal('arg: Int'); + expectASTNode(testDirective.args[0]).to.equal('arg: Int'); }); it('builds types with deprecated fields/values', () => { @@ -594,13 +513,11 @@ describe('extendSchema', () => { const someType = assertObjectType(extendedSchema.getType('SomeObject')); expect(someType.getFields().deprecatedField).to.include({ - isDeprecated: true, deprecationReason: 'not used anymore', }); const someEnum = assertEnumType(extendedSchema.getType('SomeEnum')); expect(someEnum.getValue('DEPRECATED_VALUE')).to.include({ - isDeprecated: true, deprecationReason: 'do not use', }); }); @@ -616,7 +533,6 @@ describe('extendSchema', () => { const someType = assertObjectType(extendedSchema.getType('SomeObject')); expect(someType.getFields().deprecatedField).to.include({ - isDeprecated: true, deprecationReason: 'not used anymore', }); }); @@ -632,7 +548,6 @@ describe('extendSchema', () => { const someEnum = assertEnumType(extendedSchema.getType('SomeEnum')); expect(someEnum.getValue('DEPRECATED_VALUE')).to.include({ - isDeprecated: true, deprecationReason: 'do not use', }); }); @@ -669,7 +584,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, parse(extensionSDL)); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(extensionSDL); + expectSchemaChanges(schema, extendedSchema).to.equal(extensionSDL); }); it('extends objects by adding new fields with arguments', () => { @@ -694,7 +609,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` type SomeObject { newField(arg1: String, arg2: NewInputObj!): String } @@ -724,7 +639,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` type SomeObject { newField(arg1: SomeEnum!): SomeEnum } @@ -751,7 +666,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` type SomeObject implements SomeInterface { foo: String } @@ -798,7 +713,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` type SomeObject { oldField: String newObject: NewObject @@ -839,7 +754,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` type SomeObject implements OldInterface & NewInterface { oldField: String newField: String @@ -900,11 +815,10 @@ describe('extendSchema', () => { interface AnotherNewInterface { anotherNewField: String - }`; + } + `; const schemaWithNewTypes = extendSchema(schema, parse(newTypesSDL)); - expect(printSchemaChanges(schema, schemaWithNewTypes)).to.equal( - newTypesSDL + '\n', - ); + expectSchemaChanges(schema, schemaWithNewTypes).to.equal(newTypesSDL); const extendAST = parse(` extend scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") @@ -940,7 +854,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schemaWithNewTypes, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") type SomeObject implements SomeInterface & NewInterface & AnotherNewInterface { @@ -1001,7 +915,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` interface SomeInterface { oldField: String newField: String @@ -1053,7 +967,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` interface AnotherInterface implements SomeInterface & NewInterface { oldField: String newField: String @@ -1092,7 +1006,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.have.lengthOf.above(0); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` interface SomeInterface { oldField: SomeInterface newField: String @@ -1123,7 +1037,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + expectSchemaChanges(schema, extendedSchema).to.equal(dedent` interface SomeInterface { some: SomeInterface newFieldA: Int @@ -1194,25 +1108,7 @@ describe('extendSchema', () => { const extendedSchema = extendSchema(schema, parse(extensionSDL)); expect(validateSchema(extendedSchema)).to.deep.equal([]); - expect(printSchemaChanges(schema, extendedSchema)).to.equal(extensionSDL); - }); - - it('sets correct description using legacy comments', () => { - const schema = buildSchema(` - type Query { - foo: String - } - `); - const extendAST = parse(` - # new directive - directive @new on QUERY - `); - const extendedSchema = extendSchema(schema, extendAST, { - commentDescriptions: true, - }); - - const newDirective = extendedSchema.getDirective('new'); - expect(newDirective).to.include({ description: 'new directive' }); + expectSchemaChanges(schema, extendedSchema).to.equal(extensionSDL); }); it('Rejects invalid SDL', () => { @@ -1247,12 +1143,12 @@ describe('extendSchema', () => { it('Rejects invalid AST', () => { const schema = new GraphQLSchema({}); - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (Second argument expects DocumentNode) expect(() => extendSchema(schema, null)).to.throw( 'Must provide valid Document AST', ); - // $FlowExpectedError[prop-missing] + // @ts-expect-error expect(() => extendSchema(schema, {})).to.throw( 'Must provide valid Document AST', ); @@ -1311,7 +1207,7 @@ describe('extendSchema', () => { const queryType = extendedSchema.getQueryType(); expect(queryType).to.include({ name: 'Foo' }); - expect(printASTNode(extendedSchema) + '\n').to.equal(extensionSDL); + expectASTNode(extendedSchema).to.equal(extensionSDL); }); it('adds new root types via schema extension', () => { @@ -1328,7 +1224,7 @@ describe('extendSchema', () => { const mutationType = extendedSchema.getMutationType(); expect(mutationType).to.include({ name: 'MutationRoot' }); - expect(printExtensionNodes(extendedSchema)).to.equal(extensionSDL); + expectExtensionASTNodes(extendedSchema).to.equal(extensionSDL); }); it('adds directive via schema extension', () => { @@ -1342,7 +1238,7 @@ describe('extendSchema', () => { `; const extendedSchema = extendSchema(schema, parse(extensionSDL)); - expect(printExtensionNodes(extendedSchema)).to.equal(extensionSDL); + expectExtensionASTNodes(extendedSchema).to.equal(extensionSDL); }); it('adds multiple new root types via schema extension', () => { @@ -1410,7 +1306,7 @@ describe('extendSchema', () => { const secondExtendAST = parse('extend schema @foo'); const extendedTwiceSchema = extendSchema(extendedSchema, secondExtendAST); - expect(printExtensionNodes(extendedTwiceSchema)).to.equal(dedent` + expectExtensionASTNodes(extendedTwiceSchema).to.equal(dedent` extend schema { mutation: Mutation } diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.ts similarity index 99% rename from src/utilities/__tests__/findBreakingChanges-test.js rename to src/utilities/__tests__/findBreakingChanges-test.ts index a4ab722084..ba526deb48 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.ts @@ -1,13 +1,14 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { GraphQLSchema } from '../../type/schema'; import { - GraphQLSkipDirective, + GraphQLDeprecatedDirective, GraphQLIncludeDirective, + GraphQLOneOfDirective, + GraphQLSkipDirective, GraphQLSpecifiedByDirective, - GraphQLDeprecatedDirective, } from '../../type/directives'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../buildASTSchema'; import { @@ -802,6 +803,7 @@ describe('findBreakingChanges', () => { GraphQLSkipDirective, GraphQLIncludeDirective, GraphQLSpecifiedByDirective, + GraphQLOneOfDirective, ], }); diff --git a/src/utilities/__tests__/getIntrospectionQuery-test.js b/src/utilities/__tests__/getIntrospectionQuery-test.ts similarity index 80% rename from src/utilities/__tests__/getIntrospectionQuery-test.js rename to src/utilities/__tests__/getIntrospectionQuery-test.ts index 3f0c36298f..86d1c549db 100644 --- a/src/utilities/__tests__/getIntrospectionQuery-test.js +++ b/src/utilities/__tests__/getIntrospectionQuery-test.ts @@ -1,12 +1,26 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import { parse } from '../../language/parser'; + +import { validate } from '../../validation/validate'; + +import { buildSchema } from '../buildASTSchema'; import type { IntrospectionOptions } from '../getIntrospectionQuery'; import { getIntrospectionQuery } from '../getIntrospectionQuery'; +const dummySchema = buildSchema(` + type Query { + dummy: String + } +`); + function expectIntrospectionQuery(options?: IntrospectionOptions) { const query = getIntrospectionQuery(options); + const validationErrors = validate(dummySchema, parse(query)); + expect(validationErrors).to.deep.equal([]); + return { toMatch(name: string, times: number = 1): void { const pattern = toRegExp(name); @@ -63,15 +77,15 @@ describe('getIntrospectionQuery', () => { }).toNotMatch('description'); }); - it('include "specifiedByUrl" field', () => { - expectIntrospectionQuery().toNotMatch('specifiedByUrl'); + it('include "specifiedBy" field', () => { + expectIntrospectionQuery().toNotMatch('specifiedByURL'); expectIntrospectionQuery({ specifiedByUrl: true }).toMatch( - 'specifiedByUrl', + 'specifiedByURL', ); expectIntrospectionQuery({ specifiedByUrl: false }).toNotMatch( - 'specifiedByUrl', + 'specifiedByURL', ); }); @@ -103,6 +117,14 @@ describe('getIntrospectionQuery', () => { ); }); + it('include "isOneOf" field on input objects', () => { + expectIntrospectionQuery().toNotMatch('isOneOf'); + + expectIntrospectionQuery({ oneOf: true }).toMatch('isOneOf', 1); + + expectIntrospectionQuery({ oneOf: false }).toNotMatch('isOneOf'); + }); + it('include deprecated input field and args', () => { expectIntrospectionQuery().toMatch('includeDeprecated: true', 2); diff --git a/src/utilities/__tests__/getOperationAST-test.js b/src/utilities/__tests__/getOperationAST-test.ts similarity index 100% rename from src/utilities/__tests__/getOperationAST-test.js rename to src/utilities/__tests__/getOperationAST-test.ts diff --git a/src/utilities/__tests__/getOperationRootType-test.js b/src/utilities/__tests__/getOperationRootType-test.ts similarity index 88% rename from src/utilities/__tests__/getOperationRootType-test.js rename to src/utilities/__tests__/getOperationRootType-test.ts index 8ebdcdfd8b..ce683a5a12 100644 --- a/src/utilities/__tests__/getOperationRootType-test.js +++ b/src/utilities/__tests__/getOperationRootType-test.ts @@ -1,15 +1,15 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; +import { invariant } from '../../jsutils/invariant'; -import type { DocumentNode } from '../../language/ast'; +import type { DocumentNode, OperationDefinitionNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; +import { GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { getOperationRootType } from '../getOperationRootType'; @@ -34,13 +34,13 @@ const subscriptionType = new GraphQLObjectType({ }), }); -function getOperationNode(doc: DocumentNode) { +function getOperationNode(doc: DocumentNode): OperationDefinitionNode { const operationNode = doc.definitions[0]; - invariant(operationNode && operationNode.kind === Kind.OPERATION_DEFINITION); + invariant(operationNode.kind === Kind.OPERATION_DEFINITION); return operationNode; } -describe('getOperationRootType', () => { +describe('Deprecated - getOperationRootType', () => { it('Gets a Query type for an unnamed OperationDefinitionNode', () => { const testSchema = new GraphQLSchema({ query: queryType, @@ -76,12 +76,9 @@ describe('getOperationRootType', () => { `); const schemaNode = doc.definitions[0]; - invariant(schemaNode && schemaNode.kind === Kind.SCHEMA_DEFINITION); - const [ - queryNode, - mutationNode, - subscriptionNode, - ] = schemaNode.operationTypes; + invariant(schemaNode.kind === Kind.SCHEMA_DEFINITION); + const [queryNode, mutationNode, subscriptionNode] = + schemaNode.operationTypes; expect(getOperationRootType(testSchema, queryNode)).to.equal(queryType); expect(getOperationRootType(testSchema, mutationNode)).to.equal( @@ -149,12 +146,12 @@ describe('getOperationRootType', () => { it('Throws when operation not a valid operation kind', () => { const testSchema = new GraphQLSchema({}); const doc = parse('{ field }'); - const operationNode = { + const operationNode: OperationDefinitionNode = { ...getOperationNode(doc), + // @ts-expect-error operation: 'non_existent_operation', }; - // $FlowExpectedError[incompatible-call] expect(() => getOperationRootType(testSchema, operationNode)).to.throw( 'Can only have query, mutation and subscription operations.', ); diff --git a/src/utilities/__tests__/introspectionFromSchema-test.js b/src/utilities/__tests__/introspectionFromSchema-test.ts similarity index 96% rename from src/utilities/__tests__/introspectionFromSchema-test.js rename to src/utilities/__tests__/introspectionFromSchema-test.ts index 4afbbeb855..2ba66348d3 100644 --- a/src/utilities/__tests__/introspectionFromSchema-test.js +++ b/src/utilities/__tests__/introspectionFromSchema-test.ts @@ -1,16 +1,16 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; +import { GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; -import type { IntrospectionQuery } from '../getIntrospectionQuery'; -import { printSchema } from '../printSchema'; import { buildClientSchema } from '../buildClientSchema'; +import type { IntrospectionQuery } from '../getIntrospectionQuery'; import { introspectionFromSchema } from '../introspectionFromSchema'; +import { printSchema } from '../printSchema'; function introspectionToSDL(introspection: IntrospectionQuery): string { return printSchema(buildClientSchema(introspection)); diff --git a/src/utilities/__tests__/lexicographicSortSchema-test.js b/src/utilities/__tests__/lexicographicSortSchema-test.ts similarity index 99% rename from src/utilities/__tests__/lexicographicSortSchema-test.js rename to src/utilities/__tests__/lexicographicSortSchema-test.ts index b885733c23..bce12e3ac5 100644 --- a/src/utilities/__tests__/lexicographicSortSchema-test.js +++ b/src/utilities/__tests__/lexicographicSortSchema-test.ts @@ -1,11 +1,11 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; -import { printSchema } from '../printSchema'; import { buildSchema } from '../buildASTSchema'; import { lexicographicSortSchema } from '../lexicographicSortSchema'; +import { printSchema } from '../printSchema'; function sortSDL(sdl: string): string { const schema = buildSchema(sdl); diff --git a/src/utilities/__tests__/printSchema-test.js b/src/utilities/__tests__/printSchema-test.ts similarity index 73% rename from src/utilities/__tests__/printSchema-test.js rename to src/utilities/__tests__/printSchema-test.ts index df064c3724..37af4a60f7 100644 --- a/src/utilities/__tests__/printSchema-test.js +++ b/src/utilities/__tests__/printSchema-test.ts @@ -1,27 +1,27 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent, dedentString } from '../../__testUtils__/dedent'; import { DirectiveLocation } from '../../language/directiveLocation'; import type { GraphQLFieldConfig } from '../../type/definition'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLDirective } from '../../type/directives'; -import { GraphQLInt, GraphQLString, GraphQLBoolean } from '../../type/scalars'; import { + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, - GraphQLScalarType, GraphQLObjectType, - GraphQLInterfaceType, + GraphQLScalarType, GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, } from '../../type/definition'; +import { GraphQLDirective } from '../../type/directives'; +import { GraphQLBoolean, GraphQLInt, GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../buildASTSchema'; -import { printSchema, printIntrospectionSchema } from '../printSchema'; +import { printIntrospectionSchema, printSchema } from '../printSchema'; function expectPrintedSchema(schema: GraphQLSchema) { const schemaText = printSchema(schema); @@ -30,7 +30,9 @@ function expectPrintedSchema(schema: GraphQLSchema) { return expect(schemaText); } -function buildSingleFieldSchema(fieldConfig: GraphQLFieldConfig) { +function buildSingleFieldSchema( + fieldConfig: GraphQLFieldConfig, +) { const Query = new GraphQLObjectType({ name: 'Query', fields: { singleField: fieldConfig }, @@ -157,8 +159,7 @@ describe('Type System Printer', () => { }); expectPrintedSchema(schema).to.equal( - // $FlowFixMe[incompatible-call] - dedent(String.raw` + dedentString(String.raw` type Query { singleField(argOne: String = "tes\t de\fault"): String } @@ -275,6 +276,22 @@ describe('Type System Printer', () => { `); }); + it('Omits schema of common names', () => { + const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ name: 'Query', fields: {} }), + mutation: new GraphQLObjectType({ name: 'Mutation', fields: {} }), + subscription: new GraphQLObjectType({ name: 'Subscription', fields: {} }), + }); + + expectPrintedSchema(schema).to.equal(dedent` + type Query + + type Mutation + + type Subscription + `); + }); + it('Prints custom query root types', () => { const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'CustomType', fields: {} }), @@ -486,6 +503,23 @@ describe('Type System Printer', () => { `); }); + it('Print Input Type with @oneOf directive', () => { + const InputType = new GraphQLInputObjectType({ + name: 'InputType', + isOneOf: true, + fields: { + int: { type: GraphQLInt }, + }, + }); + + const schema = new GraphQLSchema({ types: [InputType] }); + expectPrintedSchema(schema).to.equal(dedent` + input InputType @oneOf { + int: Int + } + `); + }); + it('Custom Scalar', () => { const OddType = new GraphQLScalarType({ name: 'Odd' }); @@ -495,10 +529,10 @@ describe('Type System Printer', () => { `); }); - it('Custom Scalar with specifiedByUrl', () => { + it('Custom Scalar with specifiedByURL', () => { const FooType = new GraphQLScalarType({ name: 'Foo', - specifiedByUrl: 'https://example.com/foo_spec', + specifiedByURL: 'https://example.com/foo_spec', }); const schema = new GraphQLSchema({ types: [FooType] }); @@ -592,6 +626,20 @@ describe('Type System Printer', () => { `); }); + it('Prints an description with only whitespace', () => { + const schema = buildSingleFieldSchema({ + type: GraphQLString, + description: ' ', + }); + + expectPrintedSchema(schema).to.equal(dedent` + type Query { + " " + singleField: String + } + `); + }); + it('One-line prints a short description', () => { const schema = buildSingleFieldSchema({ type: GraphQLString, @@ -635,12 +683,17 @@ describe('Type System Printer', () => { reason: String = "No longer supported" ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE - """Exposes a URL that specifies the behaviour of this scalar.""" + """Exposes a URL that specifies the behavior of this scalar.""" directive @specifiedBy( - """The URL that specifies the behaviour of this scalar.""" + """The URL that specifies the behavior of this scalar.""" url: String! ) on SCALAR + """ + Indicates exactly one field must be supplied and this field must not be \`null\`. + """ + directive @oneOf on INPUT_OBJECT + """ A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations. """ @@ -670,19 +723,20 @@ describe('Type System Printer', () => { """ The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the \`__TypeKind\` enum. - Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional \`specifiedByUrl\`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types. + Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional \`specifiedByURL\`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types. """ type __Type { kind: __TypeKind! name: String description: String - specifiedByUrl: String + specifiedByURL: String fields(includeDeprecated: Boolean = false): [__Field!] interfaces: [__Type!] possibleTypes: [__Type!] enumValues(includeDeprecated: Boolean = false): [__EnumValue!] inputFields(includeDeprecated: Boolean = false): [__InputValue!] ofType: __Type + isOneOf: Boolean } """An enum describing what kind of type a given \`__Type\` is.""" @@ -766,7 +820,7 @@ describe('Type System Printer', () => { description: String isRepeatable: Boolean! locations: [__DirectiveLocation!]! - args: [__InputValue!]! + args(includeDeprecated: Boolean = false): [__InputValue!]! } """ @@ -832,201 +886,4 @@ describe('Type System Printer', () => { } `); }); - - it('Print Introspection Schema with comment descriptions', () => { - const schema = new GraphQLSchema({}); - const output = printIntrospectionSchema(schema, { - commentDescriptions: true, - }); - - expect(output).to.equal(dedent` - # Directs the executor to include this field or fragment only when the \`if\` argument is true. - directive @include( - # Included when true. - if: Boolean! - ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - - # Directs the executor to skip this field or fragment when the \`if\` argument is true. - directive @skip( - # Skipped when true. - if: Boolean! - ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - - # Marks an element of a GraphQL schema as no longer supported. - directive @deprecated( - # Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/). - reason: String = "No longer supported" - ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE - - # Exposes a URL that specifies the behaviour of this scalar. - directive @specifiedBy( - # The URL that specifies the behaviour of this scalar. - url: String! - ) on SCALAR - - # A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations. - type __Schema { - description: String - - # A list of all types supported by this server. - types: [__Type!]! - - # The type that query operations will be rooted at. - queryType: __Type! - - # If this server supports mutation, the type that mutation operations will be rooted at. - mutationType: __Type - - # If this server support subscription, the type that subscription operations will be rooted at. - subscriptionType: __Type - - # A list of all directives supported by this server. - directives: [__Directive!]! - } - - # The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the \`__TypeKind\` enum. - # - # Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional \`specifiedByUrl\`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types. - type __Type { - kind: __TypeKind! - name: String - description: String - specifiedByUrl: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields(includeDeprecated: Boolean = false): [__InputValue!] - ofType: __Type - } - - # An enum describing what kind of type a given \`__Type\` is. - enum __TypeKind { - # Indicates this type is a scalar. - SCALAR - - # Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields. - OBJECT - - # Indicates this type is an interface. \`fields\`, \`interfaces\`, and \`possibleTypes\` are valid fields. - INTERFACE - - # Indicates this type is a union. \`possibleTypes\` is a valid field. - UNION - - # Indicates this type is an enum. \`enumValues\` is a valid field. - ENUM - - # Indicates this type is an input object. \`inputFields\` is a valid field. - INPUT_OBJECT - - # Indicates this type is a list. \`ofType\` is a valid field. - LIST - - # Indicates this type is a non-null. \`ofType\` is a valid field. - NON_NULL - } - - # Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type. - type __Field { - name: String! - description: String - args(includeDeprecated: Boolean = false): [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - } - - # Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value. - type __InputValue { - name: String! - description: String - type: __Type! - - # A GraphQL-formatted string representing the default value for this input value. - defaultValue: String - isDeprecated: Boolean! - deprecationReason: String - } - - # One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string. - type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - } - - # A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. - # - # In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor. - type __Directive { - name: String! - description: String - isRepeatable: Boolean! - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - } - - # A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies. - enum __DirectiveLocation { - # Location adjacent to a query operation. - QUERY - - # Location adjacent to a mutation operation. - MUTATION - - # Location adjacent to a subscription operation. - SUBSCRIPTION - - # Location adjacent to a field. - FIELD - - # Location adjacent to a fragment definition. - FRAGMENT_DEFINITION - - # Location adjacent to a fragment spread. - FRAGMENT_SPREAD - - # Location adjacent to an inline fragment. - INLINE_FRAGMENT - - # Location adjacent to a variable definition. - VARIABLE_DEFINITION - - # Location adjacent to a schema definition. - SCHEMA - - # Location adjacent to a scalar definition. - SCALAR - - # Location adjacent to an object type definition. - OBJECT - - # Location adjacent to a field definition. - FIELD_DEFINITION - - # Location adjacent to an argument definition. - ARGUMENT_DEFINITION - - # Location adjacent to an interface definition. - INTERFACE - - # Location adjacent to a union definition. - UNION - - # Location adjacent to an enum definition. - ENUM - - # Location adjacent to an enum value definition. - ENUM_VALUE - - # Location adjacent to an input object type definition. - INPUT_OBJECT - - # Location adjacent to an input object field definition. - INPUT_FIELD_DEFINITION - } - `); - }); }); diff --git a/src/utilities/__tests__/separateOperations-test.js b/src/utilities/__tests__/separateOperations-test.ts similarity index 86% rename from src/utilities/__tests__/separateOperations-test.js rename to src/utilities/__tests__/separateOperations-test.ts index 1e336a6ad5..2f14bae9ac 100644 --- a/src/utilities/__tests__/separateOperations-test.js +++ b/src/utilities/__tests__/separateOperations-test.ts @@ -1,9 +1,9 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; +import { dedent } from '../../__testUtils__/dedent'; -import mapValue from '../../jsutils/mapValue'; +import { mapValue } from '../../jsutils/mapValue'; import { parse } from '../../language/parser'; import { print } from '../../language/printer'; @@ -201,6 +201,34 @@ describe('separateOperations', () => { }); }); + it('ignores type definitions', () => { + const ast = parse(` + query Foo { + ...Bar + } + + fragment Bar on T { + baz + } + + scalar Foo + type Bar + `); + + const separatedASTs = mapValue(separateOperations(ast), print); + expect(separatedASTs).to.deep.equal({ + Foo: dedent` + query Foo { + ...Bar + } + + fragment Bar on T { + baz + } + `, + }); + }); + it('handles unknown fragments', () => { const ast = parse(` { diff --git a/src/utilities/__tests__/sortValueNode-test.ts b/src/utilities/__tests__/sortValueNode-test.ts new file mode 100644 index 0000000000..5bda137d14 --- /dev/null +++ b/src/utilities/__tests__/sortValueNode-test.ts @@ -0,0 +1,40 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { parseValue } from '../../language/parser'; +import { print } from '../../language/printer'; + +import { sortValueNode } from '../sortValueNode'; + +describe('sortValueNode', () => { + function expectSortedValue(source: string) { + return expect(print(sortValueNode(parseValue(source)))); + } + + it('do not change non-object values', () => { + expectSortedValue('1').to.equal('1'); + expectSortedValue('3.14').to.equal('3.14'); + expectSortedValue('null').to.equal('null'); + expectSortedValue('true').to.equal('true'); + expectSortedValue('false').to.equal('false'); + expectSortedValue('"cba"').to.equal('"cba"'); + expectSortedValue('"""cba"""').to.equal('"""cba"""'); + expectSortedValue('[1, 3.14, null, false, "cba"]').to.equal( + '[1, 3.14, null, false, "cba"]', + ); + expectSortedValue('[[1, 3.14, null, false, "cba"]]').to.equal( + '[[1, 3.14, null, false, "cba"]]', + ); + }); + + it('sort input object fields', () => { + expectSortedValue('{ b: 2, a: 1 }').to.equal('{a: 1, b: 2}'); + expectSortedValue('{ a: { c: 3, b: 2 } }').to.equal('{a: {b: 2, c: 3}}'); + expectSortedValue('[{ b: 2, a: 1 }, { d: 4, c: 3}]').to.equal( + '[{a: 1, b: 2}, {c: 3, d: 4}]', + ); + expectSortedValue( + '{ b: { g: 7, f: 6 }, c: 3 , a: { d: 4, e: 5 } }', + ).to.equal('{a: {d: 4, e: 5}, b: {f: 6, g: 7}, c: 3}'); + }); +}); diff --git a/src/utilities/__tests__/stripIgnoredCharacters-fuzz.js b/src/utilities/__tests__/stripIgnoredCharacters-fuzz.ts similarity index 85% rename from src/utilities/__tests__/stripIgnoredCharacters-fuzz.js rename to src/utilities/__tests__/stripIgnoredCharacters-fuzz.ts index 34a2c9a7a5..29a22ed838 100644 --- a/src/utilities/__tests__/stripIgnoredCharacters-fuzz.js +++ b/src/utilities/__tests__/stripIgnoredCharacters-fuzz.ts @@ -1,10 +1,10 @@ import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; -import inspectStr from '../../__testUtils__/inspectStr'; -import genFuzzStrings from '../../__testUtils__/genFuzzStrings'; +import { dedent } from '../../__testUtils__/dedent'; +import { genFuzzStrings } from '../../__testUtils__/genFuzzStrings'; +import { inspectStr } from '../../__testUtils__/inspectStr'; -import invariant from '../../jsutils/invariant'; +import { invariant } from '../../jsutils/invariant'; import { Lexer } from '../../language/lexer'; import { Source } from '../../language/source'; diff --git a/src/utilities/__tests__/stripIgnoredCharacters-test.js b/src/utilities/__tests__/stripIgnoredCharacters-test.ts similarity index 94% rename from src/utilities/__tests__/stripIgnoredCharacters-test.js rename to src/utilities/__tests__/stripIgnoredCharacters-test.ts index fdc7d907d6..4115742f5c 100644 --- a/src/utilities/__tests__/stripIgnoredCharacters-test.js +++ b/src/utilities/__tests__/stripIgnoredCharacters-test.ts @@ -1,12 +1,13 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../__testUtils__/dedent'; -import inspectStr from '../../__testUtils__/inspectStr'; -import kitchenSinkSDL from '../../__testUtils__/kitchenSinkSDL'; -import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; +import { dedent } from '../../__testUtils__/dedent'; +import { inspectStr } from '../../__testUtils__/inspectStr'; +import { kitchenSinkQuery } from '../../__testUtils__/kitchenSinkQuery'; +import { kitchenSinkSDL } from '../../__testUtils__/kitchenSinkSDL'; -import invariant from '../../jsutils/invariant'; +import { invariant } from '../../jsutils/invariant'; +import type { Maybe } from '../../jsutils/Maybe'; import { Lexer } from '../../language/lexer'; import { parse } from '../../language/parser'; @@ -58,7 +59,7 @@ const nonPunctuatorTokens = [ '"""block\nstring\nvalue"""', // StringValue(BlockString) ]; -function lexValue(str: string): ?string { +function lexValue(str: string): Maybe { const lexer = new Lexer(new Source(str)); const value = lexer.advance().value; @@ -147,7 +148,7 @@ describe('stripIgnoredCharacters', () => { caughtError = e; } - expect(String(caughtError) + '\n').to.equal(dedent` + expect(String(caughtError)).to.equal(dedent` Syntax Error: Unterminated string. GraphQL request:1:13 @@ -370,7 +371,7 @@ describe('stripIgnoredCharacters', () => { expectStripped('""",|"""').toStayTheSame(); const ignoredTokensWithoutFormatting = ignoredTokens.filter( - (token) => ['\n', '\r', '\r\n', '\t', ' '].indexOf(token) === -1, + (token) => !['\n', '\r', '\r\n', '\t', ' '].includes(token), ); for (const ignored of ignoredTokensWithoutFormatting) { expectStripped('"""|' + ignored + '|"""').toStayTheSame(); @@ -395,10 +396,10 @@ describe('stripIgnoredCharacters', () => { invariant( originalValue === strippedValue, dedent` - Expected lexValue(stripIgnoredCharacters(${inspectStr(blockStr)})) - to equal ${inspectStr(originalValue)} - but got ${inspectStr(strippedValue)} - `, + Expected lexValue(stripIgnoredCharacters(${inspectStr(blockStr)})) + to equal ${inspectStr(originalValue)} + but got ${inspectStr(strippedValue)} + `, ); return expectStripped(blockStr); } diff --git a/src/utilities/__tests__/typeComparators-test.js b/src/utilities/__tests__/typeComparators-test.ts similarity index 97% rename from src/utilities/__tests__/typeComparators-test.js rename to src/utilities/__tests__/typeComparators-test.ts index 3f2a87ae78..f2709bf740 100644 --- a/src/utilities/__tests__/typeComparators-test.js +++ b/src/utilities/__tests__/typeComparators-test.ts @@ -2,15 +2,15 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import type { GraphQLFieldConfigMap } from '../../type/definition'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString, GraphQLInt, GraphQLFloat } from '../../type/scalars'; import { + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLInterfaceType, GraphQLUnionType, } from '../../type/definition'; +import { GraphQLFloat, GraphQLInt, GraphQLString } from '../../type/scalars'; +import { GraphQLSchema } from '../../type/schema'; import { isEqualType, isTypeSubTypeOf } from '../typeComparators'; @@ -53,7 +53,7 @@ describe('typeComparators', () => { }); describe('isTypeSubTypeOf', () => { - function testSchema(fields: GraphQLFieldConfigMap) { + function testSchema(fields: GraphQLFieldConfigMap) { return new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', diff --git a/src/utilities/__tests__/valueFromAST-test.js b/src/utilities/__tests__/valueFromAST-test.ts similarity index 89% rename from src/utilities/__tests__/valueFromAST-test.js rename to src/utilities/__tests__/valueFromAST-test.ts index f4dc325206..05924f3c56 100644 --- a/src/utilities/__tests__/valueFromAST-test.js +++ b/src/utilities/__tests__/valueFromAST-test.ts @@ -1,27 +1,27 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import { identityFunc } from '../../jsutils/identityFunc'; +import { invariant } from '../../jsutils/invariant'; import type { ObjMap } from '../../jsutils/ObjMap'; -import invariant from '../../jsutils/invariant'; -import identityFunc from '../../jsutils/identityFunc'; import { parseValue } from '../../language/parser'; import type { GraphQLInputType } from '../../type/definition'; import { - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, - GraphQLID, -} from '../../type/scalars'; -import { + GraphQLEnumType, + GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, - GraphQLEnumType, - GraphQLInputObjectType, } from '../../type/definition'; +import { + GraphQLBoolean, + GraphQLFloat, + GraphQLID, + GraphQLInt, + GraphQLString, +} from '../../type/scalars'; import { valueFromAST } from '../valueFromAST'; @@ -29,7 +29,7 @@ describe('valueFromAST', () => { function expectValueFrom( valueText: string, type: GraphQLInputType, - variables: ?ObjMap, + variables?: ObjMap, ) { const ast = parseValue(valueText); const value = valueFromAST(ast, type, variables); @@ -196,6 +196,14 @@ describe('valueFromAST', () => { requiredBool: { type: nonNullBool }, }, }); + const testOneOfInputObj = new GraphQLInputObjectType({ + name: 'TestOneOfInput', + fields: { + a: { type: GraphQLString }, + b: { type: GraphQLString }, + }, + isOneOf: true, + }); it('coerces input objects according to input coercion rules', () => { expectValueFrom('null', testInputObj).to.equal(null); @@ -221,6 +229,22 @@ describe('valueFromAST', () => { ); expectValueFrom('{ requiredBool: null }', testInputObj).to.equal(undefined); expectValueFrom('{ bool: true }', testInputObj).to.equal(undefined); + expectValueFrom('{ a: "abc" }', testOneOfInputObj).to.deep.equal({ + a: 'abc', + }); + expectValueFrom('{ b: "def" }', testOneOfInputObj).to.deep.equal({ + b: 'def', + }); + expectValueFrom('{ a: "abc", b: null }', testOneOfInputObj).to.deep.equal( + undefined, + ); + expectValueFrom('{ a: null }', testOneOfInputObj).to.equal(undefined); + expectValueFrom('{ a: 1 }', testOneOfInputObj).to.equal(undefined); + expectValueFrom('{ a: "abc", b: "def" }', testOneOfInputObj).to.equal( + undefined, + ); + expectValueFrom('{}', testOneOfInputObj).to.equal(undefined); + expectValueFrom('{ c: "abc" }', testOneOfInputObj).to.equal(undefined); }); it('accepts variable values assuming already coerced', () => { diff --git a/src/utilities/__tests__/valueFromASTUntyped-test.js b/src/utilities/__tests__/valueFromASTUntyped-test.ts similarity index 93% rename from src/utilities/__tests__/valueFromASTUntyped-test.js rename to src/utilities/__tests__/valueFromASTUntyped-test.ts index 5e971a43f6..9ad004c42e 100644 --- a/src/utilities/__tests__/valueFromASTUntyped-test.js +++ b/src/utilities/__tests__/valueFromASTUntyped-test.ts @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import type { Maybe } from '../../jsutils/Maybe'; import type { ObjMap } from '../../jsutils/ObjMap'; import { parseValue } from '../../language/parser'; @@ -8,7 +9,10 @@ import { parseValue } from '../../language/parser'; import { valueFromASTUntyped } from '../valueFromASTUntyped'; describe('valueFromASTUntyped', () => { - function expectValueFrom(valueText: string, variables?: ?ObjMap) { + function expectValueFrom( + valueText: string, + variables?: Maybe>, + ) { const ast = parseValue(valueText); const value = valueFromASTUntyped(ast, variables); return expect(value); diff --git a/src/utilities/assertValidName.d.ts b/src/utilities/assertValidName.d.ts deleted file mode 100644 index 5a1011e706..0000000000 --- a/src/utilities/assertValidName.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { GraphQLError } from '../error/GraphQLError'; - -/** - * Upholds the spec rules about naming. - */ -export function assertValidName(name: string): string; - -/** - * Returns an Error if a name is invalid. - */ -export function isValidNameError(name: string): GraphQLError | undefined; diff --git a/src/utilities/assertValidName.js b/src/utilities/assertValidName.ts similarity index 52% rename from src/utilities/assertValidName.js rename to src/utilities/assertValidName.ts index b919b61be7..3e66461ae6 100644 --- a/src/utilities/assertValidName.js +++ b/src/utilities/assertValidName.ts @@ -1,11 +1,13 @@ -import devAssert from '../jsutils/devAssert'; +import { devAssert } from '../jsutils/devAssert'; import { GraphQLError } from '../error/GraphQLError'; -const NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/; +import { assertName } from '../type/assertName'; +/* c8 ignore start */ /** * Upholds the spec rules about naming. + * @deprecated Please use `assertName` instead. Will be removed in v17 */ export function assertValidName(name: string): string { const error = isValidNameError(name); @@ -17,17 +19,21 @@ export function assertValidName(name: string): string { /** * Returns an Error if a name is invalid. + * @deprecated Please use `assertName` instead. Will be removed in v17 */ -export function isValidNameError(name: string): GraphQLError | void { +export function isValidNameError(name: string): GraphQLError | undefined { devAssert(typeof name === 'string', 'Expected name to be a string.'); - if (name.length > 1 && name[0] === '_' && name[1] === '_') { + + if (name.startsWith('__')) { return new GraphQLError( `Name "${name}" must not begin with "__", which is reserved by GraphQL introspection.`, ); } - if (!NAME_RX.test(name)) { - return new GraphQLError( - `Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "${name}" does not.`, - ); + + try { + assertName(name); + } catch (error) { + return error; } } +/* c8 ignore stop */ diff --git a/src/utilities/astFromValue.d.ts b/src/utilities/astFromValue.d.ts deleted file mode 100644 index 19f0a8feed..0000000000 --- a/src/utilities/astFromValue.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { ValueNode } from '../language/ast'; -import { GraphQLInputType } from '../type/definition'; - -/** - * Produces a GraphQL Value AST given a JavaScript value. - * - * A GraphQL type must be provided, which will be used to interpret different - * JavaScript values. - * - * | JSON Value | GraphQL Value | - * | ------------- | -------------------- | - * | Object | Input Object | - * | Array | List | - * | Boolean | Boolean | - * | String | String / Enum Value | - * | Number | Int / Float | - * | Mixed | Enum Value | - * | null | NullValue | - * - */ -export function astFromValue( - value: any, - type: GraphQLInputType, -): Maybe; diff --git a/src/utilities/astFromValue.js b/src/utilities/astFromValue.ts similarity index 76% rename from src/utilities/astFromValue.js rename to src/utilities/astFromValue.ts index 39ab089d27..1a880449c8 100644 --- a/src/utilities/astFromValue.js +++ b/src/utilities/astFromValue.ts @@ -1,24 +1,21 @@ -import isFinite from '../polyfills/isFinite'; -import arrayFrom from '../polyfills/arrayFrom'; -import objectValues from '../polyfills/objectValues'; +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import { isIterableObject } from '../jsutils/isIterableObject'; +import { isObjectLike } from '../jsutils/isObjectLike'; +import type { Maybe } from '../jsutils/Maybe'; -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; -import isObjectLike from '../jsutils/isObjectLike'; -import isCollection from '../jsutils/isCollection'; - -import type { ValueNode } from '../language/ast'; +import type { ObjectFieldNode, ValueNode } from '../language/ast'; import { Kind } from '../language/kinds'; import type { GraphQLInputType } from '../type/definition'; -import { GraphQLID } from '../type/scalars'; import { - isLeafType, isEnumType, isInputObjectType, + isLeafType, isListType, isNonNullType, } from '../type/definition'; +import { GraphQLID } from '../type/scalars'; /** * Produces a GraphQL Value AST given a JavaScript object. @@ -37,11 +34,14 @@ import { * | Boolean | Boolean | * | String | String / Enum Value | * | Number | Int / Float | - * | Mixed | Enum Value | + * | Unknown | Enum Value | * | null | NullValue | * */ -export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { +export function astFromValue( + value: unknown, + type: GraphQLInputType, +): Maybe { if (isNonNullType(type)) { const astValue = astFromValue(value, type.ofType); if (astValue?.kind === Kind.NULL) { @@ -64,11 +64,9 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { // the value is not an array, convert the value using the list's item type. if (isListType(type)) { const itemType = type.ofType; - if (isCollection(value)) { + if (isIterableObject(value)) { const valuesNodes = []; - // Since we transpile for-of in loose mode it doesn't support iterators - // and it's required to first convert iteratable into array - for (const item of arrayFrom(value)) { + for (const item of value) { const itemNode = astFromValue(item, itemType); if (itemNode != null) { valuesNodes.push(itemNode); @@ -85,8 +83,8 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { if (!isObjectLike(value)) { return null; } - const fieldNodes = []; - for (const field of objectValues(type.getFields())) { + const fieldNodes: Array = []; + for (const field of Object.values(type.getFields())) { const fieldValue = astFromValue(value[field.name], field.type); if (fieldValue) { fieldNodes.push({ @@ -99,7 +97,6 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { return { kind: Kind.OBJECT, fields: fieldNodes }; } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isLeafType(type)) { // Since value is an internally represented value, it must be serialized // to an externally represented value before converting into an AST. @@ -114,7 +111,7 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { } // JavaScript numbers can be Int or Float values. - if (typeof serialized === 'number' && isFinite(serialized)) { + if (typeof serialized === 'number' && Number.isFinite(serialized)) { const stringNum = String(serialized); return integerStringRegExp.test(stringNum) ? { kind: Kind.INT, value: stringNum } @@ -140,9 +137,9 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { throw new TypeError(`Cannot convert value to AST: ${inspect(serialized)}.`); } - - // istanbul ignore next (Not reachable. All possible input types have been considered) - invariant(false, 'Unexpected input type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable, all possible types have been considered. + invariant(false, 'Unexpected input type: ' + inspect(type)); } /** diff --git a/src/utilities/buildASTSchema.d.ts b/src/utilities/buildASTSchema.d.ts deleted file mode 100644 index e0514369d8..0000000000 --- a/src/utilities/buildASTSchema.d.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { DocumentNode } from '../language/ast'; -import { Source } from '../language/source'; -import { GraphQLSchema, GraphQLSchemaValidationOptions } from '../type/schema'; -import { ParseOptions } from '../language/parser'; - -export interface BuildSchemaOptions extends GraphQLSchemaValidationOptions { - /** - * Descriptions are defined as preceding string literals, however an older - * experimental version of the SDL supported preceding comments as - * descriptions. Set to true to enable this deprecated behavior. - * This option is provided to ease adoption and will be removed in v16. - * - * Default: false - */ - commentDescriptions?: boolean; - - /** - * Set to true to assume the SDL is valid. - * - * Default: false - */ - assumeValidSDL?: boolean; -} - -/** - * This takes the ast of a schema document produced by the parse function in - * src/language/parser.js. - * - * If no schema definition is provided, then it will look for types named Query - * and Mutation. - * - * Given that AST it constructs a GraphQLSchema. The resulting schema - * has no resolve methods, so execution will use default resolvers. - * - * Accepts options as a second argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * - */ -export function buildASTSchema( - documentAST: DocumentNode, - options?: BuildSchemaOptions, -): GraphQLSchema; - -/** - * A helper function to build a GraphQLSchema directly from a source - * document. - */ -export function buildSchema( - source: string | Source, - options?: BuildSchemaOptions & ParseOptions, -): GraphQLSchema; diff --git a/src/utilities/buildASTSchema.js b/src/utilities/buildASTSchema.ts similarity index 61% rename from src/utilities/buildASTSchema.js rename to src/utilities/buildASTSchema.ts index 067338611e..eeff08e6ed 100644 --- a/src/utilities/buildASTSchema.js +++ b/src/utilities/buildASTSchema.ts @@ -1,55 +1,37 @@ -import devAssert from '../jsutils/devAssert'; +import { devAssert } from '../jsutils/devAssert'; -import type { Source } from '../language/source'; import type { DocumentNode } from '../language/ast'; -import type { ParseOptions } from '../language/parser'; import { Kind } from '../language/kinds'; +import type { ParseOptions } from '../language/parser'; import { parse } from '../language/parser'; +import type { Source } from '../language/source'; -import { assertValidSDL } from '../validation/validate'; - +import { specifiedDirectives } from '../type/directives'; import type { GraphQLSchemaValidationOptions } from '../type/schema'; import { GraphQLSchema } from '../type/schema'; -import { specifiedDirectives } from '../type/directives'; -import { extendSchemaImpl } from './extendSchema'; - -export type BuildSchemaOptions = {| - ...GraphQLSchemaValidationOptions, +import { assertValidSDL } from '../validation/validate'; - /** - * Descriptions are defined as preceding string literals, however an older - * experimental version of the SDL supported preceding comments as - * descriptions. Set to true to enable this deprecated behavior. - * This option is provided to ease adoption and will be removed in v16. - * - * Default: false - */ - commentDescriptions?: boolean, +import { extendSchemaImpl } from './extendSchema'; +export interface BuildSchemaOptions extends GraphQLSchemaValidationOptions { /** * Set to true to assume the SDL is valid. * * Default: false */ - assumeValidSDL?: boolean, -|}; + assumeValidSDL?: boolean; +} /** * This takes the ast of a schema document produced by the parse function in * src/language/parser.js. * - * If no schema definition is provided, then it will look for types named Query - * and Mutation. + * If no schema definition is provided, then it will look for types named Query, + * Mutation and Subscription. * * Given that AST it constructs a GraphQLSchema. The resulting schema * has no resolve methods, so execution will use default resolvers. - * - * Accepts options as a second argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * */ export function buildASTSchema( documentAST: DocumentNode, @@ -68,7 +50,7 @@ export function buildASTSchema( description: undefined, types: [], directives: [], - extensions: undefined, + extensions: Object.create(null), extensionASTNodes: [], assumeValid: false, }; @@ -81,27 +63,32 @@ export function buildASTSchema( // typed values below, that would throw immediately while type system // validation with validateSchema() will produce more actionable results. case 'Query': - config.query = (type: any); + // @ts-expect-error validated in `validateSchema` + config.query = type; break; case 'Mutation': - config.mutation = (type: any); + // @ts-expect-error validated in `validateSchema` + config.mutation = type; break; case 'Subscription': - config.subscription = (type: any); + // @ts-expect-error validated in `validateSchema` + config.subscription = type; break; } } } - const { directives } = config; - // If specified directives were not explicitly declared, add them. - for (const stdDirective of specifiedDirectives) { - if (directives.every((directive) => directive.name !== stdDirective.name)) { - directives.push(stdDirective); - } - } + const directives = [ + ...config.directives, + // If specified directives were not explicitly declared, add them. + ...specifiedDirectives.filter((stdDirective) => + config.directives.every( + (directive) => directive.name !== stdDirective.name, + ), + ), + ]; - return new GraphQLSchema(config); + return new GraphQLSchema({ ...config, directives }); } /** @@ -110,18 +97,14 @@ export function buildASTSchema( */ export function buildSchema( source: string | Source, - options?: {| ...BuildSchemaOptions, ...ParseOptions |}, + options?: BuildSchemaOptions & ParseOptions, ): GraphQLSchema { const document = parse(source, { noLocation: options?.noLocation, - allowLegacySDLEmptyFields: options?.allowLegacySDLEmptyFields, - allowLegacySDLImplementsInterfaces: - options?.allowLegacySDLImplementsInterfaces, - experimentalFragmentVariables: options?.experimentalFragmentVariables, + allowLegacyFragmentVariables: options?.allowLegacyFragmentVariables, }); return buildASTSchema(document, { - commentDescriptions: options?.commentDescriptions, assumeValidSDL: options?.assumeValidSDL, assumeValid: options?.assumeValid, }); diff --git a/src/utilities/buildClientSchema.d.ts b/src/utilities/buildClientSchema.d.ts deleted file mode 100644 index a541cd307d..0000000000 --- a/src/utilities/buildClientSchema.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { GraphQLSchema, GraphQLSchemaValidationOptions } from '../type/schema'; - -import { IntrospectionQuery } from './getIntrospectionQuery'; - -/** - * Build a GraphQLSchema for use by client tools. - * - * Given the result of a client running the introspection query, creates and - * returns a GraphQLSchema instance which can be then used with all graphql-js - * tools, but cannot be used to execute a query, as introspection does not - * represent the "resolver", "parse" or "serialize" functions or any other - * server-internal mechanisms. - * - * This function expects a complete introspection result. Don't forget to check - * the "errors" field of a server response before calling this function. - */ -export function buildClientSchema( - introspection: IntrospectionQuery, - options?: GraphQLSchemaValidationOptions, -): GraphQLSchema; diff --git a/src/utilities/buildClientSchema.js b/src/utilities/buildClientSchema.ts similarity index 93% rename from src/utilities/buildClientSchema.js rename to src/utilities/buildClientSchema.ts index bdf4420001..83f6abada8 100644 --- a/src/utilities/buildClientSchema.js +++ b/src/utilities/buildClientSchema.ts @@ -1,53 +1,51 @@ -import objectValues from '../polyfills/objectValues'; - -import inspect from '../jsutils/inspect'; -import devAssert from '../jsutils/devAssert'; -import keyValMap from '../jsutils/keyValMap'; -import isObjectLike from '../jsutils/isObjectLike'; +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; +import { isObjectLike } from '../jsutils/isObjectLike'; +import { keyValMap } from '../jsutils/keyValMap'; import { parseValue } from '../language/parser'; -import type { GraphQLSchemaValidationOptions } from '../type/schema'; import type { - GraphQLType, - GraphQLNamedType, GraphQLFieldConfig, GraphQLFieldConfigMap, + GraphQLNamedType, + GraphQLType, } from '../type/definition'; -import { GraphQLSchema } from '../type/schema'; -import { GraphQLDirective } from '../type/directives'; -import { specifiedScalarTypes } from '../type/scalars'; -import { introspectionTypes, TypeKind } from '../type/introspection'; import { - isInputType, - isOutputType, + assertInterfaceType, + assertNullableType, + assertObjectType, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, - GraphQLScalarType, GraphQLObjectType, - GraphQLInterfaceType, + GraphQLScalarType, GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, - assertNullableType, - assertObjectType, - assertInterfaceType, + isInputType, + isOutputType, } from '../type/definition'; +import { GraphQLDirective } from '../type/directives'; +import { introspectionTypes, TypeKind } from '../type/introspection'; +import { specifiedScalarTypes } from '../type/scalars'; +import type { GraphQLSchemaValidationOptions } from '../type/schema'; +import { GraphQLSchema } from '../type/schema'; import type { - IntrospectionQuery, IntrospectionDirective, + IntrospectionEnumType, IntrospectionField, + IntrospectionInputObjectType, IntrospectionInputValue, - IntrospectionType, - IntrospectionScalarType, - IntrospectionObjectType, IntrospectionInterfaceType, - IntrospectionUnionType, - IntrospectionEnumType, - IntrospectionInputObjectType, - IntrospectionTypeRef, IntrospectionNamedTypeRef, + IntrospectionObjectType, + IntrospectionQuery, + IntrospectionScalarType, + IntrospectionType, + IntrospectionTypeRef, + IntrospectionUnionType, } from './getIntrospectionQuery'; import { valueFromAST } from './valueFromAST'; @@ -116,7 +114,7 @@ export function buildClientSchema( query: queryType, mutation: mutationType, subscription: subscriptionType, - types: objectValues(typeMap), + types: Object.values(typeMap), directives, assumeValid: options?.assumeValid, }); @@ -142,9 +140,7 @@ export function buildClientSchema( return getNamedType(typeRef); } - function getNamedType( - typeRef: IntrospectionNamedTypeRef<>, - ): GraphQLNamedType { + function getNamedType(typeRef: IntrospectionNamedTypeRef): GraphQLNamedType { const typeName = typeRef.name; if (!typeName) { throw new Error(`Unknown type reference: ${inspect(typeRef)}.`); @@ -175,7 +171,10 @@ export function buildClientSchema( // Given a type's introspection result, construct the correct // GraphQLType instance. function buildType(type: IntrospectionType): GraphQLNamedType { + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain if (type != null && type.name != null && type.kind != null) { + // FIXME: Properly type IntrospectionType, it's a breaking change so fix in v17 + // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (type.kind) { case TypeKind.SCALAR: return buildScalarDef(type); @@ -203,7 +202,7 @@ export function buildClientSchema( return new GraphQLScalarType({ name: scalarIntrospection.name, description: scalarIntrospection.description, - specifiedByUrl: scalarIntrospection.specifiedByUrl, + specifiedByURL: scalarIntrospection.specifiedByURL, }); } @@ -305,12 +304,13 @@ export function buildClientSchema( name: inputObjectIntrospection.name, description: inputObjectIntrospection.description, fields: () => buildInputValueDefMap(inputObjectIntrospection.inputFields), + isOneOf: inputObjectIntrospection.isOneOf, }); } function buildFieldDefMap( typeIntrospection: IntrospectionObjectType | IntrospectionInterfaceType, - ): GraphQLFieldConfigMap { + ): GraphQLFieldConfigMap { if (!typeIntrospection.fields) { throw new Error( `Introspection result missing fields: ${inspect(typeIntrospection)}.`, @@ -326,7 +326,7 @@ export function buildClientSchema( function buildField( fieldIntrospection: IntrospectionField, - ): GraphQLFieldConfig { + ): GraphQLFieldConfig { const type = getType(fieldIntrospection.type); if (!isOutputType(type)) { const typeStr = inspect(type); @@ -351,7 +351,7 @@ export function buildClientSchema( } function buildInputValueDefMap( - inputValueIntrospections: $ReadOnlyArray, + inputValueIntrospections: ReadonlyArray, ) { return keyValMap( inputValueIntrospections, diff --git a/src/utilities/coerceInputValue.d.ts b/src/utilities/coerceInputValue.d.ts deleted file mode 100644 index 45c70a5d33..0000000000 --- a/src/utilities/coerceInputValue.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { GraphQLInputType } from '../type/definition'; -import { GraphQLError } from '../error/GraphQLError'; - -type OnErrorCB = ( - path: ReadonlyArray, - invalidValue: any, - error: GraphQLError, -) => void; - -/** - * Coerces a JavaScript value given a GraphQL Input Type. - */ -export function coerceInputValue( - inputValue: any, - type: GraphQLInputType, - onError?: OnErrorCB, -): any; diff --git a/src/utilities/coerceInputValue.js b/src/utilities/coerceInputValue.ts similarity index 70% rename from src/utilities/coerceInputValue.js rename to src/utilities/coerceInputValue.ts index be8526108a..eeab0614f8 100644 --- a/src/utilities/coerceInputValue.js +++ b/src/utilities/coerceInputValue.ts @@ -1,29 +1,26 @@ -import arrayFrom from '../polyfills/arrayFrom'; -import objectValues from '../polyfills/objectValues'; - +import { didYouMean } from '../jsutils/didYouMean'; +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import { isIterableObject } from '../jsutils/isIterableObject'; +import { isObjectLike } from '../jsutils/isObjectLike'; import type { Path } from '../jsutils/Path'; -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; -import didYouMean from '../jsutils/didYouMean'; -import isObjectLike from '../jsutils/isObjectLike'; -import isCollection from '../jsutils/isCollection'; -import suggestionList from '../jsutils/suggestionList'; -import printPathArray from '../jsutils/printPathArray'; import { addPath, pathToArray } from '../jsutils/Path'; +import { printPathArray } from '../jsutils/printPathArray'; +import { suggestionList } from '../jsutils/suggestionList'; import { GraphQLError } from '../error/GraphQLError'; import type { GraphQLInputType } from '../type/definition'; import { - isLeafType, isInputObjectType, + isLeafType, isListType, isNonNullType, } from '../type/definition'; type OnErrorCB = ( - path: $ReadOnlyArray, - invalidValue: mixed, + path: ReadonlyArray, + invalidValue: unknown, error: GraphQLError, ) => void; @@ -31,16 +28,16 @@ type OnErrorCB = ( * Coerces a JavaScript value given a GraphQL Input Type. */ export function coerceInputValue( - inputValue: mixed, + inputValue: unknown, type: GraphQLInputType, onError: OnErrorCB = defaultOnError, -): mixed { - return coerceInputValueImpl(inputValue, type, onError); +): unknown { + return coerceInputValueImpl(inputValue, type, onError, undefined); } function defaultOnError( - path: $ReadOnlyArray, - invalidValue: mixed, + path: ReadonlyArray, + invalidValue: unknown, error: GraphQLError, ): void { let errorPrefix = 'Invalid value ' + inspect(invalidValue); @@ -52,11 +49,11 @@ function defaultOnError( } function coerceInputValueImpl( - inputValue: mixed, + inputValue: unknown, type: GraphQLInputType, onError: OnErrorCB, - path: Path | void, -): mixed { + path: Path | undefined, +): unknown { if (isNonNullType(type)) { if (inputValue != null) { return coerceInputValueImpl(inputValue, type.ofType, onError, path); @@ -78,8 +75,8 @@ function coerceInputValueImpl( if (isListType(type)) { const itemType = type.ofType; - if (isCollection(inputValue)) { - return arrayFrom(inputValue, (itemValue, index) => { + if (isIterableObject(inputValue)) { + return Array.from(inputValue, (itemValue, index) => { const itemPath = addPath(path, index, undefined); return coerceInputValueImpl(itemValue, itemType, onError, itemPath); }); @@ -98,10 +95,10 @@ function coerceInputValueImpl( return; } - const coercedValue = {}; + const coercedValue: any = {}; const fieldDefs = type.getFields(); - for (const field of objectValues(fieldDefs)) { + for (const field of Object.values(fieldDefs)) { const fieldValue = inputValue[field.name]; if (fieldValue === undefined) { @@ -145,10 +142,33 @@ function coerceInputValueImpl( ); } } + + if (type.isOneOf) { + const keys = Object.keys(coercedValue); + if (keys.length !== 1) { + onError( + pathToArray(path), + inputValue, + new GraphQLError( + `Exactly one key must be specified for OneOf type "${type.name}".`, + ), + ); + } + + const key = keys[0]; + const value = coercedValue[key]; + if (value === null) { + onError( + pathToArray(path).concat(key), + value, + new GraphQLError(`Field "${key}" must be non-null.`), + ); + } + } + return coercedValue; } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isLeafType(type)) { let parseResult; @@ -164,14 +184,9 @@ function coerceInputValueImpl( onError( pathToArray(path), inputValue, - new GraphQLError( - `Expected type "${type.name}". ` + error.message, - undefined, - undefined, - undefined, - undefined, - error, - ), + new GraphQLError(`Expected type "${type.name}". ` + error.message, { + originalError: error, + }), ); } return; @@ -185,7 +200,7 @@ function coerceInputValueImpl( } return parseResult; } - - // istanbul ignore next (Not reachable. All possible input types have been considered) - invariant(false, 'Unexpected input type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable, all possible types have been considered. + invariant(false, 'Unexpected input type: ' + inspect(type)); } diff --git a/src/utilities/concatAST.d.ts b/src/utilities/concatAST.d.ts deleted file mode 100644 index 03d441e1ca..0000000000 --- a/src/utilities/concatAST.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { DocumentNode } from '../language/ast'; - -/** - * Provided a collection of ASTs, presumably each from different files, - * concatenate the ASTs together into batched AST, useful for validating many - * GraphQL source files which together represent one conceptual application. - */ -export function concatAST(asts: ReadonlyArray): DocumentNode; diff --git a/src/utilities/concatAST.js b/src/utilities/concatAST.ts similarity index 52% rename from src/utilities/concatAST.js rename to src/utilities/concatAST.ts index b7a0ea4726..33062f610e 100644 --- a/src/utilities/concatAST.js +++ b/src/utilities/concatAST.ts @@ -1,4 +1,5 @@ -import type { DocumentNode } from '../language/ast'; +import type { DefinitionNode, DocumentNode } from '../language/ast'; +import { Kind } from '../language/kinds'; /** * Provided a collection of ASTs, presumably each from different files, @@ -6,11 +7,11 @@ import type { DocumentNode } from '../language/ast'; * GraphQL source files which together represent one conceptual application. */ export function concatAST( - documents: $ReadOnlyArray, + documents: ReadonlyArray, ): DocumentNode { - let definitions = []; + const definitions: Array = []; for (const doc of documents) { - definitions = definitions.concat(doc.definitions); + definitions.push(...doc.definitions); } - return { kind: 'Document', definitions }; + return { kind: Kind.DOCUMENT, definitions }; } diff --git a/src/utilities/extendSchema.d.ts b/src/utilities/extendSchema.d.ts deleted file mode 100644 index 6795e01437..0000000000 --- a/src/utilities/extendSchema.d.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { Location, DocumentNode, StringValueNode } from '../language/ast'; -import { - GraphQLSchemaValidationOptions, - GraphQLSchema, - GraphQLSchemaNormalizedConfig, -} from '../type/schema'; - -interface Options extends GraphQLSchemaValidationOptions { - /** - * Descriptions are defined as preceding string literals, however an older - * experimental version of the SDL supported preceding comments as - * descriptions. Set to true to enable this deprecated behavior. - * This option is provided to ease adoption and will be removed in v16. - * - * Default: false - */ - commentDescriptions?: boolean; - - /** - * Set to true to assume the SDL is valid. - * - * Default: false - */ - assumeValidSDL?: boolean; -} - -/** - * Produces a new schema given an existing schema and a document which may - * contain GraphQL type extensions and definitions. The original schema will - * remain unaltered. - * - * Because a schema represents a graph of references, a schema cannot be - * extended without effectively making an entire copy. We do not know until it's - * too late if subgraphs remain unchanged. - * - * This algorithm copies the provided schema, applying extensions while - * producing the copy. The original schema remains unaltered. - * - * Accepts options as a third argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * - */ -export function extendSchema( - schema: GraphQLSchema, - documentAST: DocumentNode, - options?: Options, -): GraphQLSchema; - -/** - * @internal - */ -export function extendSchemaImpl( - schemaConfig: GraphQLSchemaNormalizedConfig, - documentAST: DocumentNode, - options?: Options, -): GraphQLSchemaNormalizedConfig; - -/** - * Given an ast node, returns its string description. - * @deprecated: provided to ease adoption and will be removed in v16. - * - * Accepts options as a second argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * - */ -export function getDescription( - node: { readonly description?: StringValueNode; readonly loc?: Location }, - options?: Maybe<{ commentDescriptions?: boolean }>, -): string | undefined; diff --git a/src/utilities/extendSchema.js b/src/utilities/extendSchema.ts similarity index 70% rename from src/utilities/extendSchema.js rename to src/utilities/extendSchema.ts index b7d3bfcfd0..d53752d919 100644 --- a/src/utilities/extendSchema.js +++ b/src/utilities/extendSchema.ts @@ -1,113 +1,96 @@ -import objectValues from '../polyfills/objectValues'; +import { devAssert } from '../jsutils/devAssert'; +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import { keyMap } from '../jsutils/keyMap'; +import { mapValue } from '../jsutils/mapValue'; +import type { Maybe } from '../jsutils/Maybe'; -import keyMap from '../jsutils/keyMap'; -import inspect from '../jsutils/inspect'; -import mapValue from '../jsutils/mapValue'; -import invariant from '../jsutils/invariant'; -import devAssert from '../jsutils/devAssert'; - -import type { DirectiveLocationEnum } from '../language/directiveLocation'; import type { - Location, + DirectiveDefinitionNode, DocumentNode, - StringValueNode, - TypeNode, - NamedTypeNode, - SchemaDefinitionNode, - SchemaExtensionNode, - TypeDefinitionNode, - InterfaceTypeDefinitionNode, - InterfaceTypeExtensionNode, - ObjectTypeDefinitionNode, - ObjectTypeExtensionNode, - UnionTypeDefinitionNode, - UnionTypeExtensionNode, + EnumTypeDefinitionNode, + EnumTypeExtensionNode, + EnumValueDefinitionNode, FieldDefinitionNode, InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, InputValueDefinitionNode, - EnumTypeDefinitionNode, - EnumTypeExtensionNode, - EnumValueDefinitionNode, - DirectiveDefinitionNode, + InterfaceTypeDefinitionNode, + InterfaceTypeExtensionNode, + NamedTypeNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, ScalarTypeDefinitionNode, ScalarTypeExtensionNode, + SchemaDefinitionNode, + SchemaExtensionNode, + TypeDefinitionNode, + TypeNode, + UnionTypeDefinitionNode, + UnionTypeExtensionNode, } from '../language/ast'; import { Kind } from '../language/kinds'; -import { TokenKind } from '../language/tokenKind'; -import { dedentBlockStringValue } from '../language/blockString'; import { isTypeDefinitionNode, isTypeExtensionNode, } from '../language/predicates'; -import { assertValidSDLExtension } from '../validation/validate'; - -import { getDirectiveValues } from '../execution/values'; - -import type { - GraphQLSchemaValidationOptions, - GraphQLSchemaNormalizedConfig, -} from '../type/schema'; import type { - GraphQLType, - GraphQLNamedType, - GraphQLFieldConfig, - GraphQLFieldConfigMap, GraphQLArgumentConfig, - GraphQLFieldConfigArgumentMap, GraphQLEnumValueConfigMap, + GraphQLFieldConfig, + GraphQLFieldConfigArgumentMap, + GraphQLFieldConfigMap, GraphQLInputFieldConfigMap, + GraphQLNamedType, + GraphQLType, } from '../type/definition'; -import { assertSchema, GraphQLSchema } from '../type/schema'; -import { specifiedScalarTypes, isSpecifiedScalarType } from '../type/scalars'; -import { introspectionTypes, isIntrospectionType } from '../type/introspection'; import { - GraphQLDirective, - GraphQLDeprecatedDirective, - GraphQLSpecifiedByDirective, -} from '../type/directives'; -import { - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, - isListType, - isNonNullType, - isEnumType, - isInputObjectType, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, - GraphQLScalarType, GraphQLObjectType, - GraphQLInterfaceType, + GraphQLScalarType, GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, + isEnumType, + isInputObjectType, + isInterfaceType, + isListType, + isNonNullType, + isObjectType, + isScalarType, + isUnionType, } from '../type/definition'; +import { + GraphQLDeprecatedDirective, + GraphQLDirective, + GraphQLOneOfDirective, + GraphQLSpecifiedByDirective, +} from '../type/directives'; +import { introspectionTypes, isIntrospectionType } from '../type/introspection'; +import { isSpecifiedScalarType, specifiedScalarTypes } from '../type/scalars'; +import type { + GraphQLSchemaNormalizedConfig, + GraphQLSchemaValidationOptions, +} from '../type/schema'; +import { assertSchema, GraphQLSchema } from '../type/schema'; -import { valueFromAST } from './valueFromAST'; +import { assertValidSDLExtension } from '../validation/validate'; -type Options = {| - ...GraphQLSchemaValidationOptions, +import { getDirectiveValues } from '../execution/values'; - /** - * Descriptions are defined as preceding string literals, however an older - * experimental version of the SDL supported preceding comments as - * descriptions. Set to true to enable this deprecated behavior. - * This option is provided to ease adoption and will be removed in v16. - * - * Default: false - */ - commentDescriptions?: boolean, +import { valueFromAST } from './valueFromAST'; +interface Options extends GraphQLSchemaValidationOptions { /** * Set to true to assume the SDL is valid. * * Default: false */ - assumeValidSDL?: boolean, -|}; + assumeValidSDL?: boolean; +} /** * Produces a new schema given an existing schema and a document which may @@ -120,12 +103,6 @@ type Options = {| * * This algorithm copies the provided schema, applying extensions while * producing the copy. The original schema remains unaltered. - * - * Accepts options as a third argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * */ export function extendSchema( schema: GraphQLSchema, @@ -166,7 +143,7 @@ export function extendSchemaImpl( // have the same name. For example, a type named "skip". const directiveDefs: Array = []; - let schemaDef: ?SchemaDefinitionNode; + let schemaDef: Maybe; // Schema extensions are collected which may add additional operation types. const schemaExtensions: Array = []; @@ -225,12 +202,12 @@ export function extendSchemaImpl( return { description: schemaDef?.description?.value, ...operationTypes, - types: objectValues(typeMap), + types: Object.values(typeMap), directives: [ ...schemaConfig.directives.map(replaceDirective), ...directiveDefs.map(buildDirective), ], - extensions: undefined, + extensions: Object.create(null), astNode: schemaDef ?? schemaConfig.astNode, extensionASTNodes: schemaConfig.extensionASTNodes.concat(schemaExtensions), assumeValid: options?.assumeValid ?? false, @@ -239,23 +216,24 @@ export function extendSchemaImpl( // Below are functions used for producing this schema that have closed over // this scope and have access to the schema, cache, and newly defined types. - function replaceType(type: T): T { + function replaceType(type: T): T { if (isListType(type)) { - // $FlowFixMe[incompatible-return] + // @ts-expect-error return new GraphQLList(replaceType(type.ofType)); } if (isNonNullType(type)) { - // $FlowFixMe[incompatible-return] + // @ts-expect-error return new GraphQLNonNull(replaceType(type.ofType)); } + // @ts-expect-error FIXME return replaceNamedType(type); } - function replaceNamedType(type: T): T { + function replaceNamedType(type: T): T { // Note: While this could make early assertions to get the correctly // typed values, that would throw immediately while type system // validation with validateSchema() will produce more actionable results. - return ((typeMap[type.name]: any): T); + return typeMap[type.name]; } function replaceDirective(directive: GraphQLDirective): GraphQLDirective { @@ -286,13 +264,12 @@ export function extendSchemaImpl( if (isEnumType(type)) { return extendEnumType(type); } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isInputObjectType(type)) { return extendInputObjectType(type); } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable, all possible type definition nodes have been considered. + invariant(false, 'Unexpected type: ' + inspect(type)); } function extendInputObjectType( @@ -332,14 +309,14 @@ export function extendSchemaImpl( const config = type.toConfig(); const extensions = typeExtensionsMap[config.name] ?? []; - let specifiedByUrl = config.specifiedByUrl; + let specifiedByURL = config.specifiedByURL; for (const extensionNode of extensions) { - specifiedByUrl = getSpecifiedByUrl(extensionNode) ?? specifiedByUrl; + specifiedByURL = getSpecifiedByURL(extensionNode) ?? specifiedByURL; } return new GraphQLScalarType({ ...config, - specifiedByUrl, + specifiedByURL, extensionASTNodes: config.extensionASTNodes.concat(extensions), }); } @@ -397,13 +374,12 @@ export function extendSchemaImpl( } function extendField( - field: GraphQLFieldConfig, - ): GraphQLFieldConfig { + field: GraphQLFieldConfig, + ): GraphQLFieldConfig { return { ...field, type: replaceType(field.type), - // $FlowFixMe[incompatible-call] - args: mapValue(field.args, extendArg), + args: field.args && mapValue(field.args, extendArg), }; } @@ -415,26 +391,28 @@ export function extendSchemaImpl( } function getOperationTypes( - nodes: $ReadOnlyArray, - ): {| - query: ?GraphQLObjectType, - mutation: ?GraphQLObjectType, - subscription: ?GraphQLObjectType, - |} { + nodes: ReadonlyArray, + ): { + query?: Maybe; + mutation?: Maybe; + subscription?: Maybe; + } { const opTypes = {}; for (const node of nodes) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const operationTypesNodes = node.operationTypes ?? []; + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + const operationTypesNodes = + /* c8 ignore next */ node.operationTypes ?? []; for (const operationType of operationTypesNodes) { + // Note: While this could make early assertions to get the correctly + // typed values below, that would throw immediately while type system + // validation with validateSchema() will produce more actionable results. + // @ts-expect-error opTypes[operationType.operation] = getNamedType(operationType.type); } } - // Note: While this could make early assertions to get the correctly - // typed values below, that would throw immediately while type system - // validation with validateSchema() will produce more actionable results. - return (opTypes: any); + return opTypes; } function getNamedType(node: NamedTypeNode): GraphQLNamedType { @@ -458,14 +436,11 @@ export function extendSchemaImpl( } function buildDirective(node: DirectiveDefinitionNode): GraphQLDirective { - const locations = node.locations.map( - ({ value }) => ((value: any): DirectiveLocationEnum), - ); - return new GraphQLDirective({ name: node.name.value, - description: getDescription(node, options), - locations, + description: node.description?.value, + // @ts-expect-error + locations: node.locations.map(({ value }) => value), isRepeatable: node.repeatable, args: buildArgumentMap(node.arguments), astNode: node, @@ -473,25 +448,25 @@ export function extendSchemaImpl( } function buildFieldMap( - nodes: $ReadOnlyArray< + nodes: ReadonlyArray< | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode | ObjectTypeDefinitionNode - | ObjectTypeExtensionNode, + | ObjectTypeExtensionNode >, - ): GraphQLFieldConfigMap { + ): GraphQLFieldConfigMap { const fieldConfigMap = Object.create(null); for (const node of nodes) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const nodeFields = node.fields ?? []; + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + const nodeFields = /* c8 ignore next */ node.fields ?? []; for (const field of nodeFields) { fieldConfigMap[field.name.value] = { // Note: While this could make assertions to get the correctly typed // value, that would throw immediately while type system validation // with validateSchema() will produce more actionable results. - type: (getWrappedType(field.type): any), - description: getDescription(field, options), + type: getWrappedType(field.type), + description: field.description?.value, args: buildArgumentMap(field.arguments), deprecationReason: getDeprecationReason(field), astNode: field, @@ -502,10 +477,10 @@ export function extendSchemaImpl( } function buildArgumentMap( - args: ?$ReadOnlyArray, + args: Maybe>, ): GraphQLFieldConfigArgumentMap { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const argsNodes = args ?? []; + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + const argsNodes = /* c8 ignore next */ args ?? []; const argConfigMap = Object.create(null); for (const arg of argsNodes) { @@ -516,7 +491,7 @@ export function extendSchemaImpl( argConfigMap[arg.name.value] = { type, - description: getDescription(arg, options), + description: arg.description?.value, defaultValue: valueFromAST(arg.defaultValue, type), deprecationReason: getDeprecationReason(arg), astNode: arg, @@ -526,14 +501,14 @@ export function extendSchemaImpl( } function buildInputFieldMap( - nodes: $ReadOnlyArray< - InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode, + nodes: ReadonlyArray< + InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode >, ): GraphQLInputFieldConfigMap { const inputFieldMap = Object.create(null); for (const node of nodes) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const fieldsNodes = node.fields ?? []; + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + const fieldsNodes = /* c8 ignore next */ node.fields ?? []; for (const field of fieldsNodes) { // Note: While this could make assertions to get the correctly typed @@ -543,7 +518,7 @@ export function extendSchemaImpl( inputFieldMap[field.name.value] = { type, - description: getDescription(field, options), + description: field.description?.value, defaultValue: valueFromAST(field.defaultValue, type), deprecationReason: getDeprecationReason(field), astNode: field, @@ -554,16 +529,16 @@ export function extendSchemaImpl( } function buildEnumValueMap( - nodes: $ReadOnlyArray, + nodes: ReadonlyArray, ): GraphQLEnumValueConfigMap { const enumValueMap = Object.create(null); for (const node of nodes) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const valuesNodes = node.values ?? []; + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + const valuesNodes = /* c8 ignore next */ node.values ?? []; for (const value of valuesNodes) { enumValueMap[value.name.value] = { - description: getDescription(value, options), + description: value.description?.value, deprecationReason: getDeprecationReason(value), astNode: value, }; @@ -573,61 +548,47 @@ export function extendSchemaImpl( } function buildInterfaces( - nodes: $ReadOnlyArray< + nodes: ReadonlyArray< | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode | ObjectTypeDefinitionNode - | ObjectTypeExtensionNode, + | ObjectTypeExtensionNode >, ): Array { - const interfaces = []; - for (const node of nodes) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const interfacesNodes = node.interfaces ?? []; - - for (const type of interfacesNodes) { - // Note: While this could make assertions to get the correctly typed - // values below, that would throw immediately while type system - // validation with validateSchema() will produce more actionable - // results. - interfaces.push((getNamedType(type): any)); - } - } - return interfaces; + // Note: While this could make assertions to get the correctly typed + // values below, that would throw immediately while type system + // validation with validateSchema() will produce more actionable results. + // @ts-expect-error + return nodes.flatMap( + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + (node) => /* c8 ignore next */ node.interfaces?.map(getNamedType) ?? [], + ); } function buildUnionTypes( - nodes: $ReadOnlyArray, + nodes: ReadonlyArray, ): Array { - const types = []; - for (const node of nodes) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const typeNodes = node.types ?? []; - - for (const type of typeNodes) { - // Note: While this could make assertions to get the correctly typed - // values below, that would throw immediately while type system - // validation with validateSchema() will produce more actionable - // results. - types.push((getNamedType(type): any)); - } - } - return types; + // Note: While this could make assertions to get the correctly typed + // values below, that would throw immediately while type system + // validation with validateSchema() will produce more actionable results. + // @ts-expect-error + return nodes.flatMap( + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + (node) => /* c8 ignore next */ node.types?.map(getNamedType) ?? [], + ); } function buildType(astNode: TypeDefinitionNode): GraphQLNamedType { const name = astNode.name.value; - const description = getDescription(astNode, options); - const extensionNodes = typeExtensionsMap[name] ?? []; + const extensionASTNodes = typeExtensionsMap[name] ?? []; switch (astNode.kind) { case Kind.OBJECT_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLObjectType({ name, - description, + description: astNode.description?.value, interfaces: () => buildInterfaces(allNodes), fields: () => buildFieldMap(allNodes), astNode, @@ -635,12 +596,11 @@ export function extendSchemaImpl( }); } case Kind.INTERFACE_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLInterfaceType({ name, - description, + description: astNode.description?.value, interfaces: () => buildInterfaces(allNodes), fields: () => buildFieldMap(allNodes), astNode, @@ -648,64 +608,54 @@ export function extendSchemaImpl( }); } case Kind.ENUM_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLEnumType({ name, - description, + description: astNode.description?.value, values: buildEnumValueMap(allNodes), astNode, extensionASTNodes, }); } case Kind.UNION_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLUnionType({ name, - description, + description: astNode.description?.value, types: () => buildUnionTypes(allNodes), astNode, extensionASTNodes, }); } case Kind.SCALAR_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); - return new GraphQLScalarType({ name, - description, - specifiedByUrl: getSpecifiedByUrl(astNode), + description: astNode.description?.value, + specifiedByURL: getSpecifiedByURL(astNode), astNode, extensionASTNodes, }); } case Kind.INPUT_OBJECT_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLInputObjectType({ name, - description, + description: astNode.description?.value, fields: () => buildInputFieldMap(allNodes), astNode, extensionASTNodes, + isOneOf: isOneOf(astNode), }); } } - - // istanbul ignore next (Not reachable. All possible type definition nodes have been considered) - invariant( - false, - 'Unexpected type definition node: ' + inspect((astNode: empty)), - ); } } const stdTypeMap = keyMap( - specifiedScalarTypes.concat(introspectionTypes), + [...specifiedScalarTypes, ...introspectionTypes], (type) => type.name, ); @@ -718,64 +668,26 @@ function getDeprecationReason( | EnumValueDefinitionNode | FieldDefinitionNode | InputValueDefinitionNode, -): ?string { +): Maybe { const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node); - return (deprecated?.reason: any); + // @ts-expect-error validated by `getDirectiveValues` + return deprecated?.reason; } /** - * Given a scalar node, returns the string value for the specifiedByUrl. + * Given a scalar node, returns the string value for the specifiedByURL. */ -function getSpecifiedByUrl( +function getSpecifiedByURL( node: ScalarTypeDefinitionNode | ScalarTypeExtensionNode, -): ?string { +): Maybe { const specifiedBy = getDirectiveValues(GraphQLSpecifiedByDirective, node); - return (specifiedBy?.url: any); + // @ts-expect-error validated by `getDirectiveValues` + return specifiedBy?.url; } /** - * Given an ast node, returns its string description. - * @deprecated: provided to ease adoption and will be removed in v16. - * - * Accepts options as a second argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * + * Given an input object node, returns if the node should be OneOf. */ -export function getDescription( - node: { +description?: StringValueNode, +loc?: Location, ... }, - options: ?{ commentDescriptions?: boolean, ... }, -): void | string { - if (node.description) { - return node.description.value; - } - if (options?.commentDescriptions === true) { - const rawValue = getLeadingCommentBlock(node); - if (rawValue !== undefined) { - return dedentBlockStringValue('\n' + rawValue); - } - } -} - -function getLeadingCommentBlock(node): void | string { - const loc = node.loc; - if (!loc) { - return; - } - const comments = []; - let token = loc.startToken.prev; - while ( - token != null && - token.kind === TokenKind.COMMENT && - token.next && - token.prev && - token.line + 1 === token.next.line && - token.line !== token.prev.line - ) { - const value = String(token.value); - comments.push(value); - token = token.prev; - } - return comments.length > 0 ? comments.reverse().join('\n') : undefined; +function isOneOf(node: InputObjectTypeDefinitionNode): boolean { + return Boolean(getDirectiveValues(GraphQLOneOfDirective, node)); } diff --git a/src/utilities/findBreakingChanges.d.ts b/src/utilities/findBreakingChanges.d.ts deleted file mode 100644 index df35805f17..0000000000 --- a/src/utilities/findBreakingChanges.d.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { GraphQLSchema } from '../type/schema'; - -export const BreakingChangeType: { - TYPE_REMOVED: 'TYPE_REMOVED'; - TYPE_CHANGED_KIND: 'TYPE_CHANGED_KIND'; - TYPE_REMOVED_FROM_UNION: 'TYPE_REMOVED_FROM_UNION'; - VALUE_REMOVED_FROM_ENUM: 'VALUE_REMOVED_FROM_ENUM'; - REQUIRED_INPUT_FIELD_ADDED: 'REQUIRED_INPUT_FIELD_ADDED'; - IMPLEMENTED_INTERFACE_REMOVED: 'IMPLEMENTED_INTERFACE_REMOVED'; - FIELD_REMOVED: 'FIELD_REMOVED'; - FIELD_CHANGED_KIND: 'FIELD_CHANGED_KIND'; - REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED'; - ARG_REMOVED: 'ARG_REMOVED'; - ARG_CHANGED_KIND: 'ARG_CHANGED_KIND'; - DIRECTIVE_REMOVED: 'DIRECTIVE_REMOVED'; - DIRECTIVE_ARG_REMOVED: 'DIRECTIVE_ARG_REMOVED'; - REQUIRED_DIRECTIVE_ARG_ADDED: 'REQUIRED_DIRECTIVE_ARG_ADDED'; - DIRECTIVE_REPEATABLE_REMOVED: 'DIRECTIVE_REPEATABLE_REMOVED'; - DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED'; -}; - -export const DangerousChangeType: { - VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM'; - TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION'; - OPTIONAL_INPUT_FIELD_ADDED: 'OPTIONAL_INPUT_FIELD_ADDED'; - OPTIONAL_ARG_ADDED: 'OPTIONAL_ARG_ADDED'; - IMPLEMENTED_INTERFACE_ADDED: 'IMPLEMENTED_INTERFACE_ADDED'; - ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE'; -}; - -export interface BreakingChange { - type: keyof typeof BreakingChangeType; - description: string; -} - -export interface DangerousChange { - type: keyof typeof DangerousChangeType; - description: string; -} - -/** - * Given two schemas, returns an Array containing descriptions of all the types - * of breaking changes covered by the other functions down below. - */ -export function findBreakingChanges( - oldSchema: GraphQLSchema, - newSchema: GraphQLSchema, -): Array; - -/** - * Given two schemas, returns an Array containing descriptions of all the types - * of potentially dangerous changes covered by the other functions down below. - */ -export function findDangerousChanges( - oldSchema: GraphQLSchema, - newSchema: GraphQLSchema, -): Array; diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.ts similarity index 82% rename from src/utilities/findBreakingChanges.js rename to src/utilities/findBreakingChanges.ts index 9f74a2d95c..2489af9d62 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.ts @@ -1,79 +1,78 @@ -import objectValues from '../polyfills/objectValues'; - -import keyMap from '../jsutils/keyMap'; -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; -import naturalCompare from '../jsutils/naturalCompare'; +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import { keyMap } from '../jsutils/keyMap'; import { print } from '../language/printer'; -import { visit } from '../language/visitor'; -import type { GraphQLSchema } from '../type/schema'; import type { + GraphQLEnumType, GraphQLField, - GraphQLType, + GraphQLInputObjectType, GraphQLInputType, + GraphQLInterfaceType, GraphQLNamedType, - GraphQLEnumType, - GraphQLUnionType, GraphQLObjectType, - GraphQLInterfaceType, - GraphQLInputObjectType, + GraphQLType, + GraphQLUnionType, } from '../type/definition'; -import { isSpecifiedScalarType } from '../type/scalars'; import { - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, isEnumType, isInputObjectType, - isNonNullType, + isInterfaceType, isListType, isNamedType, + isNonNullType, + isObjectType, isRequiredArgument, isRequiredInputField, + isScalarType, + isUnionType, } from '../type/definition'; +import { isSpecifiedScalarType } from '../type/scalars'; +import type { GraphQLSchema } from '../type/schema'; import { astFromValue } from './astFromValue'; +import { sortValueNode } from './sortValueNode'; + +enum BreakingChangeType { + TYPE_REMOVED = 'TYPE_REMOVED', + TYPE_CHANGED_KIND = 'TYPE_CHANGED_KIND', + TYPE_REMOVED_FROM_UNION = 'TYPE_REMOVED_FROM_UNION', + VALUE_REMOVED_FROM_ENUM = 'VALUE_REMOVED_FROM_ENUM', + REQUIRED_INPUT_FIELD_ADDED = 'REQUIRED_INPUT_FIELD_ADDED', + IMPLEMENTED_INTERFACE_REMOVED = 'IMPLEMENTED_INTERFACE_REMOVED', + FIELD_REMOVED = 'FIELD_REMOVED', + FIELD_CHANGED_KIND = 'FIELD_CHANGED_KIND', + REQUIRED_ARG_ADDED = 'REQUIRED_ARG_ADDED', + ARG_REMOVED = 'ARG_REMOVED', + ARG_CHANGED_KIND = 'ARG_CHANGED_KIND', + DIRECTIVE_REMOVED = 'DIRECTIVE_REMOVED', + DIRECTIVE_ARG_REMOVED = 'DIRECTIVE_ARG_REMOVED', + REQUIRED_DIRECTIVE_ARG_ADDED = 'REQUIRED_DIRECTIVE_ARG_ADDED', + DIRECTIVE_REPEATABLE_REMOVED = 'DIRECTIVE_REPEATABLE_REMOVED', + DIRECTIVE_LOCATION_REMOVED = 'DIRECTIVE_LOCATION_REMOVED', +} +export { BreakingChangeType }; + +enum DangerousChangeType { + VALUE_ADDED_TO_ENUM = 'VALUE_ADDED_TO_ENUM', + TYPE_ADDED_TO_UNION = 'TYPE_ADDED_TO_UNION', + OPTIONAL_INPUT_FIELD_ADDED = 'OPTIONAL_INPUT_FIELD_ADDED', + OPTIONAL_ARG_ADDED = 'OPTIONAL_ARG_ADDED', + IMPLEMENTED_INTERFACE_ADDED = 'IMPLEMENTED_INTERFACE_ADDED', + ARG_DEFAULT_VALUE_CHANGE = 'ARG_DEFAULT_VALUE_CHANGE', +} +export { DangerousChangeType }; -export const BreakingChangeType = Object.freeze({ - TYPE_REMOVED: 'TYPE_REMOVED', - TYPE_CHANGED_KIND: 'TYPE_CHANGED_KIND', - TYPE_REMOVED_FROM_UNION: 'TYPE_REMOVED_FROM_UNION', - VALUE_REMOVED_FROM_ENUM: 'VALUE_REMOVED_FROM_ENUM', - REQUIRED_INPUT_FIELD_ADDED: 'REQUIRED_INPUT_FIELD_ADDED', - IMPLEMENTED_INTERFACE_REMOVED: 'IMPLEMENTED_INTERFACE_REMOVED', - FIELD_REMOVED: 'FIELD_REMOVED', - FIELD_CHANGED_KIND: 'FIELD_CHANGED_KIND', - REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED', - ARG_REMOVED: 'ARG_REMOVED', - ARG_CHANGED_KIND: 'ARG_CHANGED_KIND', - DIRECTIVE_REMOVED: 'DIRECTIVE_REMOVED', - DIRECTIVE_ARG_REMOVED: 'DIRECTIVE_ARG_REMOVED', - REQUIRED_DIRECTIVE_ARG_ADDED: 'REQUIRED_DIRECTIVE_ARG_ADDED', - DIRECTIVE_REPEATABLE_REMOVED: 'DIRECTIVE_REPEATABLE_REMOVED', - DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED', -}); - -export const DangerousChangeType = Object.freeze({ - VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM', - TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION', - OPTIONAL_INPUT_FIELD_ADDED: 'OPTIONAL_INPUT_FIELD_ADDED', - OPTIONAL_ARG_ADDED: 'OPTIONAL_ARG_ADDED', - IMPLEMENTED_INTERFACE_ADDED: 'IMPLEMENTED_INTERFACE_ADDED', - ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE', -}); - -export type BreakingChange = {| - type: $Keys, - description: string, -|}; - -export type DangerousChange = {| - type: $Keys, - description: string, -|}; +export interface BreakingChange { + type: BreakingChangeType; + description: string; +} + +export interface DangerousChange { + type: DangerousChangeType; + description: string; +} /** * Given two schemas, returns an Array containing descriptions of all the types @@ -83,10 +82,10 @@ export function findBreakingChanges( oldSchema: GraphQLSchema, newSchema: GraphQLSchema, ): Array { - const breakingChanges = findSchemaChanges(oldSchema, newSchema).filter( + // @ts-expect-error + return findSchemaChanges(oldSchema, newSchema).filter( (change) => change.type in BreakingChangeType, ); - return ((breakingChanges: any): Array); } /** @@ -97,10 +96,10 @@ export function findDangerousChanges( oldSchema: GraphQLSchema, newSchema: GraphQLSchema, ): Array { - const dangerousChanges = findSchemaChanges(oldSchema, newSchema).filter( + // @ts-expect-error + return findSchemaChanges(oldSchema, newSchema).filter( (change) => change.type in DangerousChangeType, ); - return ((dangerousChanges: any): Array); } function findSchemaChanges( @@ -158,7 +157,7 @@ function findDirectiveChanges( } for (const location of oldDirective.locations) { - if (newDirective.locations.indexOf(location) === -1) { + if (!newDirective.locations.includes(location)) { schemaChanges.push({ type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, description: `${location} was removed from ${oldDirective.name}.`, @@ -177,8 +176,8 @@ function findTypeChanges( const schemaChanges = []; const typesDiff = diff( - objectValues(oldSchema.getTypeMap()), - objectValues(newSchema.getTypeMap()), + Object.values(oldSchema.getTypeMap()), + Object.values(newSchema.getTypeMap()), ); for (const oldType of typesDiff.removed) { @@ -226,8 +225,8 @@ function findInputObjectTypeChanges( ): Array { const schemaChanges = []; const fieldsDiff = diff( - objectValues(oldType.getFields()), - objectValues(newType.getFields()), + Object.values(oldType.getFields()), + Object.values(newType.getFields()), ); for (const newField of fieldsDiff.added) { @@ -347,8 +346,8 @@ function findFieldChanges( ): Array { const schemaChanges = []; const fieldsDiff = diff( - objectValues(oldType.getFields()), - objectValues(newType.getFields()), + Object.values(oldType.getFields()), + Object.values(newType.getFields()), ); for (const oldField of fieldsDiff.removed) { @@ -380,8 +379,8 @@ function findFieldChanges( function findArgChanges( oldType: GraphQLObjectType | GraphQLInterfaceType, - oldField: GraphQLField, - newField: GraphQLField, + oldField: GraphQLField, + newField: GraphQLField, ): Array { const schemaChanges = []; const argsDiff = diff(oldField.args, newField.args); @@ -527,45 +526,31 @@ function typeKindName(type: GraphQLNamedType): string { if (isEnumType(type)) { return 'an Enum type'; } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isInputObjectType(type)) { return 'an Input type'; } - - // istanbul ignore next (Not reachable. All possible named types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable, all possible types have been considered. + invariant(false, 'Unexpected type: ' + inspect(type)); } -function stringifyValue(value: mixed, type: GraphQLInputType): string { +function stringifyValue(value: unknown, type: GraphQLInputType): string { const ast = astFromValue(value, type); invariant(ast != null); - - const sortedAST = visit(ast, { - ObjectValue(objectNode) { - // Make a copy since sort mutates array - const fields = [...objectNode.fields]; - - fields.sort((fieldA, fieldB) => - naturalCompare(fieldA.name.value, fieldB.name.value), - ); - return { ...objectNode, fields }; - }, - }); - - return print(sortedAST); + return print(sortValueNode(ast)); } -function diff( - oldArray: $ReadOnlyArray, - newArray: $ReadOnlyArray, -): {| - added: Array, - removed: Array, - persisted: Array<[T, T]>, -|} { - const added = []; - const removed = []; - const persisted = []; +function diff( + oldArray: ReadonlyArray, + newArray: ReadonlyArray, +): { + added: ReadonlyArray; + removed: ReadonlyArray; + persisted: ReadonlyArray<[T, T]>; +} { + const added: Array = []; + const removed: Array = []; + const persisted: Array<[T, T]> = []; const oldMap = keyMap(oldArray, ({ name }) => name); const newMap = keyMap(newArray, ({ name }) => name); diff --git a/src/utilities/findDeprecatedUsages.d.ts b/src/utilities/findDeprecatedUsages.d.ts deleted file mode 100644 index bbdf94391e..0000000000 --- a/src/utilities/findDeprecatedUsages.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { GraphQLError } from '../error/GraphQLError'; -import { DocumentNode } from '../language/ast'; -import { GraphQLSchema } from '../type/schema'; - -/** - * A validation rule which reports deprecated usages. - * - * Returns a list of GraphQLError instances describing each deprecated use. - * - * @deprecated Please use `validate` with `NoDeprecatedCustomRule` instead: - * - * ``` - * import { validate, NoDeprecatedCustomRule } from 'graphql' - * - * const errors = validate(schema, document, [NoDeprecatedCustomRule]) - * ``` - */ -export function findDeprecatedUsages( - schema: GraphQLSchema, - ast: DocumentNode, -): ReadonlyArray; diff --git a/src/utilities/findDeprecatedUsages.js b/src/utilities/findDeprecatedUsages.js deleted file mode 100644 index f193494bab..0000000000 --- a/src/utilities/findDeprecatedUsages.js +++ /dev/null @@ -1,28 +0,0 @@ -import type { GraphQLError } from '../error/GraphQLError'; - -import type { DocumentNode } from '../language/ast'; - -import type { GraphQLSchema } from '../type/schema'; - -import { validate } from '../validation/validate'; -import { NoDeprecatedCustomRule } from '../validation/rules/custom/NoDeprecatedCustomRule'; - -/** - * A validation rule which reports deprecated usages. - * - * Returns a list of GraphQLError instances describing each deprecated use. - * - * @deprecated Please use `validate` with `NoDeprecatedCustomRule` instead: - * - * ``` - * import { validate, NoDeprecatedCustomRule } from 'graphql' - * - * const errors = validate(schema, document, [NoDeprecatedCustomRule]) - * ``` - */ -export function findDeprecatedUsages( - schema: GraphQLSchema, - ast: DocumentNode, -): $ReadOnlyArray { - return validate(schema, ast, [NoDeprecatedCustomRule]); -} diff --git a/src/utilities/getIntrospectionQuery.d.ts b/src/utilities/getIntrospectionQuery.d.ts deleted file mode 100644 index 6e5fad16e6..0000000000 --- a/src/utilities/getIntrospectionQuery.d.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { DirectiveLocationEnum } from '../language/directiveLocation'; - -export interface IntrospectionOptions { - // Whether to include descriptions in the introspection result. - // Default: true - descriptions?: boolean; - - // Whether to include `specifiedByUrl` in the introspection result. - // Default: false - specifiedByUrl?: boolean; - - // Whether to include `isRepeatable` flag on directives. - // Default: false - directiveIsRepeatable?: boolean; - - // Whether to include `description` field on schema. - // Default: false - schemaDescription?: boolean; - - // Whether target GraphQL server support deprecation of input values. - // Default: false - inputValueDeprecation?: boolean; -} - -export function getIntrospectionQuery(options?: IntrospectionOptions): string; - -export interface IntrospectionQuery { - readonly __schema: IntrospectionSchema; -} - -export interface IntrospectionSchema { - readonly queryType: IntrospectionNamedTypeRef; - readonly mutationType: Maybe< - IntrospectionNamedTypeRef - >; - readonly subscriptionType: Maybe< - IntrospectionNamedTypeRef - >; - readonly types: ReadonlyArray; - readonly directives: ReadonlyArray; -} - -export type IntrospectionType = - | IntrospectionScalarType - | IntrospectionObjectType - | IntrospectionInterfaceType - | IntrospectionUnionType - | IntrospectionEnumType - | IntrospectionInputObjectType; - -export type IntrospectionOutputType = - | IntrospectionScalarType - | IntrospectionObjectType - | IntrospectionInterfaceType - | IntrospectionUnionType - | IntrospectionEnumType; - -export type IntrospectionInputType = - | IntrospectionScalarType - | IntrospectionEnumType - | IntrospectionInputObjectType; - -export interface IntrospectionScalarType { - readonly kind: 'SCALAR'; - readonly name: string; - readonly description?: Maybe; - readonly specifiedByUrl?: Maybe; -} - -export interface IntrospectionObjectType { - readonly kind: 'OBJECT'; - readonly name: string; - readonly description?: Maybe; - readonly fields: ReadonlyArray; - readonly interfaces: ReadonlyArray< - IntrospectionNamedTypeRef - >; -} - -export interface IntrospectionInterfaceType { - readonly kind: 'INTERFACE'; - readonly name: string; - readonly description?: Maybe; - readonly fields: ReadonlyArray; - readonly interfaces: ReadonlyArray< - IntrospectionNamedTypeRef - >; - readonly possibleTypes: ReadonlyArray< - IntrospectionNamedTypeRef - >; -} - -export interface IntrospectionUnionType { - readonly kind: 'UNION'; - readonly name: string; - readonly description?: Maybe; - readonly possibleTypes: ReadonlyArray< - IntrospectionNamedTypeRef - >; -} - -export interface IntrospectionEnumType { - readonly kind: 'ENUM'; - readonly name: string; - readonly description?: Maybe; - readonly enumValues: ReadonlyArray; -} - -export interface IntrospectionInputObjectType { - readonly kind: 'INPUT_OBJECT'; - readonly name: string; - readonly description?: Maybe; - readonly inputFields: ReadonlyArray; -} - -export interface IntrospectionListTypeRef< - T extends IntrospectionTypeRef = IntrospectionTypeRef -> { - readonly kind: 'LIST'; - readonly ofType: T; -} - -export interface IntrospectionNonNullTypeRef< - T extends IntrospectionTypeRef = IntrospectionTypeRef -> { - readonly kind: 'NON_NULL'; - readonly ofType: T; -} - -export type IntrospectionTypeRef = - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - | IntrospectionNonNullTypeRef< - IntrospectionNamedTypeRef | IntrospectionListTypeRef - >; - -export type IntrospectionOutputTypeRef = - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - | IntrospectionNonNullTypeRef< - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - >; - -export type IntrospectionInputTypeRef = - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - | IntrospectionNonNullTypeRef< - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - >; - -export interface IntrospectionNamedTypeRef< - T extends IntrospectionType = IntrospectionType -> { - readonly kind: T['kind']; - readonly name: string; -} - -export interface IntrospectionField { - readonly name: string; - readonly description?: Maybe; - readonly args: ReadonlyArray; - readonly type: IntrospectionOutputTypeRef; - readonly isDeprecated: boolean; - readonly deprecationReason?: Maybe; -} - -export interface IntrospectionInputValue { - readonly name: string; - readonly description?: Maybe; - readonly type: IntrospectionInputTypeRef; - readonly defaultValue?: Maybe; - readonly isDeprecated?: boolean; - readonly deprecationReason?: Maybe; -} - -export interface IntrospectionEnumValue { - readonly name: string; - readonly description?: Maybe; - readonly isDeprecated: boolean; - readonly deprecationReason?: Maybe; -} - -export interface IntrospectionDirective { - readonly name: string; - readonly description?: Maybe; - readonly isRepeatable?: boolean; - readonly locations: ReadonlyArray; - readonly args: ReadonlyArray; -} diff --git a/src/utilities/getIntrospectionQuery.js b/src/utilities/getIntrospectionQuery.js deleted file mode 100644 index 1c9abb4204..0000000000 --- a/src/utilities/getIntrospectionQuery.js +++ /dev/null @@ -1,311 +0,0 @@ -import type { DirectiveLocationEnum } from '../language/directiveLocation'; - -export type IntrospectionOptions = {| - // Whether to include descriptions in the introspection result. - // Default: true - descriptions?: boolean, - - // Whether to include `specifiedByUrl` in the introspection result. - // Default: false - specifiedByUrl?: boolean, - - // Whether to include `isRepeatable` field on directives. - // Default: false - directiveIsRepeatable?: boolean, - - // Whether to include `description` field on schema. - // Default: false - schemaDescription?: boolean, - - // Whether target GraphQL server support deprecation of input values. - // Default: false - inputValueDeprecation?: boolean, -|}; - -export function getIntrospectionQuery(options?: IntrospectionOptions): string { - const optionsWithDefault = { - descriptions: true, - specifiedByUrl: false, - directiveIsRepeatable: false, - schemaDescription: false, - inputValueDeprecation: false, - ...options, - }; - - const descriptions = optionsWithDefault.descriptions ? 'description' : ''; - const specifiedByUrl = optionsWithDefault.specifiedByUrl - ? 'specifiedByUrl' - : ''; - const directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable - ? 'isRepeatable' - : ''; - const schemaDescription = optionsWithDefault.schemaDescription - ? descriptions - : ''; - - function inputDeprecation(str) { - return optionsWithDefault.inputValueDeprecation ? str : ''; - } - - return ` - query IntrospectionQuery { - __schema { - ${schemaDescription} - queryType { name } - mutationType { name } - subscriptionType { name } - types { - ...FullType - } - directives { - name - ${descriptions} - ${directiveIsRepeatable} - locations - args${inputDeprecation('(includeDeprecated: true)')} { - ...InputValue - } - } - } - } - - fragment FullType on __Type { - kind - name - ${descriptions} - ${specifiedByUrl} - fields(includeDeprecated: true) { - name - ${descriptions} - args${inputDeprecation('(includeDeprecated: true)')} { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields${inputDeprecation('(includeDeprecated: true)')} { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - ${descriptions} - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } - } - - fragment InputValue on __InputValue { - name - ${descriptions} - type { ...TypeRef } - defaultValue - ${inputDeprecation('isDeprecated')} - ${inputDeprecation('deprecationReason')} - } - - fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - `; -} - -export type IntrospectionQuery = {| - +__schema: IntrospectionSchema, -|}; - -export type IntrospectionSchema = {| - +description?: ?string, - +queryType: IntrospectionNamedTypeRef, - +mutationType: ?IntrospectionNamedTypeRef, - +subscriptionType: ?IntrospectionNamedTypeRef, - +types: $ReadOnlyArray, - +directives: $ReadOnlyArray, -|}; - -export type IntrospectionType = - | IntrospectionScalarType - | IntrospectionObjectType - | IntrospectionInterfaceType - | IntrospectionUnionType - | IntrospectionEnumType - | IntrospectionInputObjectType; - -export type IntrospectionOutputType = - | IntrospectionScalarType - | IntrospectionObjectType - | IntrospectionInterfaceType - | IntrospectionUnionType - | IntrospectionEnumType; - -export type IntrospectionInputType = - | IntrospectionScalarType - | IntrospectionEnumType - | IntrospectionInputObjectType; - -export type IntrospectionScalarType = {| - +kind: 'SCALAR', - +name: string, - +description?: ?string, - +specifiedByUrl?: ?string, -|}; - -export type IntrospectionObjectType = {| - +kind: 'OBJECT', - +name: string, - +description?: ?string, - +fields: $ReadOnlyArray, - +interfaces: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, -|}; - -export type IntrospectionInterfaceType = {| - +kind: 'INTERFACE', - +name: string, - +description?: ?string, - +fields: $ReadOnlyArray, - +interfaces: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, - +possibleTypes: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, -|}; - -export type IntrospectionUnionType = {| - +kind: 'UNION', - +name: string, - +description?: ?string, - +possibleTypes: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, -|}; - -export type IntrospectionEnumType = {| - +kind: 'ENUM', - +name: string, - +description?: ?string, - +enumValues: $ReadOnlyArray, -|}; - -export type IntrospectionInputObjectType = {| - +kind: 'INPUT_OBJECT', - +name: string, - +description?: ?string, - +inputFields: $ReadOnlyArray, -|}; - -export type IntrospectionListTypeRef< - T: IntrospectionTypeRef = IntrospectionTypeRef, -> = {| - +kind: 'LIST', - +ofType: T, -|}; - -export type IntrospectionNonNullTypeRef< - T: IntrospectionTypeRef = IntrospectionTypeRef, -> = {| - +kind: 'NON_NULL', - +ofType: T, -|}; - -export type IntrospectionTypeRef = - | IntrospectionNamedTypeRef<> - | IntrospectionListTypeRef<> - | IntrospectionNonNullTypeRef< - IntrospectionNamedTypeRef<> | IntrospectionListTypeRef<>, - >; - -export type IntrospectionOutputTypeRef = - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - | IntrospectionNonNullTypeRef< - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef, - >; - -export type IntrospectionInputTypeRef = - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - | IntrospectionNonNullTypeRef< - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef, - >; - -export type IntrospectionNamedTypeRef< - T: IntrospectionType = IntrospectionType, -> = {| - +kind: $PropertyType, - +name: string, -|}; - -export type IntrospectionField = {| - +name: string, - +description?: ?string, - +args: $ReadOnlyArray, - +type: IntrospectionOutputTypeRef, - +isDeprecated: boolean, - +deprecationReason: ?string, -|}; - -export type IntrospectionInputValue = {| - +name: string, - +description?: ?string, - +type: IntrospectionInputTypeRef, - +defaultValue: ?string, - +isDeprecated?: boolean, - +deprecationReason?: ?string, -|}; - -export type IntrospectionEnumValue = {| - +name: string, - +description?: ?string, - +isDeprecated: boolean, - +deprecationReason: ?string, -|}; - -export type IntrospectionDirective = {| - +name: string, - +description?: ?string, - +isRepeatable?: boolean, - +locations: $ReadOnlyArray, - +args: $ReadOnlyArray, -|}; diff --git a/src/utilities/getIntrospectionQuery.ts b/src/utilities/getIntrospectionQuery.ts new file mode 100644 index 0000000000..373b474ed5 --- /dev/null +++ b/src/utilities/getIntrospectionQuery.ts @@ -0,0 +1,349 @@ +import type { Maybe } from '../jsutils/Maybe'; + +import type { DirectiveLocation } from '../language/directiveLocation'; + +export interface IntrospectionOptions { + /** + * Whether to include descriptions in the introspection result. + * Default: true + */ + descriptions?: boolean; + + /** + * Whether to include `specifiedByURL` in the introspection result. + * Default: false + */ + specifiedByUrl?: boolean; + + /** + * Whether to include `isRepeatable` flag on directives. + * Default: false + */ + directiveIsRepeatable?: boolean; + + /** + * Whether to include `description` field on schema. + * Default: false + */ + schemaDescription?: boolean; + + /** + * Whether target GraphQL server support deprecation of input values. + * Default: false + */ + inputValueDeprecation?: boolean; + + /** + * Whether target GraphQL server supports `@oneOf` input objects. + * Default: false + */ + oneOf?: boolean; +} + +/** + * Produce the GraphQL query recommended for a full schema introspection. + * Accepts optional IntrospectionOptions. + */ +export function getIntrospectionQuery(options?: IntrospectionOptions): string { + const optionsWithDefault = { + descriptions: true, + specifiedByUrl: false, + directiveIsRepeatable: false, + schemaDescription: false, + inputValueDeprecation: false, + oneOf: false, + ...options, + }; + + const descriptions = optionsWithDefault.descriptions ? 'description' : ''; + const specifiedByUrl = optionsWithDefault.specifiedByUrl + ? 'specifiedByURL' + : ''; + const directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable + ? 'isRepeatable' + : ''; + const schemaDescription = optionsWithDefault.schemaDescription + ? descriptions + : ''; + + function inputDeprecation(str: string) { + return optionsWithDefault.inputValueDeprecation ? str : ''; + } + const oneOf = optionsWithDefault.oneOf ? 'isOneOf' : ''; + + return ` + query IntrospectionQuery { + __schema { + ${schemaDescription} + queryType { name kind } + mutationType { name kind } + subscriptionType { name kind } + types { + ...FullType + } + directives { + name + ${descriptions} + ${directiveIsRepeatable} + locations + args${inputDeprecation('(includeDeprecated: true)')} { + ...InputValue + } + } + } + } + + fragment FullType on __Type { + kind + name + ${descriptions} + ${specifiedByUrl} + ${oneOf} + fields(includeDeprecated: true) { + name + ${descriptions} + args${inputDeprecation('(includeDeprecated: true)')} { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields${inputDeprecation('(includeDeprecated: true)')} { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + ${descriptions} + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } + } + + fragment InputValue on __InputValue { + name + ${descriptions} + type { ...TypeRef } + defaultValue + ${inputDeprecation('isDeprecated')} + ${inputDeprecation('deprecationReason')} + } + + fragment TypeRef on __Type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } + } + } + } + `; +} + +export interface IntrospectionQuery { + readonly __schema: IntrospectionSchema; +} + +export interface IntrospectionSchema { + readonly description?: Maybe; + readonly queryType: IntrospectionNamedTypeRef; + readonly mutationType: Maybe< + IntrospectionNamedTypeRef + >; + readonly subscriptionType: Maybe< + IntrospectionNamedTypeRef + >; + readonly types: ReadonlyArray; + readonly directives: ReadonlyArray; +} + +export type IntrospectionType = + | IntrospectionScalarType + | IntrospectionObjectType + | IntrospectionInterfaceType + | IntrospectionUnionType + | IntrospectionEnumType + | IntrospectionInputObjectType; + +export type IntrospectionOutputType = + | IntrospectionScalarType + | IntrospectionObjectType + | IntrospectionInterfaceType + | IntrospectionUnionType + | IntrospectionEnumType; + +export type IntrospectionInputType = + | IntrospectionScalarType + | IntrospectionEnumType + | IntrospectionInputObjectType; + +export interface IntrospectionScalarType { + readonly kind: 'SCALAR'; + readonly name: string; + readonly description?: Maybe; + readonly specifiedByURL?: Maybe; +} + +export interface IntrospectionObjectType { + readonly kind: 'OBJECT'; + readonly name: string; + readonly description?: Maybe; + readonly fields: ReadonlyArray; + readonly interfaces: ReadonlyArray< + IntrospectionNamedTypeRef + >; +} + +export interface IntrospectionInterfaceType { + readonly kind: 'INTERFACE'; + readonly name: string; + readonly description?: Maybe; + readonly fields: ReadonlyArray; + readonly interfaces: ReadonlyArray< + IntrospectionNamedTypeRef + >; + readonly possibleTypes: ReadonlyArray< + IntrospectionNamedTypeRef + >; +} + +export interface IntrospectionUnionType { + readonly kind: 'UNION'; + readonly name: string; + readonly description?: Maybe; + readonly possibleTypes: ReadonlyArray< + IntrospectionNamedTypeRef + >; +} + +export interface IntrospectionEnumType { + readonly kind: 'ENUM'; + readonly name: string; + readonly description?: Maybe; + readonly enumValues: ReadonlyArray; +} + +export interface IntrospectionInputObjectType { + readonly kind: 'INPUT_OBJECT'; + readonly name: string; + readonly description?: Maybe; + readonly inputFields: ReadonlyArray; + readonly isOneOf: boolean; +} + +export interface IntrospectionListTypeRef< + T extends IntrospectionTypeRef = IntrospectionTypeRef, +> { + readonly kind: 'LIST'; + readonly ofType: T; +} + +export interface IntrospectionNonNullTypeRef< + T extends IntrospectionTypeRef = IntrospectionTypeRef, +> { + readonly kind: 'NON_NULL'; + readonly ofType: T; +} + +export type IntrospectionTypeRef = + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + | IntrospectionNonNullTypeRef< + IntrospectionNamedTypeRef | IntrospectionListTypeRef + >; + +export type IntrospectionOutputTypeRef = + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + | IntrospectionNonNullTypeRef< + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + >; + +export type IntrospectionInputTypeRef = + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + | IntrospectionNonNullTypeRef< + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + >; + +export interface IntrospectionNamedTypeRef< + T extends IntrospectionType = IntrospectionType, +> { + readonly kind: T['kind']; + readonly name: string; +} + +export interface IntrospectionField { + readonly name: string; + readonly description?: Maybe; + readonly args: ReadonlyArray; + readonly type: IntrospectionOutputTypeRef; + readonly isDeprecated: boolean; + readonly deprecationReason: Maybe; +} + +export interface IntrospectionInputValue { + readonly name: string; + readonly description?: Maybe; + readonly type: IntrospectionInputTypeRef; + readonly defaultValue: Maybe; + readonly isDeprecated?: boolean; + readonly deprecationReason?: Maybe; +} + +export interface IntrospectionEnumValue { + readonly name: string; + readonly description?: Maybe; + readonly isDeprecated: boolean; + readonly deprecationReason: Maybe; +} + +export interface IntrospectionDirective { + readonly name: string; + readonly description?: Maybe; + readonly isRepeatable?: boolean; + readonly locations: ReadonlyArray; + readonly args: ReadonlyArray; +} diff --git a/src/utilities/getOperationAST.d.ts b/src/utilities/getOperationAST.d.ts deleted file mode 100644 index d17a9b495c..0000000000 --- a/src/utilities/getOperationAST.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { DocumentNode, OperationDefinitionNode } from '../language/ast'; - -/** - * Returns an operation AST given a document AST and optionally an operation - * name. If a name is not provided, an operation is only returned if only one is - * provided in the document. - */ -export function getOperationAST( - documentAST: DocumentNode, - operationName?: Maybe, -): Maybe; diff --git a/src/utilities/getOperationAST.js b/src/utilities/getOperationAST.ts similarity index 88% rename from src/utilities/getOperationAST.js rename to src/utilities/getOperationAST.ts index 259d2f05c5..8decf943f6 100644 --- a/src/utilities/getOperationAST.js +++ b/src/utilities/getOperationAST.ts @@ -1,3 +1,5 @@ +import type { Maybe } from '../jsutils/Maybe'; + import type { DocumentNode, OperationDefinitionNode } from '../language/ast'; import { Kind } from '../language/kinds'; @@ -8,8 +10,8 @@ import { Kind } from '../language/kinds'; */ export function getOperationAST( documentAST: DocumentNode, - operationName?: ?string, -): ?OperationDefinitionNode { + operationName?: Maybe, +): Maybe { let operation = null; for (const definition of documentAST.definitions) { if (definition.kind === Kind.OPERATION_DEFINITION) { diff --git a/src/utilities/getOperationRootType.d.ts b/src/utilities/getOperationRootType.d.ts deleted file mode 100644 index 5adc59c7af..0000000000 --- a/src/utilities/getOperationRootType.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { - OperationDefinitionNode, - OperationTypeDefinitionNode, -} from '../language/ast'; -import { GraphQLSchema } from '../type/schema'; -import { GraphQLObjectType } from '../type/definition'; - -/** - * Extracts the root type of the operation from the schema. - */ -export function getOperationRootType( - schema: GraphQLSchema, - operation: OperationDefinitionNode | OperationTypeDefinitionNode, -): GraphQLObjectType; diff --git a/src/utilities/getOperationRootType.js b/src/utilities/getOperationRootType.ts similarity index 75% rename from src/utilities/getOperationRootType.js rename to src/utilities/getOperationRootType.ts index 039cefaa40..db20a793a8 100644 --- a/src/utilities/getOperationRootType.js +++ b/src/utilities/getOperationRootType.ts @@ -5,11 +5,13 @@ import type { OperationTypeDefinitionNode, } from '../language/ast'; -import type { GraphQLSchema } from '../type/schema'; import type { GraphQLObjectType } from '../type/definition'; +import type { GraphQLSchema } from '../type/schema'; /** * Extracts the root type of the operation from the schema. + * + * @deprecated Please use `GraphQLSchema.getRootType` instead. Will be removed in v17 */ export function getOperationRootType( schema: GraphQLSchema, @@ -20,7 +22,7 @@ export function getOperationRootType( if (!queryType) { throw new GraphQLError( 'Schema does not define the required query root type.', - operation, + { nodes: operation }, ); } return queryType; @@ -29,10 +31,9 @@ export function getOperationRootType( if (operation.operation === 'mutation') { const mutationType = schema.getMutationType(); if (!mutationType) { - throw new GraphQLError( - 'Schema is not configured for mutations.', - operation, - ); + throw new GraphQLError('Schema is not configured for mutations.', { + nodes: operation, + }); } return mutationType; } @@ -40,16 +41,15 @@ export function getOperationRootType( if (operation.operation === 'subscription') { const subscriptionType = schema.getSubscriptionType(); if (!subscriptionType) { - throw new GraphQLError( - 'Schema is not configured for subscriptions.', - operation, - ); + throw new GraphQLError('Schema is not configured for subscriptions.', { + nodes: operation, + }); } return subscriptionType; } throw new GraphQLError( 'Can only have query, mutation and subscription operations.', - operation, + { nodes: operation }, ); } diff --git a/src/utilities/index.d.ts b/src/utilities/index.d.ts deleted file mode 100644 index a8019f99d8..0000000000 --- a/src/utilities/index.d.ts +++ /dev/null @@ -1,119 +0,0 @@ -export { - // Produce the GraphQL query recommended for a full schema introspection. - // Accepts optional IntrospectionOptions. - getIntrospectionQuery, - IntrospectionOptions, - IntrospectionQuery, - IntrospectionSchema, - IntrospectionType, - IntrospectionInputType, - IntrospectionOutputType, - IntrospectionScalarType, - IntrospectionObjectType, - IntrospectionInterfaceType, - IntrospectionUnionType, - IntrospectionEnumType, - IntrospectionInputObjectType, - IntrospectionTypeRef, - IntrospectionInputTypeRef, - IntrospectionOutputTypeRef, - IntrospectionNamedTypeRef, - IntrospectionListTypeRef, - IntrospectionNonNullTypeRef, - IntrospectionField, - IntrospectionInputValue, - IntrospectionEnumValue, - IntrospectionDirective, -} from './getIntrospectionQuery'; - -// Gets the target Operation from a Document -export { getOperationAST } from './getOperationAST'; - -// Gets the Type for the target Operation AST. -export { getOperationRootType } from './getOperationRootType'; - -// Convert a GraphQLSchema to an IntrospectionQuery -export { introspectionFromSchema } from './introspectionFromSchema'; - -// Build a GraphQLSchema from an introspection result. -export { buildClientSchema } from './buildClientSchema'; - -// Build a GraphQLSchema from GraphQL Schema language. -export { - buildASTSchema, - buildSchema, - BuildSchemaOptions, -} from './buildASTSchema'; - -// Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST. -export { - extendSchema, - // @deprecated: Get the description from a schema AST node and supports legacy - // syntax for specifying descriptions - will be removed in v16 - getDescription, -} from './extendSchema'; - -// Sort a GraphQLSchema. -export { lexicographicSortSchema } from './lexicographicSortSchema'; - -// Print a GraphQLSchema to GraphQL Schema language. -export { - printSchema, - printType, - printIntrospectionSchema, -} from './printSchema'; - -// Create a GraphQLType from a GraphQL language AST. -export { typeFromAST } from './typeFromAST'; - -// Create a JavaScript value from a GraphQL language AST with a type. -export { valueFromAST } from './valueFromAST'; - -// Create a JavaScript value from a GraphQL language AST without a type. -export { valueFromASTUntyped } from './valueFromASTUntyped'; - -// Create a GraphQL language AST from a JavaScript value. -export { astFromValue } from './astFromValue'; - -// A helper to use within recursive-descent visitors which need to be aware of -// the GraphQL type system. -export { TypeInfo, visitWithTypeInfo } from './TypeInfo'; - -// Coerces a JavaScript value to a GraphQL type, or produces errors. -export { coerceInputValue } from './coerceInputValue'; - -// Concatenates multiple AST together. -export { concatAST } from './concatAST'; - -// Separates an AST into an AST per Operation. -export { separateOperations } from './separateOperations'; - -// Strips characters that are not significant to the validity or execution -// of a GraphQL document. -export { stripIgnoredCharacters } from './stripIgnoredCharacters'; - -// Comparators for types -export { - isEqualType, - isTypeSubTypeOf, - doTypesOverlap, -} from './typeComparators'; - -// Asserts that a string is a valid GraphQL name -export { assertValidName, isValidNameError } from './assertValidName'; - -// Compares two GraphQLSchemas and detects breaking changes. -export { - BreakingChangeType, - DangerousChangeType, - findBreakingChanges, - findDangerousChanges, - BreakingChange, - DangerousChange, -} from './findBreakingChanges'; - -// Wrapper type that contains DocumentNode and types that can be deduced from it. -export { TypedQueryDocumentNode } from './typedQueryDocumentNode'; - -// @deprecated: Report all deprecated usage within a GraphQL document. -export { findDeprecatedUsages } from './findDeprecatedUsages'; diff --git a/src/utilities/index.js b/src/utilities/index.ts similarity index 87% rename from src/utilities/index.js rename to src/utilities/index.ts index 27f849014e..452b975233 100644 --- a/src/utilities/index.js +++ b/src/utilities/index.ts @@ -1,5 +1,4 @@ // Produce the GraphQL query recommended for a full schema introspection. -// Accepts optional IntrospectionOptions. export { getIntrospectionQuery } from './getIntrospectionQuery'; export type { @@ -44,12 +43,7 @@ export { buildASTSchema, buildSchema } from './buildASTSchema'; export type { BuildSchemaOptions } from './buildASTSchema'; // Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST. -export { - extendSchema, - // @deprecated: Get the description from a schema AST node and supports legacy - // syntax for specifying descriptions - will be removed in v16. - getDescription, -} from './extendSchema'; +export { extendSchema } from './extendSchema'; // Sort a GraphQLSchema. export { lexicographicSortSchema } from './lexicographicSortSchema'; @@ -73,8 +67,7 @@ export { valueFromASTUntyped } from './valueFromASTUntyped'; // Create a GraphQL language AST from a JavaScript value. export { astFromValue } from './astFromValue'; -// A helper to use within recursive-descent visitors which need to be aware of -// the GraphQL type system. +// A helper to use within recursive-descent visitors which need to be aware of the GraphQL type system. export { TypeInfo, visitWithTypeInfo } from './TypeInfo'; // Coerces a JavaScript value to a GraphQL type, or produces errors. @@ -86,8 +79,7 @@ export { concatAST } from './concatAST'; // Separates an AST into an AST per Operation. export { separateOperations } from './separateOperations'; -// Strips characters that are not significant to the validity or execution -// of a GraphQL document. +// Strips characters that are not significant to the validity or execution of a GraphQL document. export { stripIgnoredCharacters } from './stripIgnoredCharacters'; // Comparators for types @@ -109,5 +101,5 @@ export { } from './findBreakingChanges'; export type { BreakingChange, DangerousChange } from './findBreakingChanges'; -// @deprecated: Report all deprecated usage within a GraphQL document. -export { findDeprecatedUsages } from './findDeprecatedUsages'; +// Wrapper type that contains DocumentNode and types that can be deduced from it. +export type { TypedQueryDocumentNode } from './typedQueryDocumentNode'; diff --git a/src/utilities/introspectionFromSchema.d.ts b/src/utilities/introspectionFromSchema.d.ts deleted file mode 100644 index ed9abf16ef..0000000000 --- a/src/utilities/introspectionFromSchema.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { GraphQLSchema } from '../type/schema'; - -import { - IntrospectionQuery, - IntrospectionOptions, -} from './getIntrospectionQuery'; - -/** - * Build an IntrospectionQuery from a GraphQLSchema - * - * IntrospectionQuery is useful for utilities that care about type and field - * relationships, but do not need to traverse through those relationships. - * - * This is the inverse of buildClientSchema. The primary use case is outside - * of the server context, for instance when doing schema comparisons. - */ -export function introspectionFromSchema( - schema: GraphQLSchema, - options?: IntrospectionOptions, -): IntrospectionQuery; diff --git a/src/utilities/introspectionFromSchema.js b/src/utilities/introspectionFromSchema.ts similarity index 92% rename from src/utilities/introspectionFromSchema.js rename to src/utilities/introspectionFromSchema.ts index 45d2c042c5..5f58248363 100644 --- a/src/utilities/introspectionFromSchema.js +++ b/src/utilities/introspectionFromSchema.ts @@ -1,4 +1,4 @@ -import invariant from '../jsutils/invariant'; +import { invariant } from '../jsutils/invariant'; import { parse } from '../language/parser'; @@ -7,8 +7,8 @@ import type { GraphQLSchema } from '../type/schema'; import { executeSync } from '../execution/execute'; import type { - IntrospectionQuery, IntrospectionOptions, + IntrospectionQuery, } from './getIntrospectionQuery'; import { getIntrospectionQuery } from './getIntrospectionQuery'; @@ -30,11 +30,12 @@ export function introspectionFromSchema( directiveIsRepeatable: true, schemaDescription: true, inputValueDeprecation: true, + oneOf: true, ...options, }; const document = parse(getIntrospectionQuery(optionsWithDefaults)); const result = executeSync({ schema, document }); invariant(!result.errors && result.data); - return (result.data: any); + return result.data as any; } diff --git a/src/utilities/lexicographicSortSchema.d.ts b/src/utilities/lexicographicSortSchema.d.ts deleted file mode 100644 index 7dfde701d7..0000000000 --- a/src/utilities/lexicographicSortSchema.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { GraphQLSchema } from '../type/schema'; - -/** - * Sort GraphQLSchema. - * - * This function returns a sorted copy of the given GraphQLSchema. - */ -export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema; diff --git a/src/utilities/lexicographicSortSchema.js b/src/utilities/lexicographicSortSchema.ts similarity index 71% rename from src/utilities/lexicographicSortSchema.js rename to src/utilities/lexicographicSortSchema.ts index 3c727c70f0..26b6908c9f 100644 --- a/src/utilities/lexicographicSortSchema.js +++ b/src/utilities/lexicographicSortSchema.ts @@ -1,38 +1,37 @@ -import objectValues from '../polyfills/objectValues'; - +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import { keyValMap } from '../jsutils/keyValMap'; +import type { Maybe } from '../jsutils/Maybe'; +import { naturalCompare } from '../jsutils/naturalCompare'; import type { ObjMap } from '../jsutils/ObjMap'; -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; -import keyValMap from '../jsutils/keyValMap'; -import naturalCompare from '../jsutils/naturalCompare'; import type { - GraphQLType, - GraphQLNamedType, - GraphQLFieldConfigMap, GraphQLFieldConfigArgumentMap, + GraphQLFieldConfigMap, GraphQLInputFieldConfigMap, + GraphQLNamedType, + GraphQLType, } from '../type/definition'; -import { GraphQLSchema } from '../type/schema'; -import { GraphQLDirective } from '../type/directives'; -import { isIntrospectionType } from '../type/introspection'; import { + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLInterfaceType, GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, + isEnumType, + isInputObjectType, + isInterfaceType, isListType, isNonNullType, - isScalarType, isObjectType, - isInterfaceType, + isScalarType, isUnionType, - isEnumType, - isInputObjectType, } from '../type/definition'; +import { GraphQLDirective } from '../type/directives'; +import { isIntrospectionType } from '../type/introspection'; +import { GraphQLSchema } from '../type/schema'; /** * Sort GraphQLSchema. @@ -49,29 +48,32 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { return new GraphQLSchema({ ...schemaConfig, - types: objectValues(typeMap), + types: Object.values(typeMap), directives: sortByName(schemaConfig.directives).map(sortDirective), query: replaceMaybeType(schemaConfig.query), mutation: replaceMaybeType(schemaConfig.mutation), subscription: replaceMaybeType(schemaConfig.subscription), }); - function replaceType(type: T): T { + function replaceType(type: T): T { if (isListType(type)) { - // $FlowFixMe[incompatible-return] + // @ts-expect-error return new GraphQLList(replaceType(type.ofType)); } else if (isNonNullType(type)) { - // $FlowFixMe[incompatible-return] + // @ts-expect-error return new GraphQLNonNull(replaceType(type.ofType)); } - return replaceNamedType(type); + // @ts-expect-error FIXME: TS Conversion + return replaceNamedType(type); } - function replaceNamedType(type: T): T { - return ((typeMap[type.name]: any): T); + function replaceNamedType(type: T): T { + return typeMap[type.name] as T; } - function replaceMaybeType(maybeType: T): T { + function replaceMaybeType( + maybeType: Maybe, + ): Maybe { return maybeType && replaceNamedType(maybeType); } @@ -91,11 +93,11 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { })); } - function sortFields(fieldsMap: GraphQLFieldConfigMap) { + function sortFields(fieldsMap: GraphQLFieldConfigMap) { return sortObjMap(fieldsMap, (field) => ({ ...field, type: replaceType(field.type), - args: sortArgs(field.args), + args: field.args && sortArgs(field.args), })); } @@ -106,8 +108,10 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { })); } - function sortTypes(arr: $ReadOnlyArray): Array { - return sortByName(arr).map(replaceNamedType); + function sortTypes( + array: ReadonlyArray, + ): Array { + return sortByName(array).map(replaceNamedType); } function sortNamedType(type: GraphQLNamedType): GraphQLNamedType { @@ -141,10 +145,9 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { const config = type.toConfig(); return new GraphQLEnumType({ ...config, - values: sortObjMap(config.values), + values: sortObjMap(config.values, (value) => value), }); } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isInputObjectType(type)) { const config = type.toConfig(); return new GraphQLInputObjectType({ @@ -152,31 +155,32 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { fields: () => sortInputFields(config.fields), }); } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable, all possible types have been considered. + invariant(false, 'Unexpected type: ' + inspect(type)); } } -function sortObjMap(map: ObjMap, sortValueFn?: (T) => R): ObjMap { +function sortObjMap( + map: ObjMap, + sortValueFn: (value: T) => R, +): ObjMap { const sortedMap = Object.create(null); - const sortedKeys = sortBy(Object.keys(map), (x) => x); - for (const key of sortedKeys) { - const value = map[key]; - sortedMap[key] = sortValueFn ? sortValueFn(value) : value; + for (const key of Object.keys(map).sort(naturalCompare)) { + sortedMap[key] = sortValueFn(map[key]); } return sortedMap; } -function sortByName( - array: $ReadOnlyArray, +function sortByName( + array: ReadonlyArray, ): Array { return sortBy(array, (obj) => obj.name); } function sortBy( - array: $ReadOnlyArray, - mapToKey: (T) => string, + array: ReadonlyArray, + mapToKey: (item: T) => string, ): Array { return array.slice().sort((obj1, obj2) => { const key1 = mapToKey(obj1); diff --git a/src/utilities/printSchema.d.ts b/src/utilities/printSchema.d.ts deleted file mode 100644 index 1417ee5892..0000000000 --- a/src/utilities/printSchema.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { GraphQLSchema } from '../type/schema'; -import { GraphQLNamedType } from '../type/definition'; - -export interface Options { - /** - * Descriptions are defined as preceding string literals, however an older - * experimental version of the SDL supported preceding comments as - * descriptions. Set to true to enable this deprecated behavior. - * This option is provided to ease adoption and will be removed in v16. - * - * Default: false - */ - commentDescriptions?: boolean; -} - -/** - * Accepts options as a second argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * - */ -export function printSchema(schema: GraphQLSchema, options?: Options): string; - -export function printIntrospectionSchema( - schema: GraphQLSchema, - options?: Options, -): string; - -export function printType(type: GraphQLNamedType, options?: Options): string; diff --git a/src/utilities/printSchema.js b/src/utilities/printSchema.ts similarity index 50% rename from src/utilities/printSchema.js rename to src/utilities/printSchema.ts index c76f01bef8..edac6262c5 100644 --- a/src/utilities/printSchema.js +++ b/src/utilities/printSchema.ts @@ -1,79 +1,51 @@ -import objectValues from '../polyfills/objectValues'; - -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import type { Maybe } from '../jsutils/Maybe'; +import { isPrintableAsBlockString } from '../language/blockString'; +import { Kind } from '../language/kinds'; import { print } from '../language/printer'; -import { printBlockString } from '../language/blockString'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLDirective } from '../type/directives'; import type { - GraphQLNamedType, GraphQLArgument, - GraphQLInputField, - GraphQLScalarType, GraphQLEnumType, - GraphQLObjectType, + GraphQLInputField, + GraphQLInputObjectType, GraphQLInterfaceType, + GraphQLNamedType, + GraphQLObjectType, + GraphQLScalarType, GraphQLUnionType, - GraphQLInputObjectType, } from '../type/definition'; -import { isIntrospectionType } from '../type/introspection'; -import { GraphQLString, isSpecifiedScalarType } from '../type/scalars'; -import { - DEFAULT_DEPRECATION_REASON, - isSpecifiedDirective, -} from '../type/directives'; import { - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, isEnumType, isInputObjectType, + isInterfaceType, + isObjectType, + isScalarType, + isUnionType, } from '../type/definition'; +import type { GraphQLDirective } from '../type/directives'; +import { + DEFAULT_DEPRECATION_REASON, + isSpecifiedDirective, +} from '../type/directives'; +import { isIntrospectionType } from '../type/introspection'; +import { isSpecifiedScalarType } from '../type/scalars'; +import type { GraphQLSchema } from '../type/schema'; import { astFromValue } from './astFromValue'; -type Options = {| - /** - * Descriptions are defined as preceding string literals, however an older - * experimental version of the SDL supported preceding comments as - * descriptions. Set to true to enable this deprecated behavior. - * This option is provided to ease adoption and will be removed in v16. - * - * Default: false - */ - commentDescriptions?: boolean, -|}; - -/** - * Accepts options as a second argument: - * - * - commentDescriptions: - * Provide true to use preceding comments as the description. - * - */ -export function printSchema(schema: GraphQLSchema, options?: Options): string { +export function printSchema(schema: GraphQLSchema): string { return printFilteredSchema( schema, (n) => !isSpecifiedDirective(n), isDefinedType, - options, ); } -export function printIntrospectionSchema( - schema: GraphQLSchema, - options?: Options, -): string { - return printFilteredSchema( - schema, - isSpecifiedDirective, - isIntrospectionType, - options, - ); +export function printIntrospectionSchema(schema: GraphQLSchema): string { + return printFilteredSchema(schema, isSpecifiedDirective, isIntrospectionType); } function isDefinedType(type: GraphQLNamedType): boolean { @@ -84,23 +56,20 @@ function printFilteredSchema( schema: GraphQLSchema, directiveFilter: (type: GraphQLDirective) => boolean, typeFilter: (type: GraphQLNamedType) => boolean, - options, ): string { const directives = schema.getDirectives().filter(directiveFilter); - const types = objectValues(schema.getTypeMap()).filter(typeFilter); - - return ( - [printSchemaDefinition(schema)] - .concat( - directives.map((directive) => printDirective(directive, options)), - types.map((type) => printType(type, options)), - ) - .filter(Boolean) - .join('\n\n') + '\n' - ); + const types = Object.values(schema.getTypeMap()).filter(typeFilter); + + return [ + printSchemaDefinition(schema), + ...directives.map((directive) => printDirective(directive)), + ...types.map((type) => printType(type)), + ] + .filter(Boolean) + .join('\n\n'); } -function printSchemaDefinition(schema: GraphQLSchema): ?string { +function printSchemaDefinition(schema: GraphQLSchema): Maybe { if (schema.description == null && isSchemaOfCommonNames(schema)) { return; } @@ -122,9 +91,7 @@ function printSchemaDefinition(schema: GraphQLSchema): ?string { operationTypes.push(` subscription: ${subscriptionType.name}`); } - return ( - printDescription({}, schema) + `schema {\n${operationTypes.join('\n')}\n}` - ); + return printDescription(schema) + `schema {\n${operationTypes.join('\n')}\n}`; } /** @@ -132,10 +99,13 @@ function printSchemaDefinition(schema: GraphQLSchema): ?string { * the same as any other type and can be named in any manner, however there is * a common naming convention: * + * ```graphql * schema { * query: Query * mutation: Mutation + * subscription: Subscription * } + * ``` * * When using this naming convention, the schema description can be omitted. */ @@ -158,36 +128,33 @@ function isSchemaOfCommonNames(schema: GraphQLSchema): boolean { return true; } -export function printType(type: GraphQLNamedType, options?: Options): string { +export function printType(type: GraphQLNamedType): string { if (isScalarType(type)) { - return printScalar(type, options); + return printScalar(type); } if (isObjectType(type)) { - return printObject(type, options); + return printObject(type); } if (isInterfaceType(type)) { - return printInterface(type, options); + return printInterface(type); } if (isUnionType(type)) { - return printUnion(type, options); + return printUnion(type); } if (isEnumType(type)) { - return printEnum(type, options); + return printEnum(type); } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isInputObjectType(type)) { - return printInputObject(type, options); + return printInputObject(type); } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable, all possible types have been considered. + invariant(false, 'Unexpected type: ' + inspect(type)); } -function printScalar(type: GraphQLScalarType, options): string { +function printScalar(type: GraphQLScalarType): string { return ( - printDescription(options, type) + - `scalar ${type.name}` + - printSpecifiedByUrl(type) + printDescription(type) + `scalar ${type.name}` + printSpecifiedByURL(type) ); } @@ -200,66 +167,63 @@ function printImplementedInterfaces( : ''; } -function printObject(type: GraphQLObjectType, options): string { +function printObject(type: GraphQLObjectType): string { return ( - printDescription(options, type) + + printDescription(type) + `type ${type.name}` + printImplementedInterfaces(type) + - printFields(options, type) + printFields(type) ); } -function printInterface(type: GraphQLInterfaceType, options): string { +function printInterface(type: GraphQLInterfaceType): string { return ( - printDescription(options, type) + + printDescription(type) + `interface ${type.name}` + printImplementedInterfaces(type) + - printFields(options, type) + printFields(type) ); } -function printUnion(type: GraphQLUnionType, options): string { +function printUnion(type: GraphQLUnionType): string { const types = type.getTypes(); const possibleTypes = types.length ? ' = ' + types.join(' | ') : ''; - return printDescription(options, type) + 'union ' + type.name + possibleTypes; + return printDescription(type) + 'union ' + type.name + possibleTypes; } -function printEnum(type: GraphQLEnumType, options): string { +function printEnum(type: GraphQLEnumType): string { const values = type .getValues() .map( (value, i) => - printDescription(options, value, ' ', !i) + + printDescription(value, ' ', !i) + ' ' + value.name + printDeprecated(value.deprecationReason), ); - return ( - printDescription(options, type) + `enum ${type.name}` + printBlock(values) - ); + return printDescription(type) + `enum ${type.name}` + printBlock(values); } -function printInputObject(type: GraphQLInputObjectType, options): string { - const fields = objectValues(type.getFields()).map( - (f, i) => - printDescription(options, f, ' ', !i) + ' ' + printInputValue(f), +function printInputObject(type: GraphQLInputObjectType): string { + const fields = Object.values(type.getFields()).map( + (f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f), ); return ( - printDescription(options, type) + `input ${type.name}` + printBlock(fields) + printDescription(type) + + `input ${type.name}` + + (type.isOneOf ? ' @oneOf' : '') + + printBlock(fields) ); } -function printFields( - options, - type: GraphQLObjectType | GraphQLInterfaceType, -): string { - const fields = objectValues(type.getFields()).map( +function printFields(type: GraphQLObjectType | GraphQLInterfaceType): string { + const fields = Object.values(type.getFields()).map( (f, i) => - printDescription(options, f, ' ', !i) + + printDescription(f, ' ', !i) + ' ' + f.name + - printArgs(options, f.args, ' ') + + printArgs(f.args, ' ') + ': ' + String(f.type) + printDeprecated(f.deprecationReason), @@ -267,13 +231,12 @@ function printFields( return printBlock(fields); } -function printBlock(items: $ReadOnlyArray): string { +function printBlock(items: ReadonlyArray): string { return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : ''; } function printArgs( - options, - args: Array, + args: ReadonlyArray, indentation: string = '', ): string { if (args.length === 0) { @@ -290,7 +253,7 @@ function printArgs( args .map( (arg, i) => - printDescription(options, arg, ' ' + indentation, !i) + + printDescription(arg, ' ' + indentation, !i) + ' ' + indentation + printInputValue(arg), @@ -311,45 +274,42 @@ function printInputValue(arg: GraphQLInputField): string { return argDecl + printDeprecated(arg.deprecationReason); } -function printDirective(directive: GraphQLDirective, options): string { +function printDirective(directive: GraphQLDirective): string { return ( - printDescription(options, directive) + + printDescription(directive) + 'directive @' + directive.name + - printArgs(options, directive.args) + + printArgs(directive.args) + (directive.isRepeatable ? ' repeatable' : '') + ' on ' + directive.locations.join(' | ') ); } -function printDeprecated(reason: ?string): string { +function printDeprecated(reason: Maybe): string { if (reason == null) { return ''; } - const reasonAST = astFromValue(reason, GraphQLString); - if (reasonAST && reason !== DEFAULT_DEPRECATION_REASON) { - return ' @deprecated(reason: ' + print(reasonAST) + ')'; + if (reason !== DEFAULT_DEPRECATION_REASON) { + const astValue = print({ kind: Kind.STRING, value: reason }); + return ` @deprecated(reason: ${astValue})`; } return ' @deprecated'; } -function printSpecifiedByUrl(scalar: GraphQLScalarType): string { - if (scalar.specifiedByUrl == null) { +function printSpecifiedByURL(scalar: GraphQLScalarType): string { + if (scalar.specifiedByURL == null) { return ''; } - const url = scalar.specifiedByUrl; - const urlAST = astFromValue(url, GraphQLString); - invariant( - urlAST, - 'Unexpected null value returned from `astFromValue` for specifiedByUrl', - ); - return ' @specifiedBy(url: ' + print(urlAST) + ')'; + const astValue = print({ + kind: Kind.STRING, + value: scalar.specifiedByURL, + }); + return ` @specifiedBy(url: ${astValue})`; } function printDescription( - options, - def: { +description: ?string, ... }, + def: { readonly description: Maybe }, indentation: string = '', firstInBlock: boolean = true, ): string { @@ -358,24 +318,14 @@ function printDescription( return ''; } - if (options?.commentDescriptions === true) { - return printDescriptionWithComments(description, indentation, firstInBlock); - } + const blockString = print({ + kind: Kind.STRING, + value: description, + block: isPrintableAsBlockString(description), + }); - const preferMultipleLines = description.length > 70; - const blockString = printBlockString(description, '', preferMultipleLines); const prefix = indentation && !firstInBlock ? '\n' + indentation : indentation; return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n'; } - -function printDescriptionWithComments(description, indentation, firstInBlock) { - const prefix = indentation && !firstInBlock ? '\n' : ''; - const comment = description - .split('\n') - .map((line) => indentation + (line !== '' ? '# ' + line : '#')) - .join('\n'); - - return prefix + comment + '\n'; -} diff --git a/src/utilities/separateOperations.d.ts b/src/utilities/separateOperations.d.ts deleted file mode 100644 index 28654fdb1b..0000000000 --- a/src/utilities/separateOperations.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DocumentNode } from '../language/ast'; - -/** - * separateOperations accepts a single AST document which may contain many - * operations and fragments and returns a collection of AST documents each of - * which contains a single operation as well the fragment definitions it - * refers to. - */ -export function separateOperations( - documentAST: DocumentNode, -): { [key: string]: DocumentNode }; diff --git a/src/utilities/separateOperations.js b/src/utilities/separateOperations.ts similarity index 93% rename from src/utilities/separateOperations.js rename to src/utilities/separateOperations.ts index 5da3c1d1ea..84a8b774f9 100644 --- a/src/utilities/separateOperations.js +++ b/src/utilities/separateOperations.ts @@ -31,6 +31,8 @@ export function separateOperations( definitionNode.selectionSet, ); break; + default: + // ignore non-executable definitions } } @@ -38,7 +40,7 @@ export function separateOperations( // is necessary for completing that operation. const separatedDocumentASTs = Object.create(null); for (const operation of operations) { - const dependencies = new Set(); + const dependencies = new Set(); for (const fragmentName of collectDependencies(operation.selectionSet)) { collectTransitiveDependencies(dependencies, depGraph, fragmentName); @@ -63,7 +65,7 @@ export function separateOperations( return separatedDocumentASTs; } -type DepGraph = ObjMap>; +type DepGraph = ObjMap>; // From a dependency graph, collects a list of transitive dependencies by // recursing through a dependency graph. @@ -85,7 +87,7 @@ function collectTransitiveDependencies( } function collectDependencies(selectionSet: SelectionSetNode): Array { - const dependencies = []; + const dependencies: Array = []; visit(selectionSet, { FragmentSpread(node) { diff --git a/src/utilities/sortValueNode.ts b/src/utilities/sortValueNode.ts new file mode 100644 index 0000000000..6050c9a907 --- /dev/null +++ b/src/utilities/sortValueNode.ts @@ -0,0 +1,47 @@ +import { naturalCompare } from '../jsutils/naturalCompare'; + +import type { ObjectFieldNode, ValueNode } from '../language/ast'; +import { Kind } from '../language/kinds'; + +/** + * Sort ValueNode. + * + * This function returns a sorted copy of the given ValueNode. + * + * @internal + */ +export function sortValueNode(valueNode: ValueNode): ValueNode { + switch (valueNode.kind) { + case Kind.OBJECT: + return { + ...valueNode, + fields: sortFields(valueNode.fields), + }; + case Kind.LIST: + return { + ...valueNode, + values: valueNode.values.map(sortValueNode), + }; + case Kind.INT: + case Kind.FLOAT: + case Kind.STRING: + case Kind.BOOLEAN: + case Kind.NULL: + case Kind.ENUM: + case Kind.VARIABLE: + return valueNode; + } +} + +function sortFields( + fields: ReadonlyArray, +): Array { + return fields + .map((fieldNode) => ({ + ...fieldNode, + value: sortValueNode(fieldNode.value), + })) + .sort((fieldA, fieldB) => + naturalCompare(fieldA.name.value, fieldB.name.value), + ); +} diff --git a/src/utilities/stripIgnoredCharacters.d.ts b/src/utilities/stripIgnoredCharacters.d.ts deleted file mode 100644 index a131af02f5..0000000000 --- a/src/utilities/stripIgnoredCharacters.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Source } from '../language/source'; - -/** - * Strips characters that are not significant to the validity or execution - * of a GraphQL document: - * - UnicodeBOM - * - WhiteSpace - * - LineTerminator - * - Comment - * - Comma - * - BlockString indentation - * - * Note: It is required to have a delimiter character between neighboring - * non-punctuator tokens and this function always uses single space as delimiter. - * - * It is guaranteed that both input and output documents if parsed would result - * in the exact same AST except for nodes location. - * - * Warning: It is guaranteed that this function will always produce stable results. - * However, it's not guaranteed that it will stay the same between different - * releases due to bugfixes or changes in the GraphQL specification. - * - * Query example: - * - * query SomeQuery($foo: String!, $bar: String) { - * someField(foo: $foo, bar: $bar) { - * a - * b { - * c - * d - * } - * } - * } - * - * Becomes: - * - * query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}} - * - * SDL example: - * - * """ - * Type description - * """ - * type Foo { - * """ - * Field description - * """ - * bar: String - * } - * - * Becomes: - * - * """Type description""" type Foo{"""Field description""" bar:String} - */ -export function stripIgnoredCharacters(source: string | Source): string; diff --git a/src/utilities/stripIgnoredCharacters.js b/src/utilities/stripIgnoredCharacters.ts similarity index 76% rename from src/utilities/stripIgnoredCharacters.js rename to src/utilities/stripIgnoredCharacters.ts index f4f53aa042..5eb5c9800c 100644 --- a/src/utilities/stripIgnoredCharacters.js +++ b/src/utilities/stripIgnoredCharacters.ts @@ -1,10 +1,7 @@ -import { Source, isSource } from '../language/source'; +import { printBlockString } from '../language/blockString'; +import { isPunctuatorTokenKind, Lexer } from '../language/lexer'; +import { isSource, Source } from '../language/source'; import { TokenKind } from '../language/tokenKind'; -import { Lexer, isPunctuatorTokenKind } from '../language/lexer'; -import { - dedentBlockStringValue, - getBlockStringIndentation, -} from '../language/blockString'; /** * Strips characters that are not significant to the validity or execution @@ -28,6 +25,7 @@ import { * * Query example: * + * ```graphql * query SomeQuery($foo: String!, $bar: String) { * someField(foo: $foo, bar: $bar) { * a @@ -37,13 +35,17 @@ import { * } * } * } + * ``` * * Becomes: * + * ```graphql * query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}} + * ``` * * SDL example: * + * ```graphql * """ * Type description * """ @@ -53,10 +55,13 @@ import { * """ * bar: String * } + * ``` * * Becomes: * + * ```graphql * """Type description""" type Foo{"""Field description""" bar:String} + * ``` */ export function stripIgnoredCharacters(source: string | Source): string { const sourceObj = isSource(source) ? source : new Source(source); @@ -84,7 +89,7 @@ export function stripIgnoredCharacters(source: string | Source): string { const tokenBody = body.slice(currentToken.start, currentToken.end); if (tokenKind === TokenKind.BLOCK_STRING) { - strippedBody += dedentBlockString(tokenBody); + strippedBody += printBlockString(currentToken.value, { minimize: true }); } else { strippedBody += tokenBody; } @@ -94,21 +99,3 @@ export function stripIgnoredCharacters(source: string | Source): string { return strippedBody; } - -function dedentBlockString(blockStr: string): string { - // skip leading and trailing triple quotations - const rawStr = blockStr.slice(3, -3); - let body = dedentBlockStringValue(rawStr); - - if (getBlockStringIndentation(body) > 0) { - body = '\n' + body; - } - - const lastChar = body[body.length - 1]; - const hasTrailingQuote = lastChar === '"' && body.slice(-4) !== '\\"""'; - if (hasTrailingQuote || lastChar === '\\') { - body += '\n'; - } - - return '"""' + body + '"""'; -} diff --git a/src/utilities/typeComparators.d.ts b/src/utilities/typeComparators.d.ts deleted file mode 100644 index 7de3e00b68..0000000000 --- a/src/utilities/typeComparators.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { GraphQLSchema } from '../type/schema'; -import { GraphQLType, GraphQLCompositeType } from '../type/definition'; - -/** - * Provided two types, return true if the types are equal (invariant). - */ -export function isEqualType(typeA: GraphQLType, typeB: GraphQLType): boolean; - -/** - * Provided a type and a super type, return true if the first type is either - * equal or a subset of the second super type (covariant). - */ -export function isTypeSubTypeOf( - schema: GraphQLSchema, - maybeSubType: GraphQLType, - superType: GraphQLType, -): boolean; - -/** - * Provided two composite types, determine if they "overlap". Two composite - * types overlap when the Sets of possible concrete types for each intersect. - * - * This is often used to determine if a fragment of a given type could possibly - * be visited in a context of another type. - * - * This function is commutative. - */ -export function doTypesOverlap( - schema: GraphQLSchema, - typeA: GraphQLCompositeType, - typeB: GraphQLCompositeType, -): boolean; diff --git a/src/utilities/typeComparators.js b/src/utilities/typeComparators.ts similarity index 98% rename from src/utilities/typeComparators.js rename to src/utilities/typeComparators.ts index 99f84d2e7a..287be40bfe 100644 --- a/src/utilities/typeComparators.js +++ b/src/utilities/typeComparators.ts @@ -1,12 +1,12 @@ -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLType, GraphQLCompositeType } from '../type/definition'; +import type { GraphQLCompositeType, GraphQLType } from '../type/definition'; import { + isAbstractType, isInterfaceType, - isObjectType, isListType, isNonNullType, - isAbstractType, + isObjectType, } from '../type/definition'; +import type { GraphQLSchema } from '../type/schema'; /** * Provided two types, return true if the types are equal (invariant). diff --git a/src/utilities/typeFromAST.d.ts b/src/utilities/typeFromAST.d.ts deleted file mode 100644 index cf32ac7cee..0000000000 --- a/src/utilities/typeFromAST.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { NamedTypeNode, ListTypeNode, NonNullTypeNode } from '../language/ast'; -import { GraphQLSchema } from '../type/schema'; -import { - GraphQLNamedType, - GraphQLList, - GraphQLNonNull, -} from '../type/definition'; - -/** - * Given a Schema and an AST node describing a type, return a GraphQLType - * definition which applies to that type. For example, if provided the parsed - * AST node for `[User]`, a GraphQLList instance will be returned, containing - * the type called "User" found in the schema. If a type called "User" is not - * found in the schema, then undefined will be returned. - */ -export function typeFromAST( - schema: GraphQLSchema, - typeNode: NamedTypeNode, -): GraphQLNamedType | undefined; - -export function typeFromAST( - schema: GraphQLSchema, - typeNode: ListTypeNode, -): GraphQLList | undefined; - -export function typeFromAST( - schema: GraphQLSchema, - typeNode: NonNullTypeNode, -): GraphQLNonNull | undefined; diff --git a/src/utilities/typeFromAST.js b/src/utilities/typeFromAST.js deleted file mode 100644 index 6903c5287a..0000000000 --- a/src/utilities/typeFromAST.js +++ /dev/null @@ -1,54 +0,0 @@ -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; - -import type { - NamedTypeNode, - ListTypeNode, - NonNullTypeNode, -} from '../language/ast'; - -import { Kind } from '../language/kinds'; - -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLNamedType } from '../type/definition'; -import { GraphQLList, GraphQLNonNull } from '../type/definition'; - -/** - * Given a Schema and an AST node describing a type, return a GraphQLType - * definition which applies to that type. For example, if provided the parsed - * AST node for `[User]`, a GraphQLList instance will be returned, containing - * the type called "User" found in the schema. If a type called "User" is not - * found in the schema, then undefined will be returned. - */ -/* eslint-disable no-redeclare */ -declare function typeFromAST( - schema: GraphQLSchema, - typeNode: NamedTypeNode, -): GraphQLNamedType | void; -declare function typeFromAST( - schema: GraphQLSchema, - typeNode: ListTypeNode, -): GraphQLList | void; -declare function typeFromAST( - schema: GraphQLSchema, - typeNode: NonNullTypeNode, -): GraphQLNonNull | void; -export function typeFromAST(schema, typeNode) { - /* eslint-enable no-redeclare */ - let innerType; - if (typeNode.kind === Kind.LIST_TYPE) { - innerType = typeFromAST(schema, typeNode.type); - return innerType && new GraphQLList(innerType); - } - if (typeNode.kind === Kind.NON_NULL_TYPE) { - innerType = typeFromAST(schema, typeNode.type); - return innerType && new GraphQLNonNull(innerType); - } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') - if (typeNode.kind === Kind.NAMED_TYPE) { - return schema.getType(typeNode.name.value); - } - - // istanbul ignore next (Not reachable. All possible type nodes have been considered) - invariant(false, 'Unexpected type node: ' + inspect((typeNode: empty))); -} diff --git a/src/utilities/typeFromAST.ts b/src/utilities/typeFromAST.ts new file mode 100644 index 0000000000..7510df1046 --- /dev/null +++ b/src/utilities/typeFromAST.ts @@ -0,0 +1,52 @@ +import type { + ListTypeNode, + NamedTypeNode, + NonNullTypeNode, + TypeNode, +} from '../language/ast'; +import { Kind } from '../language/kinds'; + +import type { GraphQLNamedType, GraphQLType } from '../type/definition'; +import { GraphQLList, GraphQLNonNull } from '../type/definition'; +import type { GraphQLSchema } from '../type/schema'; + +/** + * Given a Schema and an AST node describing a type, return a GraphQLType + * definition which applies to that type. For example, if provided the parsed + * AST node for `[User]`, a GraphQLList instance will be returned, containing + * the type called "User" found in the schema. If a type called "User" is not + * found in the schema, then undefined will be returned. + */ +export function typeFromAST( + schema: GraphQLSchema, + typeNode: NamedTypeNode, +): GraphQLNamedType | undefined; +export function typeFromAST( + schema: GraphQLSchema, + typeNode: ListTypeNode, +): GraphQLList | undefined; +export function typeFromAST( + schema: GraphQLSchema, + typeNode: NonNullTypeNode, +): GraphQLNonNull | undefined; +export function typeFromAST( + schema: GraphQLSchema, + typeNode: TypeNode, +): GraphQLType | undefined; +export function typeFromAST( + schema: GraphQLSchema, + typeNode: TypeNode, +): GraphQLType | undefined { + switch (typeNode.kind) { + case Kind.LIST_TYPE: { + const innerType = typeFromAST(schema, typeNode.type); + return innerType && new GraphQLList(innerType); + } + case Kind.NON_NULL_TYPE: { + const innerType = typeFromAST(schema, typeNode.type); + return innerType && new GraphQLNonNull(innerType); + } + case Kind.NAMED_TYPE: + return schema.getType(typeNode.name.value); + } +} diff --git a/src/utilities/typedQueryDocumentNode.d.ts b/src/utilities/typedQueryDocumentNode.ts similarity index 80% rename from src/utilities/typedQueryDocumentNode.d.ts rename to src/utilities/typedQueryDocumentNode.ts index 0d7b8de17d..1bd5cf0825 100644 --- a/src/utilities/typedQueryDocumentNode.d.ts +++ b/src/utilities/typedQueryDocumentNode.ts @@ -1,11 +1,10 @@ -import { DocumentNode, ExecutableDefinitionNode } from '../language/ast'; - +import type { DocumentNode, ExecutableDefinitionNode } from '../language/ast'; /** * Wrapper type that contains DocumentNode and types that can be deduced from it. */ export interface TypedQueryDocumentNode< - TResponseData = Record, - TRequestVariables = Record + TResponseData = { [key: string]: any }, + TRequestVariables = { [key: string]: any }, > extends DocumentNode { readonly definitions: ReadonlyArray; // FIXME: remove once TS implements proper way to enforce nominal typing diff --git a/src/utilities/valueFromAST.d.ts b/src/utilities/valueFromAST.d.ts deleted file mode 100644 index acde6ba9df..0000000000 --- a/src/utilities/valueFromAST.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { ValueNode } from '../language/ast'; -import { GraphQLInputType } from '../type/definition'; - -/** - * Produces a JavaScript value given a GraphQL Value AST. - * - * A GraphQL type must be provided, which will be used to interpret different - * GraphQL Value literals. - * - * Returns `undefined` when the value could not be validly coerced according to - * the provided type. - * - * | GraphQL Value | JSON Value | - * | -------------------- | ------------- | - * | Input Object | Object | - * | List | Array | - * | Boolean | Boolean | - * | String | String | - * | Int / Float | Number | - * | Enum Value | Mixed | - * | NullValue | null | - * - */ -export function valueFromAST( - valueNode: Maybe, - type: GraphQLInputType, - variables?: Maybe<{ [key: string]: any }>, -): any; diff --git a/src/utilities/valueFromAST.js b/src/utilities/valueFromAST.ts similarity index 84% rename from src/utilities/valueFromAST.js rename to src/utilities/valueFromAST.ts index 7afed42282..2e6cc1c613 100644 --- a/src/utilities/valueFromAST.js +++ b/src/utilities/valueFromAST.ts @@ -1,17 +1,16 @@ -import objectValues from '../polyfills/objectValues'; - +import { inspect } from '../jsutils/inspect'; +import { invariant } from '../jsutils/invariant'; +import { keyMap } from '../jsutils/keyMap'; +import type { Maybe } from '../jsutils/Maybe'; import type { ObjMap } from '../jsutils/ObjMap'; -import keyMap from '../jsutils/keyMap'; -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; import type { ValueNode } from '../language/ast'; import { Kind } from '../language/kinds'; import type { GraphQLInputType } from '../type/definition'; import { - isLeafType, isInputObjectType, + isLeafType, isListType, isNonNullType, } from '../type/definition'; @@ -32,15 +31,15 @@ import { * | Boolean | Boolean | * | String | String | * | Int / Float | Number | - * | Enum Value | Mixed | + * | Enum Value | Unknown | * | NullValue | null | * */ export function valueFromAST( - valueNode: ?ValueNode, + valueNode: Maybe, type: GraphQLInputType, - variables?: ?ObjMap, -): mixed | void { + variables?: Maybe>, +): unknown { if (!valueNode) { // When there is no node, then there is also no value. // Importantly, this is different from returning the value null. @@ -110,7 +109,7 @@ export function valueFromAST( } const coercedObj = Object.create(null); const fieldNodes = keyMap(valueNode.fields, (field) => field.name.value); - for (const field of objectValues(type.getFields())) { + for (const field of Object.values(type.getFields())) { const fieldNode = fieldNodes[field.name]; if (!fieldNode || isMissingVariable(fieldNode.value, variables)) { if (field.defaultValue !== undefined) { @@ -126,10 +125,21 @@ export function valueFromAST( } coercedObj[field.name] = fieldValue; } + + if (type.isOneOf) { + const keys = Object.keys(coercedObj); + if (keys.length !== 1) { + return; // Invalid: not exactly one key, intentionally return no value. + } + + if (coercedObj[keys[0]] === null) { + return; // Invalid: value not non-null, intentionally return no value. + } + } + return coercedObj; } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isLeafType(type)) { // Scalars and Enums fulfill parsing a literal value via parseLiteral(). // Invalid values represent a failure to parse correctly, in which case @@ -145,16 +155,16 @@ export function valueFromAST( } return result; } - - // istanbul ignore next (Not reachable. All possible input types have been considered) - invariant(false, 'Unexpected input type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable, all possible input types have been considered. + invariant(false, 'Unexpected input type: ' + inspect(type)); } // Returns true if the provided valueNode is a variable which is not defined // in the set of variables. function isMissingVariable( valueNode: ValueNode, - variables: ?ObjMap, + variables: Maybe>, ): boolean { return ( valueNode.kind === Kind.VARIABLE && diff --git a/src/utilities/valueFromASTUntyped.d.ts b/src/utilities/valueFromASTUntyped.d.ts deleted file mode 100644 index a44959da6a..0000000000 --- a/src/utilities/valueFromASTUntyped.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { ValueNode } from '../language/ast'; - -/** - * Produces a JavaScript value given a GraphQL Value AST. - * - * Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value - * will reflect the provided GraphQL value AST. - * - * | GraphQL Value | JavaScript Value | - * | -------------------- | ---------------- | - * | Input Object | Object | - * | List | Array | - * | Boolean | Boolean | - * | String / Enum | String | - * | Int / Float | Number | - * | Null | null | - * - */ -export function valueFromASTUntyped( - valueNode: ValueNode, - variables?: Maybe<{ [key: string]: any }>, -): any; diff --git a/src/utilities/valueFromASTUntyped.js b/src/utilities/valueFromASTUntyped.ts similarity index 80% rename from src/utilities/valueFromASTUntyped.js rename to src/utilities/valueFromASTUntyped.ts index 3b70329bda..05540da3a4 100644 --- a/src/utilities/valueFromASTUntyped.js +++ b/src/utilities/valueFromASTUntyped.ts @@ -1,10 +1,9 @@ +import { keyValMap } from '../jsutils/keyValMap'; +import type { Maybe } from '../jsutils/Maybe'; import type { ObjMap } from '../jsutils/ObjMap'; -import inspect from '../jsutils/inspect'; -import invariant from '../jsutils/invariant'; -import keyValMap from '../jsutils/keyValMap'; -import { Kind } from '../language/kinds'; import type { ValueNode } from '../language/ast'; +import { Kind } from '../language/kinds'; /** * Produces a JavaScript value given a GraphQL Value AST. @@ -24,8 +23,8 @@ import type { ValueNode } from '../language/ast'; */ export function valueFromASTUntyped( valueNode: ValueNode, - variables?: ?ObjMap, -): mixed { + variables?: Maybe>, +): unknown { switch (valueNode.kind) { case Kind.NULL: return null; @@ -50,7 +49,4 @@ export function valueFromASTUntyped( case Kind.VARIABLE: return variables?.[valueNode.name.value]; } - - // istanbul ignore next (Not reachable. All possible value nodes have been considered) - invariant(false, 'Unexpected value node: ' + inspect((valueNode: empty))); } diff --git a/src/validation/ValidationContext.d.ts b/src/validation/ValidationContext.d.ts deleted file mode 100644 index e0ca546b0e..0000000000 --- a/src/validation/ValidationContext.d.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { GraphQLError } from '../error/GraphQLError'; -import { ASTVisitor } from '../language/visitor'; -import { - DocumentNode, - OperationDefinitionNode, - VariableNode, - SelectionSetNode, - FragmentSpreadNode, - FragmentDefinitionNode, -} from '../language/ast'; -import { GraphQLSchema } from '../type/schema'; -import { GraphQLDirective } from '../type/directives'; -import { - GraphQLInputType, - GraphQLOutputType, - GraphQLCompositeType, - GraphQLField, - GraphQLArgument, - GraphQLEnumValue, -} from '../type/definition'; -import { TypeInfo } from '../utilities/TypeInfo'; - -type NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode; -interface VariableUsage { - readonly node: VariableNode; - readonly type: Maybe; - readonly defaultValue: Maybe; -} - -/** - * An instance of this class is passed as the "this" context to all validators, - * allowing access to commonly useful contextual information from within a - * validation rule. - */ -export class ASTValidationContext { - constructor(ast: DocumentNode, onError: (err: GraphQLError) => void); - - reportError(error: GraphQLError): undefined; - - getDocument(): DocumentNode; - - getFragment(name: string): Maybe; - - getFragmentSpreads(node: SelectionSetNode): ReadonlyArray; - - getRecursivelyReferencedFragments( - operation: OperationDefinitionNode, - ): ReadonlyArray; -} - -export class SDLValidationContext extends ASTValidationContext { - constructor( - ast: DocumentNode, - schema: Maybe, - onError: (err: GraphQLError) => void, - ); - - getSchema(): Maybe; -} - -export type SDLValidationRule = (context: SDLValidationContext) => ASTVisitor; - -export class ValidationContext extends ASTValidationContext { - constructor( - schema: GraphQLSchema, - ast: DocumentNode, - typeInfo: TypeInfo, - onError: (err: GraphQLError) => void, - ); - - getSchema(): GraphQLSchema; - - getVariableUsages(node: NodeWithSelectionSet): ReadonlyArray; - - getRecursivelyReferencedFragments( - operation: OperationDefinitionNode, - ): ReadonlyArray; - - getType(): Maybe; - - getParentType(): Maybe; - - getInputType(): Maybe; - - getParentInputType(): Maybe; - - getFieldDef(): Maybe>; - - getDirective(): Maybe; - - getArgument(): Maybe; - - getEnumValue(): Maybe; -} - -export type ValidationRule = (context: ValidationContext) => ASTVisitor; diff --git a/src/validation/ValidationContext.js b/src/validation/ValidationContext.ts similarity index 64% rename from src/validation/ValidationContext.js rename to src/validation/ValidationContext.ts index 2a0d8aef1a..f6944a6ebd 100644 --- a/src/validation/ValidationContext.js +++ b/src/validation/ValidationContext.ts @@ -1,39 +1,39 @@ +import type { Maybe } from '../jsutils/Maybe'; import type { ObjMap } from '../jsutils/ObjMap'; import type { GraphQLError } from '../error/GraphQLError'; -import type { ASTVisitor } from '../language/visitor'; import type { DocumentNode, + FragmentDefinitionNode, + FragmentSpreadNode, OperationDefinitionNode, - VariableNode, SelectionSetNode, - FragmentSpreadNode, - FragmentDefinitionNode, + VariableNode, } from '../language/ast'; - import { Kind } from '../language/kinds'; +import type { ASTVisitor } from '../language/visitor'; import { visit } from '../language/visitor'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLDirective } from '../type/directives'; import type { - GraphQLInputType, - GraphQLOutputType, - GraphQLCompositeType, - GraphQLField, GraphQLArgument, + GraphQLCompositeType, GraphQLEnumValue, + GraphQLField, + GraphQLInputType, + GraphQLOutputType, } from '../type/definition'; +import type { GraphQLDirective } from '../type/directives'; +import type { GraphQLSchema } from '../type/schema'; import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo'; type NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode; -type VariableUsage = {| - +node: VariableNode, - +type: ?GraphQLInputType, - +defaultValue: ?mixed, -|}; +interface VariableUsage { + readonly node: VariableNode; + readonly type: Maybe; + readonly defaultValue: Maybe; +} /** * An instance of this class is passed as the "this" context to all validators, @@ -41,16 +41,16 @@ type VariableUsage = {| * validation rule. */ export class ASTValidationContext { - _ast: DocumentNode; - _onError: (err: GraphQLError) => void; - _fragments: ?ObjMap; - _fragmentSpreads: Map>; - _recursivelyReferencedFragments: Map< + private _ast: DocumentNode; + private _onError: (error: GraphQLError) => void; + private _fragments: ObjMap | undefined; + private _fragmentSpreads: Map>; + private _recursivelyReferencedFragments: Map< OperationDefinitionNode, - $ReadOnlyArray, + Array >; - constructor(ast: DocumentNode, onError: (err: GraphQLError) => void) { + constructor(ast: DocumentNode, onError: (error: GraphQLError) => void) { this._ast = ast; this._fragments = undefined; this._fragmentSpreads = new Map(); @@ -58,6 +58,10 @@ export class ASTValidationContext { this._onError = onError; } + get [Symbol.toStringTag]() { + return 'ASTValidationContext'; + } + reportError(error: GraphQLError): void { this._onError(error); } @@ -66,31 +70,31 @@ export class ASTValidationContext { return this._ast; } - getFragment(name: string): ?FragmentDefinitionNode { - let fragments = this._fragments; - if (!fragments) { - this._fragments = fragments = this.getDocument().definitions.reduce( - (frags, statement) => { - if (statement.kind === Kind.FRAGMENT_DEFINITION) { - frags[statement.name.value] = statement; - } - return frags; - }, - Object.create(null), - ); + getFragment(name: string): Maybe { + let fragments: ObjMap; + if (this._fragments) { + fragments = this._fragments; + } else { + fragments = Object.create(null); + for (const defNode of this.getDocument().definitions) { + if (defNode.kind === Kind.FRAGMENT_DEFINITION) { + fragments[defNode.name.value] = defNode; + } + } + this._fragments = fragments; } return fragments[name]; } getFragmentSpreads( node: SelectionSetNode, - ): $ReadOnlyArray { + ): ReadonlyArray { let spreads = this._fragmentSpreads.get(node); if (!spreads) { spreads = []; const setsToVisit: Array = [node]; - while (setsToVisit.length !== 0) { - const set = setsToVisit.pop(); + let set: SelectionSetNode | undefined; + while ((set = setsToVisit.pop())) { for (const selection of set.selections) { if (selection.kind === Kind.FRAGMENT_SPREAD) { spreads.push(selection); @@ -106,14 +110,14 @@ export class ASTValidationContext { getRecursivelyReferencedFragments( operation: OperationDefinitionNode, - ): $ReadOnlyArray { + ): ReadonlyArray { let fragments = this._recursivelyReferencedFragments.get(operation); if (!fragments) { fragments = []; const collectedNames = Object.create(null); const nodesToVisit: Array = [operation.selectionSet]; - while (nodesToVisit.length !== 0) { - const node = nodesToVisit.pop(); + let node: SelectionSetNode | undefined; + while ((node = nodesToVisit.pop())) { for (const spread of this.getFragmentSpreads(node)) { const fragName = spread.name.value; if (collectedNames[fragName] !== true) { @@ -132,41 +136,49 @@ export class ASTValidationContext { } } -export type ASTValidationRule = (ASTValidationContext) => ASTVisitor; +export type ASTValidationRule = (context: ASTValidationContext) => ASTVisitor; export class SDLValidationContext extends ASTValidationContext { - _schema: ?GraphQLSchema; + private _schema: Maybe; constructor( ast: DocumentNode, - schema: ?GraphQLSchema, - onError: (err: GraphQLError) => void, + schema: Maybe, + onError: (error: GraphQLError) => void, ) { super(ast, onError); this._schema = schema; } - getSchema(): ?GraphQLSchema { + get [Symbol.toStringTag]() { + return 'SDLValidationContext'; + } + + getSchema(): Maybe { return this._schema; } } -export type SDLValidationRule = (SDLValidationContext) => ASTVisitor; +export type SDLValidationRule = (context: SDLValidationContext) => ASTVisitor; export class ValidationContext extends ASTValidationContext { - _schema: GraphQLSchema; - _typeInfo: TypeInfo; - _variableUsages: Map>; - _recursiveVariableUsages: Map< + private _schema: GraphQLSchema; + private _typeInfo: TypeInfo; + private _variableUsages: Map< + NodeWithSelectionSet, + ReadonlyArray + >; + + private _recursiveVariableUsages: Map< OperationDefinitionNode, - $ReadOnlyArray, + ReadonlyArray >; constructor( schema: GraphQLSchema, ast: DocumentNode, typeInfo: TypeInfo, - onError: (err: GraphQLError) => void, + onError: (error: GraphQLError) => void, ) { super(ast, onError); this._schema = schema; @@ -175,14 +187,18 @@ export class ValidationContext extends ASTValidationContext { this._recursiveVariableUsages = new Map(); } + get [Symbol.toStringTag]() { + return 'ValidationContext'; + } + getSchema(): GraphQLSchema { return this._schema; } - getVariableUsages(node: NodeWithSelectionSet): $ReadOnlyArray { + getVariableUsages(node: NodeWithSelectionSet): ReadonlyArray { let usages = this._variableUsages.get(node); if (!usages) { - const newUsages = []; + const newUsages: Array = []; const typeInfo = new TypeInfo(this._schema); visit( node, @@ -205,7 +221,7 @@ export class ValidationContext extends ASTValidationContext { getRecursiveVariableUsages( operation: OperationDefinitionNode, - ): $ReadOnlyArray { + ): ReadonlyArray { let usages = this._recursiveVariableUsages.get(operation); if (!usages) { usages = this.getVariableUsages(operation); @@ -217,37 +233,37 @@ export class ValidationContext extends ASTValidationContext { return usages; } - getType(): ?GraphQLOutputType { + getType(): Maybe { return this._typeInfo.getType(); } - getParentType(): ?GraphQLCompositeType { + getParentType(): Maybe { return this._typeInfo.getParentType(); } - getInputType(): ?GraphQLInputType { + getInputType(): Maybe { return this._typeInfo.getInputType(); } - getParentInputType(): ?GraphQLInputType { + getParentInputType(): Maybe { return this._typeInfo.getParentInputType(); } - getFieldDef(): ?GraphQLField { + getFieldDef(): Maybe> { return this._typeInfo.getFieldDef(); } - getDirective(): ?GraphQLDirective { + getDirective(): Maybe { return this._typeInfo.getDirective(); } - getArgument(): ?GraphQLArgument { + getArgument(): Maybe { return this._typeInfo.getArgument(); } - getEnumValue(): ?GraphQLEnumValue { + getEnumValue(): Maybe { return this._typeInfo.getEnumValue(); } } -export type ValidationRule = (ValidationContext) => ASTVisitor; +export type ValidationRule = (context: ValidationContext) => ASTVisitor; diff --git a/src/validation/__tests__/ExecutableDefinitionsRule-test.js b/src/validation/__tests__/ExecutableDefinitionsRule-test.ts similarity index 95% rename from src/validation/__tests__/ExecutableDefinitionsRule-test.js rename to src/validation/__tests__/ExecutableDefinitionsRule-test.ts index 4409767b5b..ec3a1afe25 100644 --- a/src/validation/__tests__/ExecutableDefinitionsRule-test.js +++ b/src/validation/__tests__/ExecutableDefinitionsRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Executable definitions', () => { @@ -53,7 +53,7 @@ describe('Validate: Executable definitions', () => { extend type Dog { color: String } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The "Cow" definition is not executable.', locations: [{ line: 8, column: 7 }], @@ -76,7 +76,7 @@ describe('Validate: Executable definitions', () => { } extend schema @directive - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The schema definition is not executable.', locations: [{ line: 2, column: 7 }], diff --git a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts similarity index 84% rename from src/validation/__tests__/FieldsOnCorrectTypeRule-test.js rename to src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts index 6ec857a683..70473fa685 100644 --- a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js +++ b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts @@ -7,19 +7,52 @@ import type { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { validate } from '../validate'; import { FieldsOnCorrectTypeRule } from '../rules/FieldsOnCorrectTypeRule'; +import { validate } from '../validate'; -import { expectValidationErrors } from './harness'; +import { expectValidationErrorsWithSchema } from './harness'; function expectErrors(queryStr: string) { - return expectValidationErrors(FieldsOnCorrectTypeRule, queryStr); + return expectValidationErrorsWithSchema( + testSchema, + FieldsOnCorrectTypeRule, + queryStr, + ); } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } +const testSchema = buildSchema(` + interface Pet { + name: String + } + + type Dog implements Pet { + name: String + nickname: String + barkVolume: Int + } + + type Cat implements Pet { + name: String + nickname: String + meowVolume: Int + } + + union CatOrDog = Cat | Dog + + type Human { + name: String + pets: [Pet] + } + + type Query { + human: Human + } +`); + describe('Validate: Fields on correct type', () => { it('Object field selection', () => { expectValid(` @@ -81,7 +114,7 @@ describe('Validate: Fields on correct type', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "unknown_pet_field" on type "Pet".', locations: [{ line: 3, column: 9 }], @@ -98,7 +131,7 @@ describe('Validate: Fields on correct type', () => { fragment fieldNotDefined on Dog { meowVolume } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?', @@ -114,7 +147,7 @@ describe('Validate: Fields on correct type', () => { deeper_unknown_field } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "unknown_field" on type "Dog".', locations: [{ line: 3, column: 9 }], @@ -129,7 +162,7 @@ describe('Validate: Fields on correct type', () => { unknown_field } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "unknown_field" on type "Pet".', locations: [{ line: 4, column: 11 }], @@ -144,7 +177,7 @@ describe('Validate: Fields on correct type', () => { meowVolume } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?', @@ -158,7 +191,7 @@ describe('Validate: Fields on correct type', () => { fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "mooVolume" on type "Dog". Did you mean "barkVolume"?', @@ -172,7 +205,7 @@ describe('Validate: Fields on correct type', () => { fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "kawVolume" on type "Dog". Did you mean "barkVolume"?', @@ -186,7 +219,7 @@ describe('Validate: Fields on correct type', () => { fragment notDefinedOnInterface on Pet { tailLength } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "tailLength" on type "Pet".', locations: [{ line: 3, column: 9 }], @@ -199,7 +232,7 @@ describe('Validate: Fields on correct type', () => { fragment definedOnImplementorsButNotInterface on Pet { nickname } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "nickname" on type "Pet". Did you mean to use an inline fragment on "Cat" or "Dog"?', @@ -221,7 +254,7 @@ describe('Validate: Fields on correct type', () => { fragment directFieldSelectionOnUnion on CatOrDog { directField } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot query field "directField" on type "CatOrDog".', locations: [{ line: 3, column: 9 }], @@ -234,10 +267,10 @@ describe('Validate: Fields on correct type', () => { fragment definedOnImplementorsQueriedOnUnion on CatOrDog { name } - `).to.deep.equal([ + `).toDeepEqual([ { message: - 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Being", "Pet", "Canine", "Cat", or "Dog"?', + 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Pet", "Cat", or "Dog"?', locations: [{ line: 3, column: 9 }], }, ]); @@ -332,7 +365,7 @@ describe('Validate: Fields on correct type', () => { }); it('Sort type suggestions based on inheritance order', () => { - const schema = buildSchema(` + const interfaceSchema = buildSchema(` interface T { bar: String } type Query { t: T } @@ -352,9 +385,27 @@ describe('Validate: Fields on correct type', () => { } `); - expectErrorMessage(schema, '{ t { foo } }').to.equal( + expectErrorMessage(interfaceSchema, '{ t { foo } }').to.equal( 'Cannot query field "foo" on type "T". Did you mean to use an inline fragment on "Z", "Y", or "X"?', ); + + const unionSchema = buildSchema(` + interface Animal { name: String } + interface Mammal implements Animal { name: String } + + interface Canine implements Animal & Mammal { name: String } + type Dog implements Animal & Mammal & Canine { name: String } + + interface Feline implements Animal & Mammal { name: String } + type Cat implements Animal & Mammal & Feline { name: String } + + union CatOrDog = Cat | Dog + type Query { catOrDog: CatOrDog } + `); + + expectErrorMessage(unionSchema, '{ catOrDog { name } }').to.equal( + 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Animal", "Mammal", "Canine", "Dog", or "Feline"?', + ); }); it('Limits lots of type suggestions', () => { diff --git a/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js b/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.ts similarity index 95% rename from src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js rename to src/validation/__tests__/FragmentsOnCompositeTypesRule-test.ts index a9b7ec17d7..dc1ed40796 100644 --- a/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js +++ b/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Fragments on composite types', () => { @@ -72,7 +72,7 @@ describe('Validate: Fragments on composite types', () => { fragment scalarFragment on Boolean { bad } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "scalarFragment" cannot condition on non composite type "Boolean".', @@ -86,7 +86,7 @@ describe('Validate: Fragments on composite types', () => { fragment scalarFragment on FurColor { bad } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "scalarFragment" cannot condition on non composite type "FurColor".', @@ -100,7 +100,7 @@ describe('Validate: Fragments on composite types', () => { fragment inputFragment on ComplexInput { stringField } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "inputFragment" cannot condition on non composite type "ComplexInput".', @@ -116,7 +116,7 @@ describe('Validate: Fragments on composite types', () => { barks } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment cannot condition on non composite type "String".', locations: [{ line: 3, column: 16 }], diff --git a/src/validation/__tests__/KnownArgumentNamesRule-test.js b/src/validation/__tests__/KnownArgumentNamesRule-test.ts similarity index 94% rename from src/validation/__tests__/KnownArgumentNamesRule-test.js rename to src/validation/__tests__/KnownArgumentNamesRule-test.ts index 8bf7567c50..4ce5fd190f 100644 --- a/src/validation/__tests__/KnownArgumentNamesRule-test.js +++ b/src/validation/__tests__/KnownArgumentNamesRule-test.ts @@ -5,18 +5,18 @@ import type { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; import { - KnownArgumentNamesRule, KnownArgumentNamesOnDirectivesRule, + KnownArgumentNamesRule, } from '../rules/KnownArgumentNamesRule'; -import { expectValidationErrors, expectSDLValidationErrors } from './harness'; +import { expectSDLValidationErrors, expectValidationErrors } from './harness'; function expectErrors(queryStr: string) { return expectValidationErrors(KnownArgumentNamesRule, queryStr); } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { @@ -28,7 +28,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string) { - expectSDLErrors(sdlStr).to.deep.equal([]); + expectSDLErrors(sdlStr).toDeepEqual([]); } describe('Validate: Known argument names', () => { @@ -102,7 +102,7 @@ describe('Validate: Known argument names', () => { { dog @skip(unless: true) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "unless" on directive "@skip".', locations: [{ line: 3, column: 19 }], @@ -123,7 +123,7 @@ describe('Validate: Known argument names', () => { { dog @onField(if: true) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "if" on directive "@onField".', locations: [{ line: 3, column: 22 }], @@ -136,7 +136,7 @@ describe('Validate: Known argument names', () => { { dog @skip(iff: true) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "iff" on directive "@skip". Did you mean "if"?', @@ -150,7 +150,7 @@ describe('Validate: Known argument names', () => { fragment invalidArgName on Dog { doesKnowCommand(unknown: true) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "unknown" on field "Dog.doesKnowCommand".', locations: [{ line: 3, column: 25 }], @@ -163,7 +163,7 @@ describe('Validate: Known argument names', () => { fragment invalidArgName on Dog { doesKnowCommand(DogCommand: true) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "DogCommand" on field "Dog.doesKnowCommand". Did you mean "dogCommand"?', @@ -177,7 +177,7 @@ describe('Validate: Known argument names', () => { fragment oneGoodArgOneInvalidArg on Dog { doesKnowCommand(whoKnows: 1, dogCommand: SIT, unknown: true) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "whoKnows" on field "Dog.doesKnowCommand".', locations: [{ line: 3, column: 25 }], @@ -203,7 +203,7 @@ describe('Validate: Known argument names', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "unknown" on field "Dog.doesKnowCommand".', locations: [{ line: 4, column: 27 }], @@ -233,7 +233,7 @@ describe('Validate: Known argument names', () => { } directive @test(arg: String) on FIELD_DEFINITION - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "unknown" on directive "@test".', locations: [{ line: 3, column: 29 }], @@ -248,7 +248,7 @@ describe('Validate: Known argument names', () => { } directive @test(arg: String) on FIELD_DEFINITION - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "agr" on directive "@test". Did you mean "arg"?', @@ -262,7 +262,7 @@ describe('Validate: Known argument names', () => { type Query { foo: String @deprecated(unknown: "") } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "unknown" on directive "@deprecated".', locations: [{ line: 3, column: 35 }], @@ -276,7 +276,7 @@ describe('Validate: Known argument names', () => { foo: String @deprecated(reason: "") } directive @deprecated(arg: String) on FIELD - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown argument "reason" on directive "@deprecated".', locations: [{ line: 3, column: 35 }], @@ -297,7 +297,7 @@ describe('Validate: Known argument names', () => { extend type Query @test(unknown: "") `, schema, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Unknown argument "unknown" on directive "@test".', locations: [{ line: 4, column: 36 }], @@ -318,7 +318,7 @@ describe('Validate: Known argument names', () => { extend type Query @test(unknown: "") `, schema, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Unknown argument "unknown" on directive "@test".', locations: [{ line: 2, column: 35 }], diff --git a/src/validation/__tests__/KnownDirectivesRule-test.js b/src/validation/__tests__/KnownDirectivesRule-test.ts similarity index 71% rename from src/validation/__tests__/KnownDirectivesRule-test.js rename to src/validation/__tests__/KnownDirectivesRule-test.ts index 13491bc6c5..4cb6e225c1 100644 --- a/src/validation/__tests__/KnownDirectivesRule-test.js +++ b/src/validation/__tests__/KnownDirectivesRule-test.ts @@ -6,14 +6,21 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { KnownDirectivesRule } from '../rules/KnownDirectivesRule'; -import { expectValidationErrors, expectSDLValidationErrors } from './harness'; +import { + expectSDLValidationErrors, + expectValidationErrorsWithSchema, +} from './harness'; function expectErrors(queryStr: string) { - return expectValidationErrors(KnownDirectivesRule, queryStr); + return expectValidationErrorsWithSchema( + schemaWithDirectives, + KnownDirectivesRule, + queryStr, + ); } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { @@ -21,9 +28,24 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } +const schemaWithDirectives = buildSchema(` + type Query { + dummy: String + } + + directive @onQuery on QUERY + directive @onMutation on MUTATION + directive @onSubscription on SUBSCRIPTION + directive @onField on FIELD + directive @onFragmentDefinition on FRAGMENT_DEFINITION + directive @onFragmentSpread on FRAGMENT_SPREAD + directive @onInlineFragment on INLINE_FRAGMENT + directive @onVariableDefinition on VARIABLE_DEFINITION +`); + const schemaWithSDLDirectives = buildSchema(` directive @onSchema on SCHEMA directive @onScalar on SCALAR @@ -52,14 +74,16 @@ describe('Validate: Known directives', () => { `); }); - it('with known directives', () => { + it('with standard directives', () => { expectValid(` { - dog @include(if: true) { - name - } human @skip(if: false) { name + pets { + ... on Dog @include(if: true) { + name + } + } } } `); @@ -68,14 +92,14 @@ describe('Validate: Known directives', () => { it('with unknown directive', () => { expectErrors(` { - dog @unknown(directive: "value") { + human @unknown(directive: "value") { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown directive "@unknown".', - locations: [{ line: 3, column: 13 }], + locations: [{ line: 3, column: 15 }], }, ]); }); @@ -83,106 +107,125 @@ describe('Validate: Known directives', () => { it('with many unknown directives', () => { expectErrors(` { - dog @unknown(directive: "value") { + __typename @unknown + human @unknown { name - } - human @unknown(directive: "value") { - name - pets @unknown(directive: "value") { + pets @unknown { name } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown directive "@unknown".', - locations: [{ line: 3, column: 13 }], + locations: [{ line: 3, column: 20 }], }, { message: 'Unknown directive "@unknown".', - locations: [{ line: 6, column: 15 }], + locations: [{ line: 4, column: 15 }], }, { message: 'Unknown directive "@unknown".', - locations: [{ line: 8, column: 16 }], + locations: [{ line: 6, column: 16 }], }, ]); }); it('with well placed directives', () => { expectValid(` - query ($var: Boolean) @onQuery { - name @include(if: $var) - ...Frag @include(if: true) - skippedField @skip(if: true) - ...SkippedFrag @skip(if: true) - - ... @skip(if: true) { - skippedField + query ($var: Boolean @onVariableDefinition) @onQuery { + human @onField { + ...Frag @onFragmentSpread + ... @onInlineFragment { + name @onField + } } } mutation @onMutation { - someField + someField @onField } subscription @onSubscription { - someField + someField @onField } - fragment Frag on SomeType @onFragmentDefinition { - someField - } - `); - }); - - it('with well placed variable definition directive', () => { - expectValid(` - query Foo($var: Boolean @onVariableDefinition) { - name + fragment Frag on Human @onFragmentDefinition { + name @onField } `); }); it('with misplaced directives', () => { expectErrors(` - query Foo($var: Boolean) @include(if: true) { - name @onQuery @include(if: $var) - ...Frag @onQuery + query ($var: Boolean @onQuery) @onMutation { + human @onQuery { + ...Frag @onQuery + ... @onQuery { + name @onQuery + } + } } - mutation Bar @onQuery { - someField + mutation @onQuery { + someField @onQuery } - `).to.deep.equal([ + + subscription @onQuery { + someField @onQuery + } + + fragment Frag on Human @onQuery { + name @onQuery + } + `).toDeepEqual([ + { + message: 'Directive "@onQuery" may not be used on VARIABLE_DEFINITION.', + locations: [{ line: 2, column: 28 }], + }, { - message: 'Directive "@include" may not be used on QUERY.', - locations: [{ line: 2, column: 32 }], + message: 'Directive "@onMutation" may not be used on QUERY.', + locations: [{ line: 2, column: 38 }], }, { message: 'Directive "@onQuery" may not be used on FIELD.', - locations: [{ line: 3, column: 14 }], + locations: [{ line: 3, column: 15 }], }, { message: 'Directive "@onQuery" may not be used on FRAGMENT_SPREAD.', - locations: [{ line: 4, column: 17 }], + locations: [{ line: 4, column: 19 }], + }, + { + message: 'Directive "@onQuery" may not be used on INLINE_FRAGMENT.', + locations: [{ line: 5, column: 15 }], + }, + { + message: 'Directive "@onQuery" may not be used on FIELD.', + locations: [{ line: 6, column: 18 }], }, { message: 'Directive "@onQuery" may not be used on MUTATION.', - locations: [{ line: 7, column: 20 }], + locations: [{ line: 11, column: 16 }], }, - ]); - }); - - it('with misplaced variable definition directive', () => { - expectErrors(` - query Foo($var: Boolean @onField) { - name - } - `).to.deep.equal([ { - message: 'Directive "@onField" may not be used on VARIABLE_DEFINITION.', - locations: [{ line: 2, column: 31 }], + message: 'Directive "@onQuery" may not be used on FIELD.', + locations: [{ column: 19, line: 12 }], + }, + { + message: 'Directive "@onQuery" may not be used on SUBSCRIPTION.', + locations: [{ column: 20, line: 15 }], + }, + { + message: 'Directive "@onQuery" may not be used on FIELD.', + locations: [{ column: 19, line: 16 }], + }, + { + message: 'Directive "@onQuery" may not be used on FRAGMENT_DEFINITION.', + locations: [{ column: 30, line: 19 }], + }, + { + message: 'Directive "@onQuery" may not be used on FIELD.', + locations: [{ column: 14, line: 20 }], }, ]); }); @@ -258,7 +301,7 @@ describe('Validate: Known directives', () => { extend type Query @unknown `, schema, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Unknown directive "@unknown".', locations: [{ line: 2, column: 29 }], @@ -341,7 +384,7 @@ describe('Validate: Known directives', () => { extend schema @onObject `, schemaWithSDLDirectives, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Directive "@onInterface" may not be used on OBJECT.', locations: [{ line: 2, column: 45 }], diff --git a/src/validation/__tests__/KnownFragmentNamesRule-test.js b/src/validation/__tests__/KnownFragmentNamesRule-test.ts similarity index 95% rename from src/validation/__tests__/KnownFragmentNamesRule-test.js rename to src/validation/__tests__/KnownFragmentNamesRule-test.ts index 68477de864..c425767806 100644 --- a/src/validation/__tests__/KnownFragmentNamesRule-test.js +++ b/src/validation/__tests__/KnownFragmentNamesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Known fragment names', () => { @@ -53,7 +53,7 @@ describe('Validate: Known fragment names', () => { name ...UnknownFragment3 } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown fragment "UnknownFragment1".', locations: [{ line: 4, column: 14 }], diff --git a/src/validation/__tests__/KnownTypeNamesRule-test.js b/src/validation/__tests__/KnownTypeNamesRule-test.ts similarity index 96% rename from src/validation/__tests__/KnownTypeNamesRule-test.js rename to src/validation/__tests__/KnownTypeNamesRule-test.ts index f56ef4ceab..34f0ca71e5 100644 --- a/src/validation/__tests__/KnownTypeNamesRule-test.js +++ b/src/validation/__tests__/KnownTypeNamesRule-test.ts @@ -7,9 +7,9 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { KnownTypeNamesRule } from '../rules/KnownTypeNamesRule'; import { + expectSDLValidationErrors, expectValidationErrors, expectValidationErrorsWithSchema, - expectSDLValidationErrors, } from './harness'; function expectErrors(queryStr: string) { @@ -21,7 +21,7 @@ function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { @@ -29,7 +29,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Known type names', () => { @@ -53,7 +53,7 @@ describe('Validate: Known type names', () => { it('unknown type names are invalid', () => { expectErrors(` - query Foo($var: JumbledUpLetters) { + query Foo($var: [JumbledUpLetters!]!) { user(id: 4) { name pets { ... on Badger { name }, ...PetFields } @@ -62,10 +62,10 @@ describe('Validate: Known type names', () => { fragment PetFields on Peat { name } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown type "JumbledUpLetters".', - locations: [{ line: 2, column: 23 }], + locations: [{ line: 2, column: 24 }], }, { message: 'Unknown type "Badger".', @@ -85,7 +85,7 @@ describe('Validate: Known type names', () => { __typename } `; - expectErrorsWithSchema(schema, query).to.deep.equal([ + expectErrorsWithSchema(schema, query).toDeepEqual([ { message: 'Unknown type "ID".', locations: [{ line: 2, column: 19 }], @@ -176,7 +176,7 @@ describe('Validate: Known type names', () => { mutation: M subscription: N } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown type "C". Did you mean "A" or "B"?', locations: [{ line: 5, column: 36 }], @@ -237,7 +237,7 @@ describe('Validate: Known type names', () => { type Query { foo: Foo } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Unknown type "Foo".', locations: [{ line: 7, column: 16 }], @@ -307,7 +307,7 @@ describe('Validate: Known type names', () => { } `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Unknown type "C". Did you mean "A" or "B"?', locations: [{ line: 4, column: 36 }], diff --git a/src/validation/__tests__/LoneAnonymousOperationRule-test.js b/src/validation/__tests__/LoneAnonymousOperationRule-test.ts similarity index 94% rename from src/validation/__tests__/LoneAnonymousOperationRule-test.js rename to src/validation/__tests__/LoneAnonymousOperationRule-test.ts index 191870dd03..a50ef1bdf0 100644 --- a/src/validation/__tests__/LoneAnonymousOperationRule-test.js +++ b/src/validation/__tests__/LoneAnonymousOperationRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Anonymous operation must be alone', () => { @@ -60,7 +60,7 @@ describe('Validate: Anonymous operation must be alone', () => { { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'This anonymous operation must be the only defined operation.', locations: [{ line: 2, column: 7 }], @@ -80,7 +80,7 @@ describe('Validate: Anonymous operation must be alone', () => { mutation Foo { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'This anonymous operation must be the only defined operation.', locations: [{ line: 2, column: 7 }], @@ -96,7 +96,7 @@ describe('Validate: Anonymous operation must be alone', () => { subscription Foo { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'This anonymous operation must be the only defined operation.', locations: [{ line: 2, column: 7 }], diff --git a/src/validation/__tests__/LoneSchemaDefinitionRule-test.js b/src/validation/__tests__/LoneSchemaDefinitionRule-test.ts similarity index 95% rename from src/validation/__tests__/LoneSchemaDefinitionRule-test.js rename to src/validation/__tests__/LoneSchemaDefinitionRule-test.ts index 6e040576b2..3f2ea895af 100644 --- a/src/validation/__tests__/LoneSchemaDefinitionRule-test.js +++ b/src/validation/__tests__/LoneSchemaDefinitionRule-test.ts @@ -13,7 +13,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Schema definition should be alone', () => { @@ -54,7 +54,7 @@ describe('Validate: Schema definition should be alone', () => { schema { subscription: Foo } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Must provide only one schema definition.', locations: [{ line: 10, column: 7 }], @@ -80,7 +80,7 @@ describe('Validate: Schema definition should be alone', () => { } `, schema, - ).to.deep.equal([]); + ).toDeepEqual([]); }); it('redefine schema in schema extension', () => { @@ -101,7 +101,7 @@ describe('Validate: Schema definition should be alone', () => { } `, schema, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Cannot define a new schema within a schema extension.', locations: [{ line: 2, column: 9 }], @@ -127,7 +127,7 @@ describe('Validate: Schema definition should be alone', () => { } `, schema, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Cannot define a new schema within a schema extension.', locations: [{ line: 2, column: 9 }], diff --git a/src/validation/__tests__/MaxIntrospectionDepthRule-test.ts b/src/validation/__tests__/MaxIntrospectionDepthRule-test.ts new file mode 100644 index 0000000000..d6609941d4 --- /dev/null +++ b/src/validation/__tests__/MaxIntrospectionDepthRule-test.ts @@ -0,0 +1,554 @@ +import { describe, it } from 'mocha'; + +import { getIntrospectionQuery } from '../../utilities/getIntrospectionQuery'; + +import { MaxIntrospectionDepthRule } from '../rules/MaxIntrospectionDepthRule'; + +import { expectValidationErrors } from './harness'; + +function expectErrors(queryStr: string) { + return expectValidationErrors(MaxIntrospectionDepthRule, queryStr); +} + +function expectValid(queryStr: string) { + expectErrors(queryStr).toDeepEqual([]); +} + +describe('Validate: Max introspection nodes rule', () => { + it('default introspection query', () => { + expectValid(getIntrospectionQuery()); + }); + + it('all options introspection query', () => { + expectValid( + getIntrospectionQuery({ + descriptions: true, + specifiedByUrl: true, + directiveIsRepeatable: true, + schemaDescription: true, + inputValueDeprecation: true, + }), + ); + }); + + it('3 flat fields introspection query', () => { + expectValid(` + { + __type(name: "Query") { + trueFields: fields(includeDeprecated: true) { + name + } + falseFields: fields(includeDeprecated: false) { + name + } + omittedFields: fields { + name + } + } + } + `); + }); + + it('3 fields deep introspection query from __schema', () => { + expectErrors(` + { + __schema { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 interfaces deep introspection query from __schema', () => { + expectErrors(` + { + __schema { + types { + interfaces { + interfaces { + interfaces { + name + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 possibleTypes deep introspection query from __schema', () => { + expectErrors(` + { + __schema { + types { + possibleTypes { + possibleTypes { + possibleTypes { + name + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 inputFields deep introspection query from __schema', () => { + expectErrors(` + { + __schema { + types { + inputFields { + type { + inputFields { + type { + inputFields { + type { + name + } + } + } + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 fields deep introspection query from multiple __schema', () => { + expectErrors(` + { + one: __schema { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + two: __schema { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + three: __schema { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + { + locations: [ + { + column: 7, + line: 18, + }, + ], + message: 'Maximum introspection depth exceeded', + }, + { + locations: [ + { + column: 7, + line: 33, + }, + ], + message: 'Maximum introspection depth exceeded', + }, + ]); + }); + + it('3 fields deep introspection query from __type', () => { + expectErrors(` + { + __type(name: "Query") { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 fields deep introspection query from multiple __type', () => { + expectErrors(` + { + one: __type(name: "Query") { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + two: __type(name: "Query") { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + three: __type(name: "Query") { + types { + fields { + type { + fields { + type { + fields { + name + } + } + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + { + locations: [ + { + column: 7, + line: 18, + }, + ], + message: 'Maximum introspection depth exceeded', + }, + { + locations: [ + { + column: 7, + line: 33, + }, + ], + message: 'Maximum introspection depth exceeded', + }, + ]); + }); + + it('1 fields deep with 3 fields introspection query', () => { + expectValid(` + { + __schema { + types { + fields { + type { + oneFields: fields { + name + } + twoFields: fields { + name + } + threeFields: fields { + name + } + } + } + } + } + } + `); + }); + + it('3 fields deep from varying parents introspection query', () => { + expectErrors(` + { + __schema { + types { + fields { + type { + fields { + type { + ofType { + fields { + name + } + } + } + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 fields deep introspection query with inline fragments', () => { + expectErrors(` + query test { + __schema { + types { + ... on __Type { + fields { + type { + ... on __Type { + ofType { + fields { + type { + ... on __Type { + fields { + name + } + } + } + } + } + } + } + } + } + } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 fields deep introspection query with fragments', () => { + expectErrors(` + query test { + __schema { + types { + ...One + } + } + } + + fragment One on __Type { + fields { + type { + ...Two + } + } + } + + fragment Two on __Type { + fields { + type { + ...Three + } + } + } + + fragment Three on __Type { + fields { + name + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 7, + line: 3, + }, + ], + }, + ]); + }); + + it('3 fields deep inside inline fragment on query', () => { + expectErrors(` + { + ... { + __schema { types { fields { type { fields { type { fields { name } } } } } } } + } + } + `).toDeepEqual([ + { + message: 'Maximum introspection depth exceeded', + locations: [ + { + column: 9, + line: 4, + }, + ], + }, + ]); + }); + + it('opts out if fragment is missing', () => { + expectValid(` + query test { + __schema { + types { + ...Missing + } + } + } + `); + }); + + it("doesn't infinitely recurse on fragment cycle", () => { + expectValid(` + query test { + __schema { + types { + ...Cycle + } + } + } + fragment Cycle on __Type { + ...Cycle + } + `); + }); +}); diff --git a/src/validation/__tests__/NoDeprecatedCustomRule-test.js b/src/validation/__tests__/NoDeprecatedCustomRule-test.ts similarity index 97% rename from src/validation/__tests__/NoDeprecatedCustomRule-test.js rename to src/validation/__tests__/NoDeprecatedCustomRule-test.ts index 12d66eafc2..512edb27dd 100644 --- a/src/validation/__tests__/NoDeprecatedCustomRule-test.js +++ b/src/validation/__tests__/NoDeprecatedCustomRule-test.ts @@ -19,7 +19,7 @@ function buildAssertion(sdlStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } } @@ -64,7 +64,7 @@ describe('Validate: no deprecated', () => { fragment QueryFragment on Query { deprecatedField } - `).to.deep.equal([ + `).toDeepEqual([ { message, locations: [{ line: 3, column: 11 }] }, { message, locations: [{ line: 7, column: 11 }] }, ]); @@ -103,7 +103,7 @@ describe('Validate: no deprecated', () => { { someField(deprecatedArg: "") } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "Query.someField" argument "deprecatedArg" is deprecated. Some arg reason.', @@ -147,7 +147,7 @@ describe('Validate: no deprecated', () => { { someField @someDirective(deprecatedArg: "") } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Directive "@someDirective" argument "deprecatedArg" is deprecated. Some arg reason.', @@ -209,7 +209,7 @@ describe('Validate: no deprecated', () => { someArg: { deprecatedField: "" } ) @someDirective(someArg: { deprecatedField: "" }) } - `).to.deep.equal([ + `).toDeepEqual([ { message, locations: [{ line: 4, column: 24 }] }, { message, locations: [{ line: 5, column: 39 }] }, ]); @@ -263,7 +263,7 @@ describe('Validate: no deprecated', () => { ) { someField(enumArg: DEPRECATED_VALUE) } - `).to.deep.equal([ + `).toDeepEqual([ { message, locations: [{ line: 3, column: 33 }] }, { message, locations: [{ line: 5, column: 30 }] }, ]); diff --git a/src/validation/__tests__/NoFragmentCyclesRule-test.js b/src/validation/__tests__/NoFragmentCyclesRule-test.ts similarity index 96% rename from src/validation/__tests__/NoFragmentCyclesRule-test.js rename to src/validation/__tests__/NoFragmentCyclesRule-test.ts index 94c3d1879b..08ac4cb4a9 100644 --- a/src/validation/__tests__/NoFragmentCyclesRule-test.js +++ b/src/validation/__tests__/NoFragmentCyclesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: No circular fragment spreads', () => { @@ -60,7 +60,7 @@ describe('Validate: No circular fragment spreads', () => { it('spreading recursively within field fails', () => { expectErrors(` fragment fragA on Human { relatives { ...fragA } }, - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself.', locations: [{ line: 2, column: 45 }], @@ -71,7 +71,7 @@ describe('Validate: No circular fragment spreads', () => { it('no spreading itself directly', () => { expectErrors(` fragment fragA on Dog { ...fragA } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself.', locations: [{ line: 2, column: 31 }], @@ -86,7 +86,7 @@ describe('Validate: No circular fragment spreads', () => { ...fragA } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself.', locations: [{ line: 4, column: 11 }], @@ -98,7 +98,7 @@ describe('Validate: No circular fragment spreads', () => { expectErrors(` fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragA } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself via "fragB".', locations: [ @@ -113,7 +113,7 @@ describe('Validate: No circular fragment spreads', () => { expectErrors(` fragment fragB on Dog { ...fragA } fragment fragA on Dog { ...fragB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragB" within itself via "fragA".', locations: [ @@ -136,7 +136,7 @@ describe('Validate: No circular fragment spreads', () => { ...fragA } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself via "fragB".', locations: [ @@ -157,7 +157,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragZ on Dog { ...fragO } fragment fragO on Dog { ...fragP } fragment fragP on Dog { ...fragA, ...fragX } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself via "fragB", "fragC", "fragO", "fragP".', @@ -188,7 +188,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragA } fragment fragC on Dog { ...fragA } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself via "fragB".', locations: [ @@ -211,7 +211,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragA on Dog { ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragA, ...fragB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragA" within itself via "fragC".', locations: [ @@ -234,7 +234,7 @@ describe('Validate: No circular fragment spreads', () => { fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragB, ...fragC } fragment fragC on Dog { ...fragA, ...fragB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot spread fragment "fragB" within itself.', locations: [{ line: 3, column: 31 }], diff --git a/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js b/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.ts similarity index 95% rename from src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js rename to src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.ts index 85a6dd0e35..cd681a7e68 100644 --- a/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js +++ b/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.ts @@ -15,7 +15,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } const schema = buildSchema(` @@ -58,7 +58,7 @@ describe('Validate: Prohibit introspection queries', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', @@ -81,7 +81,7 @@ describe('Validate: Prohibit introspection queries', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', @@ -108,7 +108,7 @@ describe('Validate: Prohibit introspection queries', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', @@ -129,7 +129,7 @@ describe('Validate: Prohibit introspection queries', () => { introspectionField } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'GraphQL introspection has been disabled, but the requested query contained the field "introspectionField".', diff --git a/src/validation/__tests__/NoUndefinedVariablesRule-test.js b/src/validation/__tests__/NoUndefinedVariablesRule-test.ts similarity index 96% rename from src/validation/__tests__/NoUndefinedVariablesRule-test.js rename to src/validation/__tests__/NoUndefinedVariablesRule-test.ts index 6969c89d8d..e027d4a49b 100644 --- a/src/validation/__tests__/NoUndefinedVariablesRule-test.js +++ b/src/validation/__tests__/NoUndefinedVariablesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: No undefined variables', () => { @@ -119,7 +119,7 @@ describe('Validate: No undefined variables', () => { query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c, d: $d) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$d" is not defined by operation "Foo".', locations: [ @@ -135,7 +135,7 @@ describe('Validate: No undefined variables', () => { { field(a: $a) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is not defined.', locations: [ @@ -151,7 +151,7 @@ describe('Validate: No undefined variables', () => { query Foo($b: String) { field(a: $a, b: $b, c: $c) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is not defined by operation "Foo".', locations: [ @@ -177,7 +177,7 @@ describe('Validate: No undefined variables', () => { fragment FragA on Type { field(a: $a) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is not defined.', locations: [ @@ -206,7 +206,7 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field(c: $c) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$c" is not defined by operation "Foo".', locations: [ @@ -235,7 +235,7 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field(c: $c) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is not defined by operation "Foo".', locations: [ @@ -264,7 +264,7 @@ describe('Validate: No undefined variables', () => { fragment FragAB on Type { field(a: $a, b: $b) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$b" is not defined by operation "Foo".', locations: [ @@ -293,7 +293,7 @@ describe('Validate: No undefined variables', () => { fragment FragAB on Type { field(a: $a, b: $b) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is not defined by operation "Foo".', locations: [ @@ -325,7 +325,7 @@ describe('Validate: No undefined variables', () => { fragment FragB on Type { field(b: $b) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is not defined by operation "Foo".', locations: [ @@ -359,7 +359,7 @@ describe('Validate: No undefined variables', () => { fragment FragC on Type { field2(c: $c) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is not defined by operation "Foo".', locations: [ diff --git a/src/validation/__tests__/NoUnusedFragmentsRule-test.js b/src/validation/__tests__/NoUnusedFragmentsRule-test.ts similarity index 96% rename from src/validation/__tests__/NoUnusedFragmentsRule-test.js rename to src/validation/__tests__/NoUnusedFragmentsRule-test.ts index d90b1b271a..abeee19e9f 100644 --- a/src/validation/__tests__/NoUnusedFragmentsRule-test.js +++ b/src/validation/__tests__/NoUnusedFragmentsRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: No unused fragments', () => { @@ -89,7 +89,7 @@ describe('Validate: No unused fragments', () => { fragment Unused2 on Human { name } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "Unused1" is never used.', locations: [{ line: 22, column: 7 }], @@ -131,7 +131,7 @@ describe('Validate: No unused fragments', () => { name ...Unused1 } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "Unused1" is never used.', locations: [{ line: 22, column: 7 }], @@ -153,7 +153,7 @@ describe('Validate: No unused fragments', () => { fragment foo on Human { name } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "foo" is never used.', locations: [{ line: 7, column: 7 }], diff --git a/src/validation/__tests__/NoUnusedVariablesRule-test.js b/src/validation/__tests__/NoUnusedVariablesRule-test.ts similarity index 96% rename from src/validation/__tests__/NoUnusedVariablesRule-test.js rename to src/validation/__tests__/NoUnusedVariablesRule-test.ts index aa111b11f5..6be63cd23d 100644 --- a/src/validation/__tests__/NoUnusedVariablesRule-test.js +++ b/src/validation/__tests__/NoUnusedVariablesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: No unused variables', () => { @@ -105,7 +105,7 @@ describe('Validate: No unused variables', () => { query ($a: String, $b: String, $c: String) { field(a: $a, b: $b) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$c" is never used.', locations: [{ line: 2, column: 38 }], @@ -118,7 +118,7 @@ describe('Validate: No unused variables', () => { query Foo($a: String, $b: String, $c: String) { field(b: $b) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is never used in operation "Foo".', locations: [{ line: 2, column: 17 }], @@ -148,7 +148,7 @@ describe('Validate: No unused variables', () => { fragment FragC on Type { field } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$c" is never used in operation "Foo".', locations: [{ line: 2, column: 41 }], @@ -174,7 +174,7 @@ describe('Validate: No unused variables', () => { fragment FragC on Type { field } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$a" is never used in operation "Foo".', locations: [{ line: 2, column: 17 }], @@ -197,7 +197,7 @@ describe('Validate: No unused variables', () => { fragment FragB on Type { field(b: $b) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$b" is never used in operation "Foo".', locations: [{ line: 2, column: 17 }], @@ -219,7 +219,7 @@ describe('Validate: No unused variables', () => { fragment FragB on Type { field(b: $b) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$b" is never used in operation "Foo".', locations: [{ line: 2, column: 17 }], diff --git a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts similarity index 87% rename from src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js rename to src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts index 080f859b89..7418c3e4e8 100644 --- a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js +++ b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts @@ -16,7 +16,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { @@ -28,7 +28,7 @@ function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { } function expectValidWithSchema(schema: GraphQLSchema, queryStr: string) { - expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); + expectErrorsWithSchema(schema, queryStr).toDeepEqual([]); } describe('Validate: Overlapping fields can be merged', () => { @@ -104,7 +104,7 @@ describe('Validate: Overlapping fields can be merged', () => { fido: name fido: nickname } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "fido" conflict because "name" and "nickname" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -137,7 +137,7 @@ describe('Validate: Overlapping fields can be merged', () => { name: nickname name } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "name" conflict because "nickname" and "name" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -155,7 +155,7 @@ describe('Validate: Overlapping fields can be merged', () => { doesKnowCommand doesKnowCommand(dogCommand: HEEL) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', @@ -173,7 +173,7 @@ describe('Validate: Overlapping fields can be merged', () => { doesKnowCommand(dogCommand: SIT) doesKnowCommand } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', @@ -191,7 +191,7 @@ describe('Validate: Overlapping fields can be merged', () => { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: HEEL) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', @@ -209,7 +209,7 @@ describe('Validate: Overlapping fields can be merged', () => { isAtLocation(x: 0) isAtLocation(y: 0) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "isAtLocation" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', @@ -236,6 +236,51 @@ describe('Validate: Overlapping fields can be merged', () => { `); }); + it('allows different order of args', () => { + const schema = buildSchema(` + type Query { + someField(a: String, b: String): String + } + `); + + // This is valid since arguments are unordered, see: + // https://spec.graphql.org/draft/#sec-Language.Arguments.Arguments-are-unordered + expectValidWithSchema( + schema, + ` + { + someField(a: null, b: null) + someField(b: null, a: null) + } + `, + ); + }); + + it('allows different order of input object fields in arg values', () => { + const schema = buildSchema(` + input SomeInput { + a: String + b: String + } + + type Query { + someField(arg: SomeInput): String + } + `); + + // This is valid since input object fields are unordered, see: + // https://spec.graphql.org/draft/#sec-Input-Object-Values.Input-object-fields-are-unordered + expectValidWithSchema( + schema, + ` + { + someField(arg: { a: null, b: null }) + someField(arg: { b: null, a: null }) + } + `, + ); + }); + it('encounters conflict in fragments', () => { expectErrors(` { @@ -248,7 +293,7 @@ describe('Validate: Overlapping fields can be merged', () => { fragment B on Type { x: b } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -283,7 +328,7 @@ describe('Validate: Overlapping fields can be merged', () => { fragment B on Type { x: b } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -321,7 +366,7 @@ describe('Validate: Overlapping fields can be merged', () => { x: b } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -347,7 +392,7 @@ describe('Validate: Overlapping fields can be merged', () => { y: d } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields and subfields "y" conflict because "c" and "d" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -377,7 +422,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "field" conflict because subfields "deepField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -410,7 +455,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "deepField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -449,7 +494,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "deeperField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -487,7 +532,7 @@ describe('Validate: Overlapping fields can be merged', () => { fragment J on T { x: b } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields and subfields "y" conflict because "c" and "d" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -503,6 +548,33 @@ describe('Validate: Overlapping fields can be merged', () => { ]); }); + it('reports deep conflict after nested fragments', () => { + expectErrors(` + fragment F on T { + ...G + } + fragment G on T { + ...H + } + fragment H on T { + x: a + } + { + x: b + ...F + } + `).toDeepEqual([ + { + message: + 'Fields "x" conflict because "b" and "a" are different fields. Use different aliases on the fields to fetch both if this was intentional.', + locations: [ + { line: 12, column: 9 }, + { line: 9, column: 9 }, + ], + }, + ]); + }); + it('ignores unknown fragments', () => { expectValid(` { @@ -601,7 +673,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "scalar" conflict because they return conflicting types "Int" and "String!". Use different aliases on the fields to fetch both if this was intentional.', @@ -653,7 +725,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "scalar" conflict because they return conflicting types "Int" and "String". Use different aliases on the fields to fetch both if this was intentional.', @@ -712,7 +784,7 @@ describe('Validate: Overlapping fields can be merged', () => { scalar: unrelatedField } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "other" conflict because subfields "scalar" conflict because "scalar" and "unrelatedField" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -741,7 +813,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "scalar" conflict because they return conflicting types "String!" and "String". Use different aliases on the fields to fetch both if this was intentional.', @@ -772,7 +844,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "box" conflict because they return conflicting types "[StringBox]" and "StringBox". Use different aliases on the fields to fetch both if this was intentional.', @@ -801,7 +873,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "box" conflict because they return conflicting types "StringBox" and "[StringBox]". Use different aliases on the fields to fetch both if this was intentional.', @@ -833,7 +905,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "val" conflict because "scalar" and "unrelatedField" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -864,7 +936,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "box" conflict because subfields "scalar" conflict because they return conflicting types "String" and "Int". Use different aliases on the fields to fetch both if this was intentional.', @@ -951,7 +1023,7 @@ describe('Validate: Overlapping fields can be merged', () => { } } `, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Fields "edges" conflict because subfields "node" conflict because subfields "id" conflict because "name" and "id" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -1011,18 +1083,64 @@ describe('Validate: Overlapping fields can be merged', () => { it('does not infinite loop on recursive fragment', () => { expectValid(` + { + ...fragA + } + fragment fragA on Human { name, relatives { name, ...fragA } } `); }); it('does not infinite loop on immediately recursive fragment', () => { expectValid(` + { + ...fragA + } + fragment fragA on Human { name, ...fragA } `); }); + it('does not infinite loop on recursive fragment with a field named after fragment', () => { + expectValid(` + { + ...fragA + fragA + } + + fragment fragA on Query { ...fragA } + `); + }); + + it('finds invalid cases even with field named after fragment', () => { + expectErrors(` + { + fragA + ...fragA + } + + fragment fragA on Type { + fragA: b + } + `).toDeepEqual([ + { + message: + 'Fields "fragA" conflict because "fragA" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', + locations: [ + { line: 3, column: 9 }, + { line: 8, column: 9 }, + ], + }, + ]); + }); + it('does not infinite loop on transitively recursive fragment', () => { expectValid(` + { + ...fragA + fragB + } + fragment fragA on Human { name, ...fragB } fragment fragB on Human { name, ...fragC } fragment fragC on Human { name, ...fragA } @@ -1036,7 +1154,7 @@ describe('Validate: Overlapping fields can be merged', () => { fido: name fido: nickname } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fields "fido" conflict because "name" and "nickname" are different fields. Use different aliases on the fields to fetch both if this was intentional.', @@ -1047,4 +1165,31 @@ describe('Validate: Overlapping fields can be merged', () => { }, ]); }); + + it('does not infinite loop on recursive fragments separated by fields', () => { + expectValid(` + { + ...fragA + ...fragB + } + + fragment fragA on T { + x { + ...fragA + x { + ...fragA + } + } + } + + fragment fragB on T { + x { + ...fragB + x { + ...fragB + } + } + } + `); + }); }); diff --git a/src/validation/__tests__/PossibleFragmentSpreadsRule-test.js b/src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts similarity index 85% rename from src/validation/__tests__/PossibleFragmentSpreadsRule-test.js rename to src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts index 267dbd3b38..3e52f234b5 100644 --- a/src/validation/__tests__/PossibleFragmentSpreadsRule-test.js +++ b/src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts @@ -1,17 +1,70 @@ import { describe, it } from 'mocha'; +import { buildSchema } from '../../utilities/buildASTSchema'; + import { PossibleFragmentSpreadsRule } from '../rules/PossibleFragmentSpreadsRule'; -import { expectValidationErrors } from './harness'; +import { expectValidationErrorsWithSchema } from './harness'; function expectErrors(queryStr: string) { - return expectValidationErrors(PossibleFragmentSpreadsRule, queryStr); + return expectValidationErrorsWithSchema( + testSchema, + PossibleFragmentSpreadsRule, + queryStr, + ); } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } +const testSchema = buildSchema(` + interface Being { + name: String + } + + interface Pet implements Being { + name: String + } + + type Dog implements Being & Pet { + name: String + barkVolume: Int + } + + type Cat implements Being & Pet { + name: String + meowVolume: Int + } + + union CatOrDog = Cat | Dog + + interface Intelligent { + iq: Int + } + + type Human implements Being & Intelligent { + name: String + pets: [Pet] + iq: Int + } + + type Alien implements Being & Intelligent { + name: String + iq: Int + } + + union DogOrHuman = Dog | Human + + union HumanOrAlien = Human | Alien + + type Query { + catOrDog: CatOrDog + dogOrHuman: DogOrHuman + humanOrAlien: HumanOrAlien + } +`); + describe('Validate: Possible fragment spreads', () => { it('of the same object', () => { expectValid(` @@ -105,7 +158,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "dogFragment" cannot be spread here as objects of type "Cat" can never be of type "Dog".', @@ -119,7 +172,7 @@ describe('Validate: Possible fragment spreads', () => { fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment cannot be spread here as objects of type "Cat" can never be of type "Dog".', @@ -132,7 +185,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "humanFragment" cannot be spread here as objects of type "Pet" can never be of type "Human".', @@ -145,7 +198,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "humanFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "Human".', @@ -158,7 +211,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "catOrDogFragment" cannot be spread here as objects of type "Human" can never be of type "CatOrDog".', @@ -171,7 +224,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "humanOrAlienFragment" cannot be spread here as objects of type "Pet" can never be of type "HumanOrAlien".', @@ -184,7 +237,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "humanOrAlienFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "HumanOrAlien".', @@ -197,7 +250,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "intelligentFragment" cannot be spread here as objects of type "Cat" can never be of type "Intelligent".', @@ -212,7 +265,7 @@ describe('Validate: Possible fragment spreads', () => { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "intelligentFragment" cannot be spread here as objects of type "Pet" can never be of type "Intelligent".', @@ -226,7 +279,7 @@ describe('Validate: Possible fragment spreads', () => { fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment cannot be spread here as objects of type "Pet" can never be of type "Intelligent".', @@ -239,7 +292,7 @@ describe('Validate: Possible fragment spreads', () => { expectErrors(` fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Fragment "petFragment" cannot be spread here as objects of type "HumanOrAlien" can never be of type "Pet".', diff --git a/src/validation/__tests__/PossibleTypeExtensionsRule-test.js b/src/validation/__tests__/PossibleTypeExtensionsRule-test.ts similarity index 97% rename from src/validation/__tests__/PossibleTypeExtensionsRule-test.js rename to src/validation/__tests__/PossibleTypeExtensionsRule-test.ts index 932f7ccef6..e29c097bdb 100644 --- a/src/validation/__tests__/PossibleTypeExtensionsRule-test.js +++ b/src/validation/__tests__/PossibleTypeExtensionsRule-test.ts @@ -13,7 +13,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Possible type extensions', () => { @@ -84,7 +84,7 @@ describe('Validate: Possible type extensions', () => { extend union Unknown @dummy extend enum Unknown @dummy extend input Unknown @dummy - `).to.deep.equal([ + `).toDeepEqual([ { message, locations: [{ line: 4, column: 21 }] }, { message, locations: [{ line: 5, column: 19 }] }, { message, locations: [{ line: 6, column: 24 }] }, @@ -108,7 +108,7 @@ describe('Validate: Possible type extensions', () => { extend union Foo @dummy extend enum Foo @dummy extend input Foo @dummy - `).to.deep.equal([ + `).toDeepEqual([ { message, locations: [{ line: 6, column: 21 }] }, { message, locations: [{ line: 7, column: 19 }] }, { message, locations: [{ line: 8, column: 24 }] }, @@ -133,7 +133,7 @@ describe('Validate: Possible type extensions', () => { extend enum FooUnion @dummy extend input FooEnum @dummy extend scalar FooInputObject @dummy - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Cannot extend non-object type "FooScalar".', locations: [ @@ -213,7 +213,7 @@ describe('Validate: Possible type extensions', () => { const message = 'Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?'; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message, locations: [{ line: 2, column: 21 }] }, { message, locations: [{ line: 3, column: 19 }] }, { message, locations: [{ line: 4, column: 24 }] }, @@ -241,7 +241,7 @@ describe('Validate: Possible type extensions', () => { extend scalar FooInputObject @dummy `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Cannot extend non-object type "FooScalar".', locations: [{ line: 2, column: 7 }], diff --git a/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js b/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.ts similarity index 95% rename from src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js rename to src/validation/__tests__/ProvidedRequiredArgumentsRule-test.ts index 7976f46bd2..23a272572c 100644 --- a/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js +++ b/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.ts @@ -5,18 +5,18 @@ import type { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; import { - ProvidedRequiredArgumentsRule, ProvidedRequiredArgumentsOnDirectivesRule, + ProvidedRequiredArgumentsRule, } from '../rules/ProvidedRequiredArgumentsRule'; -import { expectValidationErrors, expectSDLValidationErrors } from './harness'; +import { expectSDLValidationErrors, expectValidationErrors } from './harness'; function expectErrors(queryStr: string) { return expectValidationErrors(ProvidedRequiredArgumentsRule, queryStr); } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { @@ -28,7 +28,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string) { - expectSDLErrors(sdlStr).to.deep.equal([]); + expectSDLErrors(sdlStr).toDeepEqual([]); } describe('Validate: Provided required arguments', () => { @@ -162,7 +162,7 @@ describe('Validate: Provided required arguments', () => { multipleReqs(req2: 2) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.', @@ -178,7 +178,7 @@ describe('Validate: Provided required arguments', () => { multipleReqs } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.', @@ -199,7 +199,7 @@ describe('Validate: Provided required arguments', () => { multipleReqs(req1: "one") } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided.', @@ -238,7 +238,7 @@ describe('Validate: Provided required arguments', () => { name @skip } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.', @@ -271,7 +271,7 @@ describe('Validate: Provided required arguments', () => { } directive @test(arg: String!) on FIELD_DEFINITION - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', @@ -285,7 +285,7 @@ describe('Validate: Provided required arguments', () => { type Query { foo: String @include } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.', @@ -300,7 +300,7 @@ describe('Validate: Provided required arguments', () => { foo: String @deprecated } directive @deprecated(reason: String!) on FIELD - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Directive "@deprecated" argument "reason" of type "String!" is required, but it was not provided.', @@ -322,7 +322,7 @@ describe('Validate: Provided required arguments', () => { extend type Query @test `, schema, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', @@ -344,7 +344,7 @@ describe('Validate: Provided required arguments', () => { extend type Query @test `, schema, - ).to.deep.equal([ + ).toDeepEqual([ { message: 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', diff --git a/src/validation/__tests__/ScalarLeafsRule-test.js b/src/validation/__tests__/ScalarLeafsRule-test.ts similarity index 67% rename from src/validation/__tests__/ScalarLeafsRule-test.js rename to src/validation/__tests__/ScalarLeafsRule-test.ts index a441d4fcc7..0f0d8e18cb 100644 --- a/src/validation/__tests__/ScalarLeafsRule-test.js +++ b/src/validation/__tests__/ScalarLeafsRule-test.ts @@ -1,15 +1,22 @@ import { describe, it } from 'mocha'; +import { expectJSON } from '../../__testUtils__/expectJSON'; + +import type { DocumentNode } from '../../language/ast'; +import { OperationTypeNode } from '../../language/ast'; +import { Kind } from '../../language/kinds'; + import { ScalarLeafsRule } from '../rules/ScalarLeafsRule'; +import { validate } from '../validate'; -import { expectValidationErrors } from './harness'; +import { expectValidationErrors, testSchema } from './harness'; function expectErrors(queryStr: string) { return expectValidationErrors(ScalarLeafsRule, queryStr); } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Scalar leafs', () => { @@ -26,7 +33,7 @@ describe('Validate: Scalar leafs', () => { query directQueryOnObjectWithoutSubFields { human } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "human" of type "Human" must have a selection of subfields. Did you mean "human { ... }"?', @@ -40,7 +47,7 @@ describe('Validate: Scalar leafs', () => { { human { pets } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "pets" of type "[Pet]" must have a selection of subfields. Did you mean "pets { ... }"?', @@ -62,7 +69,7 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedOnBoolean on Dog { barks { sinceWhen } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "barks" must not have a selection since type "Boolean" has no subfields.', @@ -76,7 +83,7 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedOnEnum on Cat { furColor { inHexDec } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "furColor" must not have a selection since type "FurColor" has no subfields.', @@ -90,7 +97,7 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedWithArgs on Dog { doesKnowCommand(dogCommand: SIT) { sinceWhen } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.', @@ -104,7 +111,7 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedWithDirectives on Dog { name @include(if: true) { isAlsoHumanName } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "name" must not have a selection since type "String" has no subfields.', @@ -118,7 +125,7 @@ describe('Validate: Scalar leafs', () => { fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.', @@ -126,4 +133,37 @@ describe('Validate: Scalar leafs', () => { }, ]); }); + + it('object type having only one selection', () => { + const doc: DocumentNode = { + kind: Kind.DOCUMENT, + definitions: [ + { + kind: Kind.OPERATION_DEFINITION, + operation: OperationTypeNode.QUERY, + selectionSet: { + kind: Kind.SELECTION_SET, + selections: [ + { + kind: Kind.FIELD, + name: { kind: Kind.NAME, value: 'human' }, + selectionSet: { kind: Kind.SELECTION_SET, selections: [] }, + }, + ], + }, + }, + ], + }; + + // We can't leverage expectErrors since it doesn't support passing in the + // documentNode directly. We have to do this because this is technically + // an invalid document. + const errors = validate(testSchema, doc, [ScalarLeafsRule]); + expectJSON(errors).toDeepEqual([ + { + message: + 'Field "human" of type "Human" must have at least one field selected.', + }, + ]); + }); }); diff --git a/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js b/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js deleted file mode 100644 index c8ddc5add3..0000000000 --- a/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js +++ /dev/null @@ -1,86 +0,0 @@ -import { describe, it } from 'mocha'; - -import { SingleFieldSubscriptionsRule } from '../rules/SingleFieldSubscriptionsRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(SingleFieldSubscriptionsRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Subscriptions with single field', () => { - it('valid subscription', () => { - expectValid(` - subscription ImportantEmails { - importantEmails - } - `); - }); - - it('fails with more than one root field', () => { - expectErrors(` - subscription ImportantEmails { - importantEmails - notImportantEmails - } - `).to.deep.equal([ - { - message: - 'Subscription "ImportantEmails" must select only one top level field.', - locations: [{ line: 4, column: 9 }], - }, - ]); - }); - - it('fails with more than one root field including introspection', () => { - expectErrors(` - subscription ImportantEmails { - importantEmails - __typename - } - `).to.deep.equal([ - { - message: - 'Subscription "ImportantEmails" must select only one top level field.', - locations: [{ line: 4, column: 9 }], - }, - ]); - }); - - it('fails with many more than one root field', () => { - expectErrors(` - subscription ImportantEmails { - importantEmails - notImportantEmails - spamEmails - } - `).to.deep.equal([ - { - message: - 'Subscription "ImportantEmails" must select only one top level field.', - locations: [ - { line: 4, column: 9 }, - { line: 5, column: 9 }, - ], - }, - ]); - }); - - it('fails with more than one root field in anonymous subscriptions', () => { - expectErrors(` - subscription { - importantEmails - notImportantEmails - } - `).to.deep.equal([ - { - message: 'Anonymous Subscription must select only one top level field.', - locations: [{ line: 4, column: 9 }], - }, - ]); - }); -}); diff --git a/src/validation/__tests__/SingleFieldSubscriptionsRule-test.ts b/src/validation/__tests__/SingleFieldSubscriptionsRule-test.ts new file mode 100644 index 0000000000..e0d3789299 --- /dev/null +++ b/src/validation/__tests__/SingleFieldSubscriptionsRule-test.ts @@ -0,0 +1,306 @@ +import { describe, it } from 'mocha'; + +import { buildSchema } from '../../utilities/buildASTSchema'; + +import { SingleFieldSubscriptionsRule } from '../rules/SingleFieldSubscriptionsRule'; + +import { expectValidationErrorsWithSchema } from './harness'; + +function expectErrors(queryStr: string) { + return expectValidationErrorsWithSchema( + schema, + SingleFieldSubscriptionsRule, + queryStr, + ); +} + +function expectValid(queryStr: string) { + expectErrors(queryStr).toDeepEqual([]); +} + +const schema = buildSchema(` + type Message { + body: String + sender: String + } + + type SubscriptionRoot { + importantEmails: [String] + notImportantEmails: [String] + moreImportantEmails: [String] + spamEmails: [String] + deletedEmails: [String] + newMessage: Message + } + + type QueryRoot { + dummy: String + } + + schema { + query: QueryRoot + subscription: SubscriptionRoot + } +`); + +describe('Validate: Subscriptions with single field', () => { + it('valid subscription', () => { + expectValid(` + subscription ImportantEmails { + importantEmails + } + `); + }); + + it('valid subscription with fragment', () => { + // From https://spec.graphql.org/draft/#example-13061 + expectValid(` + subscription sub { + ...newMessageFields + } + + fragment newMessageFields on SubscriptionRoot { + newMessage { + body + sender + } + } + `); + }); + + it('valid subscription with fragment and field', () => { + // From https://spec.graphql.org/draft/#example-13061 + expectValid(` + subscription sub { + newMessage { + body + } + ...newMessageFields + } + + fragment newMessageFields on SubscriptionRoot { + newMessage { + body + sender + } + } + `); + }); + + it('fails with more than one root field', () => { + expectErrors(` + subscription ImportantEmails { + importantEmails + notImportantEmails + } + `).toDeepEqual([ + { + message: + 'Subscription "ImportantEmails" must select only one top level field.', + locations: [{ line: 4, column: 9 }], + }, + ]); + }); + + it('fails with more than one root field including introspection', () => { + expectErrors(` + subscription ImportantEmails { + importantEmails + __typename + } + `).toDeepEqual([ + { + message: + 'Subscription "ImportantEmails" must select only one top level field.', + locations: [{ line: 4, column: 9 }], + }, + { + message: + 'Subscription "ImportantEmails" must not select an introspection top level field.', + locations: [{ line: 4, column: 9 }], + }, + ]); + }); + + it('fails with more than one root field including aliased introspection via fragment', () => { + expectErrors(` + subscription ImportantEmails { + importantEmails + ...Introspection + } + fragment Introspection on SubscriptionRoot { + typename: __typename + } + `).toDeepEqual([ + { + message: + 'Subscription "ImportantEmails" must select only one top level field.', + locations: [{ line: 7, column: 9 }], + }, + { + message: + 'Subscription "ImportantEmails" must not select an introspection top level field.', + locations: [{ line: 7, column: 9 }], + }, + ]); + }); + + it('fails with many more than one root field', () => { + expectErrors(` + subscription ImportantEmails { + importantEmails + notImportantEmails + spamEmails + } + `).toDeepEqual([ + { + message: + 'Subscription "ImportantEmails" must select only one top level field.', + locations: [ + { line: 4, column: 9 }, + { line: 5, column: 9 }, + ], + }, + ]); + }); + + it('fails with many more than one root field via fragments', () => { + expectErrors(` + subscription ImportantEmails { + importantEmails + ... { + more: moreImportantEmails + } + ...NotImportantEmails + } + fragment NotImportantEmails on SubscriptionRoot { + notImportantEmails + deleted: deletedEmails + ...SpamEmails + } + fragment SpamEmails on SubscriptionRoot { + spamEmails + } + `).toDeepEqual([ + { + message: + 'Subscription "ImportantEmails" must select only one top level field.', + locations: [ + { line: 5, column: 11 }, + { line: 10, column: 9 }, + { line: 11, column: 9 }, + { line: 15, column: 9 }, + ], + }, + ]); + }); + + it('does not infinite loop on recursive fragments', () => { + expectErrors(` + subscription NoInfiniteLoop { + ...A + } + fragment A on SubscriptionRoot { + ...A + } + `).toDeepEqual([]); + }); + + it('fails with many more than one root field via fragments (anonymous)', () => { + expectErrors(` + subscription { + importantEmails + ... { + more: moreImportantEmails + ...NotImportantEmails + } + ...NotImportantEmails + } + fragment NotImportantEmails on SubscriptionRoot { + notImportantEmails + deleted: deletedEmails + ... { + ... { + archivedEmails + } + } + ...SpamEmails + } + fragment SpamEmails on SubscriptionRoot { + spamEmails + ...NonExistentFragment + } + `).toDeepEqual([ + { + message: 'Anonymous Subscription must select only one top level field.', + locations: [ + { line: 5, column: 11 }, + { line: 11, column: 9 }, + { line: 12, column: 9 }, + { line: 15, column: 13 }, + { line: 21, column: 9 }, + ], + }, + ]); + }); + + it('fails with more than one root field in anonymous subscriptions', () => { + expectErrors(` + subscription { + importantEmails + notImportantEmails + } + `).toDeepEqual([ + { + message: 'Anonymous Subscription must select only one top level field.', + locations: [{ line: 4, column: 9 }], + }, + ]); + }); + + it('fails with introspection field', () => { + expectErrors(` + subscription ImportantEmails { + __typename + } + `).toDeepEqual([ + { + message: + 'Subscription "ImportantEmails" must not select an introspection top level field.', + locations: [{ line: 3, column: 9 }], + }, + ]); + }); + + it('fails with introspection field in anonymous subscription', () => { + expectErrors(` + subscription { + __typename + } + `).toDeepEqual([ + { + message: + 'Anonymous Subscription must not select an introspection top level field.', + locations: [{ line: 3, column: 9 }], + }, + ]); + }); + + it('skips if not subscription type', () => { + const emptySchema = buildSchema(` + type Query { + dummy: String + } + `); + + expectValidationErrorsWithSchema( + emptySchema, + SingleFieldSubscriptionsRule, + ` + subscription { + __typename + } + `, + ).toDeepEqual([]); + }); +}); diff --git a/src/validation/__tests__/UniqueArgumentDefinitionNamesRule-test.ts b/src/validation/__tests__/UniqueArgumentDefinitionNamesRule-test.ts new file mode 100644 index 0000000000..cf63202b52 --- /dev/null +++ b/src/validation/__tests__/UniqueArgumentDefinitionNamesRule-test.ts @@ -0,0 +1,174 @@ +import { describe, it } from 'mocha'; + +import { UniqueArgumentDefinitionNamesRule } from '../rules/UniqueArgumentDefinitionNamesRule'; + +import { expectSDLValidationErrors } from './harness'; + +function expectSDLErrors(sdlStr: string) { + return expectSDLValidationErrors( + undefined, + UniqueArgumentDefinitionNamesRule, + sdlStr, + ); +} + +function expectValidSDL(sdlStr: string) { + expectSDLErrors(sdlStr).toDeepEqual([]); +} + +describe('Validate: Unique argument definition names', () => { + it('no args', () => { + expectValidSDL(` + type SomeObject { + someField: String + } + + interface SomeInterface { + someField: String + } + + directive @someDirective on QUERY + `); + }); + + it('one argument', () => { + expectValidSDL(` + type SomeObject { + someField(foo: String): String + } + + interface SomeInterface { + someField(foo: String): String + } + + extend type SomeObject { + anotherField(foo: String): String + } + + extend interface SomeInterface { + anotherField(foo: String): String + } + + directive @someDirective(foo: String) on QUERY + `); + }); + + it('multiple arguments', () => { + expectValidSDL(` + type SomeObject { + someField( + foo: String + bar: String + ): String + } + + interface SomeInterface { + someField( + foo: String + bar: String + ): String + } + + extend type SomeObject { + anotherField( + foo: String + bar: String + ): String + } + + extend interface SomeInterface { + anotherField( + foo: String + bar: String + ): String + } + + directive @someDirective( + foo: String + bar: String + ) on QUERY + `); + }); + + it('duplicating arguments', () => { + expectSDLErrors(` + type SomeObject { + someField( + foo: String + bar: String + foo: String + ): String + } + + interface SomeInterface { + someField( + foo: String + bar: String + foo: String + ): String + } + + extend type SomeObject { + anotherField( + foo: String + bar: String + bar: String + ): String + } + + extend interface SomeInterface { + anotherField( + bar: String + foo: String + foo: String + ): String + } + + directive @someDirective( + foo: String + bar: String + foo: String + ) on QUERY + `).toDeepEqual([ + { + message: + 'Argument "SomeObject.someField(foo:)" can only be defined once.', + locations: [ + { line: 4, column: 11 }, + { line: 6, column: 11 }, + ], + }, + { + message: + 'Argument "SomeInterface.someField(foo:)" can only be defined once.', + locations: [ + { line: 12, column: 11 }, + { line: 14, column: 11 }, + ], + }, + { + message: + 'Argument "SomeObject.anotherField(bar:)" can only be defined once.', + locations: [ + { line: 21, column: 11 }, + { line: 22, column: 11 }, + ], + }, + { + message: + 'Argument "SomeInterface.anotherField(foo:)" can only be defined once.', + locations: [ + { line: 29, column: 11 }, + { line: 30, column: 11 }, + ], + }, + { + message: 'Argument "@someDirective(foo:)" can only be defined once.', + locations: [ + { line: 35, column: 9 }, + { line: 37, column: 9 }, + ], + }, + ]); + }); +}); diff --git a/src/validation/__tests__/UniqueArgumentNamesRule-test.js b/src/validation/__tests__/UniqueArgumentNamesRule-test.ts similarity index 87% rename from src/validation/__tests__/UniqueArgumentNamesRule-test.js rename to src/validation/__tests__/UniqueArgumentNamesRule-test.ts index a18c56bd8f..f5709e321a 100644 --- a/src/validation/__tests__/UniqueArgumentNamesRule-test.js +++ b/src/validation/__tests__/UniqueArgumentNamesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Unique argument names', () => { @@ -91,7 +91,7 @@ describe('Validate: Unique argument names', () => { { field(arg1: "value", arg1: "value") } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one argument named "arg1".', locations: [ @@ -107,18 +107,12 @@ describe('Validate: Unique argument names', () => { { field(arg1: "value", arg1: "value", arg1: "value") } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one argument named "arg1".', locations: [ { line: 3, column: 15 }, { line: 3, column: 30 }, - ], - }, - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 15 }, { line: 3, column: 45 }, ], }, @@ -130,7 +124,7 @@ describe('Validate: Unique argument names', () => { { field @directive(arg1: "value", arg1: "value") } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one argument named "arg1".', locations: [ @@ -146,18 +140,12 @@ describe('Validate: Unique argument names', () => { { field @directive(arg1: "value", arg1: "value", arg1: "value") } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one argument named "arg1".', locations: [ { line: 3, column: 26 }, { line: 3, column: 41 }, - ], - }, - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 26 }, { line: 3, column: 56 }, ], }, diff --git a/src/validation/__tests__/UniqueDirectiveNamesRule-test.js b/src/validation/__tests__/UniqueDirectiveNamesRule-test.ts similarity index 91% rename from src/validation/__tests__/UniqueDirectiveNamesRule-test.js rename to src/validation/__tests__/UniqueDirectiveNamesRule-test.ts index 5e898998ed..a632af286a 100644 --- a/src/validation/__tests__/UniqueDirectiveNamesRule-test.js +++ b/src/validation/__tests__/UniqueDirectiveNamesRule-test.ts @@ -13,7 +13,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Unique directive names', () => { @@ -52,7 +52,7 @@ describe('Validate: Unique directive names', () => { directive @foo on SCHEMA directive @foo on SCHEMA - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one directive named "@foo".', locations: [ @@ -72,7 +72,7 @@ describe('Validate: Unique directive names', () => { it('adding new directive with standard name to existing schema', () => { const schema = buildSchema('type foo'); - expectSDLErrors('directive @skip on SCHEMA', schema).to.deep.equal([ + expectSDLErrors('directive @skip on SCHEMA', schema).toDeepEqual([ { message: 'Directive "@skip" already exists in the schema. It cannot be redefined.', @@ -90,7 +90,7 @@ describe('Validate: Unique directive names', () => { it('adding conflicting directives to existing schema', () => { const schema = buildSchema('directive @foo on SCHEMA'); - expectSDLErrors('directive @foo on SCHEMA', schema).to.deep.equal([ + expectSDLErrors('directive @foo on SCHEMA', schema).toDeepEqual([ { message: 'Directive "@foo" already exists in the schema. It cannot be redefined.', diff --git a/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js b/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.ts similarity index 97% rename from src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js rename to src/validation/__tests__/UniqueDirectivesPerLocationRule-test.ts index 79a7522419..d57a3df684 100644 --- a/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js +++ b/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.ts @@ -9,9 +9,9 @@ import { extendSchema } from '../../utilities/extendSchema'; import { UniqueDirectivesPerLocationRule } from '../rules/UniqueDirectivesPerLocationRule'; import { - testSchema, - expectValidationErrorsWithSchema, expectSDLValidationErrors, + expectValidationErrorsWithSchema, + testSchema, } from './harness'; const extensionSDL = ` @@ -31,7 +31,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { @@ -109,7 +109,7 @@ describe('Validate: Directives Are Unique Per Location', () => { fragment Test on Type { field @directive @directive } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@directive" can only be used once at this location.', @@ -126,7 +126,7 @@ describe('Validate: Directives Are Unique Per Location', () => { fragment Test on Type { field @directive @directive @directive } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@directive" can only be used once at this location.', @@ -151,7 +151,7 @@ describe('Validate: Directives Are Unique Per Location', () => { fragment Test on Type { field @directiveA @directiveB @directiveA @directiveB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@directiveA" can only be used once at this location.', @@ -176,7 +176,7 @@ describe('Validate: Directives Are Unique Per Location', () => { fragment Test on Type @directive @directive { field @directive @directive } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@directive" can only be used once at this location.', @@ -208,7 +208,7 @@ describe('Validate: Directives Are Unique Per Location', () => { interface TestInterface @nonRepeatable @nonRepeatable union TestUnion @nonRepeatable @nonRepeatable input TestInput @nonRepeatable @nonRepeatable - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@nonRepeatable" can only be used once at this location.', @@ -272,7 +272,7 @@ describe('Validate: Directives Are Unique Per Location', () => { extend interface TestInterface @nonRepeatable @nonRepeatable extend union TestUnion @nonRepeatable @nonRepeatable extend input TestInput @nonRepeatable @nonRepeatable - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@nonRepeatable" can only be used once at this location.', @@ -330,7 +330,7 @@ describe('Validate: Directives Are Unique Per Location', () => { schema @nonRepeatable { query: Dummy } extend schema @nonRepeatable - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@nonRepeatable" can only be used once at this location.', @@ -347,7 +347,7 @@ describe('Validate: Directives Are Unique Per Location', () => { scalar TestScalar @nonRepeatable extend scalar TestScalar @nonRepeatable scalar TestScalar @nonRepeatable - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@nonRepeatable" can only be used once at this location.', @@ -372,7 +372,7 @@ describe('Validate: Directives Are Unique Per Location', () => { extend type TestObject @nonRepeatable type TestObject @nonRepeatable extend type TestObject @nonRepeatable - `).to.deep.equal([ + `).toDeepEqual([ { message: 'The directive "@nonRepeatable" can only be used once at this location.', diff --git a/src/validation/__tests__/UniqueEnumValueNamesRule-test.js b/src/validation/__tests__/UniqueEnumValueNamesRule-test.ts similarity index 94% rename from src/validation/__tests__/UniqueEnumValueNamesRule-test.js rename to src/validation/__tests__/UniqueEnumValueNamesRule-test.ts index a97ac3b687..17a71a6e90 100644 --- a/src/validation/__tests__/UniqueEnumValueNamesRule-test.js +++ b/src/validation/__tests__/UniqueEnumValueNamesRule-test.ts @@ -13,7 +13,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Unique enum value names', () => { @@ -47,7 +47,7 @@ describe('Validate: Unique enum value names', () => { BAR FOO } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum value "SomeEnum.FOO" can only be defined once.', locations: [ @@ -80,7 +80,7 @@ describe('Validate: Unique enum value names', () => { enum SomeEnum { FOO } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum value "SomeEnum.FOO" can only be defined once.', locations: [ @@ -99,7 +99,7 @@ describe('Validate: Unique enum value names', () => { BAR FOO } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum value "SomeEnum.FOO" can only be defined once.', locations: [ @@ -119,7 +119,7 @@ describe('Validate: Unique enum value names', () => { extend enum SomeEnum { FOO } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum value "SomeEnum.FOO" can only be defined once.', locations: [ @@ -156,7 +156,7 @@ describe('Validate: Unique enum value names', () => { } `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension.', @@ -181,7 +181,7 @@ describe('Validate: Unique enum value names', () => { } `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Enum value "SomeEnum.FOO" can only be defined once.', locations: [ diff --git a/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js b/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.ts similarity index 97% rename from src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js rename to src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.ts index c27182d1ac..441e85d31a 100644 --- a/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js +++ b/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.ts @@ -17,7 +17,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Unique field definition names', () => { @@ -83,7 +83,7 @@ describe('Validate: Unique field definition names', () => { bar: String foo: String } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "SomeObject.foo" can only be defined once.', locations: [ @@ -164,7 +164,7 @@ describe('Validate: Unique field definition names', () => { input SomeInputObject { foo: String } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "SomeObject.foo" can only be defined once.', locations: [ @@ -211,7 +211,7 @@ describe('Validate: Unique field definition names', () => { bar: String foo: String } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "SomeObject.foo" can only be defined once.', locations: [ @@ -261,7 +261,7 @@ describe('Validate: Unique field definition names', () => { extend input SomeInputObject { foo: String } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "SomeObject.foo" can only be defined once.', locations: [ @@ -345,7 +345,7 @@ describe('Validate: Unique field definition names', () => { } `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension.', @@ -408,7 +408,7 @@ describe('Validate: Unique field definition names', () => { } `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Field "SomeObject.foo" can only be defined once.', locations: [ diff --git a/src/validation/__tests__/UniqueFragmentNamesRule-test.js b/src/validation/__tests__/UniqueFragmentNamesRule-test.ts similarity index 95% rename from src/validation/__tests__/UniqueFragmentNamesRule-test.js rename to src/validation/__tests__/UniqueFragmentNamesRule-test.ts index f67b462e80..2a693a6781 100644 --- a/src/validation/__tests__/UniqueFragmentNamesRule-test.js +++ b/src/validation/__tests__/UniqueFragmentNamesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Unique fragment names', () => { @@ -87,7 +87,7 @@ describe('Validate: Unique fragment names', () => { fragment fragA on Type { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one fragment named "fragA".', locations: [ @@ -106,7 +106,7 @@ describe('Validate: Unique fragment names', () => { fragment fragA on Type { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one fragment named "fragA".', locations: [ diff --git a/src/validation/__tests__/UniqueInputFieldNamesRule-test.js b/src/validation/__tests__/UniqueInputFieldNamesRule-test.ts similarity index 95% rename from src/validation/__tests__/UniqueInputFieldNamesRule-test.js rename to src/validation/__tests__/UniqueInputFieldNamesRule-test.ts index 8f2426db4e..33e4a2db01 100644 --- a/src/validation/__tests__/UniqueInputFieldNamesRule-test.js +++ b/src/validation/__tests__/UniqueInputFieldNamesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Unique input field names', () => { @@ -58,7 +58,7 @@ describe('Validate: Unique input field names', () => { { field(arg: { f1: "value", f1: "value" }) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one input field named "f1".', locations: [ @@ -74,7 +74,7 @@ describe('Validate: Unique input field names', () => { { field(arg: { f1: "value", f1: "value", f1: "value" }) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one input field named "f1".', locations: [ @@ -97,7 +97,7 @@ describe('Validate: Unique input field names', () => { { field(arg: { f1: {f2: "value", f2: "value" }}) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one input field named "f2".', locations: [ diff --git a/src/validation/__tests__/UniqueOperationNamesRule-test.js b/src/validation/__tests__/UniqueOperationNamesRule-test.ts similarity index 95% rename from src/validation/__tests__/UniqueOperationNamesRule-test.js rename to src/validation/__tests__/UniqueOperationNamesRule-test.ts index 720a285d26..f84abda63e 100644 --- a/src/validation/__tests__/UniqueOperationNamesRule-test.js +++ b/src/validation/__tests__/UniqueOperationNamesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Unique operation names', () => { @@ -84,7 +84,7 @@ describe('Validate: Unique operation names', () => { query Foo { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one operation named "Foo".', locations: [ @@ -103,7 +103,7 @@ describe('Validate: Unique operation names', () => { mutation Foo { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one operation named "Foo".', locations: [ @@ -122,7 +122,7 @@ describe('Validate: Unique operation names', () => { subscription Foo { fieldB } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one operation named "Foo".', locations: [ diff --git a/src/validation/__tests__/UniqueOperationTypesRule-test.js b/src/validation/__tests__/UniqueOperationTypesRule-test.ts similarity index 97% rename from src/validation/__tests__/UniqueOperationTypesRule-test.js rename to src/validation/__tests__/UniqueOperationTypesRule-test.ts index fd73040c44..61e819b022 100644 --- a/src/validation/__tests__/UniqueOperationTypesRule-test.js +++ b/src/validation/__tests__/UniqueOperationTypesRule-test.ts @@ -13,7 +13,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Unique operation types', () => { @@ -82,7 +82,7 @@ describe('Validate: Unique operation types', () => { mutation: Foo subscription: Foo } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one query type in schema.', locations: [ @@ -122,7 +122,7 @@ describe('Validate: Unique operation types', () => { mutation: Foo subscription: Foo } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one query type in schema.', locations: [ @@ -168,7 +168,7 @@ describe('Validate: Unique operation types', () => { mutation: Foo subscription: Foo } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one query type in schema.', locations: [ @@ -232,7 +232,7 @@ describe('Validate: Unique operation types', () => { mutation: Foo subscription: Foo } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one query type in schema.', locations: [ @@ -308,7 +308,7 @@ describe('Validate: Unique operation types', () => { } `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Type for query already defined in the schema. It cannot be redefined.', @@ -348,7 +348,7 @@ describe('Validate: Unique operation types', () => { } `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Type for query already defined in the schema. It cannot be redefined.', diff --git a/src/validation/__tests__/UniqueTypeNamesRule-test.js b/src/validation/__tests__/UniqueTypeNamesRule-test.ts similarity index 96% rename from src/validation/__tests__/UniqueTypeNamesRule-test.js rename to src/validation/__tests__/UniqueTypeNamesRule-test.ts index 6525275e92..5478467dec 100644 --- a/src/validation/__tests__/UniqueTypeNamesRule-test.js +++ b/src/validation/__tests__/UniqueTypeNamesRule-test.ts @@ -13,7 +13,7 @@ function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { } function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); + expectSDLErrors(sdlStr, schema).toDeepEqual([]); } describe('Validate: Unique type names', () => { @@ -57,7 +57,7 @@ describe('Validate: Unique type names', () => { union Foo enum Foo input Foo - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one type named "Foo".', locations: [ @@ -126,7 +126,7 @@ describe('Validate: Unique type names', () => { input Foo `; - expectSDLErrors(sdl, schema).to.deep.equal([ + expectSDLErrors(sdl, schema).toDeepEqual([ { message: 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', diff --git a/src/validation/__tests__/UniqueVariableNamesRule-test.js b/src/validation/__tests__/UniqueVariableNamesRule-test.ts similarity index 86% rename from src/validation/__tests__/UniqueVariableNamesRule-test.js rename to src/validation/__tests__/UniqueVariableNamesRule-test.ts index 4b950fb4cf..9d51b62170 100644 --- a/src/validation/__tests__/UniqueVariableNamesRule-test.js +++ b/src/validation/__tests__/UniqueVariableNamesRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Unique variable names', () => { @@ -25,18 +25,12 @@ describe('Validate: Unique variable names', () => { query A($x: Int, $x: Int, $x: String) { __typename } query B($x: String, $x: Int) { __typename } query C($x: Int, $x: Int) { __typename } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'There can be only one variable named "$x".', locations: [ { line: 2, column: 16 }, { line: 2, column: 25 }, - ], - }, - { - message: 'There can be only one variable named "$x".', - locations: [ - { line: 2, column: 16 }, { line: 2, column: 34 }, ], }, diff --git a/src/validation/__tests__/ValidationContext-test.ts b/src/validation/__tests__/ValidationContext-test.ts new file mode 100644 index 0000000000..159aa30549 --- /dev/null +++ b/src/validation/__tests__/ValidationContext-test.ts @@ -0,0 +1,40 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { identityFunc } from '../../jsutils/identityFunc'; + +import { parse } from '../../language/parser'; + +import { GraphQLSchema } from '../../type/schema'; + +import { TypeInfo } from '../../utilities/TypeInfo'; + +import { + ASTValidationContext, + SDLValidationContext, + ValidationContext, +} from '../ValidationContext'; + +describe('ValidationContext', () => { + it('can be Object.toStringified', () => { + const schema = new GraphQLSchema({}); + const typeInfo = new TypeInfo(schema); + const ast = parse('{ foo }'); + const onError = identityFunc; + + const astContext = new ASTValidationContext(ast, onError); + expect(Object.prototype.toString.call(astContext)).to.equal( + '[object ASTValidationContext]', + ); + + const sdlContext = new SDLValidationContext(ast, schema, onError); + expect(Object.prototype.toString.call(sdlContext)).to.equal( + '[object SDLValidationContext]', + ); + + const context = new ValidationContext(schema, ast, typeInfo, onError); + expect(Object.prototype.toString.call(context)).to.equal( + '[object ValidationContext]', + ); + }); +}); diff --git a/src/validation/__tests__/ValuesOfCorrectTypeRule-test.js b/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts similarity index 87% rename from src/validation/__tests__/ValuesOfCorrectTypeRule-test.js rename to src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts index 1831b4670d..3610fa648b 100644 --- a/src/validation/__tests__/ValuesOfCorrectTypeRule-test.js +++ b/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts @@ -1,12 +1,18 @@ +import { expect } from 'chai'; import { describe, it } from 'mocha'; -import inspect from '../../jsutils/inspect'; +import { expectJSON } from '../../__testUtils__/expectJSON'; -import { GraphQLSchema } from '../../type/schema'; +import { inspect } from '../../jsutils/inspect'; + +import { parse } from '../../language/parser'; + +import { GraphQLObjectType, GraphQLScalarType } from '../../type/definition'; import { GraphQLString } from '../../type/scalars'; -import { GraphQLScalarType, GraphQLObjectType } from '../../type/definition'; +import { GraphQLSchema } from '../../type/schema'; import { ValuesOfCorrectTypeRule } from '../rules/ValuesOfCorrectTypeRule'; +import { validate } from '../validate'; import { expectValidationErrors, @@ -26,11 +32,11 @@ function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } function expectValidWithSchema(schema: GraphQLSchema, queryStr: string) { - expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); + expectErrorsWithSchema(schema, queryStr).toDeepEqual([]); } describe('Validate: Values of correct type', () => { @@ -182,7 +188,7 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: 1) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: 1', locations: [{ line: 4, column: 39 }], @@ -197,7 +203,7 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: 1.0) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: 1.0', locations: [{ line: 4, column: 39 }], @@ -212,7 +218,7 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: true) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: true', locations: [{ line: 4, column: 39 }], @@ -227,7 +233,7 @@ describe('Validate: Values of correct type', () => { stringArgField(stringArg: BAR) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: BAR', locations: [{ line: 4, column: 39 }], @@ -244,7 +250,7 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: "3") } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non-integer value: "3"', locations: [{ line: 4, column: 33 }], @@ -259,7 +265,7 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: 829384293849283498239482938) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non 32-bit signed integer value: 829384293849283498239482938', @@ -275,7 +281,7 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: FOO) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non-integer value: FOO', locations: [{ line: 4, column: 33 }], @@ -290,7 +296,7 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: 3.0) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non-integer value: 3.0', locations: [{ line: 4, column: 33 }], @@ -305,7 +311,7 @@ describe('Validate: Values of correct type', () => { intArgField(intArg: 3.333) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non-integer value: 3.333', locations: [{ line: 4, column: 33 }], @@ -322,7 +328,7 @@ describe('Validate: Values of correct type', () => { floatArgField(floatArg: "3.333") } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Float cannot represent non numeric value: "3.333"', locations: [{ line: 4, column: 37 }], @@ -337,7 +343,7 @@ describe('Validate: Values of correct type', () => { floatArgField(floatArg: true) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Float cannot represent non numeric value: true', locations: [{ line: 4, column: 37 }], @@ -352,7 +358,7 @@ describe('Validate: Values of correct type', () => { floatArgField(floatArg: FOO) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Float cannot represent non numeric value: FOO', locations: [{ line: 4, column: 37 }], @@ -369,7 +375,7 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: 2) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Boolean cannot represent a non boolean value: 2', locations: [{ line: 4, column: 41 }], @@ -384,7 +390,7 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: 1.0) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Boolean cannot represent a non boolean value: 1.0', locations: [{ line: 4, column: 41 }], @@ -399,7 +405,7 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: "true") } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Boolean cannot represent a non boolean value: "true"', locations: [{ line: 4, column: 41 }], @@ -414,7 +420,7 @@ describe('Validate: Values of correct type', () => { booleanArgField(booleanArg: TRUE) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Boolean cannot represent a non boolean value: TRUE', locations: [{ line: 4, column: 41 }], @@ -431,7 +437,7 @@ describe('Validate: Values of correct type', () => { idArgField(idArg: 1.0) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'ID cannot represent a non-string and non-integer value: 1.0', @@ -447,7 +453,7 @@ describe('Validate: Values of correct type', () => { idArgField(idArg: true) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'ID cannot represent a non-string and non-integer value: true', @@ -463,7 +469,7 @@ describe('Validate: Values of correct type', () => { idArgField(idArg: SOMETHING) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'ID cannot represent a non-string and non-integer value: SOMETHING', @@ -481,7 +487,7 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: 2) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum "DogCommand" cannot represent non-enum value: 2.', locations: [{ line: 4, column: 41 }], @@ -496,7 +502,7 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: 1.0) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum "DogCommand" cannot represent non-enum value: 1.0.', locations: [{ line: 4, column: 41 }], @@ -511,7 +517,7 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: "SIT") } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum "DogCommand" cannot represent non-enum value: "SIT". Did you mean the enum value "SIT"?', @@ -527,7 +533,7 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: true) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Enum "DogCommand" cannot represent non-enum value: true.', locations: [{ line: 4, column: 41 }], @@ -542,7 +548,7 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: JUGGLE) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Value "JUGGLE" does not exist in "DogCommand" enum.', locations: [{ line: 4, column: 41 }], @@ -557,7 +563,7 @@ describe('Validate: Values of correct type', () => { doesKnowCommand(dogCommand: sit) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Value "sit" does not exist in "DogCommand" enum. Did you mean the enum value "SIT"?', @@ -617,7 +623,7 @@ describe('Validate: Values of correct type', () => { stringListArgField(stringListArg: ["one", 2]) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: 2', locations: [{ line: 4, column: 55 }], @@ -632,7 +638,7 @@ describe('Validate: Values of correct type', () => { stringListArgField(stringListArg: 1) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: 1', locations: [{ line: 4, column: 47 }], @@ -751,7 +757,7 @@ describe('Validate: Values of correct type', () => { multipleReqs(req2: "two", req1: "one") } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non-integer value: "two"', locations: [{ line: 4, column: 32 }], @@ -770,7 +776,7 @@ describe('Validate: Values of correct type', () => { multipleReqs(req1: "one") } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non-integer value: "one"', locations: [{ line: 4, column: 32 }], @@ -785,7 +791,7 @@ describe('Validate: Values of correct type', () => { multipleReqs(req1: null) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Expected value of type "Int!", found null.', locations: [{ line: 4, column: 32 }], @@ -868,6 +874,28 @@ describe('Validate: Values of correct type', () => { }); }); + describe('Valid oneOf input object value', () => { + it('Exactly one field', () => { + expectValid(` + { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: "abc" }) + } + } + `); + }); + + it('Exactly one non-nullable variable', () => { + expectValid(` + query ($string: String!) { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: $string }) + } + } + `); + }); + }); + describe('Invalid input object value', () => { it('Partial object, missing required', () => { expectErrors(` @@ -876,7 +904,7 @@ describe('Validate: Values of correct type', () => { complexArgField(complexArg: { intField: 4 }) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "ComplexInput.requiredField" of required type "Boolean!" was not provided.', @@ -895,7 +923,7 @@ describe('Validate: Values of correct type', () => { }) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: 2', locations: [{ line: 5, column: 40 }], @@ -913,7 +941,7 @@ describe('Validate: Values of correct type', () => { }) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Expected value of type "Boolean!", found null.', locations: [{ line: 6, column: 29 }], @@ -931,7 +959,7 @@ describe('Validate: Values of correct type', () => { }) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "invalidField" is not defined by type "ComplexInput". Did you mean "intField"?', @@ -962,12 +990,10 @@ describe('Validate: Values of correct type', () => { }), }); - const expectedErrors = expectErrorsWithSchema( - schema, - '{ invalidArg(arg: 123) }', - ); + const doc = parse('{ invalidArg(arg: 123) }'); + const errors = validate(schema, doc, [ValuesOfCorrectTypeRule]); - expectedErrors.to.deep.equal([ + expectJSON(errors).toDeepEqual([ { message: 'Expected value of type "Invalid", found 123; Invalid scalar is always invalid: 123', @@ -975,8 +1001,8 @@ describe('Validate: Values of correct type', () => { }, ]); - expectedErrors.to.have.nested.property( - '[0].originalError.message', + expect(errors[0]).to.have.nested.property( + 'originalError.message', 'Invalid scalar is always invalid: 123', ); }); @@ -1001,7 +1027,7 @@ describe('Validate: Values of correct type', () => { }), }); - expectErrorsWithSchema(schema, '{ invalidArg(arg: 123) }').to.deep.equal([ + expectErrorsWithSchema(schema, '{ invalidArg(arg: 123) }').toDeepEqual([ { message: 'Expected value of type "CustomScalar", found 123.', locations: [{ line: 1, column: 19 }], @@ -1037,6 +1063,70 @@ describe('Validate: Values of correct type', () => { }); }); + describe('Invalid oneOf input object value', () => { + it('Invalid field type', () => { + expectErrors(` + { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: 2 }) + } + } + `).toDeepEqual([ + { + message: 'String cannot represent a non string value: 2', + locations: [{ line: 4, column: 52 }], + }, + ]); + }); + + it('Exactly one null field', () => { + expectErrors(` + { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: null }) + } + } + `).toDeepEqual([ + { + message: 'Field "OneOfInput.stringField" must be non-null.', + locations: [{ line: 4, column: 37 }], + }, + ]); + }); + + it('Exactly one nullable variable', () => { + expectErrors(` + query ($string: String) { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: $string }) + } + } + `).toDeepEqual([ + { + message: + 'Variable "string" must be non-nullable to be used for OneOf Input Object "OneOfInput".', + locations: [{ line: 4, column: 37 }], + }, + ]); + }); + + it('More than one field', () => { + expectErrors(` + { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: "abc", intField: 123 }) + } + } + `).toDeepEqual([ + { + message: + 'OneOf Input Object "OneOfInput" must specify exactly one key.', + locations: [{ line: 4, column: 37 }], + }, + ]); + }); + }); + describe('Directive arguments', () => { it('with directives of valid types', () => { expectValid(` @@ -1058,7 +1148,7 @@ describe('Validate: Values of correct type', () => { name @skip(if: ENUM) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Boolean cannot represent a non boolean value: "yes"', locations: [{ line: 3, column: 28 }], @@ -1106,7 +1196,7 @@ describe('Validate: Values of correct type', () => { ) { dog { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Expected value of type "Int!", found null.', locations: [{ line: 3, column: 22 }], @@ -1131,7 +1221,7 @@ describe('Validate: Values of correct type', () => { ) { dog { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Int cannot represent non-integer value: "one"', locations: [{ line: 3, column: 21 }], @@ -1155,7 +1245,7 @@ describe('Validate: Values of correct type', () => { ) { dog { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Boolean cannot represent a non boolean value: 123', locations: [{ line: 3, column: 47 }], @@ -1172,7 +1262,7 @@ describe('Validate: Values of correct type', () => { query MissingRequiredField($a: ComplexInput = {intField: 3}) { dog { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Field "ComplexInput.requiredField" of required type "Boolean!" was not provided.', @@ -1186,7 +1276,7 @@ describe('Validate: Values of correct type', () => { query InvalidItem($a: [String] = ["one", 2]) { dog { name } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'String cannot represent a non string value: 2', locations: [{ line: 2, column: 50 }], diff --git a/src/validation/__tests__/VariablesAreInputTypesRule-test.js b/src/validation/__tests__/VariablesAreInputTypesRule-test.ts similarity index 83% rename from src/validation/__tests__/VariablesAreInputTypesRule-test.js rename to src/validation/__tests__/VariablesAreInputTypesRule-test.ts index 5a19fca650..7b754fd76f 100644 --- a/src/validation/__tests__/VariablesAreInputTypesRule-test.js +++ b/src/validation/__tests__/VariablesAreInputTypesRule-test.ts @@ -9,10 +9,18 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Variables are input types', () => { + it('unknown types are ignored', () => { + expectValid(` + query Foo($a: Unknown, $b: [[Unknown!]]!) { + field(a: $a, b: $b) + } + `); + }); + it('input types are valid', () => { expectValid(` query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { @@ -26,7 +34,7 @@ describe('Validate: Variables are input types', () => { query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { field(a: $a, b: $b, c: $c) } - `).to.deep.equal([ + `).toDeepEqual([ { locations: [{ line: 2, column: 21 }], message: 'Variable "$a" cannot be non-input type "Dog".', diff --git a/src/validation/__tests__/VariablesInAllowedPositionRule-test.js b/src/validation/__tests__/VariablesInAllowedPositionRule-test.ts similarity index 97% rename from src/validation/__tests__/VariablesInAllowedPositionRule-test.js rename to src/validation/__tests__/VariablesInAllowedPositionRule-test.ts index 2b9ebc5c2d..090f1680c4 100644 --- a/src/validation/__tests__/VariablesInAllowedPositionRule-test.js +++ b/src/validation/__tests__/VariablesInAllowedPositionRule-test.ts @@ -9,7 +9,7 @@ function expectErrors(queryStr: string) { } function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); + expectErrors(queryStr).toDeepEqual([]); } describe('Validate: Variables are in allowed positions', () => { @@ -158,7 +158,7 @@ describe('Validate: Variables are in allowed positions', () => { nonNullIntArgField(nonNullIntArg: $intArg) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', @@ -181,7 +181,7 @@ describe('Validate: Variables are in allowed positions', () => { ...nonNullIntArgFieldFrag } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', @@ -208,7 +208,7 @@ describe('Validate: Variables are in allowed positions', () => { ...outerFrag } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', @@ -227,7 +227,7 @@ describe('Validate: Variables are in allowed positions', () => { booleanArgField(booleanArg: $stringVar) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$stringVar" of type "String" used in position expecting type "Boolean".', @@ -246,7 +246,7 @@ describe('Validate: Variables are in allowed positions', () => { stringListArgField(stringListArg: $stringVar) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$stringVar" of type "String" used in position expecting type "[String]".', @@ -263,7 +263,7 @@ describe('Validate: Variables are in allowed positions', () => { query Query($boolVar: Boolean) { dog @include(if: $boolVar) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$boolVar" of type "Boolean" used in position expecting type "Boolean!".', @@ -280,7 +280,7 @@ describe('Validate: Variables are in allowed positions', () => { query Query($stringVar: String) { dog @include(if: $stringVar) } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$stringVar" of type "String" used in position expecting type "Boolean!".', @@ -300,7 +300,7 @@ describe('Validate: Variables are in allowed positions', () => { stringListNonNullArgField(stringListNonNullArg: $stringListVar) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$stringListVar" of type "[String]" used in position expecting type "[String!]".', @@ -320,7 +320,7 @@ describe('Validate: Variables are in allowed positions', () => { nonNullIntArgField(nonNullIntArg: $intVar) } } - `).to.deep.equal([ + `).toDeepEqual([ { message: 'Variable "$intVar" of type "Int" used in position expecting type "Int!".', diff --git a/src/validation/__tests__/harness.js b/src/validation/__tests__/harness.ts similarity index 70% rename from src/validation/__tests__/harness.js rename to src/validation/__tests__/harness.ts index 99683412d8..ea4840341c 100644 --- a/src/validation/__tests__/harness.js +++ b/src/validation/__tests__/harness.ts @@ -1,29 +1,27 @@ -import { expect } from 'chai'; +import { expectJSON } from '../../__testUtils__/expectJSON'; + +import type { Maybe } from '../../jsutils/Maybe'; import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; +import type { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; import { validate, validateSDL } from '../validate'; -import type { ValidationRule, SDLValidationRule } from '../ValidationContext'; - -export const testSchema = buildSchema(` - interface Being { - name(surname: Boolean): String - } +import type { SDLValidationRule, ValidationRule } from '../ValidationContext'; +export const testSchema: GraphQLSchema = buildSchema(` interface Mammal { mother: Mammal father: Mammal } - interface Pet implements Being { + interface Pet { name(surname: Boolean): String } - interface Canine implements Mammal & Being { + interface Canine implements Mammal { name(surname: Boolean): String mother: Canine father: Canine @@ -35,7 +33,7 @@ export const testSchema = buildSchema(` DOWN } - type Dog implements Being & Pet & Mammal & Canine { + type Dog implements Pet & Mammal & Canine { name(surname: Boolean): String nickname: String barkVolume: Int @@ -47,7 +45,7 @@ export const testSchema = buildSchema(` father: Dog } - type Cat implements Being & Pet { + type Cat implements Pet { name(surname: Boolean): String nickname: String meows: Boolean @@ -57,27 +55,12 @@ export const testSchema = buildSchema(` union CatOrDog = Cat | Dog - interface Intelligent { - iq: Int - } - - type Human implements Being & Intelligent { + type Human { name(surname: Boolean): String pets: [Pet] relatives: [Human] - iq: Int } - type Alien implements Being & Intelligent { - name(surname: Boolean): String - numEyes: Int - iq: Int - } - - union DogOrHuman = Dog | Human - - union HumanOrAlien = Human | Alien - enum FurColor { BROWN BLACK @@ -96,6 +79,11 @@ export const testSchema = buildSchema(` stringListField: [String] } + input OneOfInput @oneOf { + stringField: String + intField: Int + } + type ComplicatedArgs { # TODO List # TODO Coercion @@ -110,6 +98,7 @@ export const testSchema = buildSchema(` stringListArgField(stringListArg: [String]): String stringListNonNullArgField(stringListNonNullArg: [String!]): String complexArgField(complexArg: ComplexInput): String + oneOfArgField(oneOfArg: OneOfInput): String multipleReqs(req1: Int!, req2: Int!): String nonNullFieldWithDefault(arg: Int! = 0): String multipleOpts(opt1: Int = 0, opt2: Int = 0): String @@ -118,13 +107,10 @@ export const testSchema = buildSchema(` type QueryRoot { human(id: ID): Human - alien: Alien dog: Dog cat: Cat pet: Pet catOrDog: CatOrDog - dogOrHuman: DogOrHuman - humanOrAlien: HumanOrAlien complicatedArgs: ComplicatedArgs } @@ -132,14 +118,7 @@ export const testSchema = buildSchema(` query: QueryRoot } - directive @onQuery on QUERY - directive @onMutation on MUTATION - directive @onSubscription on SUBSCRIPTION directive @onField on FIELD - directive @onFragmentDefinition on FRAGMENT_DEFINITION - directive @onFragmentSpread on FRAGMENT_SPREAD - directive @onInlineFragment on INLINE_FRAGMENT - directive @onVariableDefinition on VARIABLE_DEFINITION `); export function expectValidationErrorsWithSchema( @@ -149,7 +128,7 @@ export function expectValidationErrorsWithSchema( ): any { const doc = parse(queryStr); const errors = validate(schema, doc, [rule]); - return expect(errors); + return expectJSON(errors); } export function expectValidationErrors( @@ -160,11 +139,11 @@ export function expectValidationErrors( } export function expectSDLValidationErrors( - schema: ?GraphQLSchema, + schema: Maybe, rule: SDLValidationRule, sdlStr: string, ): any { const doc = parse(sdlStr); const errors = validateSDL(doc, schema, [rule]); - return expect(errors); + return expectJSON(errors); } diff --git a/src/validation/__tests__/validation-test.js b/src/validation/__tests__/validation-test.ts similarity index 69% rename from src/validation/__tests__/validation-test.js rename to src/validation/__tests__/validation-test.ts index b1113d2d01..2d49f9335b 100644 --- a/src/validation/__tests__/validation-test.js +++ b/src/validation/__tests__/validation-test.ts @@ -1,40 +1,45 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import { expectJSON } from '../../__testUtils__/expectJSON'; + import { GraphQLError } from '../../error/GraphQLError'; +import type { DirectiveNode } from '../../language/ast'; import { parse } from '../../language/parser'; -import { TypeInfo } from '../../utilities/TypeInfo'; import { buildSchema } from '../../utilities/buildASTSchema'; +import { TypeInfo } from '../../utilities/TypeInfo'; -import type { ValidationContext } from '../ValidationContext'; import { validate } from '../validate'; +import type { ValidationContext } from '../ValidationContext'; import { testSchema } from './harness'; describe('Validate: Supports full validation', () => { it('rejects invalid documents', () => { - // $FlowExpectedError[incompatible-call] + // @ts-expect-error (expects a DocumentNode as a second parameter) expect(() => validate(testSchema, null)).to.throw('Must provide document.'); }); it('validates queries', () => { const doc = parse(` query { - catOrDog { - ... on Cat { - furColor - } - ... on Dog { - isHouseTrained + human { + pets { + ... on Cat { + meowsVolume + } + ... on Dog { + barkVolume + } } } } `); const errors = validate(testSchema, doc); - expect(errors).to.deep.equal([]); + expectJSON(errors).toDeepEqual([]); }); it('detects unknown fields', () => { @@ -45,7 +50,7 @@ describe('Validate: Supports full validation', () => { `); const errors = validate(testSchema, doc); - expect(errors).to.deep.equal([ + expectJSON(errors).toDeepEqual([ { locations: [{ line: 3, column: 9 }], message: 'Cannot query field "unknown" on type "QueryRoot".', @@ -53,31 +58,32 @@ describe('Validate: Supports full validation', () => { ]); }); - // NOTE: experimental - it('validates using a custom TypeInfo', () => { + it('Deprecated: validates using a custom TypeInfo', () => { // This TypeInfo will never return a valid field. - const typeInfo = new TypeInfo(testSchema, () => null); + const typeInfo = new TypeInfo(testSchema, null, () => null); const doc = parse(` query { - catOrDog { - ... on Cat { - furColor - } - ... on Dog { - isHouseTrained + human { + pets { + ... on Cat { + meowsVolume + } + ... on Dog { + barkVolume + } } } } `); - const errors = validate(testSchema, doc, undefined, typeInfo); - const errorMessages = errors.map((err) => err.message); + const errors = validate(testSchema, doc, undefined, undefined, typeInfo); + const errorMessages = errors.map((error) => error.message); expect(errorMessages).to.deep.equal([ - 'Cannot query field "catOrDog" on type "QueryRoot". Did you mean "catOrDog"?', - 'Cannot query field "furColor" on type "Cat". Did you mean "furColor"?', - 'Cannot query field "isHouseTrained" on type "Dog". Did you mean "isHouseTrained"?', + 'Cannot query field "human" on type "QueryRoot". Did you mean "human"?', + 'Cannot query field "meowsVolume" on type "Cat". Did you mean "meowsVolume"?', + 'Cannot query field "barkVolume" on type "Dog". Did you mean "barkVolume"?', ]); }); @@ -98,11 +104,11 @@ describe('Validate: Supports full validation', () => { function customRule(context: ValidationContext) { return { - Directive(node) { + Directive(node: DirectiveNode) { const directiveDef = context.getDirective(); const error = new GraphQLError( 'Reporting directive: ' + String(directiveDef), - node, + { nodes: node }, ); context.reportError(error); }, @@ -110,7 +116,7 @@ describe('Validate: Supports full validation', () => { } const errors = validate(schema, doc, [customRule]); - expect(errors).to.deep.equal([ + expectJSON(errors).toDeepEqual([ { message: 'Reporting directive: @custom', locations: [{ line: 3, column: 14 }], @@ -129,20 +135,19 @@ describe('Validate: Limit maximum number of validation errors', () => { `; const doc = parse(query, { noLocation: true }); - function validateDocument(options: {| maxErrors?: number |}) { - return validate(testSchema, doc, undefined, undefined, options); + function validateDocument(options: { maxErrors?: number }) { + return validate(testSchema, doc, undefined, options); } function invalidFieldError(fieldName: string) { return { message: `Cannot query field "${fieldName}" on type "QueryRoot".`, - locations: [], }; } it('when maxErrors is equal to number of errors', () => { const errors = validateDocument({ maxErrors: 3 }); - expect(errors).to.be.deep.equal([ + expectJSON(errors).toDeepEqual([ invalidFieldError('firstUnknownField'), invalidFieldError('secondUnknownField'), invalidFieldError('thirdUnknownField'), @@ -151,7 +156,7 @@ describe('Validate: Limit maximum number of validation errors', () => { it('when maxErrors is less than number of errors', () => { const errors = validateDocument({ maxErrors: 2 }); - expect(errors).to.be.deep.equal([ + expectJSON(errors).toDeepEqual([ invalidFieldError('firstUnknownField'), invalidFieldError('secondUnknownField'), { @@ -170,7 +175,7 @@ describe('Validate: Limit maximum number of validation errors', () => { }; } expect(() => - validate(testSchema, doc, [customRule], undefined, { maxErrors: 1 }), + validate(testSchema, doc, [customRule], { maxErrors: 1 }), ).to.throw(/^Error from custom rule!$/); }); }); diff --git a/src/validation/index.d.ts b/src/validation/index.d.ts deleted file mode 100644 index f049bf397e..0000000000 --- a/src/validation/index.d.ts +++ /dev/null @@ -1,96 +0,0 @@ -export { validate } from './validate'; - -export { ValidationContext, ValidationRule } from './ValidationContext'; - -export { specifiedRules } from './specifiedRules'; - -// Spec Section: "Executable Definitions" -export { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule'; - -// Spec Section: "Field Selections on Objects, Interfaces, and Unions Types" -export { FieldsOnCorrectTypeRule } from './rules/FieldsOnCorrectTypeRule'; - -// Spec Section: "Fragments on Composite Types" -export { FragmentsOnCompositeTypesRule } from './rules/FragmentsOnCompositeTypesRule'; - -// Spec Section: "Argument Names" -export { KnownArgumentNamesRule } from './rules/KnownArgumentNamesRule'; - -// Spec Section: "Directives Are Defined" -export { KnownDirectivesRule } from './rules/KnownDirectivesRule'; - -// Spec Section: "Fragment spread target defined" -export { KnownFragmentNamesRule } from './rules/KnownFragmentNamesRule'; - -// Spec Section: "Fragment Spread Type Existence" -export { KnownTypeNamesRule } from './rules/KnownTypeNamesRule'; - -// Spec Section: "Lone Anonymous Operation" -export { LoneAnonymousOperationRule } from './rules/LoneAnonymousOperationRule'; - -// Spec Section: "Fragments must not form cycles" -export { NoFragmentCyclesRule } from './rules/NoFragmentCyclesRule'; - -// Spec Section: "All Variable Used Defined" -export { NoUndefinedVariablesRule } from './rules/NoUndefinedVariablesRule'; - -// Spec Section: "Fragments must be used" -export { NoUnusedFragmentsRule } from './rules/NoUnusedFragmentsRule'; - -// Spec Section: "All Variables Used" -export { NoUnusedVariablesRule } from './rules/NoUnusedVariablesRule'; - -// Spec Section: "Field Selection Merging" -export { OverlappingFieldsCanBeMergedRule } from './rules/OverlappingFieldsCanBeMergedRule'; - -// Spec Section: "Fragment spread is possible" -export { PossibleFragmentSpreadsRule } from './rules/PossibleFragmentSpreadsRule'; - -// Spec Section: "Argument Optionality" -export { ProvidedRequiredArgumentsRule } from './rules/ProvidedRequiredArgumentsRule'; - -// Spec Section: "Leaf Field Selections" -export { ScalarLeafsRule } from './rules/ScalarLeafsRule'; - -// Spec Section: "Subscriptions with Single Root Field" -export { SingleFieldSubscriptionsRule } from './rules/SingleFieldSubscriptionsRule'; - -// Spec Section: "Argument Uniqueness" -export { UniqueArgumentNamesRule } from './rules/UniqueArgumentNamesRule'; - -// Spec Section: "Directives Are Unique Per Location" -export { UniqueDirectivesPerLocationRule } from './rules/UniqueDirectivesPerLocationRule'; - -// Spec Section: "Fragment Name Uniqueness" -export { UniqueFragmentNamesRule } from './rules/UniqueFragmentNamesRule'; - -// Spec Section: "Input Object Field Uniqueness" -export { UniqueInputFieldNamesRule } from './rules/UniqueInputFieldNamesRule'; - -// Spec Section: "Operation Name Uniqueness" -export { UniqueOperationNamesRule } from './rules/UniqueOperationNamesRule'; - -// Spec Section: "Variable Uniqueness" -export { UniqueVariableNamesRule } from './rules/UniqueVariableNamesRule'; - -// Spec Section: "Values Type Correctness" -export { ValuesOfCorrectTypeRule } from './rules/ValuesOfCorrectTypeRule'; - -// Spec Section: "Variables are Input Types" -export { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule'; - -// Spec Section: "All Variable Usages Are Allowed" -export { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule'; - -// SDL-specific validation rules -export { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule'; -export { UniqueOperationTypesRule } from './rules/UniqueOperationTypesRule'; -export { UniqueTypeNamesRule } from './rules/UniqueTypeNamesRule'; -export { UniqueEnumValueNamesRule } from './rules/UniqueEnumValueNamesRule'; -export { UniqueFieldDefinitionNamesRule } from './rules/UniqueFieldDefinitionNamesRule'; -export { UniqueDirectiveNamesRule } from './rules/UniqueDirectiveNamesRule'; -export { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule'; - -// Optional rules not defined by the GraphQL Specification -export { NoDeprecatedCustomRule } from './rules/custom/NoDeprecatedCustomRule'; -export { NoSchemaIntrospectionCustomRule } from './rules/custom/NoSchemaIntrospectionCustomRule'; diff --git a/src/validation/index.js b/src/validation/index.ts similarity index 94% rename from src/validation/index.js rename to src/validation/index.ts index c0f24a0316..587479e351 100644 --- a/src/validation/index.js +++ b/src/validation/index.ts @@ -4,7 +4,7 @@ export { ValidationContext } from './ValidationContext'; export type { ValidationRule } from './ValidationContext'; // All validation rules in the GraphQL Specification. -export { specifiedRules } from './specifiedRules'; +export { specifiedRules, recommendedRules } from './specifiedRules'; // Spec Section: "Executable Definitions" export { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule'; @@ -84,12 +84,15 @@ export { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule'; // Spec Section: "All Variable Usages Are Allowed" export { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule'; +export { MaxIntrospectionDepthRule } from './rules/MaxIntrospectionDepthRule'; + // SDL-specific validation rules export { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule'; export { UniqueOperationTypesRule } from './rules/UniqueOperationTypesRule'; export { UniqueTypeNamesRule } from './rules/UniqueTypeNamesRule'; export { UniqueEnumValueNamesRule } from './rules/UniqueEnumValueNamesRule'; export { UniqueFieldDefinitionNamesRule } from './rules/UniqueFieldDefinitionNamesRule'; +export { UniqueArgumentDefinitionNamesRule } from './rules/UniqueArgumentDefinitionNamesRule'; export { UniqueDirectiveNamesRule } from './rules/UniqueDirectiveNamesRule'; export { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule'; diff --git a/src/validation/rules/ExecutableDefinitions.d.ts b/src/validation/rules/ExecutableDefinitions.d.ts deleted file mode 100644 index 94557ad8de..0000000000 --- a/src/validation/rules/ExecutableDefinitions.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { ExecutableDefinitionsRule } from 'graphql' - * or - * import { ExecutableDefinitionsRule } from 'graphql/validation' - */ -export { ExecutableDefinitionsRule as ExecutableDefinitions } from './ExecutableDefinitionsRule'; diff --git a/src/validation/rules/ExecutableDefinitions.js b/src/validation/rules/ExecutableDefinitions.js deleted file mode 100644 index 94557ad8de..0000000000 --- a/src/validation/rules/ExecutableDefinitions.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { ExecutableDefinitionsRule } from 'graphql' - * or - * import { ExecutableDefinitionsRule } from 'graphql/validation' - */ -export { ExecutableDefinitionsRule as ExecutableDefinitions } from './ExecutableDefinitionsRule'; diff --git a/src/validation/rules/ExecutableDefinitionsRule.d.ts b/src/validation/rules/ExecutableDefinitionsRule.d.ts deleted file mode 100644 index 9709256c48..0000000000 --- a/src/validation/rules/ExecutableDefinitionsRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Executable definitions - * - * A GraphQL document is only valid for execution if all definitions are either - * operation or fragment definitions. - */ -export function ExecutableDefinitionsRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/ExecutableDefinitionsRule.js b/src/validation/rules/ExecutableDefinitionsRule.ts similarity index 83% rename from src/validation/rules/ExecutableDefinitionsRule.js rename to src/validation/rules/ExecutableDefinitionsRule.ts index c446e000e1..8f82a6797b 100644 --- a/src/validation/rules/ExecutableDefinitionsRule.js +++ b/src/validation/rules/ExecutableDefinitionsRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import { Kind } from '../../language/kinds'; import { isExecutableDefinitionNode } from '../../language/predicates'; +import type { ASTVisitor } from '../../language/visitor'; import type { ASTValidationContext } from '../ValidationContext'; @@ -11,6 +11,8 @@ import type { ASTValidationContext } from '../ValidationContext'; * * A GraphQL document is only valid for execution if all definitions are either * operation or fragment definitions. + * + * See https://spec.graphql.org/draft/#sec-Executable-Definitions */ export function ExecutableDefinitionsRule( context: ASTValidationContext, @@ -25,10 +27,9 @@ export function ExecutableDefinitionsRule( ? 'schema' : '"' + definition.name.value + '"'; context.reportError( - new GraphQLError( - `The ${defName} definition is not executable.`, - definition, - ), + new GraphQLError(`The ${defName} definition is not executable.`, { + nodes: definition, + }), ); } } diff --git a/src/validation/rules/FieldsOnCorrectTypeRule.d.ts b/src/validation/rules/FieldsOnCorrectTypeRule.d.ts deleted file mode 100644 index 6091c6ce2e..0000000000 --- a/src/validation/rules/FieldsOnCorrectTypeRule.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Fields on correct type - * - * A GraphQL document is only valid if all fields selected are defined by the - * parent type, or are an allowed meta field such as __typename. - */ -export function FieldsOnCorrectTypeRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/FieldsOnCorrectTypeRule.js b/src/validation/rules/FieldsOnCorrectTypeRule.ts similarity index 91% rename from src/validation/rules/FieldsOnCorrectTypeRule.js rename to src/validation/rules/FieldsOnCorrectTypeRule.ts index 58149d90d5..9182f9c4a1 100644 --- a/src/validation/rules/FieldsOnCorrectTypeRule.js +++ b/src/validation/rules/FieldsOnCorrectTypeRule.ts @@ -1,25 +1,23 @@ -import arrayFrom from '../../polyfills/arrayFrom'; - -import didYouMean from '../../jsutils/didYouMean'; -import suggestionList from '../../jsutils/suggestionList'; -import naturalCompare from '../../jsutils/naturalCompare'; +import { didYouMean } from '../../jsutils/didYouMean'; +import { naturalCompare } from '../../jsutils/naturalCompare'; +import { suggestionList } from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; import type { FieldNode } from '../../language/ast'; import type { ASTVisitor } from '../../language/visitor'; -import type { GraphQLSchema } from '../../type/schema'; import type { - GraphQLOutputType, - GraphQLObjectType, GraphQLInterfaceType, + GraphQLObjectType, + GraphQLOutputType, } from '../../type/definition'; import { - isObjectType, - isInterfaceType, isAbstractType, + isInterfaceType, + isObjectType, } from '../../type/definition'; +import type { GraphQLSchema } from '../../type/schema'; import type { ValidationContext } from '../ValidationContext'; @@ -28,6 +26,8 @@ import type { ValidationContext } from '../ValidationContext'; * * A GraphQL document is only valid if all fields selected are defined by the * parent type, or are an allowed meta field such as __typename. + * + * See https://spec.graphql.org/draft/#sec-Field-Selections */ export function FieldsOnCorrectTypeRule( context: ValidationContext, @@ -58,7 +58,7 @@ export function FieldsOnCorrectTypeRule( new GraphQLError( `Cannot query field "${fieldName}" on type "${type.name}".` + suggestion, - node, + { nodes: node }, ), ); } @@ -82,9 +82,8 @@ function getSuggestedTypeNames( return []; } - const suggestedTypes: Set< - GraphQLObjectType | GraphQLInterfaceType, - > = new Set(); + const suggestedTypes: Set = + new Set(); const usageCount = Object.create(null); for (const possibleType of schema.getPossibleTypes(type)) { if (!possibleType.getFields()[fieldName]) { @@ -107,7 +106,7 @@ function getSuggestedTypeNames( } } - return arrayFrom(suggestedTypes) + return [...suggestedTypes] .sort((typeA, typeB) => { // Suggest both interface and object types based on how common they are. const usageCountDiff = usageCount[typeB.name] - usageCount[typeA.name]; diff --git a/src/validation/rules/FragmentsOnCompositeTypesRule.d.ts b/src/validation/rules/FragmentsOnCompositeTypesRule.d.ts deleted file mode 100644 index 70b9b140f4..0000000000 --- a/src/validation/rules/FragmentsOnCompositeTypesRule.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Fragments on composite type - * - * Fragments use a type condition to determine if they apply, since fragments - * can only be spread into a composite type (object, interface, or union), the - * type condition must also be a composite type. - */ -export function FragmentsOnCompositeTypesRule( - context: ValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/FragmentsOnCompositeTypesRule.js b/src/validation/rules/FragmentsOnCompositeTypesRule.ts similarity index 90% rename from src/validation/rules/FragmentsOnCompositeTypesRule.js rename to src/validation/rules/FragmentsOnCompositeTypesRule.ts index 75f49158c7..fb71f63836 100644 --- a/src/validation/rules/FragmentsOnCompositeTypesRule.js +++ b/src/validation/rules/FragmentsOnCompositeTypesRule.ts @@ -1,7 +1,7 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import { print } from '../../language/printer'; +import type { ASTVisitor } from '../../language/visitor'; import { isCompositeType } from '../../type/definition'; @@ -15,6 +15,8 @@ import type { ValidationContext } from '../ValidationContext'; * Fragments use a type condition to determine if they apply, since fragments * can only be spread into a composite type (object, interface, or union), the * type condition must also be a composite type. + * + * See https://spec.graphql.org/draft/#sec-Fragments-On-Composite-Types */ export function FragmentsOnCompositeTypesRule( context: ValidationContext, @@ -29,7 +31,7 @@ export function FragmentsOnCompositeTypesRule( context.reportError( new GraphQLError( `Fragment cannot condition on non composite type "${typeStr}".`, - typeCondition, + { nodes: typeCondition }, ), ); } @@ -42,7 +44,7 @@ export function FragmentsOnCompositeTypesRule( context.reportError( new GraphQLError( `Fragment "${node.name.value}" cannot condition on non composite type "${typeStr}".`, - node.typeCondition, + { nodes: node.typeCondition }, ), ); } diff --git a/src/validation/rules/KnownArgumentNamesRule.d.ts b/src/validation/rules/KnownArgumentNamesRule.d.ts deleted file mode 100644 index 8c0f828994..0000000000 --- a/src/validation/rules/KnownArgumentNamesRule.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ValidationContext, SDLValidationContext } from '../ValidationContext'; -import { ASTVisitor } from '../../language/visitor'; - -/** - * Known argument names - * - * A GraphQL field is only valid if all supplied arguments are defined by - * that field. - */ -export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor; - -/** - * @internal - */ -export function KnownArgumentNamesOnDirectivesRule( - context: ValidationContext | SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/KnownArgumentNamesRule.js b/src/validation/rules/KnownArgumentNamesRule.ts similarity index 85% rename from src/validation/rules/KnownArgumentNamesRule.js rename to src/validation/rules/KnownArgumentNamesRule.ts index b1fd082463..332b21c1ca 100644 --- a/src/validation/rules/KnownArgumentNamesRule.js +++ b/src/validation/rules/KnownArgumentNamesRule.ts @@ -1,16 +1,16 @@ -import didYouMean from '../../jsutils/didYouMean'; -import suggestionList from '../../jsutils/suggestionList'; +import { didYouMean } from '../../jsutils/didYouMean'; +import { suggestionList } from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import { Kind } from '../../language/kinds'; +import type { ASTVisitor } from '../../language/visitor'; import { specifiedDirectives } from '../../type/directives'; import type { - ValidationContext, SDLValidationContext, + ValidationContext, } from '../ValidationContext'; /** @@ -18,6 +18,9 @@ import type { * * A GraphQL field is only valid if all supplied arguments are defined by * that field. + * + * See https://spec.graphql.org/draft/#sec-Argument-Names + * See https://spec.graphql.org/draft/#sec-Directives-Are-In-Valid-Locations */ export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor { return { @@ -36,7 +39,7 @@ export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor { new GraphQLError( `Unknown argument "${argName}" on field "${parentType.name}.${fieldDef.name}".` + didYouMean(suggestions), - argNode, + { nodes: argNode }, ), ); } @@ -63,7 +66,8 @@ export function KnownArgumentNamesOnDirectivesRule( const astDefinitions = context.getDocument().definitions; for (const def of astDefinitions) { if (def.kind === Kind.DIRECTIVE_DEFINITION) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const argsNodes = def.arguments ?? []; directiveArgs[def.name.value] = argsNodes.map((arg) => arg.name.value); @@ -78,13 +82,13 @@ export function KnownArgumentNamesOnDirectivesRule( if (directiveNode.arguments && knownArgs) { for (const argNode of directiveNode.arguments) { const argName = argNode.name.value; - if (knownArgs.indexOf(argName) === -1) { + if (!knownArgs.includes(argName)) { const suggestions = suggestionList(argName, knownArgs); context.reportError( new GraphQLError( `Unknown argument "${argName}" on directive "@${directiveName}".` + didYouMean(suggestions), - argNode, + { nodes: argNode }, ), ); } diff --git a/src/validation/rules/KnownDirectivesRule.d.ts b/src/validation/rules/KnownDirectivesRule.d.ts deleted file mode 100644 index dcb6af6138..0000000000 --- a/src/validation/rules/KnownDirectivesRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext, SDLValidationContext } from '../ValidationContext'; - -/** - * Known directives - * - * A GraphQL document is only valid if all `@directives` are known by the - * schema and legally positioned. - */ -export function KnownDirectivesRule( - context: ValidationContext | SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/KnownDirectivesRule.js b/src/validation/rules/KnownDirectivesRule.ts similarity index 79% rename from src/validation/rules/KnownDirectivesRule.js rename to src/validation/rules/KnownDirectivesRule.ts index 8c2e60de88..f24dbe7d28 100644 --- a/src/validation/rules/KnownDirectivesRule.js +++ b/src/validation/rules/KnownDirectivesRule.ts @@ -1,19 +1,19 @@ -import inspect from '../../jsutils/inspect'; -import invariant from '../../jsutils/invariant'; +import { inspect } from '../../jsutils/inspect'; +import { invariant } from '../../jsutils/invariant'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { ASTNode, OperationTypeNode } from '../../language/ast'; -import type { DirectiveLocationEnum } from '../../language/directiveLocation'; -import { Kind } from '../../language/kinds'; +import type { ASTNode } from '../../language/ast'; +import { OperationTypeNode } from '../../language/ast'; import { DirectiveLocation } from '../../language/directiveLocation'; +import { Kind } from '../../language/kinds'; +import type { ASTVisitor } from '../../language/visitor'; import { specifiedDirectives } from '../../type/directives'; import type { - ValidationContext, SDLValidationContext, + ValidationContext, } from '../ValidationContext'; /** @@ -21,6 +21,8 @@ import type { * * A GraphQL document is only valid if all `@directives` are known by the * schema and legally positioned. + * + * See https://spec.graphql.org/draft/#sec-Directives-Are-Defined */ export function KnownDirectivesRule( context: ValidationContext | SDLValidationContext, @@ -49,17 +51,17 @@ export function KnownDirectivesRule( if (!locations) { context.reportError( - new GraphQLError(`Unknown directive "@${name}".`, node), + new GraphQLError(`Unknown directive "@${name}".`, { nodes: node }), ); return; } const candidateLocation = getDirectiveLocationForASTPath(ancestors); - if (candidateLocation && locations.indexOf(candidateLocation) === -1) { + if (candidateLocation && !locations.includes(candidateLocation)) { context.reportError( new GraphQLError( `Directive "@${name}" may not be used on ${candidateLocation}.`, - node, + { nodes: node }, ), ); } @@ -68,10 +70,10 @@ export function KnownDirectivesRule( } function getDirectiveLocationForASTPath( - ancestors: $ReadOnlyArray>, -): DirectiveLocationEnum | void { + ancestors: ReadonlyArray>, +): DirectiveLocation | undefined { const appliedTo = ancestors[ancestors.length - 1]; - invariant(!Array.isArray(appliedTo)); + invariant('kind' in appliedTo); switch (appliedTo.kind) { case Kind.OPERATION_DEFINITION: @@ -113,25 +115,27 @@ function getDirectiveLocationForASTPath( return DirectiveLocation.INPUT_OBJECT; case Kind.INPUT_VALUE_DEFINITION: { const parentNode = ancestors[ancestors.length - 3]; + invariant('kind' in parentNode); return parentNode.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION ? DirectiveLocation.INPUT_FIELD_DEFINITION : DirectiveLocation.ARGUMENT_DEFINITION; } + // Not reachable, all possible types have been considered. + /* c8 ignore next */ + default: + invariant(false, 'Unexpected kind: ' + inspect(appliedTo.kind)); } } function getDirectiveLocationForOperation( operation: OperationTypeNode, -): DirectiveLocationEnum { +): DirectiveLocation { switch (operation) { - case 'query': + case OperationTypeNode.QUERY: return DirectiveLocation.QUERY; - case 'mutation': + case OperationTypeNode.MUTATION: return DirectiveLocation.MUTATION; - case 'subscription': + case OperationTypeNode.SUBSCRIPTION: return DirectiveLocation.SUBSCRIPTION; } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected operation: ' + inspect((operation: empty))); } diff --git a/src/validation/rules/KnownFragmentNamesRule.d.ts b/src/validation/rules/KnownFragmentNamesRule.d.ts deleted file mode 100644 index 7b594fd912..0000000000 --- a/src/validation/rules/KnownFragmentNamesRule.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Known fragment names - * - * A GraphQL document is only valid if all `...Fragment` fragment spreads refer - * to fragments defined in the same document. - */ -export function KnownFragmentNamesRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/KnownFragmentNamesRule.js b/src/validation/rules/KnownFragmentNamesRule.ts similarity index 85% rename from src/validation/rules/KnownFragmentNamesRule.js rename to src/validation/rules/KnownFragmentNamesRule.ts index 0f3412bb45..c37403f752 100644 --- a/src/validation/rules/KnownFragmentNamesRule.js +++ b/src/validation/rules/KnownFragmentNamesRule.ts @@ -9,6 +9,8 @@ import type { ValidationContext } from '../ValidationContext'; * * A GraphQL document is only valid if all `...Fragment` fragment spreads refer * to fragments defined in the same document. + * + * See https://spec.graphql.org/draft/#sec-Fragment-spread-target-defined */ export function KnownFragmentNamesRule(context: ValidationContext): ASTVisitor { return { @@ -17,7 +19,9 @@ export function KnownFragmentNamesRule(context: ValidationContext): ASTVisitor { const fragment = context.getFragment(fragmentName); if (!fragment) { context.reportError( - new GraphQLError(`Unknown fragment "${fragmentName}".`, node.name), + new GraphQLError(`Unknown fragment "${fragmentName}".`, { + nodes: node.name, + }), ); } }, diff --git a/src/validation/rules/KnownTypeNamesRule.d.ts b/src/validation/rules/KnownTypeNamesRule.d.ts deleted file mode 100644 index b7cd75d4a1..0000000000 --- a/src/validation/rules/KnownTypeNamesRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext, SDLValidationContext } from '../ValidationContext'; - -/** - * Known type names - * - * A GraphQL document is only valid if referenced types (specifically - * variable definitions and fragment conditions) are defined by the type schema. - */ -export function KnownTypeNamesRule( - context: ValidationContext | SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/KnownTypeNamesRule.js b/src/validation/rules/KnownTypeNamesRule.ts similarity index 80% rename from src/validation/rules/KnownTypeNamesRule.js rename to src/validation/rules/KnownTypeNamesRule.ts index 38efd5a603..fadc080c35 100644 --- a/src/validation/rules/KnownTypeNamesRule.js +++ b/src/validation/rules/KnownTypeNamesRule.ts @@ -1,22 +1,22 @@ -import didYouMean from '../../jsutils/didYouMean'; -import suggestionList from '../../jsutils/suggestionList'; +import { didYouMean } from '../../jsutils/didYouMean'; +import { suggestionList } from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; import type { ASTNode } from '../../language/ast'; -import type { ASTVisitor } from '../../language/visitor'; import { isTypeDefinitionNode, isTypeSystemDefinitionNode, isTypeSystemExtensionNode, } from '../../language/predicates'; +import type { ASTVisitor } from '../../language/visitor'; -import { specifiedScalarTypes } from '../../type/scalars'; import { introspectionTypes } from '../../type/introspection'; +import { specifiedScalarTypes } from '../../type/scalars'; import type { - ValidationContext, SDLValidationContext, + ValidationContext, } from '../ValidationContext'; /** @@ -24,6 +24,8 @@ import type { * * A GraphQL document is only valid if referenced types (specifically * variable definitions and fragment conditions) are defined by the type schema. + * + * See https://spec.graphql.org/draft/#sec-Fragment-Spread-Type-Existence */ export function KnownTypeNamesRule( context: ValidationContext | SDLValidationContext, @@ -38,9 +40,10 @@ export function KnownTypeNamesRule( } } - const typeNames = Object.keys(existingTypesMap).concat( - Object.keys(definedTypes), - ); + const typeNames = [ + ...Object.keys(existingTypesMap), + ...Object.keys(definedTypes), + ]; return { NamedType(node, _1, parent, _2, ancestors) { @@ -48,7 +51,7 @@ export function KnownTypeNamesRule( if (!existingTypesMap[typeName] && !definedTypes[typeName]) { const definitionNode = ancestors[2] ?? parent; const isSDL = definitionNode != null && isSDLNode(definitionNode); - if (isSDL && isStandardTypeName(typeName)) { + if (isSDL && standardTypeNames.includes(typeName)) { return; } @@ -59,7 +62,7 @@ export function KnownTypeNamesRule( context.reportError( new GraphQLError( `Unknown type "${typeName}".` + didYouMean(suggestedTypes), - node, + { nodes: node }, ), ); } @@ -71,13 +74,9 @@ const standardTypeNames = [...specifiedScalarTypes, ...introspectionTypes].map( (type) => type.name, ); -function isStandardTypeName(typeName: string): boolean { - return standardTypeNames.indexOf(typeName) !== -1; -} - -function isSDLNode(value: ASTNode | $ReadOnlyArray): boolean { +function isSDLNode(value: ASTNode | ReadonlyArray): boolean { return ( - !Array.isArray(value) && + 'kind' in value && (isTypeSystemDefinitionNode(value) || isTypeSystemExtensionNode(value)) ); } diff --git a/src/validation/rules/LoneAnonymousOperationRule.d.ts b/src/validation/rules/LoneAnonymousOperationRule.d.ts deleted file mode 100644 index 1ac19ef4b7..0000000000 --- a/src/validation/rules/LoneAnonymousOperationRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Lone anonymous operation - * - * A GraphQL document is only valid if when it contains an anonymous operation - * (the query short-hand) that it contains only that one operation definition. - */ -export function LoneAnonymousOperationRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/LoneAnonymousOperationRule.js b/src/validation/rules/LoneAnonymousOperationRule.ts similarity index 90% rename from src/validation/rules/LoneAnonymousOperationRule.js rename to src/validation/rules/LoneAnonymousOperationRule.ts index 617c80639f..291a494c76 100644 --- a/src/validation/rules/LoneAnonymousOperationRule.js +++ b/src/validation/rules/LoneAnonymousOperationRule.ts @@ -1,7 +1,7 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import { Kind } from '../../language/kinds'; +import type { ASTVisitor } from '../../language/visitor'; import type { ASTValidationContext } from '../ValidationContext'; @@ -10,6 +10,8 @@ import type { ASTValidationContext } from '../ValidationContext'; * * A GraphQL document is only valid if when it contains an anonymous operation * (the query short-hand) that it contains only that one operation definition. + * + * See https://spec.graphql.org/draft/#sec-Lone-Anonymous-Operation */ export function LoneAnonymousOperationRule( context: ASTValidationContext, @@ -26,7 +28,7 @@ export function LoneAnonymousOperationRule( context.reportError( new GraphQLError( 'This anonymous operation must be the only defined operation.', - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/LoneSchemaDefinition.d.ts b/src/validation/rules/LoneSchemaDefinition.d.ts deleted file mode 100644 index a38ad06a6d..0000000000 --- a/src/validation/rules/LoneSchemaDefinition.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { LoneSchemaDefinitionRule } from 'graphql' - * or - * import { LoneSchemaDefinitionRule } from 'graphql/validation' - */ -export { LoneSchemaDefinitionRule as LoneSchemaDefinition } from './LoneSchemaDefinitionRule'; diff --git a/src/validation/rules/LoneSchemaDefinition.js b/src/validation/rules/LoneSchemaDefinition.js deleted file mode 100644 index a38ad06a6d..0000000000 --- a/src/validation/rules/LoneSchemaDefinition.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { LoneSchemaDefinitionRule } from 'graphql' - * or - * import { LoneSchemaDefinitionRule } from 'graphql/validation' - */ -export { LoneSchemaDefinitionRule as LoneSchemaDefinition } from './LoneSchemaDefinitionRule'; diff --git a/src/validation/rules/LoneSchemaDefinitionRule.d.ts b/src/validation/rules/LoneSchemaDefinitionRule.d.ts deleted file mode 100644 index 5075e74e9b..0000000000 --- a/src/validation/rules/LoneSchemaDefinitionRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { SDLValidationContext } from '../ValidationContext'; - -/** - * Lone Schema definition - * - * A GraphQL document is only valid if it contains only one schema definition. - */ -export function LoneSchemaDefinitionRule( - context: SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/LoneSchemaDefinitionRule.js b/src/validation/rules/LoneSchemaDefinitionRule.ts similarity index 93% rename from src/validation/rules/LoneSchemaDefinitionRule.js rename to src/validation/rules/LoneSchemaDefinitionRule.ts index 1c2b02371e..4eeb8cdcba 100644 --- a/src/validation/rules/LoneSchemaDefinitionRule.js +++ b/src/validation/rules/LoneSchemaDefinitionRule.ts @@ -1,4 +1,5 @@ import { GraphQLError } from '../../error/GraphQLError'; + import type { ASTVisitor } from '../../language/visitor'; import type { SDLValidationContext } from '../ValidationContext'; @@ -25,7 +26,7 @@ export function LoneSchemaDefinitionRule( context.reportError( new GraphQLError( 'Cannot define a new schema within a schema extension.', - node, + { nodes: node }, ), ); return; @@ -33,7 +34,9 @@ export function LoneSchemaDefinitionRule( if (schemaDefinitionsCount > 0) { context.reportError( - new GraphQLError('Must provide only one schema definition.', node), + new GraphQLError('Must provide only one schema definition.', { + nodes: node, + }), ); } ++schemaDefinitionsCount; diff --git a/src/validation/rules/MaxIntrospectionDepthRule.ts b/src/validation/rules/MaxIntrospectionDepthRule.ts new file mode 100644 index 0000000000..0c2dbd3879 --- /dev/null +++ b/src/validation/rules/MaxIntrospectionDepthRule.ts @@ -0,0 +1,91 @@ +import { GraphQLError } from '../../error/GraphQLError'; + +import type { ASTNode } from '../../language/ast'; +import { Kind } from '../../language/kinds'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ASTValidationContext } from '../ValidationContext'; + +const MAX_LISTS_DEPTH = 3; + +export function MaxIntrospectionDepthRule( + context: ASTValidationContext, +): ASTVisitor { + /** + * Counts the depth of list fields in "__Type" recursively and + * returns `true` if the limit has been reached. + */ + function checkDepth( + node: ASTNode, + visitedFragments: { + [fragmentName: string]: true | undefined; + } = Object.create(null), + depth: number = 0, + ): boolean { + if (node.kind === Kind.FRAGMENT_SPREAD) { + const fragmentName = node.name.value; + if (visitedFragments[fragmentName] === true) { + // Fragment cycles are handled by `NoFragmentCyclesRule`. + return false; + } + const fragment = context.getFragment(fragmentName); + if (!fragment) { + // Missing fragments checks are handled by `KnownFragmentNamesRule`. + return false; + } + + // Rather than following an immutable programming pattern which has + // significant memory and garbage collection overhead, we've opted to + // take a mutable approach for efficiency's sake. Importantly visiting a + // fragment twice is fine, so long as you don't do one visit inside the + // other. + try { + visitedFragments[fragmentName] = true; + return checkDepth(fragment, visitedFragments, depth); + } finally { + visitedFragments[fragmentName] = undefined; + } + } + + if ( + node.kind === Kind.FIELD && + // check all introspection lists + (node.name.value === 'fields' || + node.name.value === 'interfaces' || + node.name.value === 'possibleTypes' || + node.name.value === 'inputFields') + ) { + // eslint-disable-next-line no-param-reassign + depth++; + if (depth >= MAX_LISTS_DEPTH) { + return true; + } + } + + // handles fields and inline fragments + if ('selectionSet' in node && node.selectionSet) { + for (const child of node.selectionSet.selections) { + if (checkDepth(child, visitedFragments, depth)) { + return true; + } + } + } + + return false; + } + + return { + Field(node) { + if (node.name.value === '__schema' || node.name.value === '__type') { + if (checkDepth(node)) { + context.reportError( + new GraphQLError('Maximum introspection depth exceeded', { + nodes: [node], + }), + ); + return false; + } + } + }, + }; +} diff --git a/src/validation/rules/NoFragmentCyclesRule.d.ts b/src/validation/rules/NoFragmentCyclesRule.d.ts deleted file mode 100644 index 85b2b106ed..0000000000 --- a/src/validation/rules/NoFragmentCyclesRule.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -export function NoFragmentCyclesRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/NoFragmentCyclesRule.js b/src/validation/rules/NoFragmentCyclesRule.ts similarity index 75% rename from src/validation/rules/NoFragmentCyclesRule.js rename to src/validation/rules/NoFragmentCyclesRule.ts index 54fba26e43..448b1cf496 100644 --- a/src/validation/rules/NoFragmentCyclesRule.js +++ b/src/validation/rules/NoFragmentCyclesRule.ts @@ -1,22 +1,35 @@ +import type { ObjMap } from '../../jsutils/ObjMap'; + import { GraphQLError } from '../../error/GraphQLError'; +import type { + FragmentDefinitionNode, + FragmentSpreadNode, +} from '../../language/ast'; import type { ASTVisitor } from '../../language/visitor'; -import type { FragmentDefinitionNode } from '../../language/ast'; import type { ASTValidationContext } from '../ValidationContext'; +/** + * No fragment cycles + * + * The graph of fragment spreads must not form any cycles including spreading itself. + * Otherwise an operation could infinitely spread or infinitely execute on cycles in the underlying data. + * + * See https://spec.graphql.org/draft/#sec-Fragment-spreads-must-not-form-cycles + */ export function NoFragmentCyclesRule( context: ASTValidationContext, ): ASTVisitor { // Tracks already visited fragments to maintain O(N) and to ensure that cycles // are not redundantly reported. - const visitedFrags = Object.create(null); + const visitedFrags: ObjMap = Object.create(null); // Array of AST nodes used to produce meaningful errors - const spreadPath = []; + const spreadPath: Array = []; // Position in the spread path - const spreadPathIndexByName = Object.create(null); + const spreadPathIndexByName: ObjMap = Object.create(null); return { OperationDefinition: () => false, @@ -65,7 +78,7 @@ export function NoFragmentCyclesRule( new GraphQLError( `Cannot spread fragment "${spreadName}" within itself` + (viaPath !== '' ? ` via ${viaPath}.` : '.'), - cyclePath, + { nodes: cyclePath }, ), ); } diff --git a/src/validation/rules/NoUndefinedVariablesRule.d.ts b/src/validation/rules/NoUndefinedVariablesRule.d.ts deleted file mode 100644 index d1a080655b..0000000000 --- a/src/validation/rules/NoUndefinedVariablesRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * No undefined variables - * - * A GraphQL operation is only valid if all variables encountered, both directly - * and via fragment spreads, are defined by that operation. - */ -export function NoUndefinedVariablesRule( - context: ValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/NoUndefinedVariablesRule.js b/src/validation/rules/NoUndefinedVariablesRule.ts similarity index 91% rename from src/validation/rules/NoUndefinedVariablesRule.js rename to src/validation/rules/NoUndefinedVariablesRule.ts index de1a84807f..3d499b5dcc 100644 --- a/src/validation/rules/NoUndefinedVariablesRule.js +++ b/src/validation/rules/NoUndefinedVariablesRule.ts @@ -9,6 +9,8 @@ import type { ValidationContext } from '../ValidationContext'; * * A GraphQL operation is only valid if all variables encountered, both directly * and via fragment spreads, are defined by that operation. + * + * See https://spec.graphql.org/draft/#sec-All-Variable-Uses-Defined */ export function NoUndefinedVariablesRule( context: ValidationContext, @@ -31,7 +33,7 @@ export function NoUndefinedVariablesRule( operation.name ? `Variable "$${varName}" is not defined by operation "${operation.name.value}".` : `Variable "$${varName}" is not defined.`, - [node, operation], + { nodes: [node, operation] }, ), ); } diff --git a/src/validation/rules/NoUnusedFragmentsRule.d.ts b/src/validation/rules/NoUnusedFragmentsRule.d.ts deleted file mode 100644 index 8435bab17a..0000000000 --- a/src/validation/rules/NoUnusedFragmentsRule.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * No unused fragments - * - * A GraphQL document is only valid if all fragment definitions are spread - * within operations, or spread within other fragments spread within operations. - */ -export function NoUnusedFragmentsRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/NoUnusedFragmentsRule.js b/src/validation/rules/NoUnusedFragmentsRule.ts similarity index 74% rename from src/validation/rules/NoUnusedFragmentsRule.js rename to src/validation/rules/NoUnusedFragmentsRule.ts index d69bf241cf..aebf34535d 100644 --- a/src/validation/rules/NoUnusedFragmentsRule.js +++ b/src/validation/rules/NoUnusedFragmentsRule.ts @@ -1,5 +1,9 @@ import { GraphQLError } from '../../error/GraphQLError'; +import type { + FragmentDefinitionNode, + OperationDefinitionNode, +} from '../../language/ast'; import type { ASTVisitor } from '../../language/visitor'; import type { ASTValidationContext } from '../ValidationContext'; @@ -9,12 +13,14 @@ import type { ASTValidationContext } from '../ValidationContext'; * * A GraphQL document is only valid if all fragment definitions are spread * within operations, or spread within other fragments spread within operations. + * + * See https://spec.graphql.org/draft/#sec-Fragments-Must-Be-Used */ export function NoUnusedFragmentsRule( context: ASTValidationContext, ): ASTVisitor { - const operationDefs = []; - const fragmentDefs = []; + const operationDefs: Array = []; + const fragmentDefs: Array = []; return { OperationDefinition(node) { @@ -40,10 +46,9 @@ export function NoUnusedFragmentsRule( const fragName = fragmentDef.name.value; if (fragmentNameUsed[fragName] !== true) { context.reportError( - new GraphQLError( - `Fragment "${fragName}" is never used.`, - fragmentDef, - ), + new GraphQLError(`Fragment "${fragName}" is never used.`, { + nodes: fragmentDef, + }), ); } } diff --git a/src/validation/rules/NoUnusedVariablesRule.d.ts b/src/validation/rules/NoUnusedVariablesRule.d.ts deleted file mode 100644 index 351449d8b9..0000000000 --- a/src/validation/rules/NoUnusedVariablesRule.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * No unused variables - * - * A GraphQL operation is only valid if all variables defined by an operation - * are used, either directly or within a spread fragment. - */ -export function NoUnusedVariablesRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/NoUnusedVariablesRule.js b/src/validation/rules/NoUnusedVariablesRule.ts similarity index 85% rename from src/validation/rules/NoUnusedVariablesRule.js rename to src/validation/rules/NoUnusedVariablesRule.ts index 70bc81c941..5083af4f28 100644 --- a/src/validation/rules/NoUnusedVariablesRule.js +++ b/src/validation/rules/NoUnusedVariablesRule.ts @@ -1,5 +1,6 @@ import { GraphQLError } from '../../error/GraphQLError'; +import type { VariableDefinitionNode } from '../../language/ast'; import type { ASTVisitor } from '../../language/visitor'; import type { ValidationContext } from '../ValidationContext'; @@ -9,9 +10,11 @@ import type { ValidationContext } from '../ValidationContext'; * * A GraphQL operation is only valid if all variables defined by an operation * are used, either directly or within a spread fragment. + * + * See https://spec.graphql.org/draft/#sec-All-Variables-Used */ export function NoUnusedVariablesRule(context: ValidationContext): ASTVisitor { - let variableDefs = []; + let variableDefs: Array = []; return { OperationDefinition: { @@ -34,7 +37,7 @@ export function NoUnusedVariablesRule(context: ValidationContext): ASTVisitor { operation.name ? `Variable "$${variableName}" is never used in operation "${operation.name.value}".` : `Variable "$${variableName}" is never used.`, - variableDef, + { nodes: variableDef }, ), ); } diff --git a/src/validation/rules/OverlappingFieldsCanBeMergedRule.d.ts b/src/validation/rules/OverlappingFieldsCanBeMergedRule.d.ts deleted file mode 100644 index c1671c265a..0000000000 --- a/src/validation/rules/OverlappingFieldsCanBeMergedRule.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Overlapping fields can be merged - * - * A selection set is only valid if all fields (including spreading any - * fragments) either correspond to distinct response names or can be merged - * without ambiguity. - */ -export function OverlappingFieldsCanBeMergedRule( - context: ValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/OverlappingFieldsCanBeMergedRule.js b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts similarity index 71% rename from src/validation/rules/OverlappingFieldsCanBeMergedRule.js rename to src/validation/rules/OverlappingFieldsCanBeMergedRule.ts index 2d79dd098f..8397a35b80 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMergedRule.js +++ b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts @@ -1,37 +1,35 @@ -import find from '../../polyfills/find'; -import objectEntries from '../../polyfills/objectEntries'; - +import { inspect } from '../../jsutils/inspect'; +import type { Maybe } from '../../jsutils/Maybe'; import type { ObjMap } from '../../jsutils/ObjMap'; -import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import type { - SelectionSetNode, - ValueNode, + DirectiveNode, FieldNode, - ArgumentNode, FragmentDefinitionNode, + SelectionSetNode, + ValueNode, } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { print } from '../../language/printer'; +import type { ASTVisitor } from '../../language/visitor'; import type { + GraphQLField, GraphQLNamedType, GraphQLOutputType, - GraphQLCompositeType, - GraphQLField, } from '../../type/definition'; import { getNamedType, - isNonNullType, + isInterfaceType, isLeafType, - isObjectType, isListType, - isInterfaceType, + isNonNullType, + isObjectType, } from '../../type/definition'; +import { sortValueNode } from '../../utilities/sortValueNode'; import { typeFromAST } from '../../utilities/typeFromAST'; import type { ValidationContext } from '../ValidationContext'; @@ -55,14 +53,20 @@ function reasonMessage(reason: ConflictReasonMessage): string { * A selection set is only valid if all fields (including spreading any * fragments) either correspond to distinct response names or can be merged * without ambiguity. + * + * See https://spec.graphql.org/draft/#sec-Field-Selection-Merging */ export function OverlappingFieldsCanBeMergedRule( context: ValidationContext, ): ASTVisitor { - // A memoization for when two fragments are compared "between" each other for - // conflicts. Two fragments may be compared many times, so memoizing this can - // dramatically improve the performance of this validator. - const comparedFragmentPairs = new PairSet(); + // A memoization for when fields and a fragment or two fragments are compared + // "between" each other for conflicts. Comparisons made be made many times, + // so memoizing this can dramatically improve the performance of this validator. + const comparedFieldsAndFragmentPairs = new OrderedPairSet< + NodeAndDefCollection, + string + >(); + const comparedFragmentPairs = new PairSet(); // A cache for the "field map" and list of fragment names found in any given // selection set. Selection sets may be asked for this information multiple @@ -74,6 +78,7 @@ export function OverlappingFieldsCanBeMergedRule( const conflicts = findConflictsWithinSelectionSet( context, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, context.getParentType(), selectionSet, @@ -83,7 +88,7 @@ export function OverlappingFieldsCanBeMergedRule( context.reportError( new GraphQLError( `Fields "${responseName}" conflict because ${reasonMsg}. Use different aliases on the fields to fetch both if this was intentional.`, - fields1.concat(fields2), + { nodes: fields1.concat(fields2) }, ), ); } @@ -98,12 +103,14 @@ type ConflictReason = [string, ConflictReasonMessage]; type ConflictReasonMessage = string | Array; // Tuple defining a field node in a context. type NodeAndDef = [ - GraphQLCompositeType, + Maybe, FieldNode, - ?GraphQLField, + Maybe>, ]; // Map of array of those. type NodeAndDefCollection = ObjMap>; +type FragmentNames = Array; +type FieldsAndFragmentNames = readonly [NodeAndDefCollection, FragmentNames]; /** * Algorithm: @@ -165,12 +172,13 @@ type NodeAndDefCollection = ObjMap>; // GraphQL Document. function findConflictsWithinSelectionSet( context: ValidationContext, - cachedFieldsAndFragmentNames, - comparedFragmentPairs: PairSet, - parentType: ?GraphQLNamedType, + cachedFieldsAndFragmentNames: Map, + comparedFieldsAndFragmentPairs: OrderedPairSet, + comparedFragmentPairs: PairSet, + parentType: Maybe, selectionSet: SelectionSetNode, ): Array { - const conflicts = []; + const conflicts: Array = []; const [fieldMap, fragmentNames] = getFieldsAndFragmentNames( context, @@ -185,6 +193,7 @@ function findConflictsWithinSelectionSet( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, fieldMap, ); @@ -197,6 +206,7 @@ function findConflictsWithinSelectionSet( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, false, fieldMap, @@ -211,6 +221,7 @@ function findConflictsWithinSelectionSet( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, false, fragmentNames[i], @@ -227,22 +238,41 @@ function findConflictsWithinSelectionSet( function collectConflictsBetweenFieldsAndFragment( context: ValidationContext, conflicts: Array, - cachedFieldsAndFragmentNames, - comparedFragmentPairs: PairSet, + cachedFieldsAndFragmentNames: Map, + comparedFieldsAndFragmentPairs: OrderedPairSet, + comparedFragmentPairs: PairSet, areMutuallyExclusive: boolean, fieldMap: NodeAndDefCollection, fragmentName: string, ): void { + // Memoize so the fields and fragments are not compared for conflicts more + // than once. + if ( + comparedFieldsAndFragmentPairs.has( + fieldMap, + fragmentName, + areMutuallyExclusive, + ) + ) { + return; + } + comparedFieldsAndFragmentPairs.add( + fieldMap, + fragmentName, + areMutuallyExclusive, + ); + const fragment = context.getFragment(fragmentName); if (!fragment) { return; } - const [fieldMap2, fragmentNames2] = getReferencedFieldsAndFragmentNames( - context, - cachedFieldsAndFragmentNames, - fragment, - ); + const [fieldMap2, referencedFragmentNames] = + getReferencedFieldsAndFragmentNames( + context, + cachedFieldsAndFragmentNames, + fragment, + ); // Do not compare a fragment's fieldMap to itself. if (fieldMap === fieldMap2) { @@ -255,6 +285,7 @@ function collectConflictsBetweenFieldsAndFragment( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, fieldMap, @@ -263,15 +294,16 @@ function collectConflictsBetweenFieldsAndFragment( // (E) Then collect any conflicts between the provided collection of fields // and any fragment names found in the given fragment. - for (let i = 0; i < fragmentNames2.length; i++) { + for (const referencedFragmentName of referencedFragmentNames) { collectConflictsBetweenFieldsAndFragment( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, fieldMap, - fragmentNames2[i], + referencedFragmentName, ); } } @@ -281,8 +313,9 @@ function collectConflictsBetweenFieldsAndFragment( function collectConflictsBetweenFragments( context: ValidationContext, conflicts: Array, - cachedFieldsAndFragmentNames, - comparedFragmentPairs: PairSet, + cachedFieldsAndFragmentNames: Map, + comparedFieldsAndFragmentPairs: OrderedPairSet, + comparedFragmentPairs: PairSet, areMutuallyExclusive: boolean, fragmentName1: string, fragmentName2: string, @@ -310,16 +343,18 @@ function collectConflictsBetweenFragments( return; } - const [fieldMap1, fragmentNames1] = getReferencedFieldsAndFragmentNames( - context, - cachedFieldsAndFragmentNames, - fragment1, - ); - const [fieldMap2, fragmentNames2] = getReferencedFieldsAndFragmentNames( - context, - cachedFieldsAndFragmentNames, - fragment2, - ); + const [fieldMap1, referencedFragmentNames1] = + getReferencedFieldsAndFragmentNames( + context, + cachedFieldsAndFragmentNames, + fragment1, + ); + const [fieldMap2, referencedFragmentNames2] = + getReferencedFieldsAndFragmentNames( + context, + cachedFieldsAndFragmentNames, + fragment2, + ); // (F) First, collect all conflicts between these two collections of fields // (not including any nested fragments). @@ -327,6 +362,7 @@ function collectConflictsBetweenFragments( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, @@ -335,28 +371,30 @@ function collectConflictsBetweenFragments( // (G) Then collect conflicts between the first fragment and any nested // fragments spread in the second fragment. - for (let j = 0; j < fragmentNames2.length; j++) { + for (const referencedFragmentName2 of referencedFragmentNames2) { collectConflictsBetweenFragments( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, - fragmentNames2[j], + referencedFragmentName2, ); } // (G) Then collect conflicts between the second fragment and any nested // fragments spread in the first fragment. - for (let i = 0; i < fragmentNames1.length; i++) { + for (const referencedFragmentName1 of referencedFragmentNames1) { collectConflictsBetweenFragments( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, - fragmentNames1[i], + referencedFragmentName1, fragmentName2, ); } @@ -367,15 +405,16 @@ function collectConflictsBetweenFragments( // between the sub-fields of two overlapping fields. function findConflictsBetweenSubSelectionSets( context: ValidationContext, - cachedFieldsAndFragmentNames, - comparedFragmentPairs: PairSet, + cachedFieldsAndFragmentNames: Map, + comparedFieldsAndFragmentPairs: OrderedPairSet, + comparedFragmentPairs: PairSet, areMutuallyExclusive: boolean, - parentType1: ?GraphQLNamedType, + parentType1: Maybe, selectionSet1: SelectionSetNode, - parentType2: ?GraphQLNamedType, + parentType2: Maybe, selectionSet2: SelectionSetNode, ): Array { - const conflicts = []; + const conflicts: Array = []; const [fieldMap1, fragmentNames1] = getFieldsAndFragmentNames( context, @@ -395,6 +434,7 @@ function findConflictsBetweenSubSelectionSets( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, @@ -403,49 +443,48 @@ function findConflictsBetweenSubSelectionSets( // (I) Then collect conflicts between the first collection of fields and // those referenced by each fragment name associated with the second. - if (fragmentNames2.length !== 0) { - for (let j = 0; j < fragmentNames2.length; j++) { - collectConflictsBetweenFieldsAndFragment( - context, - conflicts, - cachedFieldsAndFragmentNames, - comparedFragmentPairs, - areMutuallyExclusive, - fieldMap1, - fragmentNames2[j], - ); - } + for (const fragmentName2 of fragmentNames2) { + collectConflictsBetweenFieldsAndFragment( + context, + conflicts, + cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, + comparedFragmentPairs, + areMutuallyExclusive, + fieldMap1, + fragmentName2, + ); } // (I) Then collect conflicts between the second collection of fields and // those referenced by each fragment name associated with the first. - if (fragmentNames1.length !== 0) { - for (let i = 0; i < fragmentNames1.length; i++) { - collectConflictsBetweenFieldsAndFragment( - context, - conflicts, - cachedFieldsAndFragmentNames, - comparedFragmentPairs, - areMutuallyExclusive, - fieldMap2, - fragmentNames1[i], - ); - } + for (const fragmentName1 of fragmentNames1) { + collectConflictsBetweenFieldsAndFragment( + context, + conflicts, + cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, + comparedFragmentPairs, + areMutuallyExclusive, + fieldMap2, + fragmentName1, + ); } // (J) Also collect conflicts between any fragment names by the first and // fragment names by the second. This compares each item in the first set of // names to each item in the second set of names. - for (let i = 0; i < fragmentNames1.length; i++) { - for (let j = 0; j < fragmentNames2.length; j++) { + for (const fragmentName1 of fragmentNames1) { + for (const fragmentName2 of fragmentNames2) { collectConflictsBetweenFragments( context, conflicts, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, - fragmentNames1[i], - fragmentNames2[j], + fragmentName1, + fragmentName2, ); } } @@ -456,15 +495,16 @@ function findConflictsBetweenSubSelectionSets( function collectConflictsWithin( context: ValidationContext, conflicts: Array, - cachedFieldsAndFragmentNames, - comparedFragmentPairs: PairSet, + cachedFieldsAndFragmentNames: Map, + comparedFieldsAndFragmentPairs: OrderedPairSet, + comparedFragmentPairs: PairSet, fieldMap: NodeAndDefCollection, ): void { // A field map is a keyed collection, where each key represents a response // name and the value at that key is a list of all fields which provide that // response name. For every response name, if there are multiple fields, they // must be compared to find a potential conflict. - for (const [responseName, fields] of objectEntries(fieldMap)) { + for (const [responseName, fields] of Object.entries(fieldMap)) { // This compares every field in the list to every other field in this list // (except to itself). If the list only has one item, nothing needs to // be compared. @@ -474,6 +514,7 @@ function collectConflictsWithin( const conflict = findConflict( context, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, false, // within one collection is never mutually exclusive responseName, @@ -497,8 +538,9 @@ function collectConflictsWithin( function collectConflictsBetween( context: ValidationContext, conflicts: Array, - cachedFieldsAndFragmentNames, - comparedFragmentPairs: PairSet, + cachedFieldsAndFragmentNames: Map, + comparedFieldsAndFragmentPairs: OrderedPairSet, + comparedFragmentPairs: PairSet, parentFieldsAreMutuallyExclusive: boolean, fieldMap1: NodeAndDefCollection, fieldMap2: NodeAndDefCollection, @@ -508,20 +550,20 @@ function collectConflictsBetween( // response name. For any response name which appears in both provided field // maps, each field from the first field map must be compared to every field // in the second field map to find potential conflicts. - for (const responseName of Object.keys(fieldMap1)) { + for (const [responseName, fields1] of Object.entries(fieldMap1)) { const fields2 = fieldMap2[responseName]; if (fields2) { - const fields1 = fieldMap1[responseName]; - for (let i = 0; i < fields1.length; i++) { - for (let j = 0; j < fields2.length; j++) { + for (const field1 of fields1) { + for (const field2 of fields2) { const conflict = findConflict( context, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, - fields1[i], - fields2[j], + field1, + field2, ); if (conflict) { conflicts.push(conflict); @@ -536,13 +578,14 @@ function collectConflictsBetween( // comparing their sub-fields. function findConflict( context: ValidationContext, - cachedFieldsAndFragmentNames, - comparedFragmentPairs: PairSet, + cachedFieldsAndFragmentNames: Map, + comparedFieldsAndFragmentPairs: OrderedPairSet, + comparedFragmentPairs: PairSet, parentFieldsAreMutuallyExclusive: boolean, responseName: string, field1: NodeAndDef, field2: NodeAndDef, -): ?Conflict { +): Maybe { const [parentType1, node1, def1] = field1; const [parentType2, node2, def2] = field2; @@ -572,12 +615,8 @@ function findConflict( ]; } - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const args1 = node1.arguments ?? []; - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const args2 = node2.arguments ?? []; // Two field calls must have the same arguments. - if (!sameArguments(args1, args2)) { + if (!sameArguments(node1, node2)) { return [ [responseName, 'they have differing arguments'], [node1], @@ -612,6 +651,7 @@ function findConflict( const conflicts = findConflictsBetweenSubSelectionSets( context, cachedFieldsAndFragmentNames, + comparedFieldsAndFragmentPairs, comparedFragmentPairs, areMutuallyExclusive, getNamedType(type1), @@ -624,26 +664,40 @@ function findConflict( } function sameArguments( - arguments1: $ReadOnlyArray, - arguments2: $ReadOnlyArray, + node1: FieldNode | DirectiveNode, + node2: FieldNode | DirectiveNode, ): boolean { - if (arguments1.length !== arguments2.length) { + const args1 = node1.arguments; + const args2 = node2.arguments; + + if (args1 === undefined || args1.length === 0) { + return args2 === undefined || args2.length === 0; + } + if (args2 === undefined || args2.length === 0) { return false; } - return arguments1.every((argument1) => { - const argument2 = find( - arguments2, - (argument) => argument.name.value === argument1.name.value, - ); - if (!argument2) { + + /* c8 ignore next */ + if (args1.length !== args2.length) { + /* c8 ignore next */ + return false; + /* c8 ignore next */ + } + + const values2 = new Map(args2.map(({ name, value }) => [name.value, value])); + return args1.every((arg1) => { + const value1 = arg1.value; + const value2 = values2.get(arg1.name.value); + if (value2 === undefined) { return false; } - return sameValue(argument1.value, argument2.value); + + return stringifyValue(value1) === stringifyValue(value2); }); } -function sameValue(value1: ValueNode, value2: ValueNode): boolean { - return print(value1) === print(value2); +function stringifyValue(value: ValueNode): string | null { + return print(sortValueNode(value)); } // Two types conflict if both types could not apply to a value simultaneously. @@ -680,32 +734,33 @@ function doTypesConflict( // referenced via fragment spreads. function getFieldsAndFragmentNames( context: ValidationContext, - cachedFieldsAndFragmentNames, - parentType: ?GraphQLNamedType, + cachedFieldsAndFragmentNames: Map, + parentType: Maybe, selectionSet: SelectionSetNode, -): [NodeAndDefCollection, Array] { - let cached = cachedFieldsAndFragmentNames.get(selectionSet); - if (!cached) { - const nodeAndDefs = Object.create(null); - const fragmentNames = Object.create(null); - _collectFieldsAndFragmentNames( - context, - parentType, - selectionSet, - nodeAndDefs, - fragmentNames, - ); - cached = [nodeAndDefs, Object.keys(fragmentNames)]; - cachedFieldsAndFragmentNames.set(selectionSet, cached); +): FieldsAndFragmentNames { + const cached = cachedFieldsAndFragmentNames.get(selectionSet); + if (cached) { + return cached; } - return cached; + const nodeAndDefs: NodeAndDefCollection = Object.create(null); + const fragmentNames: ObjMap = Object.create(null); + _collectFieldsAndFragmentNames( + context, + parentType, + selectionSet, + nodeAndDefs, + fragmentNames, + ); + const result = [nodeAndDefs, Object.keys(fragmentNames)] as const; + cachedFieldsAndFragmentNames.set(selectionSet, result); + return result; } // Given a reference to a fragment, return the represented collection of fields // as well as a list of nested fragment names referenced via fragment spreads. function getReferencedFieldsAndFragmentNames( context: ValidationContext, - cachedFieldsAndFragmentNames, + cachedFieldsAndFragmentNames: Map, fragment: FragmentDefinitionNode, ) { // Short-circuit building a type from the node if possible. @@ -725,10 +780,10 @@ function getReferencedFieldsAndFragmentNames( function _collectFieldsAndFragmentNames( context: ValidationContext, - parentType: ?GraphQLNamedType, + parentType: Maybe, selectionSet: SelectionSetNode, - nodeAndDefs, - fragmentNames, + nodeAndDefs: NodeAndDefCollection, + fragmentNames: ObjMap, ): void { for (const selection of selectionSet.selections) { switch (selection.kind) { @@ -771,62 +826,75 @@ function _collectFieldsAndFragmentNames( // Given a series of Conflicts which occurred between two sub-fields, generate // a single Conflict. function subfieldConflicts( - conflicts: $ReadOnlyArray, + conflicts: ReadonlyArray, responseName: string, node1: FieldNode, node2: FieldNode, -): ?Conflict { +): Maybe { if (conflicts.length > 0) { return [ [responseName, conflicts.map(([reason]) => reason)], - conflicts.reduce((allFields, [, fields1]) => allFields.concat(fields1), [ - node1, - ]), - conflicts.reduce( - (allFields, [, , fields2]) => allFields.concat(fields2), - [node2], - ), + [node1, ...conflicts.map(([, fields1]) => fields1).flat()], + [node2, ...conflicts.map(([, , fields2]) => fields2).flat()], ]; } } /** - * A way to keep track of pairs of things when the ordering of the pair does - * not matter. We do this by maintaining a sort of double adjacency sets. + * A way to keep track of pairs of things where the ordering of the pair + * matters. + * + * Provides a third argument for has/set to allow flagging the pair as + * weakly or strongly present within the collection. */ -class PairSet { - _data: ObjMap>; +class OrderedPairSet { + _data: Map>; constructor() { - this._data = Object.create(null); + this._data = new Map(); } - has(a: string, b: string, areMutuallyExclusive: boolean): boolean { - const first = this._data[a]; - const result = first && first[b]; + has(a: T, b: U, weaklyPresent: boolean): boolean { + const result = this._data.get(a)?.get(b); if (result === undefined) { return false; } - // areMutuallyExclusive being false is a superset of being true, - // hence if we want to know if this PairSet "has" these two with no - // exclusivity, we have to ensure it was added as such. - if (areMutuallyExclusive === false) { - return result === false; + + return weaklyPresent ? true : weaklyPresent === result; + } + + add(a: T, b: U, weaklyPresent: boolean): void { + const map = this._data.get(a); + if (map === undefined) { + this._data.set(a, new Map([[b, weaklyPresent]])); + } else { + map.set(b, weaklyPresent); } - return true; + } +} + +/** + * A way to keep track of pairs of similar things when the ordering of the pair + * does not matter. + */ +class PairSet { + _orderedPairSet: OrderedPairSet; + + constructor() { + this._orderedPairSet = new OrderedPairSet(); } - add(a: string, b: string, areMutuallyExclusive: boolean): void { - this._pairSetAdd(a, b, areMutuallyExclusive); - this._pairSetAdd(b, a, areMutuallyExclusive); + has(a: T, b: T, weaklyPresent: boolean): boolean { + return a < b + ? this._orderedPairSet.has(a, b, weaklyPresent) + : this._orderedPairSet.has(b, a, weaklyPresent); } - _pairSetAdd(a: string, b: string, areMutuallyExclusive: boolean): void { - let map = this._data[a]; - if (!map) { - map = Object.create(null); - this._data[a] = map; + add(a: T, b: T, weaklyPresent: boolean): void { + if (a < b) { + this._orderedPairSet.add(a, b, weaklyPresent); + } else { + this._orderedPairSet.add(b, a, weaklyPresent); } - map[b] = areMutuallyExclusive; } } diff --git a/src/validation/rules/PossibleFragmentSpreadsRule.d.ts b/src/validation/rules/PossibleFragmentSpreadsRule.d.ts deleted file mode 100644 index 36f551df5d..0000000000 --- a/src/validation/rules/PossibleFragmentSpreadsRule.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Possible fragment spread - * - * A fragment spread is only valid if the type condition could ever possibly - * be true: if there is a non-empty intersection of the possible parent types, - * and possible types which pass the type condition. - */ -export function PossibleFragmentSpreadsRule( - context: ValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/PossibleFragmentSpreadsRule.js b/src/validation/rules/PossibleFragmentSpreadsRule.ts similarity index 92% rename from src/validation/rules/PossibleFragmentSpreadsRule.js rename to src/validation/rules/PossibleFragmentSpreadsRule.ts index ba4e9ca5ef..fe738e5559 100644 --- a/src/validation/rules/PossibleFragmentSpreadsRule.js +++ b/src/validation/rules/PossibleFragmentSpreadsRule.ts @@ -1,4 +1,5 @@ -import inspect from '../../jsutils/inspect'; +import { inspect } from '../../jsutils/inspect'; +import type { Maybe } from '../../jsutils/Maybe'; import { GraphQLError } from '../../error/GraphQLError'; @@ -7,8 +8,8 @@ import type { ASTVisitor } from '../../language/visitor'; import type { GraphQLCompositeType } from '../../type/definition'; import { isCompositeType } from '../../type/definition'; -import { typeFromAST } from '../../utilities/typeFromAST'; import { doTypesOverlap } from '../../utilities/typeComparators'; +import { typeFromAST } from '../../utilities/typeFromAST'; import type { ValidationContext } from '../ValidationContext'; @@ -36,7 +37,7 @@ export function PossibleFragmentSpreadsRule( context.reportError( new GraphQLError( `Fragment cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`, - node, + { nodes: node }, ), ); } @@ -55,7 +56,7 @@ export function PossibleFragmentSpreadsRule( context.reportError( new GraphQLError( `Fragment "${fragName}" cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`, - node, + { nodes: node }, ), ); } @@ -66,7 +67,7 @@ export function PossibleFragmentSpreadsRule( function getFragmentType( context: ValidationContext, name: string, -): ?GraphQLCompositeType { +): Maybe { const frag = context.getFragment(name); if (frag) { const type = typeFromAST(context.getSchema(), frag.typeCondition); diff --git a/src/validation/rules/PossibleTypeExtensions.d.ts b/src/validation/rules/PossibleTypeExtensions.d.ts deleted file mode 100644 index 7573375e6d..0000000000 --- a/src/validation/rules/PossibleTypeExtensions.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { PossibleTypeExtensionsRule } from 'graphql' - * or - * import { PossibleTypeExtensionsRule } from 'graphql/validation' - */ -export { PossibleTypeExtensionsRule as PossibleTypeExtensions } from './PossibleTypeExtensionsRule'; diff --git a/src/validation/rules/PossibleTypeExtensions.js b/src/validation/rules/PossibleTypeExtensions.js deleted file mode 100644 index 7573375e6d..0000000000 --- a/src/validation/rules/PossibleTypeExtensions.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { PossibleTypeExtensionsRule } from 'graphql' - * or - * import { PossibleTypeExtensionsRule } from 'graphql/validation' - */ -export { PossibleTypeExtensionsRule as PossibleTypeExtensions } from './PossibleTypeExtensionsRule'; diff --git a/src/validation/rules/PossibleTypeExtensionsRule.d.ts b/src/validation/rules/PossibleTypeExtensionsRule.d.ts deleted file mode 100644 index 8337dc5bd7..0000000000 --- a/src/validation/rules/PossibleTypeExtensionsRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { SDLValidationContext } from '../ValidationContext'; - -/** - * Possible type extension - * - * A type extension is only valid if the type is defined and has the same kind. - */ -export function PossibleTypeExtensionsRule( - context: SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/PossibleTypeExtensionsRule.js b/src/validation/rules/PossibleTypeExtensionsRule.ts similarity index 72% rename from src/validation/rules/PossibleTypeExtensionsRule.js rename to src/validation/rules/PossibleTypeExtensionsRule.ts index 2f098191ef..57d16b473f 100644 --- a/src/validation/rules/PossibleTypeExtensionsRule.js +++ b/src/validation/rules/PossibleTypeExtensionsRule.ts @@ -1,24 +1,24 @@ -import inspect from '../../jsutils/inspect'; -import invariant from '../../jsutils/invariant'; -import didYouMean from '../../jsutils/didYouMean'; -import suggestionList from '../../jsutils/suggestionList'; +import { didYouMean } from '../../jsutils/didYouMean'; +import { inspect } from '../../jsutils/inspect'; +import { invariant } from '../../jsutils/invariant'; +import type { ObjMap } from '../../jsutils/ObjMap'; +import { suggestionList } from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { KindEnum } from '../../language/kinds'; -import type { ASTVisitor } from '../../language/visitor'; -import type { TypeExtensionNode } from '../../language/ast'; +import type { DefinitionNode, TypeExtensionNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { isTypeDefinitionNode } from '../../language/predicates'; +import type { ASTVisitor } from '../../language/visitor'; import type { GraphQLNamedType } from '../../type/definition'; import { - isScalarType, - isObjectType, - isInterfaceType, - isUnionType, isEnumType, isInputObjectType, + isInterfaceType, + isObjectType, + isScalarType, + isUnionType, } from '../../type/definition'; import type { SDLValidationContext } from '../ValidationContext'; @@ -32,7 +32,7 @@ export function PossibleTypeExtensionsRule( context: SDLValidationContext, ): ASTVisitor { const schema = context.getSchema(); - const definedTypes = Object.create(null); + const definedTypes: ObjMap = Object.create(null); for (const def of context.getDocument().definitions) { if (isTypeDefinitionNode(def)) { @@ -54,7 +54,7 @@ export function PossibleTypeExtensionsRule( const defNode = definedTypes[typeName]; const existingType = schema?.getType(typeName); - let expectedKind; + let expectedKind: Kind | undefined; if (defNode) { expectedKind = defKindToExtKind[defNode.kind]; } else if (existingType) { @@ -65,31 +65,30 @@ export function PossibleTypeExtensionsRule( if (expectedKind !== node.kind) { const kindStr = extensionKindToTypeName(node.kind); context.reportError( - new GraphQLError( - `Cannot extend non-${kindStr} type "${typeName}".`, - defNode ? [defNode, node] : node, - ), + new GraphQLError(`Cannot extend non-${kindStr} type "${typeName}".`, { + nodes: defNode ? [defNode, node] : node, + }), ); } } else { - let allTypeNames = Object.keys(definedTypes); - if (schema) { - allTypeNames = allTypeNames.concat(Object.keys(schema.getTypeMap())); - } + const allTypeNames = Object.keys({ + ...definedTypes, + ...schema?.getTypeMap(), + }); const suggestedTypes = suggestionList(typeName, allTypeNames); context.reportError( new GraphQLError( `Cannot extend type "${typeName}" because it is not defined.` + didYouMean(suggestedTypes), - node.name, + { nodes: node.name }, ), ); } } } -const defKindToExtKind = { +const defKindToExtKind: ObjMap = { [Kind.SCALAR_TYPE_DEFINITION]: Kind.SCALAR_TYPE_EXTENSION, [Kind.OBJECT_TYPE_DEFINITION]: Kind.OBJECT_TYPE_EXTENSION, [Kind.INTERFACE_TYPE_DEFINITION]: Kind.INTERFACE_TYPE_EXTENSION, @@ -98,7 +97,7 @@ const defKindToExtKind = { [Kind.INPUT_OBJECT_TYPE_DEFINITION]: Kind.INPUT_OBJECT_TYPE_EXTENSION, }; -function typeToExtKind(type: GraphQLNamedType): KindEnum { +function typeToExtKind(type: GraphQLNamedType): Kind { if (isScalarType(type)) { return Kind.SCALAR_TYPE_EXTENSION; } @@ -114,16 +113,15 @@ function typeToExtKind(type: GraphQLNamedType): KindEnum { if (isEnumType(type)) { return Kind.ENUM_TYPE_EXTENSION; } - // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isInputObjectType(type)) { return Kind.INPUT_OBJECT_TYPE_EXTENSION; } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + /* c8 ignore next 3 */ + // Not reachable. All possible types have been considered + invariant(false, 'Unexpected type: ' + inspect(type)); } -function extensionKindToTypeName(kind: KindEnum): string { +function extensionKindToTypeName(kind: Kind): string { switch (kind) { case Kind.SCALAR_TYPE_EXTENSION: return 'scalar'; @@ -137,8 +135,9 @@ function extensionKindToTypeName(kind: KindEnum): string { return 'enum'; case Kind.INPUT_OBJECT_TYPE_EXTENSION: return 'input object'; + // Not reachable. All possible types have been considered + /* c8 ignore next */ + default: + invariant(false, 'Unexpected kind: ' + inspect(kind)); } - - // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected kind: ' + inspect(kind)); } diff --git a/src/validation/rules/ProvidedRequiredArgumentsRule.d.ts b/src/validation/rules/ProvidedRequiredArgumentsRule.d.ts deleted file mode 100644 index 116069ceac..0000000000 --- a/src/validation/rules/ProvidedRequiredArgumentsRule.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext, SDLValidationContext } from '../ValidationContext'; - -/** - * Provided required arguments - * - * A field or directive is only valid if all required (non-null without a - * default value) field arguments have been provided. - */ -export function ProvidedRequiredArgumentsRule( - context: ValidationContext, -): ASTVisitor; - -/** - * @internal - */ -export function ProvidedRequiredArgumentsOnDirectivesRule( - context: ValidationContext | SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/ProvidedRequiredArgumentsRule.js b/src/validation/rules/ProvidedRequiredArgumentsRule.ts similarity index 66% rename from src/validation/rules/ProvidedRequiredArgumentsRule.js rename to src/validation/rules/ProvidedRequiredArgumentsRule.ts index b9ff7a032b..b111dcee1b 100644 --- a/src/validation/rules/ProvidedRequiredArgumentsRule.js +++ b/src/validation/rules/ProvidedRequiredArgumentsRule.ts @@ -1,19 +1,21 @@ -import inspect from '../../jsutils/inspect'; -import keyMap from '../../jsutils/keyMap'; +import { inspect } from '../../jsutils/inspect'; +import { keyMap } from '../../jsutils/keyMap'; +import type { ObjMap } from '../../jsutils/ObjMap'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import type { InputValueDefinitionNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { print } from '../../language/printer'; +import type { ASTVisitor } from '../../language/visitor'; +import type { GraphQLArgument } from '../../type/definition'; +import { isRequiredArgument, isType } from '../../type/definition'; import { specifiedDirectives } from '../../type/directives'; -import { isType, isRequiredArgument } from '../../type/definition'; import type { - ValidationContext, SDLValidationContext, + ValidationContext, } from '../ValidationContext'; /** @@ -36,17 +38,18 @@ export function ProvidedRequiredArgumentsRule( return false; } - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - const argNodes = fieldNode.arguments ?? []; - const argNodeMap = keyMap(argNodes, (arg) => arg.name.value); + const providedArgs = new Set( + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ + fieldNode.arguments?.map((arg) => arg.name.value), + ); for (const argDef of fieldDef.args) { - const argNode = argNodeMap[argDef.name]; - if (!argNode && isRequiredArgument(argDef)) { + if (!providedArgs.has(argDef.name) && isRequiredArgument(argDef)) { const argTypeStr = inspect(argDef.type); context.reportError( new GraphQLError( `Field "${fieldDef.name}" argument "${argDef.name}" of type "${argTypeStr}" is required, but it was not provided.`, - fieldNode, + { nodes: fieldNode }, ), ); } @@ -62,12 +65,12 @@ export function ProvidedRequiredArgumentsRule( export function ProvidedRequiredArgumentsOnDirectivesRule( context: ValidationContext | SDLValidationContext, ): ASTVisitor { - const requiredArgsMap = Object.create(null); + const requiredArgsMap: ObjMap< + ObjMap + > = Object.create(null); const schema = context.getSchema(); - const definedDirectives = schema - ? schema.getDirectives() - : specifiedDirectives; + const definedDirectives = schema?.getDirectives() ?? specifiedDirectives; for (const directive of definedDirectives) { requiredArgsMap[directive.name] = keyMap( directive.args.filter(isRequiredArgument), @@ -78,7 +81,8 @@ export function ProvidedRequiredArgumentsOnDirectivesRule( const astDefinitions = context.getDocument().definitions; for (const def of astDefinitions) { if (def.kind === Kind.DIRECTIVE_DEFINITION) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const argNodes = def.arguments ?? []; requiredArgsMap[def.name.value] = keyMap( @@ -95,20 +99,19 @@ export function ProvidedRequiredArgumentsOnDirectivesRule( const directiveName = directiveNode.name.value; const requiredArgs = requiredArgsMap[directiveName]; if (requiredArgs) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const argNodes = directiveNode.arguments ?? []; - const argNodeMap = keyMap(argNodes, (arg) => arg.name.value); - for (const argName of Object.keys(requiredArgs)) { - if (!argNodeMap[argName]) { - const argType = requiredArgs[argName].type; - const argTypeStr = isType(argType) - ? inspect(argType) - : print(argType); - + const argNodeMap = new Set(argNodes.map((arg) => arg.name.value)); + for (const [argName, argDef] of Object.entries(requiredArgs)) { + if (!argNodeMap.has(argName)) { + const argType = isType(argDef.type) + ? inspect(argDef.type) + : print(argDef.type); context.reportError( new GraphQLError( - `Directive "@${directiveName}" argument "${argName}" of type "${argTypeStr}" is required, but it was not provided.`, - directiveNode, + `Directive "@${directiveName}" argument "${argName}" of type "${argType}" is required, but it was not provided.`, + { nodes: directiveNode }, ), ); } diff --git a/src/validation/rules/ScalarLeafsRule.d.ts b/src/validation/rules/ScalarLeafsRule.d.ts deleted file mode 100644 index ae956efc8a..0000000000 --- a/src/validation/rules/ScalarLeafsRule.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Scalar leafs - * - * A GraphQL document is valid only if all leaf fields (fields without - * sub selections) are of scalar or enum types. - */ -export function ScalarLeafsRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/ScalarLeafsRule.js b/src/validation/rules/ScalarLeafsRule.ts similarity index 74% rename from src/validation/rules/ScalarLeafsRule.js rename to src/validation/rules/ScalarLeafsRule.ts index a0c0c6cc40..966143c58b 100644 --- a/src/validation/rules/ScalarLeafsRule.js +++ b/src/validation/rules/ScalarLeafsRule.ts @@ -1,4 +1,4 @@ -import inspect from '../../jsutils/inspect'; +import { inspect } from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; @@ -28,7 +28,7 @@ export function ScalarLeafsRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Field "${fieldName}" must not have a selection since type "${typeStr}" has no subfields.`, - selectionSet, + { nodes: selectionSet }, ), ); } @@ -38,7 +38,16 @@ export function ScalarLeafsRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Field "${fieldName}" of type "${typeStr}" must have a selection of subfields. Did you mean "${fieldName} { ... }"?`, - node, + { nodes: node }, + ), + ); + } else if (selectionSet.selections.length === 0) { + const fieldName = node.name.value; + const typeStr = inspect(type); + context.reportError( + new GraphQLError( + `Field "${fieldName}" of type "${typeStr}" must have at least one field selected.`, + { nodes: node }, ), ); } diff --git a/src/validation/rules/SingleFieldSubscriptionsRule.d.ts b/src/validation/rules/SingleFieldSubscriptionsRule.d.ts deleted file mode 100644 index d56c4fdd1d..0000000000 --- a/src/validation/rules/SingleFieldSubscriptionsRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Subscriptions must only include one field. - * - * A GraphQL subscription is valid only if it contains a single root field. - */ -export function SingleFieldSubscriptionsRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/SingleFieldSubscriptionsRule.js b/src/validation/rules/SingleFieldSubscriptionsRule.js deleted file mode 100644 index 760fe3c144..0000000000 --- a/src/validation/rules/SingleFieldSubscriptionsRule.js +++ /dev/null @@ -1,32 +0,0 @@ -import { GraphQLError } from '../../error/GraphQLError'; - -import type { ASTVisitor } from '../../language/visitor'; -import type { OperationDefinitionNode } from '../../language/ast'; - -import type { ASTValidationContext } from '../ValidationContext'; - -/** - * Subscriptions must only include one field. - * - * A GraphQL subscription is valid only if it contains a single root field. - */ -export function SingleFieldSubscriptionsRule( - context: ASTValidationContext, -): ASTVisitor { - return { - OperationDefinition(node: OperationDefinitionNode) { - if (node.operation === 'subscription') { - if (node.selectionSet.selections.length !== 1) { - context.reportError( - new GraphQLError( - node.name - ? `Subscription "${node.name.value}" must select only one top level field.` - : 'Anonymous Subscription must select only one top level field.', - node.selectionSet.selections.slice(1), - ), - ); - } - } - }, - }; -} diff --git a/src/validation/rules/SingleFieldSubscriptionsRule.ts b/src/validation/rules/SingleFieldSubscriptionsRule.ts new file mode 100644 index 0000000000..21cb1abaf6 --- /dev/null +++ b/src/validation/rules/SingleFieldSubscriptionsRule.ts @@ -0,0 +1,82 @@ +import type { ObjMap } from '../../jsutils/ObjMap'; + +import { GraphQLError } from '../../error/GraphQLError'; + +import type { + FragmentDefinitionNode, + OperationDefinitionNode, +} from '../../language/ast'; +import { Kind } from '../../language/kinds'; +import type { ASTVisitor } from '../../language/visitor'; + +import { collectFields } from '../../execution/collectFields'; + +import type { ValidationContext } from '../ValidationContext'; + +/** + * Subscriptions must only include a non-introspection field. + * + * A GraphQL subscription is valid only if it contains a single root field and + * that root field is not an introspection field. + * + * See https://spec.graphql.org/draft/#sec-Single-root-field + */ +export function SingleFieldSubscriptionsRule( + context: ValidationContext, +): ASTVisitor { + return { + OperationDefinition(node: OperationDefinitionNode) { + if (node.operation === 'subscription') { + const schema = context.getSchema(); + const subscriptionType = schema.getSubscriptionType(); + if (subscriptionType) { + const operationName = node.name ? node.name.value : null; + const variableValues: { + [variable: string]: any; + } = Object.create(null); + const document = context.getDocument(); + const fragments: ObjMap = Object.create(null); + for (const definition of document.definitions) { + if (definition.kind === Kind.FRAGMENT_DEFINITION) { + fragments[definition.name.value] = definition; + } + } + const fields = collectFields( + schema, + fragments, + variableValues, + subscriptionType, + node.selectionSet, + ); + if (fields.size > 1) { + const fieldSelectionLists = [...fields.values()]; + const extraFieldSelectionLists = fieldSelectionLists.slice(1); + const extraFieldSelections = extraFieldSelectionLists.flat(); + context.reportError( + new GraphQLError( + operationName != null + ? `Subscription "${operationName}" must select only one top level field.` + : 'Anonymous Subscription must select only one top level field.', + { nodes: extraFieldSelections }, + ), + ); + } + for (const fieldNodes of fields.values()) { + const field = fieldNodes[0]; + const fieldName = field.name.value; + if (fieldName.startsWith('__')) { + context.reportError( + new GraphQLError( + operationName != null + ? `Subscription "${operationName}" must not select an introspection top level field.` + : 'Anonymous Subscription must not select an introspection top level field.', + { nodes: fieldNodes }, + ), + ); + } + } + } + } + }, + }; +} diff --git a/src/validation/rules/UniqueArgumentDefinitionNamesRule.ts b/src/validation/rules/UniqueArgumentDefinitionNamesRule.ts new file mode 100644 index 0000000000..2348276338 --- /dev/null +++ b/src/validation/rules/UniqueArgumentDefinitionNamesRule.ts @@ -0,0 +1,79 @@ +import { groupBy } from '../../jsutils/groupBy'; + +import { GraphQLError } from '../../error/GraphQLError'; + +import type { + FieldDefinitionNode, + InputValueDefinitionNode, + NameNode, +} from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { SDLValidationContext } from '../ValidationContext'; + +/** + * Unique argument definition names + * + * A GraphQL Object or Interface type is only valid if all its fields have uniquely named arguments. + * A GraphQL Directive is only valid if all its arguments are uniquely named. + */ +export function UniqueArgumentDefinitionNamesRule( + context: SDLValidationContext, +): ASTVisitor { + return { + DirectiveDefinition(directiveNode) { + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ + const argumentNodes = directiveNode.arguments ?? []; + + return checkArgUniqueness(`@${directiveNode.name.value}`, argumentNodes); + }, + InterfaceTypeDefinition: checkArgUniquenessPerField, + InterfaceTypeExtension: checkArgUniquenessPerField, + ObjectTypeDefinition: checkArgUniquenessPerField, + ObjectTypeExtension: checkArgUniquenessPerField, + }; + + function checkArgUniquenessPerField(typeNode: { + readonly name: NameNode; + readonly fields?: ReadonlyArray; + }) { + const typeName = typeNode.name.value; + + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ + const fieldNodes = typeNode.fields ?? []; + + for (const fieldDef of fieldNodes) { + const fieldName = fieldDef.name.value; + + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ + const argumentNodes = fieldDef.arguments ?? []; + + checkArgUniqueness(`${typeName}.${fieldName}`, argumentNodes); + } + + return false; + } + + function checkArgUniqueness( + parentName: string, + argumentNodes: ReadonlyArray, + ) { + const seenArgs = groupBy(argumentNodes, (arg) => arg.name.value); + + for (const [argName, argNodes] of seenArgs) { + if (argNodes.length > 1) { + context.reportError( + new GraphQLError( + `Argument "${parentName}(${argName}:)" can only be defined once.`, + { nodes: argNodes.map((node) => node.name) }, + ), + ); + } + } + + return false; + } +} diff --git a/src/validation/rules/UniqueArgumentNamesRule.d.ts b/src/validation/rules/UniqueArgumentNamesRule.d.ts deleted file mode 100644 index 1d0d4f41b3..0000000000 --- a/src/validation/rules/UniqueArgumentNamesRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique argument names - * - * A GraphQL field or directive is only valid if all supplied arguments are - * uniquely named. - */ -export function UniqueArgumentNamesRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueArgumentNamesRule.js b/src/validation/rules/UniqueArgumentNamesRule.js deleted file mode 100644 index 73289efd2f..0000000000 --- a/src/validation/rules/UniqueArgumentNamesRule.js +++ /dev/null @@ -1,38 +0,0 @@ -import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; - -import type { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique argument names - * - * A GraphQL field or directive is only valid if all supplied arguments are - * uniquely named. - */ -export function UniqueArgumentNamesRule( - context: ASTValidationContext, -): ASTVisitor { - let knownArgNames = Object.create(null); - return { - Field() { - knownArgNames = Object.create(null); - }, - Directive() { - knownArgNames = Object.create(null); - }, - Argument(node) { - const argName = node.name.value; - if (knownArgNames[argName]) { - context.reportError( - new GraphQLError( - `There can be only one argument named "${argName}".`, - [knownArgNames[argName], node.name], - ), - ); - } else { - knownArgNames[argName] = node.name; - } - return false; - }, - }; -} diff --git a/src/validation/rules/UniqueArgumentNamesRule.ts b/src/validation/rules/UniqueArgumentNamesRule.ts new file mode 100644 index 0000000000..19667efaa7 --- /dev/null +++ b/src/validation/rules/UniqueArgumentNamesRule.ts @@ -0,0 +1,46 @@ +import { groupBy } from '../../jsutils/groupBy'; + +import { GraphQLError } from '../../error/GraphQLError'; + +import type { ArgumentNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ASTValidationContext } from '../ValidationContext'; + +/** + * Unique argument names + * + * A GraphQL field or directive is only valid if all supplied arguments are + * uniquely named. + * + * See https://spec.graphql.org/draft/#sec-Argument-Names + */ +export function UniqueArgumentNamesRule( + context: ASTValidationContext, +): ASTVisitor { + return { + Field: checkArgUniqueness, + Directive: checkArgUniqueness, + }; + + function checkArgUniqueness(parentNode: { + arguments?: ReadonlyArray; + }) { + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ + const argumentNodes = parentNode.arguments ?? []; + + const seenArgs = groupBy(argumentNodes, (arg) => arg.name.value); + + for (const [argName, argNodes] of seenArgs) { + if (argNodes.length > 1) { + context.reportError( + new GraphQLError( + `There can be only one argument named "${argName}".`, + { nodes: argNodes.map((node) => node.name) }, + ), + ); + } + } + } +} diff --git a/src/validation/rules/UniqueDirectiveNames.d.ts b/src/validation/rules/UniqueDirectiveNames.d.ts deleted file mode 100644 index c197e87cb2..0000000000 --- a/src/validation/rules/UniqueDirectiveNames.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueDirectiveNamesRule } from 'graphql' - * or - * import { UniqueDirectiveNamesRule } from 'graphql/validation' - */ -export { UniqueDirectiveNamesRule as UniqueDirectiveNames } from './UniqueDirectiveNamesRule'; diff --git a/src/validation/rules/UniqueDirectiveNames.js b/src/validation/rules/UniqueDirectiveNames.js deleted file mode 100644 index c197e87cb2..0000000000 --- a/src/validation/rules/UniqueDirectiveNames.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueDirectiveNamesRule } from 'graphql' - * or - * import { UniqueDirectiveNamesRule } from 'graphql/validation' - */ -export { UniqueDirectiveNamesRule as UniqueDirectiveNames } from './UniqueDirectiveNamesRule'; diff --git a/src/validation/rules/UniqueDirectiveNamesRule.d.ts b/src/validation/rules/UniqueDirectiveNamesRule.d.ts deleted file mode 100644 index a4dd841903..0000000000 --- a/src/validation/rules/UniqueDirectiveNamesRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { SDLValidationContext } from '../ValidationContext'; - -/** - * Unique directive names - * - * A GraphQL document is only valid if all defined directives have unique names. - */ -export function UniqueDirectiveNamesRule( - context: SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueDirectiveNamesRule.js b/src/validation/rules/UniqueDirectiveNamesRule.ts similarity index 91% rename from src/validation/rules/UniqueDirectiveNamesRule.js rename to src/validation/rules/UniqueDirectiveNamesRule.ts index 0d87d9deb4..ade517ddce 100644 --- a/src/validation/rules/UniqueDirectiveNamesRule.js +++ b/src/validation/rules/UniqueDirectiveNamesRule.ts @@ -1,4 +1,5 @@ import { GraphQLError } from '../../error/GraphQLError'; + import type { ASTVisitor } from '../../language/visitor'; import type { SDLValidationContext } from '../ValidationContext'; @@ -22,7 +23,7 @@ export function UniqueDirectiveNamesRule( context.reportError( new GraphQLError( `Directive "@${directiveName}" already exists in the schema. It cannot be redefined.`, - node.name, + { nodes: node.name }, ), ); return; @@ -32,7 +33,7 @@ export function UniqueDirectiveNamesRule( context.reportError( new GraphQLError( `There can be only one directive named "@${directiveName}".`, - [knownDirectiveNames[directiveName], node.name], + { nodes: [knownDirectiveNames[directiveName], node.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueDirectivesPerLocationRule.d.ts b/src/validation/rules/UniqueDirectivesPerLocationRule.d.ts deleted file mode 100644 index d059446557..0000000000 --- a/src/validation/rules/UniqueDirectivesPerLocationRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique directive names per location - * - * A GraphQL document is only valid if all directives at a given location - * are uniquely named. - */ -export function UniqueDirectivesPerLocationRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueDirectivesPerLocationRule.js b/src/validation/rules/UniqueDirectivesPerLocationRule.ts similarity index 92% rename from src/validation/rules/UniqueDirectivesPerLocationRule.js rename to src/validation/rules/UniqueDirectivesPerLocationRule.ts index a21c081790..a4fc54690a 100644 --- a/src/validation/rules/UniqueDirectivesPerLocationRule.js +++ b/src/validation/rules/UniqueDirectivesPerLocationRule.ts @@ -1,11 +1,11 @@ import { GraphQLError } from '../../error/GraphQLError'; import { Kind } from '../../language/kinds'; -import type { ASTVisitor } from '../../language/visitor'; import { isTypeDefinitionNode, isTypeExtensionNode, } from '../../language/predicates'; +import type { ASTVisitor } from '../../language/visitor'; import { specifiedDirectives } from '../../type/directives'; @@ -19,6 +19,8 @@ import type { * * A GraphQL document is only valid if all non-repeatable directives at * a given location are uniquely named. + * + * See https://spec.graphql.org/draft/#sec-Directives-Are-Unique-Per-Location */ export function UniqueDirectivesPerLocationRule( context: ValidationContext | SDLValidationContext, @@ -48,7 +50,7 @@ export function UniqueDirectivesPerLocationRule( // them all, just listen for entering any node, and check to see if it // defines any directives. enter(node) { - if (node.directives == null) { + if (!('directives' in node) || !node.directives) { return; } @@ -76,7 +78,7 @@ export function UniqueDirectivesPerLocationRule( context.reportError( new GraphQLError( `The directive "@${directiveName}" can only be used once at this location.`, - [seenDirectives[directiveName], directive], + { nodes: [seenDirectives[directiveName], directive] }, ), ); } else { diff --git a/src/validation/rules/UniqueEnumValueNames.d.ts b/src/validation/rules/UniqueEnumValueNames.d.ts deleted file mode 100644 index 96d9b787ca..0000000000 --- a/src/validation/rules/UniqueEnumValueNames.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueEnumValueNamesRule } from 'graphql' - * or - * import { UniqueEnumValueNamesRule } from 'graphql/validation' - */ -export { UniqueEnumValueNamesRule as UniqueEnumValueNames } from './UniqueEnumValueNamesRule'; diff --git a/src/validation/rules/UniqueEnumValueNames.js b/src/validation/rules/UniqueEnumValueNames.js deleted file mode 100644 index 96d9b787ca..0000000000 --- a/src/validation/rules/UniqueEnumValueNames.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueEnumValueNamesRule } from 'graphql' - * or - * import { UniqueEnumValueNamesRule } from 'graphql/validation' - */ -export { UniqueEnumValueNamesRule as UniqueEnumValueNames } from './UniqueEnumValueNamesRule'; diff --git a/src/validation/rules/UniqueEnumValueNamesRule.d.ts b/src/validation/rules/UniqueEnumValueNamesRule.d.ts deleted file mode 100644 index 9c5ff50a90..0000000000 --- a/src/validation/rules/UniqueEnumValueNamesRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { SDLValidationContext } from '../ValidationContext'; - -/** - * Unique enum value names - * - * A GraphQL enum type is only valid if all its values are uniquely named. - */ -export function UniqueEnumValueNamesRule( - context: SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueEnumValueNamesRule.js b/src/validation/rules/UniqueEnumValueNamesRule.ts similarity index 90% rename from src/validation/rules/UniqueEnumValueNamesRule.js rename to src/validation/rules/UniqueEnumValueNamesRule.ts index 28ba114248..2bdf8749a2 100644 --- a/src/validation/rules/UniqueEnumValueNamesRule.js +++ b/src/validation/rules/UniqueEnumValueNamesRule.ts @@ -1,10 +1,10 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import type { EnumTypeDefinitionNode, EnumTypeExtensionNode, } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; import { isEnumType } from '../../type/definition'; @@ -36,7 +36,8 @@ export function UniqueEnumValueNamesRule( knownValueNames[typeName] = Object.create(null); } - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const valueNodes = node.values ?? []; const valueNames = knownValueNames[typeName]; @@ -48,14 +49,14 @@ export function UniqueEnumValueNamesRule( context.reportError( new GraphQLError( `Enum value "${typeName}.${valueName}" already exists in the schema. It cannot also be defined in this type extension.`, - valueDef.name, + { nodes: valueDef.name }, ), ); } else if (valueNames[valueName]) { context.reportError( new GraphQLError( `Enum value "${typeName}.${valueName}" can only be defined once.`, - [valueNames[valueName], valueDef.name], + { nodes: [valueNames[valueName], valueDef.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueFieldDefinitionNames.d.ts b/src/validation/rules/UniqueFieldDefinitionNames.d.ts deleted file mode 100644 index 26ebb066ce..0000000000 --- a/src/validation/rules/UniqueFieldDefinitionNames.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueFieldDefinitionNamesRule } from 'graphql' - * or - * import { UniqueFieldDefinitionNamesRule } from 'graphql/validation' - */ -export { UniqueFieldDefinitionNamesRule as UniqueFieldDefinitionNames } from './UniqueFieldDefinitionNamesRule'; diff --git a/src/validation/rules/UniqueFieldDefinitionNames.js b/src/validation/rules/UniqueFieldDefinitionNames.js deleted file mode 100644 index 26ebb066ce..0000000000 --- a/src/validation/rules/UniqueFieldDefinitionNames.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueFieldDefinitionNamesRule } from 'graphql' - * or - * import { UniqueFieldDefinitionNamesRule } from 'graphql/validation' - */ -export { UniqueFieldDefinitionNamesRule as UniqueFieldDefinitionNames } from './UniqueFieldDefinitionNamesRule'; diff --git a/src/validation/rules/UniqueFieldDefinitionNamesRule.d.ts b/src/validation/rules/UniqueFieldDefinitionNamesRule.d.ts deleted file mode 100644 index 6f356ed98d..0000000000 --- a/src/validation/rules/UniqueFieldDefinitionNamesRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { SDLValidationContext } from '../ValidationContext'; - -/** - * Unique field definition names - * - * A GraphQL complex type is only valid if all its fields are uniquely named. - */ -export function UniqueFieldDefinitionNamesRule( - context: SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueFieldDefinitionNamesRule.js b/src/validation/rules/UniqueFieldDefinitionNamesRule.ts similarity index 87% rename from src/validation/rules/UniqueFieldDefinitionNamesRule.js rename to src/validation/rules/UniqueFieldDefinitionNamesRule.ts index f912a8489f..52f6527d64 100644 --- a/src/validation/rules/UniqueFieldDefinitionNamesRule.js +++ b/src/validation/rules/UniqueFieldDefinitionNamesRule.ts @@ -1,17 +1,17 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import type { - NameNode, FieldDefinitionNode, InputValueDefinitionNode, + NameNode, } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; import type { GraphQLNamedType } from '../../type/definition'; import { - isObjectType, - isInterfaceType, isInputObjectType, + isInterfaceType, + isObjectType, } from '../../type/definition'; import type { SDLValidationContext } from '../ValidationContext'; @@ -38,9 +38,10 @@ export function UniqueFieldDefinitionNamesRule( }; function checkFieldUniqueness(node: { - +name: NameNode, - +fields?: $ReadOnlyArray, - ... + readonly name: NameNode; + readonly fields?: ReadonlyArray< + InputValueDefinitionNode | FieldDefinitionNode + >; }) { const typeName = node.name.value; @@ -48,7 +49,8 @@ export function UniqueFieldDefinitionNamesRule( knownFieldNames[typeName] = Object.create(null); } - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // FIXME: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const fieldNodes = node.fields ?? []; const fieldNames = knownFieldNames[typeName]; @@ -59,14 +61,14 @@ export function UniqueFieldDefinitionNamesRule( context.reportError( new GraphQLError( `Field "${typeName}.${fieldName}" already exists in the schema. It cannot also be defined in this type extension.`, - fieldDef.name, + { nodes: fieldDef.name }, ), ); } else if (fieldNames[fieldName]) { context.reportError( new GraphQLError( `Field "${typeName}.${fieldName}" can only be defined once.`, - [fieldNames[fieldName], fieldDef.name], + { nodes: [fieldNames[fieldName], fieldDef.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueFragmentNamesRule.d.ts b/src/validation/rules/UniqueFragmentNamesRule.d.ts deleted file mode 100644 index 6154158980..0000000000 --- a/src/validation/rules/UniqueFragmentNamesRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique fragment names - * - * A GraphQL document is only valid if all defined fragments have unique names. - */ -export function UniqueFragmentNamesRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueFragmentNamesRule.js b/src/validation/rules/UniqueFragmentNamesRule.ts similarity index 86% rename from src/validation/rules/UniqueFragmentNamesRule.js rename to src/validation/rules/UniqueFragmentNamesRule.ts index 144e0e94d5..3b4311e9c8 100644 --- a/src/validation/rules/UniqueFragmentNamesRule.js +++ b/src/validation/rules/UniqueFragmentNamesRule.ts @@ -8,6 +8,8 @@ import type { ASTValidationContext } from '../ValidationContext'; * Unique fragment names * * A GraphQL document is only valid if all defined fragments have unique names. + * + * See https://spec.graphql.org/draft/#sec-Fragment-Name-Uniqueness */ export function UniqueFragmentNamesRule( context: ASTValidationContext, @@ -21,7 +23,7 @@ export function UniqueFragmentNamesRule( context.reportError( new GraphQLError( `There can be only one fragment named "${fragmentName}".`, - [knownFragmentNames[fragmentName], node.name], + { nodes: [knownFragmentNames[fragmentName], node.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueInputFieldNamesRule.d.ts b/src/validation/rules/UniqueInputFieldNamesRule.d.ts deleted file mode 100644 index c66d65f56c..0000000000 --- a/src/validation/rules/UniqueInputFieldNamesRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique input field names - * - * A GraphQL input object value is only valid if all supplied fields are - * uniquely named. - */ -export function UniqueInputFieldNamesRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueInputFieldNamesRule.js b/src/validation/rules/UniqueInputFieldNamesRule.ts similarity index 63% rename from src/validation/rules/UniqueInputFieldNamesRule.js rename to src/validation/rules/UniqueInputFieldNamesRule.ts index 413783e930..c1916a73b3 100644 --- a/src/validation/rules/UniqueInputFieldNamesRule.js +++ b/src/validation/rules/UniqueInputFieldNamesRule.ts @@ -1,5 +1,9 @@ +import { invariant } from '../../jsutils/invariant'; +import type { ObjMap } from '../../jsutils/ObjMap'; + import { GraphQLError } from '../../error/GraphQLError'; +import type { NameNode } from '../../language/ast'; import type { ASTVisitor } from '../../language/visitor'; import type { ASTValidationContext } from '../ValidationContext'; @@ -9,12 +13,14 @@ import type { ASTValidationContext } from '../ValidationContext'; * * A GraphQL input object value is only valid if all supplied fields are * uniquely named. + * + * See https://spec.graphql.org/draft/#sec-Input-Object-Field-Uniqueness */ export function UniqueInputFieldNamesRule( context: ASTValidationContext, ): ASTVisitor { - const knownNameStack = []; - let knownNames = Object.create(null); + const knownNameStack: Array> = []; + let knownNames: ObjMap = Object.create(null); return { ObjectValue: { @@ -23,7 +29,9 @@ export function UniqueInputFieldNamesRule( knownNames = Object.create(null); }, leave() { - knownNames = knownNameStack.pop(); + const prevKnownNames = knownNameStack.pop(); + invariant(prevKnownNames); + knownNames = prevKnownNames; }, }, ObjectField(node) { @@ -32,7 +40,7 @@ export function UniqueInputFieldNamesRule( context.reportError( new GraphQLError( `There can be only one input field named "${fieldName}".`, - [knownNames[fieldName], node.name], + { nodes: [knownNames[fieldName], node.name] }, ), ); } else { diff --git a/src/validation/rules/UniqueOperationNamesRule.d.ts b/src/validation/rules/UniqueOperationNamesRule.d.ts deleted file mode 100644 index aa2d06ad36..0000000000 --- a/src/validation/rules/UniqueOperationNamesRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique operation names - * - * A GraphQL document is only valid if all defined operations have unique names. - */ -export function UniqueOperationNamesRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueOperationNamesRule.js b/src/validation/rules/UniqueOperationNamesRule.ts similarity index 79% rename from src/validation/rules/UniqueOperationNamesRule.js rename to src/validation/rules/UniqueOperationNamesRule.ts index 6051e91978..6df98be8c7 100644 --- a/src/validation/rules/UniqueOperationNamesRule.js +++ b/src/validation/rules/UniqueOperationNamesRule.ts @@ -8,6 +8,8 @@ import type { ASTValidationContext } from '../ValidationContext'; * Unique operation names * * A GraphQL document is only valid if all defined operations have unique names. + * + * See https://spec.graphql.org/draft/#sec-Operation-Name-Uniqueness */ export function UniqueOperationNamesRule( context: ASTValidationContext, @@ -21,7 +23,12 @@ export function UniqueOperationNamesRule( context.reportError( new GraphQLError( `There can be only one operation named "${operationName.value}".`, - [knownOperationNames[operationName.value], operationName], + { + nodes: [ + knownOperationNames[operationName.value], + operationName, + ], + }, ), ); } else { diff --git a/src/validation/rules/UniqueOperationTypes.d.ts b/src/validation/rules/UniqueOperationTypes.d.ts deleted file mode 100644 index 423932dba1..0000000000 --- a/src/validation/rules/UniqueOperationTypes.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueOperationTypesRule } from 'graphql' - * or - * import { UniqueOperationTypesRule } from 'graphql/validation' - */ -export { UniqueOperationTypesRule as UniqueOperationTypes } from './UniqueOperationTypesRule'; diff --git a/src/validation/rules/UniqueOperationTypes.js b/src/validation/rules/UniqueOperationTypes.js deleted file mode 100644 index 423932dba1..0000000000 --- a/src/validation/rules/UniqueOperationTypes.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueOperationTypesRule } from 'graphql' - * or - * import { UniqueOperationTypesRule } from 'graphql/validation' - */ -export { UniqueOperationTypesRule as UniqueOperationTypes } from './UniqueOperationTypesRule'; diff --git a/src/validation/rules/UniqueOperationTypesRule.d.ts b/src/validation/rules/UniqueOperationTypesRule.d.ts deleted file mode 100644 index a0d6441d52..0000000000 --- a/src/validation/rules/UniqueOperationTypesRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { SDLValidationContext } from '../ValidationContext'; - -/** - * Unique operation types - * - * A GraphQL document is only valid if it has only one type per operation. - */ -export function UniqueOperationTypesRule( - context: SDLValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueOperationTypesRule.js b/src/validation/rules/UniqueOperationTypesRule.ts similarity index 89% rename from src/validation/rules/UniqueOperationTypesRule.js rename to src/validation/rules/UniqueOperationTypesRule.ts index 5b0d2b32cf..f8ac6871ec 100644 --- a/src/validation/rules/UniqueOperationTypesRule.js +++ b/src/validation/rules/UniqueOperationTypesRule.ts @@ -1,10 +1,10 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import type { SchemaDefinitionNode, SchemaExtensionNode, } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; import type { SDLValidationContext } from '../ValidationContext'; @@ -34,7 +34,8 @@ export function UniqueOperationTypesRule( function checkOperationTypes( node: SchemaDefinitionNode | SchemaExtensionNode, ) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + // See: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ const operationTypesNodes = node.operationTypes ?? []; for (const operationType of operationTypesNodes) { @@ -45,14 +46,14 @@ export function UniqueOperationTypesRule( context.reportError( new GraphQLError( `Type for ${operation} already defined in the schema. It cannot be redefined.`, - operationType, + { nodes: operationType }, ), ); } else if (alreadyDefinedOperationType) { context.reportError( new GraphQLError( `There can be only one ${operation} type in schema.`, - [alreadyDefinedOperationType, operationType], + { nodes: [alreadyDefinedOperationType, operationType] }, ), ); } else { diff --git a/src/validation/rules/UniqueTypeNames.d.ts b/src/validation/rules/UniqueTypeNames.d.ts deleted file mode 100644 index 1740eef841..0000000000 --- a/src/validation/rules/UniqueTypeNames.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueTypeNamesRule } from 'graphql' - * or - * import { UniqueTypeNamesRule } from 'graphql/validation' - */ -export { UniqueTypeNamesRule as UniqueTypeNames } from './UniqueTypeNamesRule'; diff --git a/src/validation/rules/UniqueTypeNames.js b/src/validation/rules/UniqueTypeNames.js deleted file mode 100644 index 1740eef841..0000000000 --- a/src/validation/rules/UniqueTypeNames.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @deprecated and will be removed in v16 - * Please use either: - * import { UniqueTypeNamesRule } from 'graphql' - * or - * import { UniqueTypeNamesRule } from 'graphql/validation' - */ -export { UniqueTypeNamesRule as UniqueTypeNames } from './UniqueTypeNamesRule'; diff --git a/src/validation/rules/UniqueTypeNamesRule.d.ts b/src/validation/rules/UniqueTypeNamesRule.d.ts deleted file mode 100644 index e2b37594b4..0000000000 --- a/src/validation/rules/UniqueTypeNamesRule.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { SDLValidationContext } from '../ValidationContext'; - -/** - * Unique type names - * - * A GraphQL document is only valid if all defined types have unique names. - */ -export function UniqueTypeNamesRule(context: SDLValidationContext): ASTVisitor; diff --git a/src/validation/rules/UniqueTypeNamesRule.js b/src/validation/rules/UniqueTypeNamesRule.ts similarity index 92% rename from src/validation/rules/UniqueTypeNamesRule.js rename to src/validation/rules/UniqueTypeNamesRule.ts index fed280c446..a1f6588b11 100644 --- a/src/validation/rules/UniqueTypeNamesRule.js +++ b/src/validation/rules/UniqueTypeNamesRule.ts @@ -1,7 +1,7 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; import type { TypeDefinitionNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; import type { SDLValidationContext } from '../ValidationContext'; @@ -30,7 +30,7 @@ export function UniqueTypeNamesRule(context: SDLValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Type "${typeName}" already exists in the schema. It cannot also be defined in this type definition.`, - node.name, + { nodes: node.name }, ), ); return; @@ -38,10 +38,9 @@ export function UniqueTypeNamesRule(context: SDLValidationContext): ASTVisitor { if (knownTypeNames[typeName]) { context.reportError( - new GraphQLError(`There can be only one type named "${typeName}".`, [ - knownTypeNames[typeName], - node.name, - ]), + new GraphQLError(`There can be only one type named "${typeName}".`, { + nodes: [knownTypeNames[typeName], node.name], + }), ); } else { knownTypeNames[typeName] = node.name; diff --git a/src/validation/rules/UniqueVariableNamesRule.d.ts b/src/validation/rules/UniqueVariableNamesRule.d.ts deleted file mode 100644 index 6f15764a34..0000000000 --- a/src/validation/rules/UniqueVariableNamesRule.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique variable names - * - * A GraphQL operation is only valid if all its variables are uniquely named. - */ -export function UniqueVariableNamesRule( - context: ASTValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/UniqueVariableNamesRule.js b/src/validation/rules/UniqueVariableNamesRule.js deleted file mode 100644 index 6035cdfa3e..0000000000 --- a/src/validation/rules/UniqueVariableNamesRule.js +++ /dev/null @@ -1,35 +0,0 @@ -import { GraphQLError } from '../../error/GraphQLError'; - -import type { ASTVisitor } from '../../language/visitor'; -import type { VariableDefinitionNode } from '../../language/ast'; - -import type { ASTValidationContext } from '../ValidationContext'; - -/** - * Unique variable names - * - * A GraphQL operation is only valid if all its variables are uniquely named. - */ -export function UniqueVariableNamesRule( - context: ASTValidationContext, -): ASTVisitor { - let knownVariableNames = Object.create(null); - return { - OperationDefinition() { - knownVariableNames = Object.create(null); - }, - VariableDefinition(node: VariableDefinitionNode) { - const variableName = node.variable.name.value; - if (knownVariableNames[variableName]) { - context.reportError( - new GraphQLError( - `There can be only one variable named "$${variableName}".`, - [knownVariableNames[variableName], node.variable.name], - ), - ); - } else { - knownVariableNames[variableName] = node.variable.name; - } - }, - }; -} diff --git a/src/validation/rules/UniqueVariableNamesRule.ts b/src/validation/rules/UniqueVariableNamesRule.ts new file mode 100644 index 0000000000..3c9f76d885 --- /dev/null +++ b/src/validation/rules/UniqueVariableNamesRule.ts @@ -0,0 +1,40 @@ +import { groupBy } from '../../jsutils/groupBy'; + +import { GraphQLError } from '../../error/GraphQLError'; + +import type { ASTVisitor } from '../../language/visitor'; + +import type { ASTValidationContext } from '../ValidationContext'; + +/** + * Unique variable names + * + * A GraphQL operation is only valid if all its variables are uniquely named. + */ +export function UniqueVariableNamesRule( + context: ASTValidationContext, +): ASTVisitor { + return { + OperationDefinition(operationNode) { + // See: https://github.com/graphql/graphql-js/issues/2203 + /* c8 ignore next */ + const variableDefinitions = operationNode.variableDefinitions ?? []; + + const seenVariableDefinitions = groupBy( + variableDefinitions, + (node) => node.variable.name.value, + ); + + for (const [variableName, variableNodes] of seenVariableDefinitions) { + if (variableNodes.length > 1) { + context.reportError( + new GraphQLError( + `There can be only one variable named "$${variableName}".`, + { nodes: variableNodes.map((node) => node.variable.name) }, + ), + ); + } + } + }, + }; +} diff --git a/src/validation/rules/ValuesOfCorrectTypeRule.d.ts b/src/validation/rules/ValuesOfCorrectTypeRule.d.ts deleted file mode 100644 index 98ff7a7438..0000000000 --- a/src/validation/rules/ValuesOfCorrectTypeRule.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Value literals of correct type - * - * A GraphQL document is only valid if all value literals are of the type - * expected at their position. - */ -export function ValuesOfCorrectTypeRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/ValuesOfCorrectTypeRule.js b/src/validation/rules/ValuesOfCorrectTypeRule.ts similarity index 61% rename from src/validation/rules/ValuesOfCorrectTypeRule.js rename to src/validation/rules/ValuesOfCorrectTypeRule.ts index d97647a000..3f284d7103 100644 --- a/src/validation/rules/ValuesOfCorrectTypeRule.js +++ b/src/validation/rules/ValuesOfCorrectTypeRule.ts @@ -1,24 +1,30 @@ -import objectValues from '../../polyfills/objectValues'; - -import keyMap from '../../jsutils/keyMap'; -import inspect from '../../jsutils/inspect'; -import didYouMean from '../../jsutils/didYouMean'; -import suggestionList from '../../jsutils/suggestionList'; +import { didYouMean } from '../../jsutils/didYouMean'; +import { inspect } from '../../jsutils/inspect'; +import { keyMap } from '../../jsutils/keyMap'; +import type { ObjMap } from '../../jsutils/ObjMap'; +import { suggestionList } from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ValueNode } from '../../language/ast'; -import type { ASTVisitor } from '../../language/visitor'; +import type { + ObjectFieldNode, + ObjectValueNode, + ValueNode, + VariableDefinitionNode, +} from '../../language/ast'; +import { Kind } from '../../language/kinds'; import { print } from '../../language/printer'; +import type { ASTVisitor } from '../../language/visitor'; +import type { GraphQLInputObjectType } from '../../type/definition'; import { - isLeafType, + getNamedType, + getNullableType, isInputObjectType, + isLeafType, isListType, isNonNullType, isRequiredInputField, - getNullableType, - getNamedType, } from '../../type/definition'; import type { ValidationContext } from '../ValidationContext'; @@ -28,11 +34,23 @@ import type { ValidationContext } from '../ValidationContext'; * * A GraphQL document is only valid if all value literals are of the type * expected at their position. + * + * See https://spec.graphql.org/draft/#sec-Values-of-Correct-Type */ export function ValuesOfCorrectTypeRule( context: ValidationContext, ): ASTVisitor { + let variableDefinitions: { [key: string]: VariableDefinitionNode } = {}; + return { + OperationDefinition: { + enter() { + variableDefinitions = {}; + }, + }, + VariableDefinition(definition) { + variableDefinitions[definition.variable.name.value] = definition; + }, ListValue(node) { // Note: TypeInfo will traverse into a list's item type, so look to the // parent input type to check if it is a list. @@ -50,18 +68,28 @@ export function ValuesOfCorrectTypeRule( } // Ensure every required field exists. const fieldNodeMap = keyMap(node.fields, (field) => field.name.value); - for (const fieldDef of objectValues(type.getFields())) { + for (const fieldDef of Object.values(type.getFields())) { const fieldNode = fieldNodeMap[fieldDef.name]; if (!fieldNode && isRequiredInputField(fieldDef)) { const typeStr = inspect(fieldDef.type); context.reportError( new GraphQLError( `Field "${type.name}.${fieldDef.name}" of required type "${typeStr}" was not provided.`, - node, + { nodes: node }, ), ); } } + + if (type.isOneOf) { + validateOneOfInputObject( + context, + node, + type, + fieldNodeMap, + variableDefinitions, + ); + } }, ObjectField(node) { const parentType = getNamedType(context.getParentInputType()); @@ -75,7 +103,7 @@ export function ValuesOfCorrectTypeRule( new GraphQLError( `Field "${node.name.value}" is not defined by type "${parentType.name}".` + didYouMean(suggestions), - node, + { nodes: node }, ), ); } @@ -86,7 +114,7 @@ export function ValuesOfCorrectTypeRule( context.reportError( new GraphQLError( `Expected value of type "${inspect(type)}", found ${print(node)}.`, - node, + { nodes: node }, ), ); } @@ -117,7 +145,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { context.reportError( new GraphQLError( `Expected value of type "${typeStr}", found ${print(node)}.`, - node, + { nodes: node }, ), ); return; @@ -132,7 +160,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { context.reportError( new GraphQLError( `Expected value of type "${typeStr}", found ${print(node)}.`, - node, + { nodes: node }, ), ); } @@ -145,11 +173,56 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { new GraphQLError( `Expected value of type "${typeStr}", found ${print(node)}; ` + error.message, - node, - undefined, - undefined, - undefined, - error, // Ensure a reference to the original error is maintained. + { nodes: node, originalError: error }, + ), + ); + } + } +} + +function validateOneOfInputObject( + context: ValidationContext, + node: ObjectValueNode, + type: GraphQLInputObjectType, + fieldNodeMap: ObjMap, + variableDefinitions: { [key: string]: VariableDefinitionNode }, +): void { + const keys = Object.keys(fieldNodeMap); + const isNotExactlyOneField = keys.length !== 1; + + if (isNotExactlyOneField) { + context.reportError( + new GraphQLError( + `OneOf Input Object "${type.name}" must specify exactly one key.`, + { nodes: [node] }, + ), + ); + return; + } + + const value = fieldNodeMap[keys[0]]?.value; + const isNullLiteral = !value || value.kind === Kind.NULL; + const isVariable = value?.kind === Kind.VARIABLE; + + if (isNullLiteral) { + context.reportError( + new GraphQLError(`Field "${type.name}.${keys[0]}" must be non-null.`, { + nodes: [node], + }), + ); + return; + } + + if (isVariable) { + const variableName = value.name.value; + const definition = variableDefinitions[variableName]; + const isNullableVariable = definition.type.kind !== Kind.NON_NULL_TYPE; + + if (isNullableVariable) { + context.reportError( + new GraphQLError( + `Variable "${variableName}" must be non-nullable to be used for OneOf Input Object "${type.name}".`, + { nodes: [node] }, ), ); } diff --git a/src/validation/rules/VariablesAreInputTypesRule.d.ts b/src/validation/rules/VariablesAreInputTypesRule.d.ts deleted file mode 100644 index c82229c79e..0000000000 --- a/src/validation/rules/VariablesAreInputTypesRule.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Variables are input types - * - * A GraphQL operation is only valid if all the variables it defines are of - * input types (scalar, enum, or input object). - */ -export function VariablesAreInputTypesRule( - context: ValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/VariablesAreInputTypesRule.js b/src/validation/rules/VariablesAreInputTypesRule.ts similarity index 82% rename from src/validation/rules/VariablesAreInputTypesRule.js rename to src/validation/rules/VariablesAreInputTypesRule.ts index f16cb7461d..58d535ce81 100644 --- a/src/validation/rules/VariablesAreInputTypesRule.js +++ b/src/validation/rules/VariablesAreInputTypesRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; +import type { VariableDefinitionNode } from '../../language/ast'; import { print } from '../../language/printer'; import type { ASTVisitor } from '../../language/visitor'; -import type { VariableDefinitionNode } from '../../language/ast'; import { isInputType } from '../../type/definition'; @@ -15,22 +15,24 @@ import type { ValidationContext } from '../ValidationContext'; * * A GraphQL operation is only valid if all the variables it defines are of * input types (scalar, enum, or input object). + * + * See https://spec.graphql.org/draft/#sec-Variables-Are-Input-Types */ export function VariablesAreInputTypesRule( context: ValidationContext, ): ASTVisitor { return { - VariableDefinition(node: VariableDefinitionNode): ?GraphQLError { + VariableDefinition(node: VariableDefinitionNode) { const type = typeFromAST(context.getSchema(), node.type); - if (type && !isInputType(type)) { + if (type !== undefined && !isInputType(type)) { const variableName = node.variable.name.value; const typeName = print(node.type); context.reportError( new GraphQLError( `Variable "$${variableName}" cannot be non-input type "${typeName}".`, - node.type, + { nodes: node.type }, ), ); } diff --git a/src/validation/rules/VariablesInAllowedPositionRule.d.ts b/src/validation/rules/VariablesInAllowedPositionRule.d.ts deleted file mode 100644 index 6ee57371c9..0000000000 --- a/src/validation/rules/VariablesInAllowedPositionRule.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; - -/** - * Variables passed to field arguments conform to type - */ -export function VariablesInAllowedPositionRule( - context: ValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/VariablesInAllowedPositionRule.js b/src/validation/rules/VariablesInAllowedPositionRule.ts similarity index 88% rename from src/validation/rules/VariablesInAllowedPositionRule.js rename to src/validation/rules/VariablesInAllowedPositionRule.ts index 8d0cbbf26c..a0b7e991a6 100644 --- a/src/validation/rules/VariablesInAllowedPositionRule.js +++ b/src/validation/rules/VariablesInAllowedPositionRule.ts @@ -1,22 +1,27 @@ -import inspect from '../../jsutils/inspect'; +import { inspect } from '../../jsutils/inspect'; +import type { Maybe } from '../../jsutils/Maybe'; import { GraphQLError } from '../../error/GraphQLError'; -import { Kind } from '../../language/kinds'; import type { ValueNode } from '../../language/ast'; +import { Kind } from '../../language/kinds'; import type { ASTVisitor } from '../../language/visitor'; -import type { GraphQLSchema } from '../../type/schema'; import type { GraphQLType } from '../../type/definition'; import { isNonNullType } from '../../type/definition'; +import type { GraphQLSchema } from '../../type/schema'; -import { typeFromAST } from '../../utilities/typeFromAST'; import { isTypeSubTypeOf } from '../../utilities/typeComparators'; +import { typeFromAST } from '../../utilities/typeFromAST'; import type { ValidationContext } from '../ValidationContext'; /** - * Variables passed to field arguments conform to type + * Variables in allowed position + * + * Variable usages must be compatible with the arguments they are passed to. + * + * See https://spec.graphql.org/draft/#sec-All-Variable-Usages-are-Allowed */ export function VariablesInAllowedPositionRule( context: ValidationContext, @@ -57,7 +62,7 @@ export function VariablesInAllowedPositionRule( context.reportError( new GraphQLError( `Variable "$${varName}" of type "${varTypeStr}" used in position expecting type "${typeStr}".`, - [varDef, node], + { nodes: [varDef, node] }, ), ); } @@ -79,9 +84,9 @@ export function VariablesInAllowedPositionRule( function allowedVariableUsage( schema: GraphQLSchema, varType: GraphQLType, - varDefaultValue: ?ValueNode, + varDefaultValue: Maybe, locationType: GraphQLType, - locationDefaultValue: ?mixed, + locationDefaultValue: Maybe, ): boolean { if (isNonNullType(locationType) && !isNonNullType(varType)) { const hasNonNullVariableDefaultValue = diff --git a/src/validation/rules/custom/NoDeprecatedCustomRule.d.ts b/src/validation/rules/custom/NoDeprecatedCustomRule.d.ts deleted file mode 100644 index d376cf8572..0000000000 --- a/src/validation/rules/custom/NoDeprecatedCustomRule.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ASTVisitor } from '../../../language/visitor'; -import { ValidationContext } from '../../ValidationContext'; - -/** - * No deprecated - * - * A GraphQL document is only valid if all selected fields and all used enum values have not been - * deprecated. - * - * Note: This rule is optional and is not part of the Validation section of the GraphQL - * Specification. The main purpose of this rule is detection of deprecated usages and not - * necessarily to forbid their use when querying a service. - */ -export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor; diff --git a/src/validation/rules/custom/NoDeprecatedCustomRule.js b/src/validation/rules/custom/NoDeprecatedCustomRule.ts similarity index 93% rename from src/validation/rules/custom/NoDeprecatedCustomRule.js rename to src/validation/rules/custom/NoDeprecatedCustomRule.ts index 7fe6598bc4..e06ac2e789 100644 --- a/src/validation/rules/custom/NoDeprecatedCustomRule.js +++ b/src/validation/rules/custom/NoDeprecatedCustomRule.ts @@ -1,4 +1,4 @@ -import invariant from '../../../jsutils/invariant'; +import { invariant } from '../../../jsutils/invariant'; import { GraphQLError } from '../../../error/GraphQLError'; @@ -29,7 +29,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `The field ${parentType.name}.${fieldDef.name} is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } @@ -43,7 +43,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Directive "@${directiveDef.name}" argument "${argDef.name}" is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } else { @@ -53,7 +53,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `Field "${parentType.name}.${fieldDef.name}" argument "${argDef.name}" is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } @@ -63,13 +63,12 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { const inputObjectDef = getNamedType(context.getParentInputType()); if (isInputObjectType(inputObjectDef)) { const inputFieldDef = inputObjectDef.getFields()[node.name.value]; - // flowlint-next-line unnecessary-optional-chain:off const deprecationReason = inputFieldDef?.deprecationReason; if (deprecationReason != null) { context.reportError( new GraphQLError( `The input field ${inputObjectDef.name}.${inputFieldDef.name} is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } @@ -84,7 +83,7 @@ export function NoDeprecatedCustomRule(context: ValidationContext): ASTVisitor { context.reportError( new GraphQLError( `The enum value "${enumTypeDef.name}.${enumValueDef.name}" is deprecated. ${deprecationReason}`, - node, + { nodes: node }, ), ); } diff --git a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.d.ts b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.d.ts deleted file mode 100644 index 3677fa1c73..0000000000 --- a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ASTVisitor } from '../../../language/visitor'; -import { ValidationContext } from '../../ValidationContext'; - -/** - * Prohibit introspection queries - * - * A GraphQL document is only valid if all fields selected are not fields that - * return an introspection type. - * - * Note: This rule is optional and is not part of the Validation section of the - * GraphQL Specification. This rule effectively disables introspection, which - * does not reflect best practices and should only be done if absolutely necessary. - */ -export function NoSchemaIntrospectionCustomRule( - context: ValidationContext, -): ASTVisitor; diff --git a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.js b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts similarity index 97% rename from src/validation/rules/custom/NoSchemaIntrospectionCustomRule.js rename to src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts index 7a1c1f2ab9..257d58d723 100644 --- a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.js +++ b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts @@ -28,7 +28,7 @@ export function NoSchemaIntrospectionCustomRule( context.reportError( new GraphQLError( `GraphQL introspection has been disabled, but the requested query contained the field "${node.name.value}".`, - node, + { nodes: node }, ), ); } diff --git a/src/validation/specifiedRules.d.ts b/src/validation/specifiedRules.d.ts deleted file mode 100644 index ffb5570894..0000000000 --- a/src/validation/specifiedRules.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ValidationRule, SDLValidationRule } from './ValidationContext'; - -/** - * This set includes all validation rules defined by the GraphQL spec. - * - * The order of the rules in this list has been adjusted to lead to the - * most clear output when encountering multiple validation errors. - */ -export const specifiedRules: ReadonlyArray; - -/** - * @internal - */ -export const specifiedSDLRules: ReadonlyArray; diff --git a/src/validation/specifiedRules.js b/src/validation/specifiedRules.ts similarity index 81% rename from src/validation/specifiedRules.js rename to src/validation/specifiedRules.ts index 72f25d9490..c312c9839c 100644 --- a/src/validation/specifiedRules.js +++ b/src/validation/specifiedRules.ts @@ -1,95 +1,79 @@ // Spec Section: "Executable Definitions" import { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule'; - -// Spec Section: "Operation Name Uniqueness" -import { UniqueOperationNamesRule } from './rules/UniqueOperationNamesRule'; - -// Spec Section: "Lone Anonymous Operation" -import { LoneAnonymousOperationRule } from './rules/LoneAnonymousOperationRule'; - -// Spec Section: "Subscriptions with Single Root Field" -import { SingleFieldSubscriptionsRule } from './rules/SingleFieldSubscriptionsRule'; - -// Spec Section: "Fragment Spread Type Existence" -import { KnownTypeNamesRule } from './rules/KnownTypeNamesRule'; - -// Spec Section: "Fragments on Composite Types" -import { FragmentsOnCompositeTypesRule } from './rules/FragmentsOnCompositeTypesRule'; - -// Spec Section: "Variables are Input Types" -import { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule'; - -// Spec Section: "Leaf Field Selections" -import { ScalarLeafsRule } from './rules/ScalarLeafsRule'; - // Spec Section: "Field Selections on Objects, Interfaces, and Unions Types" import { FieldsOnCorrectTypeRule } from './rules/FieldsOnCorrectTypeRule'; - -// Spec Section: "Fragment Name Uniqueness" -import { UniqueFragmentNamesRule } from './rules/UniqueFragmentNamesRule'; - +// Spec Section: "Fragments on Composite Types" +import { FragmentsOnCompositeTypesRule } from './rules/FragmentsOnCompositeTypesRule'; +// Spec Section: "Argument Names" +import { + KnownArgumentNamesOnDirectivesRule, + KnownArgumentNamesRule, +} from './rules/KnownArgumentNamesRule'; +// Spec Section: "Directives Are Defined" +import { KnownDirectivesRule } from './rules/KnownDirectivesRule'; // Spec Section: "Fragment spread target defined" import { KnownFragmentNamesRule } from './rules/KnownFragmentNamesRule'; - -// Spec Section: "Fragments must be used" -import { NoUnusedFragmentsRule } from './rules/NoUnusedFragmentsRule'; - -// Spec Section: "Fragment spread is possible" -import { PossibleFragmentSpreadsRule } from './rules/PossibleFragmentSpreadsRule'; - +// Spec Section: "Fragment Spread Type Existence" +import { KnownTypeNamesRule } from './rules/KnownTypeNamesRule'; +// Spec Section: "Lone Anonymous Operation" +import { LoneAnonymousOperationRule } from './rules/LoneAnonymousOperationRule'; +// SDL-specific validation rules +import { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule'; +// TODO: Spec Section +import { MaxIntrospectionDepthRule } from './rules/MaxIntrospectionDepthRule'; // Spec Section: "Fragments must not form cycles" import { NoFragmentCyclesRule } from './rules/NoFragmentCyclesRule'; - -// Spec Section: "Variable Uniqueness" -import { UniqueVariableNamesRule } from './rules/UniqueVariableNamesRule'; - // Spec Section: "All Variable Used Defined" import { NoUndefinedVariablesRule } from './rules/NoUndefinedVariablesRule'; - +// Spec Section: "Fragments must be used" +import { NoUnusedFragmentsRule } from './rules/NoUnusedFragmentsRule'; // Spec Section: "All Variables Used" import { NoUnusedVariablesRule } from './rules/NoUnusedVariablesRule'; - -// Spec Section: "Directives Are Defined" -import { KnownDirectivesRule } from './rules/KnownDirectivesRule'; - -// Spec Section: "Directives Are Unique Per Location" -import { UniqueDirectivesPerLocationRule } from './rules/UniqueDirectivesPerLocationRule'; - -// Spec Section: "Argument Names" -import { - KnownArgumentNamesRule, - KnownArgumentNamesOnDirectivesRule, -} from './rules/KnownArgumentNamesRule'; - -// Spec Section: "Argument Uniqueness" -import { UniqueArgumentNamesRule } from './rules/UniqueArgumentNamesRule'; - -// Spec Section: "Value Type Correctness" -import { ValuesOfCorrectTypeRule } from './rules/ValuesOfCorrectTypeRule'; - +// Spec Section: "Field Selection Merging" +import { OverlappingFieldsCanBeMergedRule } from './rules/OverlappingFieldsCanBeMergedRule'; +// Spec Section: "Fragment spread is possible" +import { PossibleFragmentSpreadsRule } from './rules/PossibleFragmentSpreadsRule'; +import { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule'; // Spec Section: "Argument Optionality" import { - ProvidedRequiredArgumentsRule, ProvidedRequiredArgumentsOnDirectivesRule, + ProvidedRequiredArgumentsRule, } from './rules/ProvidedRequiredArgumentsRule'; - -// Spec Section: "All Variable Usages Are Allowed" -import { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule'; - -// Spec Section: "Field Selection Merging" -import { OverlappingFieldsCanBeMergedRule } from './rules/OverlappingFieldsCanBeMergedRule'; - +// Spec Section: "Leaf Field Selections" +import { ScalarLeafsRule } from './rules/ScalarLeafsRule'; +// Spec Section: "Subscriptions with Single Root Field" +import { SingleFieldSubscriptionsRule } from './rules/SingleFieldSubscriptionsRule'; +import { UniqueArgumentDefinitionNamesRule } from './rules/UniqueArgumentDefinitionNamesRule'; +// Spec Section: "Argument Uniqueness" +import { UniqueArgumentNamesRule } from './rules/UniqueArgumentNamesRule'; +import { UniqueDirectiveNamesRule } from './rules/UniqueDirectiveNamesRule'; +// Spec Section: "Directives Are Unique Per Location" +import { UniqueDirectivesPerLocationRule } from './rules/UniqueDirectivesPerLocationRule'; +import { UniqueEnumValueNamesRule } from './rules/UniqueEnumValueNamesRule'; +import { UniqueFieldDefinitionNamesRule } from './rules/UniqueFieldDefinitionNamesRule'; +// Spec Section: "Fragment Name Uniqueness" +import { UniqueFragmentNamesRule } from './rules/UniqueFragmentNamesRule'; // Spec Section: "Input Object Field Uniqueness" import { UniqueInputFieldNamesRule } from './rules/UniqueInputFieldNamesRule'; - -// SDL-specific validation rules -import { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule'; +// Spec Section: "Operation Name Uniqueness" +import { UniqueOperationNamesRule } from './rules/UniqueOperationNamesRule'; import { UniqueOperationTypesRule } from './rules/UniqueOperationTypesRule'; import { UniqueTypeNamesRule } from './rules/UniqueTypeNamesRule'; -import { UniqueEnumValueNamesRule } from './rules/UniqueEnumValueNamesRule'; -import { UniqueFieldDefinitionNamesRule } from './rules/UniqueFieldDefinitionNamesRule'; -import { UniqueDirectiveNamesRule } from './rules/UniqueDirectiveNamesRule'; -import { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule'; +// Spec Section: "Variable Uniqueness" +import { UniqueVariableNamesRule } from './rules/UniqueVariableNamesRule'; +// Spec Section: "Value Type Correctness" +import { ValuesOfCorrectTypeRule } from './rules/ValuesOfCorrectTypeRule'; +// Spec Section: "Variables are Input Types" +import { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule'; +// Spec Section: "All Variable Usages Are Allowed" +import { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule'; +import type { SDLValidationRule, ValidationRule } from './ValidationContext'; + +/** + * Technically these aren't part of the spec but they are strongly encouraged + * validation rules. + */ +export const recommendedRules = Object.freeze([MaxIntrospectionDepthRule]); /** * This set includes all validation rules defined by the GraphQL spec. @@ -97,7 +81,7 @@ import { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule'; * The order of the rules in this list has been adjusted to lead to the * most clear output when encountering multiple validation errors. */ -export const specifiedRules = Object.freeze([ +export const specifiedRules: ReadonlyArray = Object.freeze([ ExecutableDefinitionsRule, UniqueOperationNamesRule, LoneAnonymousOperationRule, @@ -124,24 +108,27 @@ export const specifiedRules = Object.freeze([ VariablesInAllowedPositionRule, OverlappingFieldsCanBeMergedRule, UniqueInputFieldNamesRule, + ...recommendedRules, ]); /** * @internal */ -export const specifiedSDLRules = Object.freeze([ - LoneSchemaDefinitionRule, - UniqueOperationTypesRule, - UniqueTypeNamesRule, - UniqueEnumValueNamesRule, - UniqueFieldDefinitionNamesRule, - UniqueDirectiveNamesRule, - KnownTypeNamesRule, - KnownDirectivesRule, - UniqueDirectivesPerLocationRule, - PossibleTypeExtensionsRule, - KnownArgumentNamesOnDirectivesRule, - UniqueArgumentNamesRule, - UniqueInputFieldNamesRule, - ProvidedRequiredArgumentsOnDirectivesRule, -]); +export const specifiedSDLRules: ReadonlyArray = + Object.freeze([ + LoneSchemaDefinitionRule, + UniqueOperationTypesRule, + UniqueTypeNamesRule, + UniqueEnumValueNamesRule, + UniqueFieldDefinitionNamesRule, + UniqueArgumentDefinitionNamesRule, + UniqueDirectiveNamesRule, + KnownTypeNamesRule, + KnownDirectivesRule, + UniqueDirectivesPerLocationRule, + PossibleTypeExtensionsRule, + KnownArgumentNamesOnDirectivesRule, + UniqueArgumentNamesRule, + UniqueInputFieldNamesRule, + ProvidedRequiredArgumentsOnDirectivesRule, + ]); diff --git a/src/validation/validate.d.ts b/src/validation/validate.d.ts deleted file mode 100644 index 5e93a8cff0..0000000000 --- a/src/validation/validate.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Maybe } from '../jsutils/Maybe'; - -import { GraphQLError } from '../error/GraphQLError'; - -import { DocumentNode } from '../language/ast'; - -import { GraphQLSchema } from '../type/schema'; - -import { TypeInfo } from '../utilities/TypeInfo'; - -import { ValidationRule, SDLValidationRule } from './ValidationContext'; - -/** - * Implements the "Validation" section of the spec. - * - * Validation runs synchronously, returning an array of encountered errors, or - * an empty array if no errors were encountered and the document is valid. - * - * A list of specific validation rules may be provided. If not provided, the - * default list of rules defined by the GraphQL specification will be used. - * - * Each validation rules is a function which returns a visitor - * (see the language/visitor API). Visitor methods are expected to return - * GraphQLErrors, or Arrays of GraphQLErrors when invalid. - * - * Optionally a custom TypeInfo instance may be provided. If not provided, one - * will be created from the provided schema. - */ -export function validate( - schema: GraphQLSchema, - documentAST: DocumentNode, - rules?: ReadonlyArray, - typeInfo?: TypeInfo, - options?: { maxErrors?: number }, -): ReadonlyArray; - -/** - * @internal - */ -export function validateSDL( - documentAST: DocumentNode, - schemaToExtend?: Maybe, - rules?: ReadonlyArray, -): Array; - -/** - * Utility function which asserts a SDL document is valid by throwing an error - * if it is invalid. - * - * @internal - */ -export function assertValidSDL(documentAST: DocumentNode): void; - -/** - * Utility function which asserts a SDL document is valid by throwing an error - * if it is invalid. - * - * @internal - */ -export function assertValidSDLExtension( - documentAST: DocumentNode, - schema: GraphQLSchema, -): void; diff --git a/src/validation/validate.js b/src/validation/validate.ts similarity index 79% rename from src/validation/validate.js rename to src/validation/validate.ts index c51a56a6b7..7259874240 100644 --- a/src/validation/validate.js +++ b/src/validation/validate.ts @@ -1,4 +1,5 @@ -import devAssert from '../jsutils/devAssert'; +import { devAssert } from '../jsutils/devAssert'; +import type { Maybe } from '../jsutils/Maybe'; import { GraphQLError } from '../error/GraphQLError'; @@ -10,8 +11,8 @@ import { assertValidSchema } from '../type/validate'; import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo'; -import type { SDLValidationRule, ValidationRule } from './ValidationContext'; import { specifiedRules, specifiedSDLRules } from './specifiedRules'; +import type { SDLValidationRule, ValidationRule } from './ValidationContext'; import { SDLValidationContext, ValidationContext } from './ValidationContext'; /** @@ -27,33 +28,42 @@ import { SDLValidationContext, ValidationContext } from './ValidationContext'; * (see the language/visitor API). Visitor methods are expected to return * GraphQLErrors, or Arrays of GraphQLErrors when invalid. * + * Validate will stop validation after a `maxErrors` limit has been reached. + * Attackers can send pathologically invalid queries to induce a DoS attack, + * so by default `maxErrors` set to 100 errors. + * * Optionally a custom TypeInfo instance may be provided. If not provided, one * will be created from the provided schema. */ export function validate( schema: GraphQLSchema, documentAST: DocumentNode, - rules: $ReadOnlyArray = specifiedRules, + rules: ReadonlyArray = specifiedRules, + options?: { maxErrors?: number }, + + /** @deprecated will be removed in 17.0.0 */ typeInfo: TypeInfo = new TypeInfo(schema), - options: {| maxErrors?: number |} = { maxErrors: undefined }, -): $ReadOnlyArray { +): ReadonlyArray { + const maxErrors = options?.maxErrors ?? 100; + devAssert(documentAST, 'Must provide document.'); // If the schema used for validation is invalid, throw an error. assertValidSchema(schema); const abortObj = Object.freeze({}); - const errors = []; + const errors: Array = []; const context = new ValidationContext( schema, documentAST, typeInfo, (error) => { - if (options.maxErrors != null && errors.length >= options.maxErrors) { + if (errors.length >= maxErrors) { errors.push( new GraphQLError( 'Too many validation errors, error limit reached. Validation aborted.', ), ); + // eslint-disable-next-line @typescript-eslint/no-throw-literal throw abortObj; } errors.push(error); @@ -80,10 +90,10 @@ export function validate( */ export function validateSDL( documentAST: DocumentNode, - schemaToExtend?: ?GraphQLSchema, - rules: $ReadOnlyArray = specifiedSDLRules, -): $ReadOnlyArray { - const errors = []; + schemaToExtend?: Maybe, + rules: ReadonlyArray = specifiedSDLRules, +): ReadonlyArray { + const errors: Array = []; const context = new SDLValidationContext( documentAST, schemaToExtend, diff --git a/src/version.d.ts b/src/version.d.ts deleted file mode 100644 index 765329b38b..0000000000 --- a/src/version.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * A string containing the version of the GraphQL.js library - */ -export const version: string; - -/** - * An object containing the components of the GraphQL.js version string - */ -export const versionInfo: { - major: number; - minor: number; - patch: number; - preReleaseTag: number | null; -}; diff --git a/src/version.js b/src/version.js deleted file mode 100644 index 27b130e655..0000000000 --- a/src/version.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Note: This file is autogenerated using "resources/gen-version.js" script and - * automatically updated by "npm version" command. - */ - -/** - * A string containing the version of the GraphQL.js library - */ -export const version = '15.4.0'; - -/** - * An object containing the components of the GraphQL.js version string - */ -export const versionInfo = Object.freeze({ - major: 15, - minor: 4, - patch: 0, - preReleaseTag: null, -}); diff --git a/src/version.ts b/src/version.ts new file mode 100644 index 0000000000..8f3b627ca1 --- /dev/null +++ b/src/version.ts @@ -0,0 +1,17 @@ +// Note: This file is autogenerated using "resources/gen-version.js" script and +// automatically updated by "npm version" command. + +/** + * A string containing the version of the GraphQL.js library + */ +export const version = '16.10.0' as string; + +/** + * An object containing the components of the GraphQL.js version string + */ +export const versionInfo = Object.freeze({ + major: 16 as number, + minor: 10 as number, + patch: 0 as number, + preReleaseTag: null as string | null, +}); diff --git a/tsconfig.json b/tsconfig.json index d158e41db9..8dfb0f4794 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,14 @@ { - "exclude": ["integrationTests/ts/**/*"], + "include": ["src/**/*"], "compilerOptions": { "module": "commonjs", - "lib": ["es6", "esnext.asynciterable"], - "noImplicitAny": true, - "noImplicitThis": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "types": [], + "lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string"], + "target": "es2019", + "strict": true, + "useUnknownInCatchVariables": false, "noEmit": true, + "isolatedModules": true, + "importsNotUsedAsValues": "error", "forceConsistentCasingInFileNames": true } } diff --git a/website/.eslintignore b/website/.eslintignore new file mode 100644 index 0000000000..e435ba4756 --- /dev/null +++ b/website/.eslintignore @@ -0,0 +1,2 @@ +/pages/_document.tsx +/pages/_app.tsx diff --git a/website/css/globals.css b/website/css/globals.css new file mode 100644 index 0000000000..d8207c0885 --- /dev/null +++ b/website/css/globals.css @@ -0,0 +1,480 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} + +.conf-hero { + background: linear-gradient( + 360deg, + #0e031c 10.63%, + #0e031c 10.65%, + rgba(14, 3, 28, 0) 166.98% + ), + url('/img/conf/graphql-conf-bg.png'); + @apply text-white max-md:text-base; +} + +.with-arrow:after { + @apply content-['_→'] font-sans text-xl; + @apply transition-all duration-75 hover:ml-1; +} + +footer { + @apply !bg-transparent; +} + +.nextra-logo { + mask-image: linear-gradient( + 60deg, + black 25%, + rgba(0, 0, 0, 0.2) 50%, + black 75% + ); + mask-size: 400%; + mask-position: 0; + + &:hover { + mask-position: 100%; + transition: mask-position 1s ease, -webkit-mask-position 1s ease; + } +} + +div[role='menu'][data-headlessui-state] { + @apply left-0 right-auto; +} + +div[id^='headlessui-menu-items'] { + @apply rounded-none; + + > a { + @apply py-3.5; + } +} + +/* should be fixed in Nextra 4 */ +._max-w-\[90rem\] { + @apply container; +} + +.nextra-nav-container + ._max-w-\[90rem\] { + @apply px-0; +} + +.nextra-nav-container > nav { + @apply gap-6; +} + +/* Move nav links to the left */ +.nextra-nav-container nav { + @apply justify-start; + + > a { + @apply hover:!text-primary; + } + + button[id^='headlessui-menu-button'] { + @apply hover:text-primary; + + + div > a { + @apply hover:text-primary; + } + } + + .nextra-search { + @apply ml-auto; + + + * { + @apply max-md:ml-auto; + } + } +} + +/*._max-w-\[90rem\] {*/ +/* !* TODO: maybe add to nextra as option to configure width? *!*/ +/* @apply container;*/ +/*}*/ + +.miniGraphiQL { + @apply !shadow-none border-2 dark:border-neutral-900 dark:!bg-neutral-900/10 !rounded-md dark:brightness-200; +} + +.result-window { + @apply !shadow-none border-l-2 dark:border-neutral-900 !rounded-none; +} + +.variable-editor { + @apply before:!bg-transparent border-t-2 dark:border-neutral-900; +} + +.CodeMirror-selected { + @apply !bg-primary/50 dark:bg-primary/40; +} + +.CodeMirror-cursor { + @apply dark:border-white; +} + +.CodeMirror { + @apply p-2; +} + +::selection { + @apply bg-primary/50 dark:bg-primary; +} + +@media (prefers-color-scheme: dark) { + body { + /*background: linear-gradient(*/ + /* 125deg,*/ + /* rgba(234, 117, 195, 0.3) -10%,*/ + /* rgba(234, 117, 195, 0) 8%*/ + /* ),*/ + /* linear-gradient(*/ + /* -125deg,*/ + /* rgba(234, 117, 195, 0.3) -10%,*/ + /* rgba(234, 117, 195, 0) 8%*/ + /* ),*/ + /* linear-gradient(0deg, #05031c, #05031c);*/ + /*@apply bg-gradient-to-b from-primary/10 to-[#05031c]*/ + + /*background:*/ + /* !*linear-gradient(0deg, #05031c, #05031c),*!*/ + /* linear-gradient(*/ + /* 125.93deg,*/ + /* rgba(234, 117, 195, 0.7) -10.45%,*/ + /* rgba(234, 117, 195, 0) 28.49%*/ + /* ),*/ + /* linear-gradient(*/ + /* -125.93deg,*/ + /* rgba(234, 117, 195, 0.7) -33.25%,*/ + /* rgba(234, 117, 195, 0) 26.45%*/ + /* );*/ + } +} + +.donts-images ul { + gap: 0 3em; + @apply flex flex-wrap; + + li { + @apply flex gap-3 grow md:basis-1/3; + + div { + @apply grow; + } + + img { + @apply bg-gray-200 p-4 h-20; + } + } +} + +.dos > ul:first-child li:before { + background: url('/img/brand/do.svg'); +} + +.donts > ul:first-child li:before { + background: url('/img/brand/dont.svg'); +} + +.dos, +.donts { + @apply mt-6; + + > ul ul { + @apply mt-0; + + li:before { + @apply grayscale; + } + } + + & > ul:first-child li { + @apply list-none relative; + + &:before { + @apply size-4 absolute content-[''] top-1 -left-6; + } + } +} + +.code-page { + background: linear-gradient( + 303.75deg, + rgba(124, 124, 124, 0.2) 0.8%, + rgba(124, 124, 124, 0) 74.17% + ), + linear-gradient(0deg, #f8f8f8, #f8f8f8); +} + +.dark .code-page { + background: linear-gradient( + 303.75deg, + rgba(124, 124, 124, 0.2) 0.8%, + rgba(124, 124, 124, 0) 74.17% + ), + linear-gradient(0deg, #1b1b1b, #1b1b1b); +} + +.dark .blog-page { + background: linear-gradient( + 250.93deg, + rgba(115, 119, 125, 0.1), + rgba(115, 119, 125, 0) + ), + #18181b; +} + +.blog-page { + background: linear-gradient( + 231.79deg, + rgba(225, 0, 152, 0.4) -23.67%, + rgba(225, 0, 152, 0) 25.9% + ), + linear-gradient( + 113.65deg, + rgba(229, 53, 171, 0.4) -49.55%, + rgba(225, 0, 152, 0) 33.97% + ), + linear-gradient(180deg, #f3f4f6 0%, #fff 100%); +} + +.conf-heading { + @apply text-3xl lg:text-[50px]/[4rem] font-bold text-balance; +} + +.conf-block { + @apply py-14 lg:py-24; +} + +.tag { + @apply hover:text-white hover:border-transparent hover:bg-primary; + @apply text-sm border border-current rounded px-2.5 py-1 font-bold transition-colors; +} + +.index { + p { + @apply text-lg lg:text-xl/9 mb-5 max-w-2xl; + } + + h2 { + @apply text-3xl lg:text-5xl font-bold mb-10 text-balance; + } + + pre { + @apply bg-white; + } +} + +.add, +.remove { + @apply shadow-[2px_0_currentColor_inset]; +} + +.add { + @apply !bg-green-200 dark:!bg-green-200/50 text-green-300; + + &::before { + @apply absolute start-1.5 content-['+']; + } +} + +.remove { + @apply !bg-red-200 dark:!bg-red-200/50 text-red-300; + + &::before { + @apply absolute start-1.5 content-['-']; + } +} + +.step0, +.step6 { + .v2 { + @apply opacity-0; + } +} + +.step1 .v2 code > span:nth-child(5) { + @apply add; +} + +.step2 .v3 code > span:nth-child(6) { + @apply add; +} + +.step3 .v4 code > { + span:nth-child(7), + span:nth-last-child(-n + 5) { + @apply add; + } +} + +.step4 { + .v4 code > span:nth-child(6) { + @apply remove; + } + + .v5 code > span:nth-child(6) { + @apply add; + } +} + +.index-button { + @apply border border-current rounded-md transition-colors py-2.5 px-6; + + &:hover, + &:focus { + @apply bg-primary border-transparent text-white; + } +} + +.nextra-codeblocks { + div.nextra-code { + pre { + @apply h-full; + } + + &:not(:first-child) { + @apply mt-0; + + > div { + @apply first:rounded-l-none; + } + + pre { + @apply rounded-l-none; + } + } + + &:not(:last-child) { + > div { + @apply first:rounded-r-none; + } + + pre { + @apply rounded-r-none; + } + } + } +} + +.index-bg { + background: linear-gradient( + 303.75deg, + rgba(124, 124, 124, 0.2) 0.8%, + rgba(124, 124, 124, 0) 74.17% + ), + linear-gradient(0deg, #f8f8f8, #f8f8f8); + + .dark & { + background: linear-gradient(0deg, #111, #111), + linear-gradient( + 303.75deg, + rgba(124, 124, 124, 0.2) 0.8%, + rgba(124, 124, 124, 0) 74.17% + ); + } +} + +.index-gradient { + @apply bg-gradient-to-b from-transparent to-primary/5 dark:to-primary/10; +} + +.type-evolution { + @apply w-full overflow-hidden; + + #typeEvolveView { + @apply select-none h-full relative left-0 flex; + + .v1, + .v2, + .v3, + .v4 { + @apply border-r dark:border-neutral-800 w-1/2 shrink-0; + } + + .v5 { + @apply w-full shrink-0; + } + + &.step1 { + .v2 { + opacity: 1; + transition: opacity 0.5s ease-in-out; + } + } + + &.step2 { + left: calc(-1 * 50%); + transition: left 0.5s ease-in-out; + } + + &.step3 { + left: calc(-2 * 50%); + transition: left 0.5s ease-in-out; + } + + &.step4 { + left: calc(-3 * 50%); + transition: left 0.5s ease-in-out; + } + + &.step5 { + left: calc(-4 * 50%); + transition: left 0.5s ease-in-out; + } + + &.step6 { + .v5 { + left: calc(-4 * 50%); + opacity: 0; + transition: opacity 0.5s ease-in-out; + } + } + } +} + +.apiIndex { + @apply mt-6; +} + +.apiIndex li { + margin: 0 0 5px 0; +} + +.apiIndex li a { + color: inherit; + display: block; + position: relative; + text-decoration: none; +} + +.apiIndex li a:hover::before { + @apply text-primary; + content: '#'; + font-size: 16px; + left: -2em; + line-height: 20px; + position: absolute; +} + +.apiIndex li { + @apply bg-white dark:bg-black; + @apply [box-shadow:inset_0_0_0_1px_#ddd,inset_4px_0_0_#ddd]; + @apply dark:[box-shadow:inset_0_0_0_1px_#444,inset_4px_0_0_#444]; + font-size: 13px; + padding: 7px 14px; +} diff --git a/website/icons/discord.svg b/website/icons/discord.svg new file mode 100644 index 0000000000..57ea755cc5 --- /dev/null +++ b/website/icons/discord.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/website/icons/github.svg b/website/icons/github.svg new file mode 100644 index 0000000000..66cb3d3791 --- /dev/null +++ b/website/icons/github.svg @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/website/icons/graphql-wordmark.svg b/website/icons/graphql-wordmark.svg new file mode 100644 index 0000000000..c407187504 --- /dev/null +++ b/website/icons/graphql-wordmark.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/website/icons/graphql.svg b/website/icons/graphql.svg new file mode 100644 index 0000000000..857fa8d9df --- /dev/null +++ b/website/icons/graphql.svg @@ -0,0 +1,18 @@ + + + + + + + + + + \ No newline at end of file diff --git a/website/icons/index.ts b/website/icons/index.ts new file mode 100644 index 0000000000..3935beb8e7 --- /dev/null +++ b/website/icons/index.ts @@ -0,0 +1,6 @@ +export { default as DiscordIcon } from './discord.svg'; +export { default as GitHubIcon } from './github.svg'; +export { default as GraphQLLogo } from './graphql.svg'; +export { default as GraphQLWordmarkLogo } from './graphql-wordmark.svg'; +export { default as StackOverflowIcon } from './stackoverflow.svg'; +export { default as TwitterIcon } from './twitter.svg'; diff --git a/website/icons/stackoverflow.svg b/website/icons/stackoverflow.svg new file mode 100644 index 0000000000..d210d7768a --- /dev/null +++ b/website/icons/stackoverflow.svg @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/website/icons/twitter.svg b/website/icons/twitter.svg new file mode 100644 index 0000000000..377365e1cf --- /dev/null +++ b/website/icons/twitter.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/website/next-env.d.ts b/website/next-env.d.ts new file mode 100644 index 0000000000..a4a7b3f5cf --- /dev/null +++ b/website/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. diff --git a/website/next.config.mjs b/website/next.config.mjs new file mode 100644 index 0000000000..0bb804d8e5 --- /dev/null +++ b/website/next.config.mjs @@ -0,0 +1,52 @@ +import nextra from 'nextra'; +import path from 'node:path'; + +const withNextra = nextra({ + theme: 'nextra-theme-docs', + themeConfig: './theme.config.tsx', +}); + +const sep = path.sep === '/' ? '/' : '\\\\'; + +const ALLOWED_SVG_REGEX = new RegExp(`${sep}icons${sep}.+\\.svg$`); + +/** + * @type {import('next').NextConfig} + */ +export default withNextra({ + webpack(config) { + const fileLoaderRule = config.module.rules.find((rule) => + rule.test?.test?.('.svg'), + ); + + fileLoaderRule.exclude = ALLOWED_SVG_REGEX; + + config.module.rules.push({ + test: ALLOWED_SVG_REGEX, + use: ['@svgr/webpack'], + }); + return config; + }, + output: 'export', + images: { + loader: 'custom', + imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], + deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], + }, + transpilePackages: ['next-image-export-optimizer'], + env: { + nextImageExportOptimizer_imageFolderPath: 'public/images', + nextImageExportOptimizer_exportFolderPath: 'out', + nextImageExportOptimizer_quality: '75', + nextImageExportOptimizer_storePicturesInWEBP: 'true', + nextImageExportOptimizer_exportFolderName: 'nextImageExportOptimizer', + // If you do not want to use blurry placeholder images, then you can set + // nextImageExportOptimizer_generateAndUseBlurImages to false and pass + // `placeholder="empty"` to all components. + nextImageExportOptimizer_generateAndUseBlurImages: 'true', + // If you want to cache the remote images, you can set the time to live of the cache in seconds. + // The default value is 0 seconds. + nextImageExportOptimizer_remoteImageCacheTTL: '0', + }, + trailingSlash: true, +}); diff --git a/website/package-lock.json b/website/package-lock.json new file mode 100644 index 0000000000..4bdfc8cfe7 --- /dev/null +++ b/website/package-lock.json @@ -0,0 +1,9536 @@ +{ + "name": "website", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "website", + "version": "0.0.0", + "devDependencies": { + "@svgr/webpack": "^8.1.0", + "@tailwindcss/typography": "^0.5.10", + "@types/node": "^22.7.5", + "autoprefixer": "^10.4.20", + "next": "^14.2.15", + "nextra": "^3.0.13", + "nextra-theme-docs": "^3.0.13", + "postcss": "^8.4.47", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "tailwindcss": "^3.4.14", + "typescript": "^5.6.3" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.4.1.tgz", + "integrity": "sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==", + "dev": true, + "dependencies": { + "package-manager-detector": "^0.2.0", + "tinyexec": "^0.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.25.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", + "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.8", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.8", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz", + "integrity": "sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz", + "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/traverse": "^7.25.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz", + "integrity": "sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "regexpu-core": "^6.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz", + "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz", + "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz", + "integrity": "sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-wrap-function": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz", + "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz", + "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz", + "integrity": "sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz", + "integrity": "sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz", + "integrity": "sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz", + "integrity": "sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz", + "integrity": "sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz", + "integrity": "sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", + "integrity": "sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", + "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", + "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz", + "integrity": "sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz", + "integrity": "sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.8.tgz", + "integrity": "sha512-9ypqkozyzpG+HxlH4o4gdctalFGIjjdufzo7I2XPda0iBnZ6a+FO0rIEQcdSPXp02CkvGsII1exJhmROPQd5oA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz", + "integrity": "sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz", + "integrity": "sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz", + "integrity": "sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz", + "integrity": "sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.8.tgz", + "integrity": "sha512-e82gl3TCorath6YLf9xUwFehVvjvfqFhdOo4+0iVIVju+6XOi5XHkqB3P2AXnSwoeTX0HBoXq5gJFtvotJzFnQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz", + "integrity": "sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/traverse": "^7.25.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz", + "integrity": "sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/template": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz", + "integrity": "sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz", + "integrity": "sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz", + "integrity": "sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.8.tgz", + "integrity": "sha512-gznWY+mr4ZQL/EWPcbBQUP3BXS5FwZp8RUOw06BaRn8tQLzN4XLIxXejpHN9Qo8x8jjBmAAKp6FoS51AgkSA/A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz", + "integrity": "sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.8.tgz", + "integrity": "sha512-sPtYrduWINTQTW7FtOy99VCTWp4H23UX7vYcut7S4CIMEXU+54zKX9uCoGkLsWXteyaMXzVHgzWbLfQ1w4GZgw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz", + "integrity": "sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz", + "integrity": "sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.8.tgz", + "integrity": "sha512-4OMNv7eHTmJ2YXs3tvxAfa/I43di+VcF+M4Wt66c88EAED1RoGaf1D64cL5FkRpNL+Vx9Hds84lksWvd/wMIdA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz", + "integrity": "sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.8.tgz", + "integrity": "sha512-f5W0AhSbbI+yY6VakT04jmxdxz+WsID0neG7+kQZbCOjuyJNdL5Nn4WIBm4hRpKnUcO9lP0eipUhFN12JpoH8g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz", + "integrity": "sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz", + "integrity": "sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz", + "integrity": "sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz", + "integrity": "sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz", + "integrity": "sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz", + "integrity": "sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.8.tgz", + "integrity": "sha512-Z7WJJWdQc8yCWgAmjI3hyC+5PXIubH9yRKzkl9ZEG647O9szl9zvmKLzpbItlijBnVhTUf1cpyWBsZ3+2wjWPQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.8.tgz", + "integrity": "sha512-rm9a5iEFPS4iMIy+/A/PiS0QN0UyjPIeVvbU5EMZFKJZHt8vQnasbpo3T3EFcxzCeYO0BHfc4RqooCZc51J86Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.8.tgz", + "integrity": "sha512-LkUu0O2hnUKHKE7/zYOIjByMa4VRaV2CD/cdGz0AxU9we+VA3kDDggKEzI0Oz1IroG+6gUP6UmWEHBMWZU316g==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-transform-parameters": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz", + "integrity": "sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.8.tgz", + "integrity": "sha512-EbQYweoMAHOn7iJ9GgZo14ghhb9tTjgOc88xFgYngifx7Z9u580cENCV159M4xDh3q/irbhSjZVpuhpC2gKBbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.8.tgz", + "integrity": "sha512-q05Bk7gXOxpTHoQ8RSzGSh/LHVB9JEIkKnk3myAWwZHnYiTGYtbdrYkIsS8Xyh4ltKf7GNUSgzs/6P2bJtBAQg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz", + "integrity": "sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz", + "integrity": "sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.8.tgz", + "integrity": "sha512-8Uh966svuB4V8RHHg0QJOB32QK287NBksJOByoKmHMp1TAobNniNalIkI2i5IPj5+S9NYCG4VIjbEuiSN8r+ow==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz", + "integrity": "sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.7.tgz", + "integrity": "sha512-/qXt69Em8HgsjCLu7G3zdIQn7A2QwmYND7Wa0LTp09Na+Zn8L5d0A7wSXrKi18TJRc/Q5S1i1De/SU1LzVkSvA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.7.tgz", + "integrity": "sha512-r0QY7NVU8OnrwE+w2IWiRom0wwsTbjx4+xH2RTd7AVdof3uurXOF+/mXHQDRk+2jIvWgSaCHKMgggfvM4dyUGA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz", + "integrity": "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.7.tgz", + "integrity": "sha512-5yd3lH1PWxzW6IZj+p+Y4OLQzz0/LzlOG8vGqonHfVR3euf1vyzyMUJk9Ac+m97BH46mFc/98t9PmYLyvgL3qg==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.7.tgz", + "integrity": "sha512-6YTHJ7yjjgYqGc8S+CbEXhLICODk0Tn92j+vNJo07HFk9t3bjFgAKxPLFhHwF2NjmQVSI1zBRfBWUeVBa2osfA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz", + "integrity": "sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz", + "integrity": "sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz", + "integrity": "sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz", + "integrity": "sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz", + "integrity": "sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz", + "integrity": "sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz", + "integrity": "sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.7.tgz", + "integrity": "sha512-VKlgy2vBzj8AmEzunocMun2fF06bsSWV+FvVXohtL6FGve/+L217qhHxRTVGHEDO/YR8IANcjzgJsd04J8ge5Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/plugin-syntax-typescript": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz", + "integrity": "sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz", + "integrity": "sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz", + "integrity": "sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz", + "integrity": "sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.8.tgz", + "integrity": "sha512-58T2yulDHMN8YMUxiLq5YmWUnlDCyY1FsHM+v12VMx+1/FlrUj5tY50iDCpofFQEM8fMYOaY9YRvym2jcjn1Dg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.8", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.25.7", + "@babel/plugin-syntax-import-attributes": "^7.25.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.8", + "@babel/plugin-transform-async-to-generator": "^7.25.7", + "@babel/plugin-transform-block-scoped-functions": "^7.25.7", + "@babel/plugin-transform-block-scoping": "^7.25.7", + "@babel/plugin-transform-class-properties": "^7.25.7", + "@babel/plugin-transform-class-static-block": "^7.25.8", + "@babel/plugin-transform-classes": "^7.25.7", + "@babel/plugin-transform-computed-properties": "^7.25.7", + "@babel/plugin-transform-destructuring": "^7.25.7", + "@babel/plugin-transform-dotall-regex": "^7.25.7", + "@babel/plugin-transform-duplicate-keys": "^7.25.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-dynamic-import": "^7.25.8", + "@babel/plugin-transform-exponentiation-operator": "^7.25.7", + "@babel/plugin-transform-export-namespace-from": "^7.25.8", + "@babel/plugin-transform-for-of": "^7.25.7", + "@babel/plugin-transform-function-name": "^7.25.7", + "@babel/plugin-transform-json-strings": "^7.25.8", + "@babel/plugin-transform-literals": "^7.25.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.8", + "@babel/plugin-transform-member-expression-literals": "^7.25.7", + "@babel/plugin-transform-modules-amd": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-modules-systemjs": "^7.25.7", + "@babel/plugin-transform-modules-umd": "^7.25.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-new-target": "^7.25.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.8", + "@babel/plugin-transform-numeric-separator": "^7.25.8", + "@babel/plugin-transform-object-rest-spread": "^7.25.8", + "@babel/plugin-transform-object-super": "^7.25.7", + "@babel/plugin-transform-optional-catch-binding": "^7.25.8", + "@babel/plugin-transform-optional-chaining": "^7.25.8", + "@babel/plugin-transform-parameters": "^7.25.7", + "@babel/plugin-transform-private-methods": "^7.25.7", + "@babel/plugin-transform-private-property-in-object": "^7.25.8", + "@babel/plugin-transform-property-literals": "^7.25.7", + "@babel/plugin-transform-regenerator": "^7.25.7", + "@babel/plugin-transform-reserved-words": "^7.25.7", + "@babel/plugin-transform-shorthand-properties": "^7.25.7", + "@babel/plugin-transform-spread": "^7.25.7", + "@babel/plugin-transform-sticky-regex": "^7.25.7", + "@babel/plugin-transform-template-literals": "^7.25.7", + "@babel/plugin-transform-typeof-symbol": "^7.25.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.7", + "@babel/plugin-transform-unicode-property-regex": "^7.25.7", + "@babel/plugin-transform-unicode-regex": "^7.25.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.7.tgz", + "integrity": "sha512-GjV0/mUEEXpi1U5ZgDprMRRgajGMRW3G5FjMr5KLKD8nT2fTG8+h/klV3+6Dm5739QE+K5+2e91qFKAYI3pmRg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-transform-react-display-name": "^7.25.7", + "@babel/plugin-transform-react-jsx": "^7.25.7", + "@babel/plugin-transform-react-jsx-development": "^7.25.7", + "@babel/plugin-transform-react-pure-annotations": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.25.7.tgz", + "integrity": "sha512-rkkpaXJZOFN45Fb+Gki0c+KMIglk4+zZXOoMJuyEK8y8Kkc8Jd3BDmP7qPsz0zQMJj+UD7EprF+AqAXcILnexw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-typescript": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.0.tgz", + "integrity": "sha512-o+UlMLt49RvtCASlOMW0AkHnabN9wR9rwCCherxO0yG4Npy34GkvrAqdXQvrhNs+jh+gkK8gB8Lf05qL/O7KWg==", + "dev": true + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "dev": true, + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "dev": true, + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "dev": true + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "dev": true + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "dev": true + }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "dev": true, + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "dev": true, + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.25", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.25.tgz", + "integrity": "sha512-hZOmgN0NTOzOuZxI1oIrDu3Gcl8WViIkvPMpB4xdd4QD6xAMtwgwr3VPoiyH/bLtRcS1cDnhxLSD1NsMJmwh/A==", + "dev": true, + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "dev": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "dev": true + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.5.tgz", + "integrity": "sha512-t5tOGMgZ/i5+ALl2/offNqAQq/lfUnKLEw0mXQI4N4bqpedhrSE+fyKLpwnd22sK0dif6AV+ufQcTsKShB9J1g==", + "dev": true, + "dependencies": { + "tslib": "^2.7.0" + } + }, + "node_modules/@headlessui/react": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.10.tgz", + "integrity": "sha512-6mLa2fjMDAFQi+/R10B+zU3edsUk/MDtENB2zHho0lqKU1uzhAfJLUduWds4nCo8wbl3vULtC5rJfZAQ1yqIng==", + "dev": true, + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.17.1", + "@react-aria/interactions": "^3.21.3", + "@tanstack/react-virtual": "^3.8.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^18", + "react-dom": "^18" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true + }, + "node_modules/@iconify/utils": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.33.tgz", + "integrity": "sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==", + "dev": true, + "dependencies": { + "@antfu/install-pkg": "^0.4.0", + "@antfu/utils": "^0.7.10", + "@iconify/types": "^2.0.0", + "debug": "^4.3.6", + "kolorist": "^1.8.0", + "local-pkg": "^0.5.0", + "mlly": "^1.7.1" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz", + "integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", + "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", + "dev": true, + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz", + "integrity": "sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==", + "dev": true, + "dependencies": { + "langium": "3.0.0" + } + }, + "node_modules/@napi-rs/simple-git": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git/-/simple-git-0.1.19.tgz", + "integrity": "sha512-jMxvwzkKzd3cXo2EB9GM2ic0eYo2rP/BS6gJt6HnWbsDO1O8GSD4k7o2Cpr2YERtMpGF/MGcDfsfj2EbQPtrXw==", + "dev": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/simple-git-android-arm-eabi": "0.1.19", + "@napi-rs/simple-git-android-arm64": "0.1.19", + "@napi-rs/simple-git-darwin-arm64": "0.1.19", + "@napi-rs/simple-git-darwin-x64": "0.1.19", + "@napi-rs/simple-git-freebsd-x64": "0.1.19", + "@napi-rs/simple-git-linux-arm-gnueabihf": "0.1.19", + "@napi-rs/simple-git-linux-arm64-gnu": "0.1.19", + "@napi-rs/simple-git-linux-arm64-musl": "0.1.19", + "@napi-rs/simple-git-linux-powerpc64le-gnu": "0.1.19", + "@napi-rs/simple-git-linux-s390x-gnu": "0.1.19", + "@napi-rs/simple-git-linux-x64-gnu": "0.1.19", + "@napi-rs/simple-git-linux-x64-musl": "0.1.19", + "@napi-rs/simple-git-win32-arm64-msvc": "0.1.19", + "@napi-rs/simple-git-win32-x64-msvc": "0.1.19" + } + }, + "node_modules/@napi-rs/simple-git-android-arm-eabi": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-android-arm-eabi/-/simple-git-android-arm-eabi-0.1.19.tgz", + "integrity": "sha512-XryEH/hadZ4Duk/HS/HC/cA1j0RHmqUGey3MsCf65ZS0VrWMqChXM/xlTPWuY5jfCc/rPubHaqI7DZlbexnX/g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-android-arm64": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-android-arm64/-/simple-git-android-arm64-0.1.19.tgz", + "integrity": "sha512-ZQ0cPvY6nV9p7zrR9ZPo7hQBkDAcY/CHj3BjYNhykeUCiSNCrhvwX+WEeg5on8M1j4d5jcI/cwVG2FslfiByUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-darwin-arm64": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-darwin-arm64/-/simple-git-darwin-arm64-0.1.19.tgz", + "integrity": "sha512-viZB5TYgjA1vH+QluhxZo0WKro3xBA+1xSzYx8mcxUMO5gnAoUMwXn0ZO/6Zy6pai+aGae+cj6XihGnrBRu3Pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-darwin-x64": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-darwin-x64/-/simple-git-darwin-x64-0.1.19.tgz", + "integrity": "sha512-6dNkzSNUV5X9rsVYQbpZLyJu4Gtkl2vNJ3abBXHX/Etk0ILG5ZasO3ncznIANZQpqcbn/QPHr49J2QYAXGoKJA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-freebsd-x64": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-freebsd-x64/-/simple-git-freebsd-x64-0.1.19.tgz", + "integrity": "sha512-sB9krVIchzd20FjI2ZZ8FDsTSsXLBdnwJ6CpeVyrhXHnoszfcqxt49ocZHujAS9lMpXq7i2Nv1EXJmCy4KdhwA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-arm-gnueabihf": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm-gnueabihf/-/simple-git-linux-arm-gnueabihf-0.1.19.tgz", + "integrity": "sha512-6HPn09lr9N1n5/XKfP8Np53g4fEXVxOFqNkS6rTH3Rm1lZHdazTRH62RggXLTguZwjcE+MvOLvoTIoR5kAS8+g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-arm64-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm64-gnu/-/simple-git-linux-arm64-gnu-0.1.19.tgz", + "integrity": "sha512-G0gISckt4cVDp3oh5Z6PV3GHJrJO6Z8bIS+9xA7vTtKdqB1i5y0n3cSFLlzQciLzhr+CajFD27doW4lEyErQ/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-arm64-musl": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm64-musl/-/simple-git-linux-arm64-musl-0.1.19.tgz", + "integrity": "sha512-OwTRF+H4IZYxmDFRi1IrLMfqbdIpvHeYbJl2X94NVsLVOY+3NUHvEzL3fYaVx5urBaMnIK0DD3wZLbcueWvxbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-powerpc64le-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-powerpc64le-gnu/-/simple-git-linux-powerpc64le-gnu-0.1.19.tgz", + "integrity": "sha512-p7zuNNVyzpRvkCt2RIGv9FX/WPcPbZ6/FRUgUTZkA2WU33mrbvNqSi4AOqCCl6mBvEd+EOw5NU4lS9ORRJvAEg==", + "cpu": [ + "powerpc64le" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-s390x-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-s390x-gnu/-/simple-git-linux-s390x-gnu-0.1.19.tgz", + "integrity": "sha512-6N2vwJUPLiak8GLrS0a3is0gSb0UwI2CHOOqtvQxPmv+JVI8kn3vKiUscsktdDb0wGEPeZ8PvZs0y8UWix7K4g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-x64-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-x64-gnu/-/simple-git-linux-x64-gnu-0.1.19.tgz", + "integrity": "sha512-61YfeO1J13WK7MalLgP3QlV6of2rWnVw1aqxWkAgy/lGxoOFSJ4Wid6ANVCEZk4tJpPX/XNeneqkUz5xpeb2Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-x64-musl": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-x64-musl/-/simple-git-linux-x64-musl-0.1.19.tgz", + "integrity": "sha512-cCTWNpMJnN3PrUBItWcs3dQKCydsIasbrS3laMzq8k7OzF93Zrp2LWDTPlLCO9brbBVpBzy2Qk5Xg9uAfe/Ukw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-win32-arm64-msvc": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-win32-arm64-msvc/-/simple-git-win32-arm64-msvc-0.1.19.tgz", + "integrity": "sha512-sWavb1BjeLKKBA+PbTsRSSzVNfb7V/dOpaJvkgR5d2kWFn/AHmCZHSSj/3nyZdYf0BdDC+DIvqk3daAEZ6QMVw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-win32-x64-msvc": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-win32-x64-msvc/-/simple-git-win32-x64-msvc-0.1.19.tgz", + "integrity": "sha512-FmNuPoK4+qwaSCkp8lm3sJlrxk374enW+zCE5ZksXlZzj/9BDJAULJb5QUJ7o9Y8A/G+d8LkdQLPBE2Jaxe5XA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/env": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.15.tgz", + "integrity": "sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ==", + "dev": true + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.15.tgz", + "integrity": "sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.15.tgz", + "integrity": "sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.15.tgz", + "integrity": "sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.15.tgz", + "integrity": "sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.15.tgz", + "integrity": "sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.15.tgz", + "integrity": "sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.15.tgz", + "integrity": "sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.15.tgz", + "integrity": "sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.15.tgz", + "integrity": "sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@react-aria/focus": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.18.4.tgz", + "integrity": "sha512-91J35077w9UNaMK1cpMUEFRkNNz0uZjnSwiyBCFuRdaVuivO53wNC9XtWSDNDdcO5cGy87vfJRVAiyoCn/mjqA==", + "dev": true, + "dependencies": { + "@react-aria/interactions": "^3.22.4", + "@react-aria/utils": "^3.25.3", + "@react-types/shared": "^3.25.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.22.4.tgz", + "integrity": "sha512-E0vsgtpItmknq/MJELqYJwib+YN18Qag8nroqwjk1qOnBa9ROIkUhWJerLi1qs5diXq9LHKehZDXRlwPvdEFww==", + "dev": true, + "dependencies": { + "@react-aria/ssr": "^3.9.6", + "@react-aria/utils": "^3.25.3", + "@react-types/shared": "^3.25.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.6.tgz", + "integrity": "sha512-iLo82l82ilMiVGy342SELjshuWottlb5+VefO3jOQqQRNYnJBFpUSadswDPbRimSgJUZuFwIEYs6AabkP038fA==", + "dev": true, + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.25.3", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.25.3.tgz", + "integrity": "sha512-PR5H/2vaD8fSq0H/UB9inNbc8KDcVmW6fYAfSWkkn+OAdhTTMVKqXXrZuZBWyFfSD5Ze7VN6acr4hrOQm2bmrA==", + "dev": true, + "dependencies": { + "@react-aria/ssr": "^3.9.6", + "@react-stately/utils": "^3.10.4", + "@react-types/shared": "^3.25.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.4.tgz", + "integrity": "sha512-gBEQEIMRh5f60KCm7QKQ2WfvhB2gLUr9b72sqUdIZ2EG+xuPgaIlCBeSicvjmjBvYZwOjoOEnmIkcx2GHp/HWw==", + "dev": true, + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-types/shared": { + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.25.0.tgz", + "integrity": "sha512-OZSyhzU6vTdW3eV/mz5i6hQwQUhkRs7xwY2d1aqPvTdMe0+2cY7Fwp45PAiwYLEj73i9ro2FxF9qC4DvHGSCgQ==", + "dev": true, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@shikijs/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.22.0.tgz", + "integrity": "sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==", + "dev": true, + "dependencies": { + "@shikijs/engine-javascript": "1.22.0", + "@shikijs/engine-oniguruma": "1.22.0", + "@shikijs/types": "1.22.0", + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.3" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.22.0.tgz", + "integrity": "sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==", + "dev": true, + "dependencies": { + "@shikijs/types": "1.22.0", + "@shikijs/vscode-textmate": "^9.3.0", + "oniguruma-to-js": "0.4.3" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.0.tgz", + "integrity": "sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==", + "dev": true, + "dependencies": { + "@shikijs/types": "1.22.0", + "@shikijs/vscode-textmate": "^9.3.0" + } + }, + "node_modules/@shikijs/twoslash": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-1.22.0.tgz", + "integrity": "sha512-r5F/x4GTh18XzhAREehgT9lCDFZlISBSIsOFZQQaqjiOLG81PIqJN1I1D6XY58UN9OJt+3mffuKq19K4FOJKJA==", + "dev": true, + "dependencies": { + "@shikijs/core": "1.22.0", + "@shikijs/types": "1.22.0", + "twoslash": "^0.2.12" + } + }, + "node_modules/@shikijs/types": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.22.0.tgz", + "integrity": "sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==", + "dev": true, + "dependencies": { + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.3.0.tgz", + "integrity": "sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==", + "dev": true + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dev": true, + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true + }, + "node_modules/@swc/helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "dev": true, + "dependencies": { + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz", + "integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.10.8.tgz", + "integrity": "sha512-VbzbVGSsZlQktyLrP5nxE+vE1ZR+U0NFAWPbJLoG2+DKPwd2D7dVICTVIIaYlJqX1ZCEnYDbaOpmMwbsyhBoIA==", + "dev": true, + "dependencies": { + "@tanstack/virtual-core": "3.10.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.8.tgz", + "integrity": "sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@theguild/remark-mermaid": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@theguild/remark-mermaid/-/remark-mermaid-0.1.3.tgz", + "integrity": "sha512-2FjVlaaKXK7Zj7UJAgOVTyaahn/3/EAfqYhyXg0BfDBVUl+lXcoIWRaxzqfnDr2rv8ax6GsC5mNh6hAaT86PDw==", + "dev": true, + "dependencies": { + "mermaid": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/@theguild/remark-npm2yarn": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@theguild/remark-npm2yarn/-/remark-npm2yarn-0.3.2.tgz", + "integrity": "sha512-H9T/GOuS/+4H7AY1cfD5DJIIIcGIIw1zMCB8OeTgXk7azJULsnuOurZ/CR54rvuTD+Krx0MVQccaUCvCWfP+vw==", + "dev": true, + "dependencies": { + "npm-to-yarn": "^3.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", + "dev": true + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "dev": true + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "dev": true, + "peer": true + }, + "node_modules/@types/react": { + "version": "18.3.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", + "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true + }, + "node_modules/@typescript/vfs": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.0.tgz", + "integrity": "sha512-hvJUjNVeBMp77qPINuUvYXj4FyWeeMMKZkxEATEU3hqBAQ7qdTBCUFT7Sp0Zu0faeEtFf+ldXxMEDr/bk73ISg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/arg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/arg/-/arg-1.0.0.tgz", + "integrity": "sha512-Wk7TEzl1KqvTGs/uyhmHO/3XLd3t1UeU4IstvPXVzGPM522cTjqjNZ99esCkcL52sjqjo8e8CTBcWhkxvGzoAw==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "dev": true, + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/better-react-mathjax": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/better-react-mathjax/-/better-react-mathjax-2.0.3.tgz", + "integrity": "sha512-wfifT8GFOKb1TWm2+E50I6DJpLZ5kLbch283Lu043EJtwSv0XvZDjr4YfR4d2MjAhqP6SH4VjjrKgbX8R00oCQ==", + "dev": true, + "dependencies": { + "mathjax-full": "^3.2.2" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "dev": true, + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "dev": true, + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "dev": true + }, + "node_modules/clipboardy": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.2.2.tgz", + "integrity": "sha512-16KrBOV7bHmHdxcQiCvfUFYVFyEah4FI8vYT1Fr7CGSA4G+xBWMEfUEQJS1hxeHGtI9ju1Bzs9uXSbj5HZKArw==", + "dev": true, + "dependencies": { + "arch": "^2.1.0", + "execa": "^0.8.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", + "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dev": true, + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "peer": true + }, + "node_modules/cytoscape": { + "version": "3.30.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.2.tgz", + "integrity": "sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dev": true, + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "dev": true, + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "dev": true, + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "dev": true + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dev": true, + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dev": true, + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dev": true, + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dev": true, + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dev": true, + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dev": true, + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dev": true, + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dev": true, + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dev": true, + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dev": true, + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "dev": true + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dev": true, + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dev": true, + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dev": true, + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dev": true, + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dev": true, + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dev": true, + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz", + "integrity": "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==", + "dev": true, + "dependencies": { + "d3": "^7.8.2", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dev": true, + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dev": true, + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/dompurify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", + "dev": true + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.39", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.39.tgz", + "integrity": "sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.1.2.tgz", + "integrity": "sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dev": true, + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flexsearch": { + "version": "0.7.43", + "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.7.43.tgz", + "integrity": "sha512-c5o/+Um8aqCSOXGcZoqZOm+NqtVwNsvVpWv6lfmSclU954O3wvQKxxK8zj74fPaSJbXpSLTs4PRhh+wnoCXnKg==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/foreground-child/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dev": true, + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-dom": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.0.tgz", + "integrity": "sha512-d6235voAp/XR3Hh5uy7aGLbM3S4KamdW0WEgOaU1YoewnuYw4HXb5eRtv9g65m/RFGEfUY1Mw4UqCc5Y8L4Stg==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "hastscript": "^8.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html-isomorphic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-dom": "^5.0.0", + "hast-util-from-html": "^2.0.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", + "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz", + "integrity": "sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "dev": true + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "dev": true, + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "dev": true + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/katex": { + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true + }, + "node_modules/langium": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.0.0.tgz", + "integrity": "sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==", + "dev": true, + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "dev": true + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true + }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz", + "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mathjax-full": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz", + "integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==", + "dev": true, + "dependencies": { + "esm": "^3.2.25", + "mhchemparser": "^4.1.0", + "mj-context-menu": "^0.6.1", + "speech-rule-engine": "^4.0.6" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", + "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "dev": true, + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "dev": true, + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mermaid": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.3.0.tgz", + "integrity": "sha512-fFmf2gRXLtlGzug4wpIGN+rQdZ30M8IZEB1D3eZkXNqC7puhqeURBcD/9tbwXsqBO+A6Nzzo3MSSepmnw5xSeg==", + "dev": true, + "dependencies": { + "@braintree/sanitize-url": "^7.0.1", + "@iconify/utils": "^2.1.32", + "@mermaid-js/parser": "^0.3.0", + "cytoscape": "^3.29.2", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.10", + "dayjs": "^1.11.10", + "dompurify": "^3.0.11 <3.1.7", + "katex": "^0.16.9", + "khroma": "^2.1.0", + "lodash-es": "^4.17.21", + "marked": "^13.0.2", + "roughjs": "^4.6.6", + "stylis": "^4.3.1", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.1" + } + }, + "node_modules/mhchemparser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz", + "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==", + "dev": true + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", + "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dev": true, + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dev": true, + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dev": true, + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "dev": true, + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dev": true, + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dev": true, + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", + "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "dev": true, + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "dev": true, + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "dev": true, + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", + "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mj-context-menu": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", + "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==", + "dev": true + }, + "node_modules/mlly": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.2.tgz", + "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.1", + "pathe": "^1.1.2", + "pkg-types": "^1.2.0", + "ufo": "^1.5.4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.15.tgz", + "integrity": "sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw==", + "dev": true, + "dependencies": { + "@next/env": "14.2.15", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.2.15", + "@next/swc-darwin-x64": "14.2.15", + "@next/swc-linux-arm64-gnu": "14.2.15", + "@next/swc-linux-arm64-musl": "14.2.15", + "@next/swc-linux-x64-gnu": "14.2.15", + "@next/swc-linux-x64-musl": "14.2.15", + "@next/swc-win32-arm64-msvc": "14.2.15", + "@next/swc-win32-ia32-msvc": "14.2.15", + "@next/swc-win32-x64-msvc": "14.2.15" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "dev": true, + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/nextra": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/nextra/-/nextra-3.0.13.tgz", + "integrity": "sha512-aK5ZEnKGE2lWhJvFfpj7T35JeA4ytvo2zUiXJ5JApIpFrwkzy8IYTa+irGHB0l9sxGiRlss4p+nAM8Kunvmlug==", + "dev": true, + "dependencies": { + "@formatjs/intl-localematcher": "^0.5.4", + "@headlessui/react": "^2.1.2", + "@mdx-js/mdx": "^3.0.0", + "@mdx-js/react": "^3.0.0", + "@napi-rs/simple-git": "^0.1.9", + "@shikijs/twoslash": "^1.0.0", + "@theguild/remark-mermaid": "^0.1.2", + "@theguild/remark-npm2yarn": "^0.3.2", + "better-react-mathjax": "^2.0.3", + "clsx": "^2.0.0", + "estree-util-to-js": "^2.0.0", + "estree-util-value-to-estree": "^3.0.1", + "github-slugger": "^2.0.0", + "graceful-fs": "^4.2.11", + "gray-matter": "^4.0.3", + "hast-util-to-estree": "^3.1.0", + "katex": "^0.16.9", + "negotiator": "^0.6.3", + "p-limit": "^6.0.0", + "rehype-katex": "^7.0.0", + "rehype-pretty-code": "0.14.0", + "rehype-raw": "^7.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "remark-math": "^6.0.0", + "remark-reading-time": "^2.0.1", + "remark-smartypants": "^3.0.0", + "shiki": "^1.0.0", + "slash": "^5.1.0", + "title": "^3.5.3", + "unist-util-remove": "^4.0.0", + "unist-util-visit": "^5.0.0", + "yaml": "^2.3.2", + "zod": "^3.22.3", + "zod-validation-error": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "next": ">=13", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/nextra-theme-docs": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/nextra-theme-docs/-/nextra-theme-docs-3.0.13.tgz", + "integrity": "sha512-1NEo4NJxXRsNPE2PXlYdVlW7N8ZWe5XssePFKUq0comQaxDNc6SaxfBNw0VoQlwB3T5ifTp9f5wb9xfIjPa6OA==", + "dev": true, + "dependencies": { + "@headlessui/react": "^2.1.2", + "clsx": "^2.0.0", + "escape-string-regexp": "^5.0.0", + "flexsearch": "^0.7.43", + "next-themes": "^0.3.0", + "scroll-into-view-if-needed": "^3.1.0", + "zod": "^3.22.3" + }, + "peerDependencies": { + "next": ">=13", + "nextra": "3.0.13", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "dev": true, + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-to-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-to-yarn/-/npm-to-yarn-3.0.0.tgz", + "integrity": "sha512-76YnmsbfrYp0tMsWxM0RNX0Vs+x8JxpJGu6B/jDn4lW8+laiTcKmKi9MeMh4UikO4RkJ1oqURoDy9bXJmMXS6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/nebrelbug/npm-to-yarn?sponsor=1" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/oniguruma-to-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz", + "integrity": "sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==", + "dev": true, + "dependencies": { + "regex": "^4.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.1.0.tgz", + "integrity": "sha512-H0jc0q1vOzlEk0TqAKXKZxdl7kX3OFUzCnNVUnq5Pc3DGo0kpeaMuPqxQn235HibwBEb0/pm9dgKTjXy66fBkg==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "node_modules/package-manager-detector": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.2.tgz", + "integrity": "sha512-VgXbyrSNsml4eHWIvxxG/nTL4wgybMTXCV2Un/+yEc3aDKKU6nQBZjbeP3Pl3qm9Qg92X/1ng4ffvCeD/zwHgg==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "dev": true, + "dependencies": { + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", + "dev": true + }, + "node_modules/parse5": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.0.tgz", + "integrity": "sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA==", + "dev": true, + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "dev": true + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz", + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "dev": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.2", + "pathe": "^1.1.2" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "dev": true + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "dev": true, + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.3.tgz", + "integrity": "sha512-r/AadFO7owAq1QJVeZ/nq9jNS1vyZt+6t1p/E59B56Rn2GCya+gr1KSyOzNL/er+r+B7phv5jG2xU2Nz1YkmJg==", + "dev": true + }, + "node_modules/regexpu-core": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", + "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", + "dev": true, + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/rehype-katex": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/katex": "^0.16.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "katex": "^0.16.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-pretty-code": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/rehype-pretty-code/-/rehype-pretty-code-0.14.0.tgz", + "integrity": "sha512-hBeKF/Wkkf3zyUS8lal9RCUuhypDWLQc+h9UrP9Pav25FUm/AQAVh4m5gdvJxh4Oz+U+xKvdsV01p1LdvsZTiQ==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.4", + "hast-util-to-string": "^3.0.0", + "parse-numeric-range": "^1.3.0", + "rehype-parse": "^9.0.0", + "unified": "^11.0.5", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "shiki": "^1.3.0" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-math": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", + "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-math": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", + "integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==", + "dev": true, + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-reading-time": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/remark-reading-time/-/remark-reading-time-2.0.1.tgz", + "integrity": "sha512-fy4BKy9SRhtYbEHvp6AItbRTnrhiDGbqLQTSYVbQPGuRCncU1ubSsh9p/W5QZSxtYcUXv8KGL0xBgPLyNJA1xw==", + "dev": true, + "dependencies": { + "estree-util-is-identifier-name": "^2.0.0", + "estree-util-value-to-estree": "^1.3.0", + "reading-time": "^1.3.0", + "unist-util-visit": "^3.1.0" + } + }, + "node_modules/remark-reading-time/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true + }, + "node_modules/remark-reading-time/node_modules/estree-util-is-identifier-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.1.0.tgz", + "integrity": "sha512-bEN9VHRyXAUOjkKVQVvArFym08BTWB0aJPppZZr0UNyAqWsLaVfAqP7hbaTJjzHifmB5ebnR8Wm7r7yGN/HonQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-reading-time/node_modules/estree-util-value-to-estree": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-1.3.0.tgz", + "integrity": "sha512-Y+ughcF9jSUJvncXwqRageavjrNPAI+1M/L3BI3PyLp1nmgYTGUXU6t5z1Y7OWuThoDdhPME07bQU+d5LxdJqw==", + "dev": true, + "dependencies": { + "is-plain-obj": "^3.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/remark-reading-time/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/remark-reading-time/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-reading-time/node_modules/unist-util-visit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-3.1.0.tgz", + "integrity": "sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-reading-time/node_modules/unist-util-visit-parents": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz", + "integrity": "sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-smartypants": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "dev": true, + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dev": true, + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "dev": true, + "dependencies": { + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "dev": true, + "dependencies": { + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "dev": true, + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "dev": true, + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "dev": true + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "dev": true, + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "dev": true, + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shiki": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.22.0.tgz", + "integrity": "sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==", + "dev": true, + "dependencies": { + "@shikijs/core": "1.22.0", + "@shikijs/engine-javascript": "1.22.0", + "@shikijs/engine-oniguruma": "1.22.0", + "@shikijs/types": "1.22.0", + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speech-rule-engine": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz", + "integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==", + "dev": true, + "dependencies": { + "commander": "9.2.0", + "wicked-good-xpath": "1.3.0", + "xmldom-sre": "0.1.31" + }, + "bin": { + "sre": "bin/sre" + } + }, + "node_modules/speech-rule-engine/node_modules/commander": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", + "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "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, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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 + }, + "node_modules/string-width-cjs/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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "dev": true, + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dev": true, + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "dev": true + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw==", + "dev": true, + "dependencies": { + "has-flag": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true + }, + "node_modules/tailwindcss": { + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/tailwindcss/node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyexec": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", + "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", + "dev": true + }, + "node_modules/title": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/title/-/title-3.5.3.tgz", + "integrity": "sha512-20JyowYglSEeCvZv3EZ0nZ046vLarO37prvV0mbtQV7C8DJPGgN967r8SJkqd3XK3K3lD3/Iyfp3avjfil8Q2Q==", + "dev": true, + "dependencies": { + "arg": "1.0.0", + "chalk": "2.3.0", + "clipboardy": "1.2.2", + "titleize": "1.0.0" + }, + "bin": { + "title": "bin/title.js" + } + }, + "node_modules/titleize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-1.0.0.tgz", + "integrity": "sha512-TARUb7z1pGvlLxgPk++7wJ6aycXF3GJ0sNSBTAsTuJrQG5QuZlkUQP+zl+nbjAh4gMX9yDw9ZYklMd7vAfJKEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "dev": true + }, + "node_modules/twoslash": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.2.12.tgz", + "integrity": "sha512-tEHPASMqi7kqwfJbkk7hc/4EhlrKCSLcur+TcvYki3vhIfaRMXnXjaYFgXpoZRbT6GdprD4tGuVBEmTpUgLBsw==", + "dev": true, + "dependencies": { + "@typescript/vfs": "^1.6.0", + "twoslash-protocol": "0.2.12" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/twoslash-protocol": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.2.12.tgz", + "integrity": "sha512-5qZLXVYfZ9ABdjqbvPc4RWMr7PrpPaaDSeaYY55vl/w1j6H6kzsWK/urAEIXlzYlyrFmyz1UbwIt+AA0ck+wbg==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-4.0.0.tgz", + "integrity": "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "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/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dev": true, + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wicked-good-xpath": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", + "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "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, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/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 + }, + "node_modules/wrap-ansi-cjs/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, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/xmldom-sre": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", + "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==", + "dev": true, + "engines": { + "node": ">=0.1" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz", + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.18.0" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000000..a69e6e4043 --- /dev/null +++ b/website/package.json @@ -0,0 +1,27 @@ +{ + "name": "website", + "version": "0.0.0", + "description": "The GraphQL.JS documentation website", + "private": true, + "directories": { + "doc": "docs" + }, + "scripts": { + "build": "next build", + "dev": "next" + }, + "devDependencies": { + "@svgr/webpack": "^8.1.0", + "@tailwindcss/typography": "^0.5.10", + "@types/node": "^22.7.5", + "autoprefixer": "^10.4.20", + "next": "^14.2.15", + "nextra": "^3.0.13", + "nextra-theme-docs": "^3.0.13", + "postcss": "^8.4.47", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "tailwindcss": "^3.4.14", + "typescript": "^5.6.3" + } +} diff --git a/website/pages/_app.tsx b/website/pages/_app.tsx new file mode 100644 index 0000000000..c50ff45c1e --- /dev/null +++ b/website/pages/_app.tsx @@ -0,0 +1,31 @@ +import type { AppProps } from 'next/app'; +import { Roboto_Flex, Roboto_Mono } from 'next/font/google'; + +import '../css/globals.css'; + +const robotoFlex = Roboto_Flex({ + subsets: ['latin'], +}); + +const robotoMono = Roboto_Mono({ + subsets: ['latin'], +}); + +// TODO: do we need google analytics? + +export default function App({ Component, pageProps }: AppProps) { + return ( + <> + + + + ); +} diff --git a/website/pages/_document.tsx b/website/pages/_document.tsx new file mode 100644 index 0000000000..e1e9cbbb75 --- /dev/null +++ b/website/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from 'next/document'; + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/website/pages/_meta.ts b/website/pages/_meta.ts new file mode 100644 index 0000000000..b56f19ce54 --- /dev/null +++ b/website/pages/_meta.ts @@ -0,0 +1,39 @@ +const meta = { + index: '', + '-- 1': { + type: 'separator', + title: 'GraphQL.JS Tutorial', + }, + 'getting-started': '', + 'running-an-express-graphql-server': '', + 'graphql-clients': '', + 'basic-types': '', + 'passing-arguments': '', + 'object-types': '', + 'mutations-and-input-types': '', + 'authentication-and-express-middleware': '', + '-- 2': { + type: 'separator', + title: 'Advanced Guides', + }, + 'constructing-types': '', + 'oneof-input-objects': 'OneOf input objects', + 'defer-stream': '', + '-- 3': { + type: 'separator', + title: 'FAQ', + }, + 'going-to-production': '', + 'api-v16': { + type: 'menu', + title: 'API', + items: { + 2: { + title: 'V16', + href: '/api-v16/graphql', + }, + }, + }, +}; + +export default meta; diff --git a/website/pages/api-v16/_meta.ts b/website/pages/api-v16/_meta.ts new file mode 100644 index 0000000000..075de90bca --- /dev/null +++ b/website/pages/api-v16/_meta.ts @@ -0,0 +1,12 @@ +const meta = { + graphql: '', + error: '', + execution: '', + language: '', + type: '', + utilities: '', + validation: '', + 'graphql-http': '', +}; + +export default meta; diff --git a/docs/APIReference-Errors.md b/website/pages/api-v16/error.mdx similarity index 55% rename from docs/APIReference-Errors.md rename to website/pages/api-v16/error.mdx index eccd0934ce..1338d321de 100644 --- a/docs/APIReference-Errors.md +++ b/website/pages/api-v16/error.mdx @@ -1,64 +1,63 @@ --- title: graphql/error -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/error/ -sublinks: formatError,GraphQLError,locatedError,syntaxError -next: /graphql-js/execution/ --- +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql/error` + The `graphql/error` module is responsible for creating and formatting GraphQL errors. You can import either from the `graphql/error` module, or from the root `graphql` module. For example: ```js import { GraphQLError } from 'graphql'; // ES6 -var { GraphQLError } = require('graphql'); // CommonJS +const { GraphQLError } = require('graphql'); // CommonJS ``` ## Overview -
    + ## Errors -### GraphQLError +### `GraphQLError` -```js +```ts class GraphQLError extends Error { - constructor( - message: string, - nodes?: Array, - stack?: ?string, - source?: Source, - positions?: Array, - originalError?: ?Error, - extensions?: ?{ [key: string]: mixed } - ) + constructor( + message: string, + nodes?: any[], + stack?: string, + source?: Source, + positions?: number[], + originalError?: Error, + extensions?: { [key: string]: mixed }, + ); } ``` @@ -66,42 +65,42 @@ A representation of an error that occurred within GraphQL. Contains information about where in the query the error occurred for debugging. Most commonly constructed with `locatedError` below. -### syntaxError +### `syntaxError` -```js +```ts function syntaxError( source: Source, position: number, - description: string + description: string, ): GraphQLError; ``` Produces a GraphQLError representing a syntax error, containing useful descriptive information about the syntax error's position in the source. -### locatedError +### `locatedError` -```js -function locatedError(error: ?Error, nodes: Array): GraphQLError { +```ts +function locatedError(error: Error, nodes: any[]): GraphQLError; ``` Given an arbitrary Error, presumably thrown while attempting to execute a GraphQL operation, produce a new GraphQLError aware of the location in the document responsible for the original Error. -### formatError +### `formatError` -```js -function formatError(error: GraphQLError): GraphQLFormattedError +```ts +function formatError(error: GraphQLError): GraphQLFormattedError; type GraphQLFormattedError = { - message: string, - locations: ?Array + message: string; + locations: GraphQLErrorLocation[]; }; type GraphQLErrorLocation = { - line: number, - column: number + line: number; + column: number; }; ``` diff --git a/docs/APIReference-Execution.md b/website/pages/api-v16/execution.mdx similarity index 50% rename from docs/APIReference-Execution.md rename to website/pages/api-v16/execution.mdx index 750c2889f8..2810ed183a 100644 --- a/docs/APIReference-Execution.md +++ b/website/pages/api-v16/execution.mdx @@ -1,27 +1,25 @@ --- title: graphql/execution -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/execution/ -sublinks: execute -next: /graphql-js/language/ --- +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql/execution` + The `graphql/execution` module is responsible for the execution phase of fulfilling a GraphQL request. You can import either from the `graphql/execution` module, or from the root `graphql` module. For example: ```js import { execute } from 'graphql'; // ES6 -var { execute } = require('graphql'); // CommonJS +const { execute } = require('graphql'); // CommonJS ``` ## Overview -
      + @@ -30,21 +28,25 @@ var { execute } = require('graphql'); // CommonJS ### execute -```js +```ts export function execute( schema: GraphQLSchema, documentAST: Document, rootValue?: mixed, contextValue?: mixed, - variableValues?: ?{[key: string]: mixed}, - operationName?: ?string -): MaybePromise + variableValues?: { [key: string]: mixed }, + operationName?: string, +): MaybePromise; type MaybePromise = Promise | T; -type ExecutionResult = { - data: ?Object; - errors?: Array; +interface ExecutionResult< + TData = ObjMap, + TExtensions = ObjMap, +> { + errors?: ReadonlyArray; + data?: TData | null; + extensions?: TExtensions; } ``` @@ -58,3 +60,25 @@ a GraphQLError will be thrown immediately explaining the invalid input. `ExecutionResult` represents the result of execution. `data` is the result of executing the query, `errors` is null if no errors occurred, and is a non-empty array if an error occurred. + +### executeSync + +```ts +export function executeSync( + schema: GraphQLSchema, + documentAST: Document, + rootValue?: mixed, + contextValue?: mixed, + variableValues?: { [key: string]: mixed }, + operationName?: string, +): ExecutionResult; + +type ExecutionResult = { + data: Object; + errors?: GraphQLError[]; +}; +``` + +This is a short-hand method that will call `execute` and when the response can +be returned synchronously it will be returned, when a `Promise` is returned this +method will throw an error. diff --git a/website/pages/api-v16/graphql-http.mdx b/website/pages/api-v16/graphql-http.mdx new file mode 100644 index 0000000000..73c36fd310 --- /dev/null +++ b/website/pages/api-v16/graphql-http.mdx @@ -0,0 +1,39 @@ +--- +title: graphql-http +--- + +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql-http` + +The [official `graphql-http` package](https://github.com/graphql/graphql-http) provides a simple way to create a fully compliant GraphQL server. It has a handler for Node.js native [`http`](https://nodejs.org/api/http.html), together with handlers for well-known frameworks like [Express](https://expressjs.com/), [Fastify](https://www.fastify.io/) and [Koa](https://koajs.com/); as well as handlers for different runtimes like [Deno](https://deno.land/) and [Bun](https://bun.sh/). + +## Express + +```js +import { createHandler } from 'graphql-http/lib/use/express'; // ES6 +const { createHandler } = require('graphql-http/lib/use/express'); // CommonJS +``` + +### createHandler + +```ts +function createHandler({ + schema, + rootValue, + context, + formatError, + validationRules, +}: { + rootValue?: any; + context?: any; + formatError?: Function; + validationRules?: any[]; +}): Handler; +``` + +Constructs an Express handler based on a GraphQL schema. + +See the [tutorial](/running-an-express-graphql-server/) for sample usage. + +See the [GitHub README](https://github.com/graphql/graphql-http) for more extensive documentation, including how to use `graphql-http` with other server frameworks and runtimes. diff --git a/website/pages/api-v16/graphql.mdx b/website/pages/api-v16/graphql.mdx new file mode 100644 index 0000000000..e6936f279c --- /dev/null +++ b/website/pages/api-v16/graphql.mdx @@ -0,0 +1,181 @@ +--- +title: graphql +--- + +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql` + +The `graphql` module exports a core subset of GraphQL functionality for creation +of GraphQL type systems and servers. + +```js +import { graphql } from 'graphql'; // ES6 +const { graphql } = require('graphql'); // CommonJS +``` + +## Overview + +### Entry Point + + + +### Schema + + + +### Type Definitions + + + +### Scalars + + + +### Errors + + + +## Entry Point + +### `graphql` + +```ts +function graphql( + schema: GraphQLSchema, + requestString: string, + rootValue?: any, + contextValue?: any, + variableValues?: { [key: string]: any }, + operationName?: string, +): Promise; + +interface ExecutionResult< + TData = ObjMap, + TExtensions = ObjMap, +> { + errors?: ReadonlyArray; + data?: TData | null; + extensions?: TExtensions; +} +``` + +The `graphql` function lexes, parses, validates and executes a GraphQL request. +It requires a `schema` and a `requestString`. Optional arguments include a +`rootValue`, which will get passed as the root value to the executor, a `contextValue`, +which will get passed to all resolve functions, +`variableValues`, which will get passed to the executor to provide values for +any variables in `requestString`, and `operationName`, which allows the caller +to specify which operation in `requestString` will be run, in cases where +`requestString` contains multiple top-level operations. + +## Schema + +See the [Type System API Reference](/type#schema). + +## Type Definitions + +See the [Type System API Reference](/type#definitions). + +## Scalars + +See the [Type System API Reference](/type#scalars). + +## Errors + +See the [Errors API Reference](/error) diff --git a/docs/APIReference-Language.md b/website/pages/api-v16/language.mdx similarity index 65% rename from docs/APIReference-Language.md rename to website/pages/api-v16/language.mdx index 4d430c3787..897bb00927 100644 --- a/docs/APIReference-Language.md +++ b/website/pages/api-v16/language.mdx @@ -1,97 +1,87 @@ --- title: graphql/language -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/language/ -sublinks: BREAK,getLocation,Kind,lex,parse,parseValue,printSource,visit -next: /graphql-js/type/ --- +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql/language` + The `graphql/language` module is responsible for parsing and operating on the GraphQL language. You can import either from the `graphql/language` module, or from the root `graphql` module. For example: ```js import { Source } from 'graphql'; // ES6 -var { Source } = require('graphql'); // CommonJS +const { Source } = require('graphql'); // CommonJS ``` ## Overview -_Source_ +### Source -
        + -_Lexer_ +### Lexer -
          + -_Parser_ +### Parser -
            + -_Visitor_ +### Visitor -
              + -_Printer_ +### Printer -
                + @@ -99,32 +89,26 @@ _Printer_ ### Source -```js +```ts export class Source { - constructor(body: string, name?: string, locationOffset?: Location) -} - -type Location = { - line: number; - column: number; + constructor(body: string, name?: string); } ``` -A representation of source input to GraphQL. The `name` and `locationOffset` parameters are -optional, but they are useful for clients who store GraphQL documents in source files. -For example, if the GraphQL input starts at line 40 in a file named `Foo.graphql`, it might -be useful for `name` to be `"Foo.graphql"` and location to be `{ line: 40, column: 1 }`. -The `line` and `column` properties in `locationOffset` are 1-indexed. +A representation of source input to GraphQL. The name is optional, +but is mostly useful for clients who store GraphQL documents in +source files; for example, if the GraphQL input is in a file Foo.graphql, +it might be useful for name to be "Foo.graphql". ### getLocation -```js -function getLocation(source: Source, position: number): SourceLocation +```ts +function getLocation(source: Source, position: number): SourceLocation; type SourceLocation = { line: number; column: number; -} +}; ``` Takes a Source and a UTF-8 character offset, and returns the corresponding @@ -132,9 +116,9 @@ line and column as a SourceLocation. ## Lexer -### lex +### `lex` -```js +```ts function lex(source: Source): Lexer; type Lexer = (resetPosition?: number) => Token; @@ -143,42 +127,42 @@ export type Token = { kind: number; start: number; end: number; - value: ?string; + value: string; }; ``` Given a Source object, this returns a Lexer for that source. -A Lexer is a function that acts as a generator in that every time +A Lexer is a function that acts like a generator in that every time it is called, it returns the next token in the Source. Assuming the source lexes, the final Token emitted by the lexer will be of kind EOF, after which the lexer will repeatedly return EOF tokens whenever called. -The argument to the lexer function is optional and can be used to +The argument to the lexer function is optional, and can be used to rewind or fast forward the lexer to a new position in the source. ## Parser -### parse +### `parse` -```js +```ts export function parse( source: Source | string, - options?: ParseOptions -): Document + options?: ParseOptions, +): Document; ``` Given a GraphQL source, parses it into a Document. Throws GraphQLError if a syntax error is encountered. -### parseValue +### `parseValue` -```js +```ts export function parseValue( source: Source | string, - options?: ParseOptions -): Value + options?: ParseOptions, +): Value; ``` Given a string containing a GraphQL value, parse the AST for that value. @@ -188,19 +172,19 @@ Throws GraphQLError if a syntax error is encountered. This is useful within tools that operate upon GraphQL Values directly and in isolation of complete GraphQL documents. -### Kind +### `Kind` An enum that describes the different kinds of AST nodes. ## Visitor -### visit +### `visit` -```js -function visit(root, visitor, keyMap) +```ts +function visit(root, visitor, keyMap); ``` -visit() will walk through an AST using a depth-first traversal, calling +visit() will walk through an AST using a depth first traversal, calling the visitor's enter function at each node in the traversal, and calling the leave function after visiting that node and all of its child nodes. @@ -214,7 +198,7 @@ a new version of the AST with the changes applied will be returned from the visit function. ```js -var editedAST = visit(ast, { +const editedAST = visit(ast, { enter(node, key, parent, path, ancestors) { // @return // undefined: no action @@ -236,10 +220,10 @@ var editedAST = visit(ast, { Alternatively to providing enter() and leave() functions, a visitor can instead provide functions named the same as the kinds of AST nodes, or -enter/leave visitors at a named key, leading to four permutations of the +enter/leave visitors at a named key, leading to four permutations of visitor API: -1. Named visitors triggered when entering a node of a specific kind. +1. Named visitors triggered when entering a node a specific kind. ```js visit(ast, { @@ -257,11 +241,11 @@ visit(ast, { Kind: { enter(node) { // enter the "Kind" node - } + }, leave(node) { // leave the "Kind" node - } - } + }, + }, }); ``` @@ -295,16 +279,16 @@ visit(ast, { }); ``` -### BREAK +### `BREAK` The sentinel `BREAK` value described in the documentation of `visitor`. ## Printer -### print +### `print` -```js -function print(ast): string +```ts +function print(ast): string; ``` Converts an AST into a string, using one set of reasonable diff --git a/docs/APIReference-TypeSystem.md b/website/pages/api-v16/type.mdx similarity index 57% rename from docs/APIReference-TypeSystem.md rename to website/pages/api-v16/type.mdx index 8efd840eb6..4ab3d7d1a2 100644 --- a/docs/APIReference-TypeSystem.md +++ b/website/pages/api-v16/type.mdx @@ -1,168 +1,157 @@ --- title: graphql/type -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/type/ -sublinks: getNamedType,getNullableType,GraphQLBoolean,GraphQLEnumType,GraphQLFloat,GraphQLID,GraphQLInputObjectType,GraphQLInt,GraphQLInterfaceType,GraphQLList,GraphQLNonNull,GraphQLObjectType,GraphQLScalarType,GraphQLSchema,GraphQLString,GraphQLUnionType,isAbstractType,isCompositeType,isInputType,isLeafType,isOutputType -next: /graphql-js/utilities/ --- +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql/type` + The `graphql/type` module is responsible for defining GraphQL types and schema. You can import either from the `graphql/type` module, or from the root `graphql` module. For example: ```js import { GraphQLSchema } from 'graphql'; // ES6 -var { GraphQLSchema } = require('graphql'); // CommonJS +const { GraphQLSchema } = require('graphql'); // CommonJS ``` ## Overview -_Schema_ +### Schema -
                  + -_Definitions_ +### Definitions -
                    + -_Predicates_ +### Predicates -
                      + -_Un-modifiers_ +### Un-modifiers -
                        + -_Scalars_ +### Scalars -
                          + @@ -170,15 +159,15 @@ _Scalars_ ### GraphQLSchema -```js +```ts class GraphQLSchema { - constructor(config: GraphQLSchemaConfig) + constructor(config: GraphQLSchemaConfig); } type GraphQLSchemaConfig = { query: GraphQLObjectType; - mutation?: ?GraphQLObjectType; -} + mutation?: GraphQLObjectType; +}; ``` A Schema is created by supplying the root types of each type of operation, @@ -188,9 +177,9 @@ validator and executor. #### Example ```js -var MyAppSchema = new GraphQLSchema({ - query: MyAppQueryRootType - mutation: MyAppMutationRootType +const MyAppSchema = new GraphQLSchema({ + query: MyAppQueryRootType, + mutation: MyAppMutationRootType, }); ``` @@ -198,19 +187,22 @@ var MyAppSchema = new GraphQLSchema({ ### GraphQLScalarType -```js -class GraphQLScalarType { - constructor(config: GraphQLScalarTypeConfig) +```ts +class GraphQLScalarType { + constructor(config: GraphQLScalarTypeConfig); } -type GraphQLScalarTypeConfig = { +type GraphQLScalarTypeConfig = { name: string; - description?: ?string; - specifiedByUrl?: string; - serialize: (value: mixed) => ?InternalType; - parseValue?: (value: mixed) => ?InternalType; - parseLiteral?: (valueAST: Value) => ?InternalType; -} + description?: string; + specifiedByURL?: Maybe; + serialize: (outputValue: unknown) => ExternalType; + parseValue?: (inputValue: unknown) => InternalType; + parseLiteral?: ( + valueAST: Value, + variables?: Maybe>, + ) => InternalType; +}; ``` The leaf values of any request and input values to arguments are @@ -220,37 +212,48 @@ functions used to ensure validity. #### Example ```js -var OddType = new GraphQLScalarType({ +const OddType = new GraphQLScalarType({ name: 'Odd', - serialize: oddValue, - parseValue: oddValue, + // Can be used to link to a specification + // for this scalar, for instance the JSON + // specification. + specifiedByURL: '', + description: + 'This custom scalar will only return a value if the passed in value is an odd integer, when it's not it will return null.' + serialize: (outputValue) => { + // This function gets called for response-data, the application returns data + // for a property and in the schema we see that this value has the "Odd" type. + return typeof outputValue === 'number' && outputValue % 2 === 1 ? value : null; + }, + parseValue: (inputValue) => { + // This function gets called for input-data, i.e. variables being passed in + return typeof inputValue === 'number' && outputValue % 2 === 1 ? value : null; + }, parseLiteral(ast) { + // This function gets called when the value is passed in as a literal on the + // Executable GraphQL Document if (ast.kind === Kind.INT) { return oddValue(parseInt(ast.value, 10)); } return null; }, }); - -function oddValue(value) { - return value % 2 === 1 ? value : null; -} ``` ### GraphQLObjectType -```js +```ts class GraphQLObjectType { - constructor(config: GraphQLObjectTypeConfig) + constructor(config: GraphQLObjectTypeConfig); } type GraphQLObjectTypeConfig = { name: string; - interfaces?: GraphQLInterfacesThunk | Array; + interfaces?: GraphQLInterfacesThunk | GraphQLInterfaceType[]; fields: GraphQLFieldConfigMapThunk | GraphQLFieldConfigMap; isTypeOf?: (value: any, info?: GraphQLResolveInfo) => boolean; - description?: ?string -} + description?: string; +}; type GraphQLInterfacesThunk = () => Array; @@ -259,30 +262,30 @@ type GraphQLFieldConfigMapThunk = () => GraphQLFieldConfigMap; // See below about resolver functions. type GraphQLFieldResolveFn = ( source?: any, - args?: {[argName: string]: any}, + args?: { [argName: string]: any }, context?: any, - info?: GraphQLResolveInfo -) => any + info?: GraphQLResolveInfo, +) => any; type GraphQLResolveInfo = { - fieldName: string, - fieldNodes: Array, - returnType: GraphQLOutputType, - parentType: GraphQLCompositeType, - schema: GraphQLSchema, - fragments: { [fragmentName: string]: FragmentDefinition }, - rootValue: any, - operation: OperationDefinition, - variableValues: { [variableName: string]: any }, -} + fieldName: string; + fieldNodes: Array; + returnType: GraphQLOutputType; + parentType: GraphQLCompositeType; + schema: GraphQLSchema; + fragments: { [fragmentName: string]: FragmentDefinition }; + rootValue: any; + operation: OperationDefinition; + variableValues: { [variableName: string]: any }; +}; type GraphQLFieldConfig = { type: GraphQLOutputType; args?: GraphQLFieldConfigArgumentMap; resolve?: GraphQLFieldResolveFn; deprecationReason?: string; - description?: ?string; -} + description?: string; +}; type GraphQLFieldConfigArgumentMap = { [argName: string]: GraphQLArgumentConfig; @@ -291,8 +294,8 @@ type GraphQLFieldConfigArgumentMap = { type GraphQLArgumentConfig = { type: GraphQLInputType; defaultValue?: any; - description?: ?string; -} + description?: string; +}; type GraphQLFieldConfigMap = { [fieldName: string]: GraphQLFieldConfig; @@ -315,7 +318,7 @@ that value can always be referenced with `this`. #### Examples ```js -var AddressType = new GraphQLObjectType({ +const AddressType = new GraphQLObjectType({ name: 'Address', fields: { street: { type: GraphQLString }, @@ -329,7 +332,7 @@ var AddressType = new GraphQLObjectType({ }, }); -var PersonType = new GraphQLObjectType({ +const PersonType = new GraphQLObjectType({ name: 'Person', fields: () => ({ name: { type: GraphQLString }, @@ -340,16 +343,16 @@ var PersonType = new GraphQLObjectType({ ### GraphQLInterfaceType -```js +```ts class GraphQLInterfaceType { - constructor(config: GraphQLInterfaceTypeConfig) + constructor(config: GraphQLInterfaceTypeConfig); } type GraphQLInterfaceTypeConfig = { - name: string, - fields: GraphQLFieldConfigMapThunk | GraphQLFieldConfigMap, - resolveType?: (value: any, info?: GraphQLResolveInfo) => ?GraphQLObjectType, - description?: ?string + name: string; + fields: GraphQLFieldConfigMapThunk | GraphQLFieldConfigMap; + resolveType?: (value: any, info?: GraphQLResolveInfo) => GraphQLObjectType; + description?: string; }; ``` @@ -361,7 +364,7 @@ when the field is resolved. #### Example ```js -var EntityType = new GraphQLInterfaceType({ +const EntityType = new GraphQLInterfaceType({ name: 'Entity', fields: { name: { type: GraphQLString }, @@ -371,19 +374,19 @@ var EntityType = new GraphQLInterfaceType({ ### GraphQLUnionType -```js +```ts class GraphQLUnionType { - constructor(config: GraphQLUnionTypeConfig) + constructor(config: GraphQLUnionTypeConfig); } type GraphQLUnionTypeConfig = { - name: string, - types: GraphQLObjectsThunk | Array, - resolveType?: (value: any, info?: GraphQLResolveInfo) => ?GraphQLObjectType; - description?: ?string; + name: string; + types: GraphQLObjectsThunk | GraphQLObjectType[]; + resolveType?: (value: any, info?: GraphQLResolveInfo) => GraphQLObjectType; + description?: string; }; -type GraphQLObjectsThunk = () => Array; +type GraphQLObjectsThunk = () => GraphQLObjectType[]; ``` When a field can return one of a heterogeneous set of types, a Union type @@ -393,7 +396,7 @@ to determine which type is actually used when the field is resolved. ### Example ```js -var PetType = new GraphQLUnionType({ +const PetType = new GraphQLUnionType({ name: 'Pet', types: [DogType, CatType], resolveType(value) { @@ -409,16 +412,16 @@ var PetType = new GraphQLUnionType({ ### GraphQLEnumType -```js +```ts class GraphQLEnumType { - constructor(config: GraphQLEnumTypeConfig) + constructor(config: GraphQLEnumTypeConfig); } type GraphQLEnumTypeConfig = { name: string; values: GraphQLEnumValueConfigMap; - description?: ?string; -} + description?: string; +}; type GraphQLEnumValueConfigMap = { [valueName: string]: GraphQLEnumValueConfig; @@ -427,15 +430,15 @@ type GraphQLEnumValueConfigMap = { type GraphQLEnumValueConfig = { value?: any; deprecationReason?: string; - description?: ?string; -} + description?: string; +}; type GraphQLEnumValueDefinition = { name: string; value?: any; deprecationReason?: string; - description?: ?string; -} + description?: string; +}; ``` Some leaf values of requests and input values are Enums. GraphQL serializes @@ -448,7 +451,7 @@ will be used as its internal value. #### Example ```js -var RGBType = new GraphQLEnumType({ +const RGBType = new GraphQLEnumType({ name: 'RGB', values: { RED: { value: 0 }, @@ -460,24 +463,27 @@ var RGBType = new GraphQLEnumType({ ### GraphQLInputObjectType -```js +```ts class GraphQLInputObjectType { - constructor(config: GraphQLInputObjectConfig) + constructor(config: GraphQLInputObjectConfig); } type GraphQLInputObjectConfig = { name: string; - fields: GraphQLInputObjectConfigFieldMapThunk | GraphQLInputObjectConfigFieldMap; - description?: ?string; -} + fields: + | GraphQLInputObjectConfigFieldMapThunk + | GraphQLInputObjectConfigFieldMap; + description?: string; +}; -type GraphQLInputObjectConfigFieldMapThunk = () => GraphQLInputObjectConfigFieldMap; +type GraphQLInputObjectConfigFieldMapThunk = + () => GraphQLInputObjectConfigFieldMap; type GraphQLInputObjectFieldConfig = { type: GraphQLInputType; defaultValue?: any; - description?: ?string; -} + description?: string; +}; type GraphQLInputObjectConfigFieldMap = { [fieldName: string]: GraphQLInputObjectFieldConfig; @@ -487,8 +493,8 @@ type GraphQLInputObjectField = { name: string; type: GraphQLInputType; defaultValue?: any; - description?: ?string; -} + description?: string; +}; type GraphQLInputObjectFieldMap = { [fieldName: string]: GraphQLInputObjectField; @@ -503,7 +509,7 @@ Using `NonNull` will ensure that a value must be provided by the query #### Example ```js -var GeoPoint = new GraphQLInputObjectType({ +const GeoPoint = new GraphQLInputObjectType({ name: 'GeoPoint', fields: { lat: { type: new GraphQLNonNull(GraphQLFloat) }, @@ -515,9 +521,9 @@ var GeoPoint = new GraphQLInputObjectType({ ### GraphQLList -```js +```ts class GraphQLList { - constructor(type: GraphQLType) + constructor(type: GraphQLType); } ``` @@ -528,20 +534,20 @@ an object type. #### Example ```js -var PersonType = new GraphQLObjectType({ +const PersonType = new GraphQLObjectType({ name: 'Person', fields: () => ({ - parents: { type: new GraphQLList(Person) }, - children: { type: new GraphQLList(Person) }, + parents: { type: new GraphQLList(PersonType) }, + children: { type: new GraphQLList(PersonType) }, }), }); ``` ### GraphQLNonNull -```js +```ts class GraphQLNonNull { - constructor(type: GraphQLType) + constructor(type: GraphQLType); } ``` @@ -554,7 +560,7 @@ usually the id field of a database row will never be null. #### Example ```js -var RowType = new GraphQLObjectType({ +const RowType = new GraphQLObjectType({ name: 'Row', fields: () => ({ id: { type: new GraphQLNonNull(String) }, @@ -567,39 +573,39 @@ var RowType = new GraphQLObjectType({ ### isInputType ```js -function isInputType(type: ?GraphQLType): boolean +function isInputType(type: GraphQLType): boolean ``` These types may be used as input types for arguments and directives. ### isOutputType -```js -function isOutputType(type: ?GraphQLType): boolean +```ts +function isOutputType(type: GraphQLType): boolean; ``` These types may be used as output types as the result of fields ### isLeafType -```js -function isLeafType(type: ?GraphQLType): boolean +```ts +function isLeafType(type: GraphQLType): boolean; ``` These types may describe types which may be leaf values ### isCompositeType -```js -function isCompositeType(type: ?GraphQLType): boolean +```ts +function isCompositeType(type: GraphQLType): boolean; ``` These types may describe the parent context of a selection set ### isAbstractType -```js -function isAbstractType(type: ?GraphQLType): boolean +```ts +function isAbstractType(type: GraphQLType): boolean; ``` These types may describe a combination of object types @@ -608,8 +614,8 @@ These types may describe a combination of object types ### getNullableType -```js -function getNullableType(type: ?GraphQLType): ?GraphQLNullableType +```ts +function getNullableType(type: GraphQLType): GraphQLNullableType; ``` If a given type is non-nullable, this strips the non-nullability and @@ -617,8 +623,8 @@ returns the underlying type. ### getNamedType -```js -function getNamedType(type: ?GraphQLType): ?GraphQLNamedType +```ts +function getNamedType(type: GraphQLType): GraphQLNamedType; ``` If a given type is non-nullable or a list, this repeated strips the @@ -628,40 +634,40 @@ non-nullability and list wrappers and returns the underlying type. ### GraphQLInt -```js -var GraphQLInt: GraphQLScalarType; +```ts +let GraphQLInt: GraphQLScalarType; ``` A `GraphQLScalarType` that represents an int. ### GraphQLFloat -```js -var GraphQLFloat: GraphQLScalarType; +```ts +let GraphQLFloat: GraphQLScalarType; ``` A `GraphQLScalarType` that represents a float. ### GraphQLString -```js -var GraphQLString: GraphQLScalarType; +```ts +let GraphQLString: GraphQLScalarType; ``` A `GraphQLScalarType` that represents a string. ### GraphQLBoolean -```js -var GraphQLBoolean: GraphQLScalarType; +```ts +let GraphQLBoolean: GraphQLScalarType; ``` A `GraphQLScalarType` that represents a boolean. ### GraphQLID -```js -var GraphQLID: GraphQLScalarType; +```ts +let GraphQLID: GraphQLScalarType; ``` A `GraphQLScalarType` that represents an ID. diff --git a/website/pages/api-v16/utilities.mdx b/website/pages/api-v16/utilities.mdx new file mode 100644 index 0000000000..ba8533c220 --- /dev/null +++ b/website/pages/api-v16/utilities.mdx @@ -0,0 +1,232 @@ +--- +title: graphql/utilities +--- + +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql/utilities` + +The `graphql/utilities` module contains common useful computations to use with +the GraphQL language and type objects. You can import either from the `graphql/utilities` module, or from the root `graphql` module. For example: + +```js +import { introspectionQuery } from 'graphql'; // ES6 +const { introspectionQuery } = require('graphql'); // CommonJS +``` + +## Overview + +### Introspection + + + +### Schema Language + + + +### Visitors + + + +### Value Validation + + + +## Introspection + +### introspectionQuery + +```js +const introspectionQuery: string; +``` + +A GraphQL query that queries a server's introspection system for enough +information to reproduce that server's type system. + +### `buildClientSchema` + +```ts +function buildClientSchema(introspection: IntrospectionQuery): GraphQLSchema; +``` + +Build a GraphQLSchema for use by client tools. + +Given the result of a client running the introspection query, creates and +returns a GraphQLSchema instance which can be then used with all GraphQL.js +tools, but cannot be used to execute a query, as introspection does not +represent the "resolver", "parse" or "serialize" functions or any other +server-internal mechanisms. + +## Schema Representation + +### `buildSchema` + +```ts +function buildSchema(source: string | Source): GraphQLSchema; +``` + +Creates a GraphQLSchema object from GraphQL schema language. The schema will use default resolvers. For more detail on the GraphQL schema language, see the [schema language docs](/learn/schema/) or this [schema language cheat sheet](https://wehavefaces.net/graphql-shorthand-notation-cheatsheet-17cd715861b6#.9oztv0a7n). + +### `printSchema` + +```ts +function printSchema(schema: GraphQLSchema): string; +``` + +Prints the provided schema in the Schema Language format. + +### `printIntrospectionSchema` + +```ts +function printIntrospectionSchema(schema: GraphQLSchema): string; +``` + +Prints the built-in introspection schema in the Schema Language format. + +### `buildASTSchema` + +```ts +function buildASTSchema( + ast: SchemaDocument, + queryTypeName: string, + mutationTypeName: string, +): GraphQLSchema; +``` + +This takes the ast of a schema document produced by `parseSchemaIntoAST` in +`graphql/language/schema` and constructs a GraphQLSchema instance which can be +then used with all GraphQL.js tools, but cannot be used to execute a query, as +introspection does not represent the "resolver", "parse" or "serialize" +functions or any other server-internal mechanisms. + +### `typeFromAST` + +```ts +function typeFromAST(schema: GraphQLSchema, inputTypeAST: Type): GraphQLType; +``` + +Given the name of a Type as it appears in a GraphQL AST and a Schema, return the +corresponding GraphQLType from that schema. + +### `astFromValue` + +```ts +function astFromValue(value: any, type: GraphQLInputType): Value; +``` + +Produces a GraphQL Input Value AST given a JavaScript value. + +Optionally, a GraphQL type may be provided, which will be used to +disambiguate between value primitives. + +## Visitors + +### `TypeInfo` + +```ts +class TypeInfo { + constructor(schema: GraphQLSchema); + getType(): GraphQLOutputType; + getParentType(): GraphQLCompositeType; + getInputType(): GraphQLInputType; + getFieldDef(): GraphQLFieldDefinition; + getDirective(): GraphQLDirective; + getArgument(): GraphQLArgument; +} +``` + +TypeInfo is a utility class which, given a GraphQL schema, can keep track +of the current field and type definitions at any point in a GraphQL document +AST during a recursive descent by calling `enter(node)` and `leave(node)`. + +## Value Validation + +### `isValidJSValue` + +```ts +function isValidJSValue(value: any, type: GraphQLInputType): string[]; +``` + +Given a JavaScript value and a GraphQL type, determine if the value will be +accepted for that type. This is primarily useful for validating the +runtime values of query variables. + +### `isValidLiteralValue` + +```ts +function isValidLiteralValue(type: GraphQLInputType, valueAST: Value): string[]; +``` + +Utility for validators which determines if a value literal AST is valid given +an input type. + +Note that this only validates literal values, variables are assumed to +provide values of the correct type. diff --git a/docs/APIReference-Validation.md b/website/pages/api-v16/validation.mdx similarity index 70% rename from docs/APIReference-Validation.md rename to website/pages/api-v16/validation.mdx index e9c28ebbe0..6b45caec6a 100644 --- a/docs/APIReference-Validation.md +++ b/website/pages/api-v16/validation.mdx @@ -1,46 +1,45 @@ --- title: graphql/validation -layout: ../_core/GraphQLJSLayout -category: API Reference -permalink: /graphql-js/validation/ -sublinks: specifiedRules,validate --- +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# `graphql/validation` + The `graphql/validation` module fulfills the Validation phase of fulfilling a GraphQL result. You can import either from the `graphql/validation` module, or from the root `graphql` module. For example: ```js import { validate } from 'graphql/validation'; // ES6 -var { validate } = require('graphql/validation'); // CommonJS +const { validate } = require('graphql/validation'); // CommonJS ``` ## Overview -
                            + ## Validation -### validate +### `validate` -```js +```ts function validate( schema: GraphQLSchema, ast: Document, - rules?: Array -): Array + rules?: any[], +): GraphQLError[]; ``` Implements the "Validation" section of the spec. @@ -59,10 +58,10 @@ Visitors can also supply `visitSpreadFragments: true` which will alter the behavior of the visitor to skip over top level defined fragments, and instead visit those fragments at every point a spread is encountered. -### specifiedRules +### `specifiedRules` -```js -var specifiedRules: Array<(context: ValidationContext): any> +```ts +let specifiedRules: Array<(context: ValidationContext) => any>; ``` This set includes all validation rules defined by the GraphQL spec diff --git a/docs/Tutorial-Authentication.md b/website/pages/authentication-and-express-middleware.mdx similarity index 51% rename from docs/Tutorial-Authentication.md rename to website/pages/authentication-and-express-middleware.mdx index 28376bc102..c03f444496 100644 --- a/docs/Tutorial-Authentication.md +++ b/website/pages/authentication-and-express-middleware.mdx @@ -1,56 +1,101 @@ --- title: Authentication and Express Middleware sidebarTitle: Authentication & Middleware -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/authentication-and-express-middleware/ -next: /graphql-js/constructing-types/ --- -It's simple to use any Express middleware in conjunction with `express-graphql`. In particular, this is a great pattern for handling authentication. +import { Tabs } from 'nextra/components'; + +It's simple to use any Express middleware in conjunction with `graphql-http`. In particular, this is a great pattern for handling authentication. To use middleware with a GraphQL resolver, just use the middleware like you would with a normal Express app. The `request` object is then available as the second argument in any resolver. For example, let's say we wanted our server to log the IP address of every request, and we also want to write an API that returns the IP address of the caller. We can do the former with middleware, and the latter by accessing the `request` object in a resolver. Here's server code that implements this: + + ```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { buildSchema } = require('graphql'); -var schema = buildSchema(` - type Query { - ip: String - } -`); +const schema = buildSchema(`type Query { ip: String }`); function loggingMiddleware(req, res, next) { console.log('ip:', req.ip); next(); } -var root = { - ip: function (args, request) { - return request.ip; +const root = { + ip(args, context) { + return context.ip; }, }; -var app = express(); +const app = express(); app.use(loggingMiddleware); -app.use( +app.all( '/graphql', - graphqlHTTP({ + createHandler({ schema: schema, rootValue: root, - graphiql: true, + context: (req) => ({ + ip: req.raw.ip, + }), }), ); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); + +```` + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +} = require('graphql'); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { ip: { type: GraphQLString } }, + }), }); -``` -In a REST API, authentication is often handled with a header, that contains an auth token which proves what user is making this request. Express middleware processes these headers and puts authentication data on the Express `request` object. Some middleware modules that handle authentication like this are [Passport](http://passportjs.org/), [express-jwt](https://github.com/auth0/express-jwt), and [express-session](https://github.com/expressjs/session). Each of these modules works with `express-graphql`. +function loggingMiddleware(req, res, next) { + console.log('ip:', req.ip); + next(); +} + +const root = { + ip(args, context) { + return context.ip; + }, +}; + +const app = express(); +app.use(loggingMiddleware); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + context: (req) => ({ + ip: req.raw.ip, + }), + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +```` + + + + +In a REST API, authentication is often handled with a header, that contains an auth token which proves what user is making this request. Express middleware processes these headers and puts authentication data on the Express `request` object. Some middleware modules that handle authentication like this are [Passport](http://passportjs.org/), [express-jwt](https://github.com/auth0/express-jwt), and [express-session](https://github.com/expressjs/session). Each of these modules works with `graphql-http`. If you aren't familiar with any of these authentication mechanisms, we recommend using `express-jwt` because it's simple without sacrificing any future flexibility. diff --git a/website/pages/basic-types.mdx b/website/pages/basic-types.mdx new file mode 100644 index 0000000000..b6480a979d --- /dev/null +++ b/website/pages/basic-types.mdx @@ -0,0 +1,115 @@ +--- +title: Basic Types +--- + +import { Tabs } from 'nextra/components'; + +In most situations, all you need to do is to specify the types for your API using the GraphQL schema language, taken as an argument to the `buildSchema` function. + +The GraphQL schema language supports the scalar types of `String`, `Int`, `Float`, `Boolean`, and `ID`, so you can use these directly in the schema you pass to `buildSchema`. + +By default, every type is nullable - it's legitimate to return `null` as any of the scalar types. Use an exclamation point to indicate a type cannot be nullable, so `String!` is a non-nullable string. + +To use a list type, surround the type in square brackets, so `[Int]` is a list of integers. + +Each of these types maps straightforwardly to JavaScript, so you can just return plain old JavaScript objects in APIs that return these types. Here's an example that shows how to use some of these basic types: + + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +const schema = buildSchema(` + type Query { + quoteOfTheDay: String + random: Float! + rollThreeDice: [Int] + } +`); + +// The root provides a resolver function for each API endpoint +const root = { + quoteOfTheDay() { + return Math.random() < 0.5 ? 'Take it easy' : 'Salvation lies within'; + }, + random() { + return Math.random(); + }, + rollThreeDice() { + return [1, 2, 3].map((\_) => 1 + Math.floor(Math.random() \* 6)); + }, +}; + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); + +```` + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { + GraphQLObjectType, + GraphQLSchema, + GraphQLString, + GraphQLFloat, + GraphQLList, +} = require('graphql'); + +// Construct a schema +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + quoteOfTheDay: { type: GraphQLString }, + random: { type: GraphQLFloat }, + rollThreeDice: { type: new GraphQLList(GraphQLFloat) }, + }, + }), +}); + +// The root provides a resolver function for each API endpoint +const root = { + quoteOfTheDay() { + return Math.random() < 0.5 ? 'Take it easy' : 'Salvation lies within'; + }, + random() { + return Math.random(); + }, + rollThreeDice() { + return [1, 2, 3].map((_) => 1 + Math.floor(Math.random() * 6)); + }, +}; + +const app = express(); + +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); + +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +```` + + + + +If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out these APIs. + +These examples show you how to call APIs that return different types. To send different types of data into an API, you will also need to learn about [passing arguments to a GraphQL API](/passing-arguments/). diff --git a/website/pages/constructing-types.mdx b/website/pages/constructing-types.mdx new file mode 100644 index 0000000000..2ae7b93872 --- /dev/null +++ b/website/pages/constructing-types.mdx @@ -0,0 +1,124 @@ +--- +title: Constructing Types +--- + +import { Tabs } from 'nextra/components'; + +For many apps, you can define a fixed schema when the application starts, and define it using GraphQL schema language. In some cases, it's useful to construct a schema programmatically. You can do this using the `GraphQLSchema` constructor. + +When you are using the `GraphQLSchema` constructor to create a schema, instead of defining `Query` and `Mutation` types solely using schema language, you create them as separate object types. + +For example, let's say we are building a simple API that lets you fetch user data for a few hardcoded users based on an id. Using `buildSchema` we could write a server with: + + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { buildSchema } = require('graphql'); + +const schema = buildSchema(` +type User { + id: String + name: String +} + +type Query { + user(id: String): User +} +`); + +// Maps id to User object +const fakeDatabase = { + a: { + id: 'a', + name: 'alice', + }, + b: { + id: 'b', + name: 'bob', + }, +}; + +const root = { + user({ id }) { + return fakeDatabase[id]; + }, +}; + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); + +```` + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const graphql = require('graphql'); + +// Maps id to User object +const fakeDatabase = { + a: { + id: 'a', + name: 'alice', + }, + b: { + id: 'b', + name: 'bob', + }, +}; + +// Define the User type +const userType = new graphql.GraphQLObjectType({ + name: 'User', + fields: { + id: { type: graphql.GraphQLString }, + name: { type: graphql.GraphQLString }, + }, +}); + +// Define the Query type +const queryType = new graphql.GraphQLObjectType({ + name: 'Query', + fields: { + user: { + type: userType, + // `args` describes the arguments that the `user` query accepts + args: { + id: { type: graphql.GraphQLString }, + }, + resolve: (_, { id }) => { + return fakeDatabase[id]; + }, + }, + }, +}); + +const schema = new graphql.GraphQLSchema({ query: queryType }); + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +```` + + + + +When we use the `GraphQLSchema` constructor method of creating the API, the root level resolvers are implemented on the `Query` and `Mutation` types rather than on a `root` object. + +This can be particularly useful if you want to create a GraphQL schema automatically from something else, like a database schema. You might have a common format for something like creating and updating database records. This is also useful for implementing features like union types which don't map cleanly to ES6 classes and schema language. diff --git a/website/pages/defer-stream.mdx b/website/pages/defer-stream.mdx new file mode 100644 index 0000000000..166bcb3eb3 --- /dev/null +++ b/website/pages/defer-stream.mdx @@ -0,0 +1,38 @@ +--- +title: Enabling Defer & Stream +--- + +import { Callout } from 'nextra/components' + + + These exports are only available in v17 and beyond. + + +The `@defer` and `@stream` directives are not enabled by default. +In order to use these directives, you must add them to your GraphQL Schema and +use the `experimentalExecuteIncrementally` function instead of `execute`. + +```js +import { + GraphQLSchema, + GraphQLDeferDirective, + GraphQLStreamDirective, + specifiedDirectives, +} from 'graphql'; + +const schema = new GraphQLSchema({ + query, + directives: [ + ...specifiedDirectives, + GraphQLDeferDirective, + GraphQLStreamDirective, + ], +}); + +const result = experimentalExecuteIncrementally({ + schema, + document, +}); +``` + +If the `directives` option is passed to `GraphQLSchema`, the default directives will not be included. `specifiedDirectives` must be passed to ensure all standard directives are added in addition to `defer` & `stream`. diff --git a/website/pages/getting-started.mdx b/website/pages/getting-started.mdx new file mode 100644 index 0000000000..049f35ef13 --- /dev/null +++ b/website/pages/getting-started.mdx @@ -0,0 +1,112 @@ +--- +title: Getting Started With GraphQL.js +sidebarTitle: Getting Started +--- + +import { Tabs } from 'nextra/components'; + +{/* title can be removed in Nextra 4, since sidebar title will take from first h1 */} + +# Getting Started With GraphQL.js + +## Prerequisites + +Before getting started, you should have Node v6 installed, although the examples should mostly work in previous versions of Node as well. +For this guide, we won't use any language features that require transpilation, but we will use some ES6 features like +[Promises](http://www.html5rocks.com/en/tutorials/es6/promises/), classes, +and arrow functions, so if you aren't familiar with them you might want to read up on them first. + +> Alternatively you can start from [this StackBlitz](https://stackblitz.com/edit/stackblitz-starters-znvgwr) - if you choose +> this route you can skip to [Basic Types](./basic-types.mdx). + +To create a new project and install GraphQL.js in your current directory: + +```sh npm2yarn +npm init +npm install graphql --save +``` + +## Writing Code + +To handle GraphQL queries, we need a schema that defines the `Query` type, and we need an API root with a function called a “resolver” for each API endpoint. For an API that just returns “Hello world!”, we can put this code in a file named `server.js`: + + + +```javascript +const { graphql, buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +const schema = buildSchema(`type Query { hello: String } `); + +// The rootValue provides a resolver function for each API endpoint +const rootValue = { + hello() { + return 'Hello world!'; + }, +}; + +// Run the GraphQL query '{ hello }' and print out the response +graphql({ + schema, + source: '{ hello }', + rootValue, + }).then((response) => { + console.log(response); + }); +}); + +```` + + +```javascript +const { graphql, GraphQLSchema, GraphQLObjectType } = require('graphql'); + +// Construct a schema +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + hello: { type: GraphQLString }, + }, + }), +}); + +// The rootValue provides a resolver function for each API endpoint +const rootValue = { + hello() { + return 'Hello world!'; + }, +}; + +// Run the GraphQL query '{ hello }' and print out the response +graphql({ + schema, + source: '{ hello }', + rootValue, +}).then((response) => { + console.log(response); +}); +```` + + + + +If you run this with: + +```sh +node server.js +``` + +You should see the GraphQL response printed out: + +```json +{ + "data": { + "hello": "Hello world!" + } +} +``` + +Congratulations - you just executed a GraphQL query! + +For practical applications, you'll probably want to run GraphQL queries from an API server, rather than executing GraphQL with a command line tool. To use GraphQL for an API server over HTTP, check out [Running an Express GraphQL Server](/running-an-express-graphql-server/). diff --git a/website/pages/going-to-production.mdx b/website/pages/going-to-production.mdx new file mode 100644 index 0000000000..862932fb10 --- /dev/null +++ b/website/pages/going-to-production.mdx @@ -0,0 +1,126 @@ +--- +title: Going to Production +--- + +GraphQL.JS contains a few development checks which in production will cause slower performance and +an increase in bundle-size. Every bundler goes about these changes different, in here we'll list +out the most popular ones. + +## Bundler-specific configuration + +Here are some bundler-specific suggestions for configuring your bundler to remove `globalThis.process` and `process.env.NODE_ENV` on build time. + +### Vite + +```js +export default defineConfig({ + // ... + define: { + 'globalThis.process': JSON.stringify(true), + 'process.env.NODE_ENV': JSON.stringify('production'), + }, +}); +``` + +### Next.js + +```js +// ... +/** @type {import('next').NextConfig} */ +const nextConfig = { + webpack(config, { webpack }) { + config.plugins.push( + new webpack.DefinePlugin({ + 'globalThis.process': JSON.stringify(true), + 'process.env.NODE_ENV': JSON.stringify('production'), + }), + ); + return config; + }, +}; + +module.exports = nextConfig; +``` + +### create-react-app + +With `create-react-app`, you need to use a third-party package like [`craco`](https://craco.js.org/) to modify the bundler configuration. + +```js +const webpack = require('webpack'); +module.exports = { + webpack: { + plugins: [ + new webpack.DefinePlugin({ + 'globalThis.process': JSON.stringify(true), + 'process.env.NODE_ENV': JSON.stringify('production'), + }), + ], + }, +}; +``` + +### esbuild + +```json +{ + "define": { + "globalThis.process": true, + "process.env.NODE_ENV": "production" + } +} +``` + +### Webpack + +```js +config.plugins.push( + new webpack.DefinePlugin({ + 'globalThis.process': JSON.stringify(true), + 'process.env.NODE_ENV': JSON.stringify('production'), + }), +); +``` + +### Rollup + +```js +export default [ + { + // ... input, output, etc. + plugins: [ + minify({ + mangle: { + toplevel: true, + }, + compress: { + toplevel: true, + global_defs: { + '@globalThis.process': JSON.stringify(true), + '@process.env.NODE_ENV': JSON.stringify('production'), + }, + }, + }), + ], + }, +]; +``` + +### SWC + +```json filename=".swcrc" +{ + "jsc": { + "transform": { + "optimizer": { + "globals": { + "vars": { + "globalThis.process": true, + "process.env.NODE_ENV": "production" + } + } + } + } + } +} +``` diff --git a/docs/Tutorial-GraphQLClients.md b/website/pages/graphql-clients.mdx similarity index 64% rename from docs/Tutorial-GraphQLClients.md rename to website/pages/graphql-clients.mdx index 578a0d8f47..342193450f 100644 --- a/docs/Tutorial-GraphQLClients.md +++ b/website/pages/graphql-clients.mdx @@ -1,14 +1,10 @@ --- title: GraphQL Clients -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/graphql-clients/ -next: /graphql-js/basic-types/ --- -Since a GraphQL API has more underlying structure than a REST API, there are more powerful clients like [Relay](https://facebook.github.io/relay/) which can automatically handle batching, caching, and other features. But you don't need a complex client to call a GraphQL server. With `express-graphql`, you can just send an HTTP POST request to the endpoint you mounted your GraphQL server on, passing the GraphQL query as the `query` field in a JSON payload. +Since a GraphQL API has more underlying structure than a REST API, there are more powerful clients like [Relay](https://facebook.github.io/relay/) which can automatically handle batching, caching, and other features. But you don't need a complex client to call a GraphQL server. With `graphql-http`, you can just send an HTTP POST request to the endpoint you mounted your GraphQL server on, passing the GraphQL query as the `query` field in a JSON payload. -For example, let's say we mounted a GraphQL server on http://localhost:4000/graphql as in the example code for [running an Express GraphQL server](/graphql-js/running-an-express-graphql-server/), and we want to send the GraphQL query `{ hello }`. We can do this from the command line with `curl`. If you paste this into a terminal: +For example, let's say we mounted a GraphQL server on http://localhost:4000/graphql as in the example code for [running an Express GraphQL server](/running-an-express-graphql-server/), and we want to send the GraphQL query `{ hello }`. We can do this from the command line with `curl`. If you paste this into a terminal: ```bash curl -X POST \ @@ -19,13 +15,13 @@ http://localhost:4000/graphql You should see the output returned as JSON: -``` -{"data":{"hello":"Hello world!"}} +```json +{ "data": { "hello": "Hello world!" } } ``` -If you prefer to use a graphical user interface to send a test query, you can use clients such as [GraphiQL](https://github.com/graphql/graphiql) and [Insomnia](https://github.com/getinsomnia/insomnia). +If you prefer to use a graphical user interface to send a test query, you can use clients such as [GraphiQL](https://github.com/graphql/graphiql), [Insomnia](https://github.com/getinsomnia/insomnia), and [Postman](https://www.postman.com/product/graphql-client/). -It's also simple to send GraphQL from the browser. Open up http://localhost:4000, open a developer console, and paste in: +It's also simple to send GraphQL from the browser. Open up http://localhost:4000/graphql, open a developer console, and paste in: ```js fetch('/graphql', { @@ -42,13 +38,13 @@ fetch('/graphql', { You should see the data returned, logged in the console: -``` +```text data returned: Object { hello: "Hello world!" } ``` -In this example, the query was just a hardcoded string. As your application becomes more complex, and you add GraphQL endpoints that take arguments as described in [Passing Arguments](/graphql-js/passing-arguments/), you will want to construct GraphQL queries using variables in client code. You can do this by including a keyword prefixed with a dollar sign in the query, and passing an extra `variables` field on the payload. +In this example, the query was just a hardcoded string. As your application becomes more complex, and you add GraphQL endpoints that take arguments as described in [Passing Arguments](/passing-arguments/), you will want to construct GraphQL queries using variables in client code. You can do this by including a keyword prefixed with a dollar sign in the query, and passing an extra `variables` field on the payload. -For example, let's say you're running the example server from [Passing Arguments](/graphql-js/passing-arguments/) that has a schema of +For example, let's say you're running the example server from [Passing Arguments](/passing-arguments/) that has a schema of ```graphql type Query { @@ -59,11 +55,13 @@ type Query { You could access this from JavaScript with the code: ```js -var dice = 3; -var sides = 6; -var query = `query RollDice($dice: Int!, $sides: Int) { - rollDice(numDice: $dice, numSides: $sides) -}`; +let dice = 3; +let sides = 6; +let query = /* GraphQL */ ` + query RollDice($dice: Int!, $sides: Int) { + rollDice(numDice: $dice, numSides: $sides) + } +`; fetch('/graphql', { method: 'POST', @@ -84,4 +82,4 @@ Using this syntax for variables is a good idea because it automatically prevents In general, it will take a bit more time to set up a GraphQL client like Relay, but it's worth it to get more features as your application grows. You might want to start out just using HTTP requests as the underlying transport layer, and switching to a more complex client as your application gets more complex. -At this point you can write a client and server in GraphQL for an API that receives a single string. To do more, you will want to [learn how to use the other basic data types](/graphql-js/basic-types/). +At this point you can write a client and server in GraphQL for an API that receives a single string. To do more, you will want to [learn how to use the other basic data types](/basic-types/). diff --git a/website/pages/index.mdx b/website/pages/index.mdx new file mode 100644 index 0000000000..4c8fb78b56 --- /dev/null +++ b/website/pages/index.mdx @@ -0,0 +1,18 @@ +--- +title: Overview +sidebarTitle: Overview +--- + +GraphQL.JS is the reference implementation to the [GraphQL Specification](https://spec.graphql.org/draft/), it's designed to be simple to use and easy to understand +while closely following the Specification. + +You can build GraphQL servers, clients, and tools with this library, it's designed so you can choose which parts you use, for example, you can build your own parser +and use the execution/validation from the library. There also a lot of useful utilities for schema-diffing, working with arguments and [many more](./utilities.mdx). + +In the following chapters you'll find out more about the three critical pieces of this library + +- The GraphQL language +- Document validation +- GraphQL Execution + +You can also code along on [a tutorial](./getting-started.mdx). diff --git a/website/pages/mutations-and-input-types.mdx b/website/pages/mutations-and-input-types.mdx new file mode 100644 index 0000000000..7b4bfa4859 --- /dev/null +++ b/website/pages/mutations-and-input-types.mdx @@ -0,0 +1,405 @@ +--- +title: Mutations and Input Types +--- + +import { Tabs } from 'nextra/components'; + +If you have an API endpoint that alters data, like inserting data into a database or altering data already in a database, you should make this endpoint a `Mutation` rather than a `Query`. This is as simple as making the API endpoint part of the top-level `Mutation` type instead of the top-level `Query` type. + +Let's say we have a “message of the day” server, where anyone can update the message of the day, and anyone can read the current one. The GraphQL schema for this is simply: + + + +```graphql +type Mutation { + setMessage(message: String): String +} + +type Query { + getMessage: String +} +```` + + +```js +const { + GraphQLObjectType, + GraphQLString, + GraphQLSchema, +} = require('graphql'); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + getMessage: { type: GraphQLString }, + }, + }), + mutation: new GraphQLObjectType({ + name: 'Mutation', + fields: { + setMessage: { type: GraphQLString }, + }, + }), +}); +```` + + + + +It's often convenient to have a mutation that maps to a database create or update operation, like `setMessage`, return the same thing that the server stored. That way, if you modify the data on the server, the client can learn about those modifications. + +Both mutations and queries can be handled by root resolvers, so the root that implements this schema can simply be: + +```js +const fakeDatabase = {}; +const root = { + setMessage({ message }) { + fakeDatabase.message = message; + return message; + }, + getMessage() { + return fakeDatabase.message; + }, +}; +``` + +You don't need anything more than this to implement mutations. But in many cases, you will find a number of different mutations that all accept the same input parameters. A common example is that creating an object in a database and updating an object in a database often take the same parameters. To make your schema simpler, you can use “input types” for this, by using the `input` keyword instead of the `type` keyword. + +For example, instead of a single message of the day, let's say we have many messages, indexed in a database by the `id` field, and each message has both a `content` string and an `author` string. We want a mutation API both for creating a new message and for updating an old message. We could use the schema: + + + +```graphql +input MessageInput { + content: String + author: String +} + +type Message { + id: ID! + content: String + author: String +} + +type Query { + getMessage(id: ID!): Message +} + +type Mutation { + createMessage(input: MessageInput): Message + updateMessage(id: ID!, input: MessageInput): Message +} + +```` + + +```js +const { + GraphQLObjectType, + GraphQLString, + GraphQLSchema, + GraphQLID, + GraphQLInputObjectType, + GraphQLNonNull, +} = require('graphql'); + +const MessageInput = new GraphQLInputObjectType({ + name: 'MessageInput', + fields: { + content: { type: GraphQLString }, + author: { type: GraphQLString }, + }, +}); + +const Message = new GraphQLObjectType({ + name: 'Message', + fields: { + id: { type: GraphQLID }, + content: { type: GraphQLString }, + author: { type: GraphQLString }, + }, +}); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + getMessage: { + type: Message, + args: { + id: { type: new GraphQLNonNull(GraphQLID) }, + }, + }, + }, + }), + mutation: new GraphQLObjectType({ + name: 'Mutation', + fields: { + createMessage: { + type: Message, + args: { + input: { type: new GraphQLNonNull(MessageInput) }, + }, + }, + updateMessage: { + type: Message, + args: { + id: { type: new GraphQLNonNull(GraphQLID) }, + input: { type: new GraphQLNonNull(MessageInput) }, + }, + }, + }, + }), +}); +```` + + + + +Here, the mutations return a `Message` type, so that the client can get more information about the newly-modified `Message` in the same request as the request that mutates it. + +Input types can't have fields that are other objects, only basic scalar types, list types, and other input types. + +Naming input types with `Input` on the end is a useful convention, because you will often want both an input type and an output type that are slightly different for a single conceptual object. + +Here's some runnable code that implements this schema, keeping the data in memory: + + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +const schema = buildSchema(` +input MessageInput { + content: String + author: String +} + +type Message { + id: ID! + content: String + author: String +} + +type Query { + getMessage(id: ID!): Message +} + +type Mutation { + createMessage(input: MessageInput): Message + updateMessage(id: ID!, input: MessageInput): Message +} +`); + +// If Message had any complex fields, we'd put them on this object. +class Message { + constructor(id, { content, author }) { + this.id = id; + this.content = content; + this.author = author; + } +} + +// Maps username to content +const fakeDatabase = {}; + +const root = { + getMessage({ id }) { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + return new Message(id, fakeDatabase[id]); + }, + createMessage({ input }) { + // Create a random id for our "database". + const id = require('crypto').randomBytes(10).toString('hex'); + + fakeDatabase[id] = input; + return new Message(id, input); + }, + updateMessage({ id, input }) { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + // This replaces all old data, but some apps might want partial update. + fakeDatabase[id] = input; + return new Message(id, input); + }, +}; + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); +app.listen(4000, () => { +console.log('Running a GraphQL API server at localhost:4000/graphql'); +}); + +```` + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { + GraphQLObjectType, + GraphQLString, + GraphQLSchema, + GraphQLID, + GraphQLInputObjectType, + GraphQLNonNull, +} = require('graphql'); + +const MessageInput = new GraphQLInputObjectType({ + name: 'MessageInput', + fields: { + content: { type: GraphQLString }, + author: { type: GraphQLString }, + }, +}); + +const Message = new GraphQLObjectType({ + name: 'Message', + fields: { + id: { type: GraphQLID }, + content: { type: GraphQLString }, + author: { type: GraphQLString }, + }, +}); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + getMessage: { + type: Message, + args: { + id: { type: new GraphQLNonNull(GraphQLID) }, + }, + }, + }, + }), + mutation: new GraphQLObjectType({ + name: 'Mutation', + fields: { + createMessage: { + type: Message, + args: { + input: { type: new GraphQLNonNull(MessageInput) }, + }, + }, + updateMessage: { + type: Message, + args: { + id: { type: new GraphQLNonNull(GraphQLID) }, + input: { type: new GraphQLNonNull(MessageInput) }, + }, + }, + }, + }), +}); + +// If Message had any complex fields, we'd put them on this object. +class Message { + constructor(id, { content, author }) { + this.id = id; + this.content = content; + this.author = author; + } +} + +// Maps username to content +const fakeDatabase = {}; + +const root = { + getMessage({ id }) { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + return new Message(id, fakeDatabase[id]); + }, + createMessage({ input }) { + // Create a random id for our "database". + const id = require('crypto').randomBytes(10).toString('hex'); + + fakeDatabase[id] = input; + return new Message(id, input); + }, + updateMessage({ id, input }) { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + // This replaces all old data, but some apps might want partial update. + fakeDatabase[id] = input; + return new Message(id, input); + }, +}; + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); +app.listen(4000, () => { + console.log('Running a GraphQL API server at localhost:4000/graphql'); +}); +```` + + + + +To call a mutation, you must use the keyword `mutation` before your GraphQL query. To pass an input type, provide the data written as if it's a JSON object. For example, with the server defined above, you can create a new message and return the `id` of the new message with this operation: + +```graphql +mutation { + createMessage(input: { author: "andy", content: "hope is a good thing" }) { + id + } +} +``` + +You can use variables to simplify mutation client logic just like you can with queries. For example, some JavaScript code that calls the server to execute this mutation is: + +```js +const author = 'andy'; +const content = 'hope is a good thing'; +const query = /* GraphQL */ ` + mutation CreateMessage($input: MessageInput) { + createMessage(input: $input) { + id + } + } +`; + +fetch('/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query, + variables: { + input: { + author, + content, + }, + }, + }), +}) + .then((r) => r.json()) + .then((data) => console.log('data returned:', data)); +``` + +One particular type of mutation is operations that change users, like signing up a new user. While you can implement this using GraphQL mutations, you can reuse many existing libraries if you learn about [GraphQL with authentication and Express middleware](/authentication-and-express-middleware/). diff --git a/website/pages/object-types.mdx b/website/pages/object-types.mdx new file mode 100644 index 0000000000..366620c970 --- /dev/null +++ b/website/pages/object-types.mdx @@ -0,0 +1,372 @@ +--- +title: Object Types +--- + +import { Tabs } from 'nextra/components'; + +In many cases, you don't want to return a number or a string from an API. You want to return an object that has its own complex behavior. GraphQL is a perfect fit for this. + +In GraphQL schema language, the way you define a new object type is the same way we have been defining the `Query` type in our examples. Each object can have fields that return a particular type, and methods that take arguments. For example, in the [Passing Arguments](/passing-arguments/) documentation, we had a method to roll some random dice: + + + +```graphql +type Query { + rollDice(numDice: Int!, numSides: Int): [Int] +} +``` + + +```js +const { + GraphQLObjectType, + GraphQLNonNull, + GraphQLInt, + GraphQLString, + GraphQLList, + GraphQLFloat, +} = require('graphql'); + +new GraphQLObjectType({ + name: 'Query', + fields: { + rollDice: { + type: new GraphQLList(GraphQLFloat), + args: { + numDice: { + type: new GraphQLNonNull(GraphQLInt) + }, + numSides: { + type: new GraphQLNonNull(GraphQLInt) + }, + }, + }, + }, +}) + +```` + + + +If we wanted to have more and more methods based on a random die over time, we could implement this with a `RandomDie` object type instead. + + + +```graphql +type RandomDie { + roll(numRolls: Int!): [Int] +} + +type Query { + getDie(numSides: Int): RandomDie +} +```` + + + +```js +const { + GraphQLObjectType, + GraphQLNonNull, + GraphQLInt, + GraphQLString, + GraphQLList, + GraphQLFloat, +} = require('graphql'); + +const RandomDie = new GraphQLObjectType({ + name: 'RandomDie', + fields: { + roll: { + type: new GraphQLList(GraphQLInt), + args: { + numRolls: { + type: new GraphQLNonNull(GraphQLInt) + } + } + } + } +}); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + getDie: { + type: RandomDie, + args: { + numSides: { + type: GraphQLInt + } + } + } + } + }) +}); + +```` + + + +Instead of a root-level resolver for the `RandomDie` type, we can instead use an ES6 class, where the resolvers are instance methods. This code shows how the `RandomDie` schema above can be implemented: + +```js +class RandomDie { + constructor(numSides) { + this.numSides = numSides; + } + + rollOnce() { + return 1 + Math.floor(Math.random() * this.numSides); + } + + roll({ numRolls }) { + const output = []; + for (const i = 0; i < numRolls; i++) { + output.push(this.rollOnce()); + } + return output; + } +} + +const root = { + getDie({ numSides }) { + return new RandomDie(numSides || 6); + }, +}; +```` + +For fields that don't use any arguments, you can use either properties on the object or instance methods. So for the example code above, both `numSides` and `rollOnce` can actually be used to implement GraphQL fields, so that code also implements the schema of: + + + +```graphql +type RandomDie { + numSides: Int! + rollOnce: Int! + roll(numRolls: Int!): [Int] +} + +type Query { +getDie(numSides: Int): RandomDie +} + +```` + + +```js +const { + GraphQLObjectType, + GraphQLNonNull, + GraphQLInt, + GraphQLString, + GraphQLList, + GraphQLFloat, +} = require('graphql'); + +const RandomDie = new GraphQLObjectType({ + name: 'RandomDie', + fields: { + numSides: { + type: new GraphQLNonNull(GraphQLInt), + }, + rollOnce: { + type: new GraphQLNonNull(GraphQLInt), + }, + roll: { + type: new GraphQLList(GraphQLInt), + args: { + numRolls: { + type: new GraphQLNonNull(GraphQLInt) + }, + } + } + } +}); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + getDie: { + type: RandomDie, + args: { + numSides: { + type: GraphQLInt + } + } + } + } + }) +}); +```` + + + + +Putting this all together, here is some sample code that runs a server with this GraphQL API: + + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +const schema = buildSchema(` +type RandomDie { + numSides: Int! + rollOnce: Int! + roll(numRolls: Int!): [Int] +} + +type Query { + getDie(numSides: Int): RandomDie +} +`); + +// This class implements the RandomDie GraphQL type +class RandomDie { + constructor(numSides) { + this.numSides = numSides; + } + + rollOnce() { + return 1 + Math.floor(Math.random() \* this.numSides); + } + + roll({ numRolls }) { + const output = []; + for (const i = 0; i < numRolls; i++) { + output.push(this.rollOnce()); + } + return output; + } +} + +// The root provides the top-level API endpoints +const root = { + getDie({ numSides }) { + return new RandomDie(numSides || 6); + }, +}; + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +```` + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { + GraphQLObjectType, + GraphQLNonNull, + GraphQLInt, + GraphQLString, + GraphQLList, + GraphQLFloat, +} = require('graphql'); + +const RandomDie = new GraphQLObjectType({ + name: 'RandomDie', + fields: { + numSides: { + type: new GraphQLNonNull(GraphQLInt), + }, + rollOnce: { + type: new GraphQLNonNull(GraphQLInt), + }, + roll: { + type: new GraphQLList(GraphQLInt), + args: { + numRolls: { + type: new GraphQLNonNull(GraphQLInt) + }, + } + } + } +}); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + getDie: { + type: RandomDie, + args: { + numSides: { + type: GraphQLInt + } + } + } + } + }) +}); + +// This class implements the RandomDie GraphQL type +class RandomDie { + constructor(numSides) { + this.numSides = numSides; + } + + rollOnce() { + return 1 + Math.floor(Math.random() * this.numSides); + } + + roll({ numRolls }) { + const output = []; + for (const i = 0; i < numRolls; i++) { + output.push(this.rollOnce()); + } + return output; + } +} + +// The root provides the top-level API endpoints +const root = { + getDie({ numSides }) { + return new RandomDie(numSides || 6); + }, +}; + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +```` + + + + +When you issue a GraphQL query against an API that returns object types, you can call multiple methods on the object at once by nesting the GraphQL field names. For example, if you wanted to call both `rollOnce` to roll a die once, and `roll` to roll a die three times, you could do it with this query: + +```graphql +{ + getDie(numSides: 6) { + rollOnce + roll(numRolls: 3) + } +} +``` + +If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out these APIs with [GraphiQL](https://github.com/graphql/graphiql). + +This way of defining object types often provides advantages over a traditional REST API. Instead of doing one API request to get basic information about an object, and then multiple subsequent API requests to find out more information about that object, you can get all of that information in one API request. That saves bandwidth, makes your app run faster, and simplifies your client-side logic. + +So far, every API we've looked at is designed for returning data. In order to modify stored data or handle complex input, it helps to [learn about mutations and input types](/mutations-and-input-types/). diff --git a/website/pages/oneof-input-objects.mdx b/website/pages/oneof-input-objects.mdx new file mode 100644 index 0000000000..95be65d2c2 --- /dev/null +++ b/website/pages/oneof-input-objects.mdx @@ -0,0 +1,91 @@ +--- +title: OneOf input objects +--- + +import { Tabs } from 'nextra/components'; + +Some inputs will behave differently depending on what input we choose. Let's look at the case for +a field named `product`, we can fetch a `Product` by either its `id` or its `name`. Currently we'd +make a tradeoff for this by introducing two arguments that are both nullable, now if both are passed +as null (or both non-null) we'd have to handle that in code - the type system wouldn't indicate that exactly one was required. To fix this, the `@oneOf` directive was introduced so we +can create this "exactly one option" constraint without sacrificing the strictly typed nature of our GraphQL Schema. + + + +```js +const schema = buildSchema(` + type Product { + id: ID! + name: String! + } + + input ProductLocation { + aisleNumber: Int! + shelfNumber: Int! + positionOnShelf: Int! + } + + input ProductSpecifier @oneOf { + id: ID + name: String + location: ProductLocation + } + + type Query { + product(by: ProductSpecifier!): Product + } +`); +``` + + +```js +const Product = new GraphQLObjectType({ + name: 'Product', + fields: { + id: { + type: new GraphQLNonNull(GraphQLID), + }, + name: { + type: new GraphQLNonNull(GraphQLString), + }, + }, +}); + +const ProductLocation = new GraphQLInputObjectType({ + name: 'ProductLocation', + isOneOf: true, + fields: { + aisleNumber: { type: GraphQLInt }, + shelfNumber: { type: GraphQLInt }, + positionOnShelf: { type: GraphQLInt }, + }, +}); + +const ProductSpecifier = new GraphQLInputObjectType({ + name: 'ProductSpecifier', + isOneOf: true, + fields: { + id: { type: GraphQLID }, + name: { type: GraphQLString }, + location: { type: ProductLocation }, + }, +}); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + product: { + type: Product, + args: { by: { type: ProductSpecifier } }, + }, + }, + }), +}); +``` + + + +It doesn't matter whether you have 2 or more inputs here, all that matters is +that your user will have to specify one, and only one, for this input to be valid. +The values are not limited to scalars, lists and other input object types are also allowed. \ No newline at end of file diff --git a/docs/Tutorial-PassingArguments.md b/website/pages/passing-arguments.mdx similarity index 51% rename from docs/Tutorial-PassingArguments.md rename to website/pages/passing-arguments.mdx index df8fda9e27..0017a69638 100644 --- a/docs/Tutorial-PassingArguments.md +++ b/website/pages/passing-arguments.mdx @@ -1,12 +1,10 @@ --- title: Passing Arguments -layout: ../_core/GraphQLJSLayout -category: GraphQL.js Tutorial -permalink: /graphql-js/passing-arguments/ -next: /graphql-js/object-types/ --- -Just like a REST API, it's common to pass arguments to an endpoint in a GraphQL API. By defining the arguments in the schema language, type checking happens automatically. Each argument must be named and have a type. For example, in the [Basic Types documentation](/graphql-js/basic-types/) we had an endpoint called `rollThreeDice`: +import { Tabs } from 'nextra/components'; + +Just like a REST API, it's common to pass arguments to an endpoint in a GraphQL API. By defining the arguments in the schema language, typechecking happens automatically. Each argument must be named and have a type. For example, in the [Basic Types documentation](/basic-types/) we had an endpoint called `rollThreeDice`: ```graphql type Query { @@ -14,37 +12,71 @@ type Query { } ``` -Instead of hard-coding “three”, we might want a more general function that rolls `numDice` dice, each of which have `numSides` sides. We can add arguments to the GraphQL schema language like this: +Instead of hard coding “three”, we might want a more general function that rolls `numDice` dice, each of which have `numSides` sides. We can add arguments to the GraphQL schema language like this: + + ```graphql type Query { rollDice(numDice: Int!, numSides: Int): [Int] } ``` + + +```js +const { + GraphQLObjectType, + GraphQLNonNull, + GraphQLInt, + GraphQLString, + GraphQLList, + GraphQLFloat, +} = require('graphql'); + +new GraphQLObjectType({ + name: 'Query', + fields: { + rollDice: { + type: new GraphQLList(GraphQLFloat), + args: { + numDice: { + type: new GraphQLNonNull(GraphQLInt) + }, + numSides: { + type: new GraphQLNonNull(GraphQLInt) + }, + }, + }, + }, +}) + +```` + + The exclamation point in `Int!` indicates that `numDice` can't be null, which means we can skip a bit of validation logic to make our server code simpler. We can let `numSides` be null and assume that by default a die has 6 sides. So far, our resolver functions took no arguments. When a resolver takes arguments, they are passed as one “args” object, as the first argument to the function. So rollDice could be implemented as: ```js -var root = { - rollDice: function (args) { - var output = []; - for (var i = 0; i < args.numDice; i++) { +const root = { + rollDice(args) { + const output = []; + for (const i = 0; i < args.numDice; i++) { output.push(1 + Math.floor(Math.random() * (args.numSides || 6))); } return output; }, }; -``` +```` It's convenient to use [ES6 destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) for these parameters, since you know what format they will be. So we can also write `rollDice` as ```js -var root = { - rollDice: function ({ numDice, numSides }) { - var output = []; - for (var i = 0; i < numDice; i++) { +const root = { + rollDice({ numDice, numSides }) { + const output = []; + for (const i = 0; i < numDice; i++) { output.push(1 + Math.floor(Math.random() * (numSides || 6))); } return output; @@ -56,42 +88,98 @@ If you're familiar with destructuring, this is a bit nicer because the line of c The entire code for a server that hosts this `rollDice` API is: + + ```js -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { buildSchema } = require('graphql'); // Construct a schema, using GraphQL schema language -var schema = buildSchema(` - type Query { - rollDice(numDice: Int!, numSides: Int): [Int] - } -`); +const schema = buildSchema(/_ GraphQL _/ ` type Query { rollDice(numDice: Int!, numSides: Int): [Int] }`); // The root provides a resolver function for each API endpoint -var root = { - rollDice: function ({ numDice, numSides }) { - var output = []; - for (var i = 0; i < numDice; i++) { +const root = { + rollDice({ numDice, numSides }) { + const output = []; + for (const i = 0; i < numDice; i++) { + output.push(1 + Math.floor(Math.random() \* (numSides || 6))); + } + return output; + }, +}; + +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); + +```` + + +```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); +const { + GraphQLObjectType, + GraphQLNonNull, + GraphQLInt, + GraphQLString, + GraphQLList, + GraphQLFloat, +} = require('graphql'); + +// Construct a schema, using GraphQL schema language +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + rollDice: { + type: new GraphQLList(GraphQLFloat), + args: { + numDice: { + type: new GraphQLNonNull(GraphQLInt) + }, + numSides: { + type: new GraphQLNonNull(GraphQLInt) + }, + }, + }, + }, + }) +}) + +// The root provides a resolver function for each API endpoint +const root = { + rollDice({ numDice, numSides }) { + const output = []; + for (const i = 0; i < numDice; i++) { output.push(1 + Math.floor(Math.random() * (numSides || 6))); } return output; }, }; -var app = express(); -app.use( +const app = express(); +app.all( '/graphql', - graphqlHTTP({ + createHandler({ schema: schema, rootValue: root, - graphiql: true, }), ); -app.listen(4000, () => { - console.log('Running a GraphQL API server at localhost:4000/graphql'); -}); -``` +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +```` + + + When you call this API, you have to pass each argument by name. So for the server above, you could issue this GraphQL query to roll three six-sided dice: @@ -108,11 +196,13 @@ When you're passing arguments in code, it's generally better to avoid constructi For example, some JavaScript code that calls our server above is: ```js -var dice = 3; -var sides = 6; -var query = `query RollDice($dice: Int!, $sides: Int) { - rollDice(numDice: $dice, numSides: $sides) -}`; +const dice = 3; +const sides = 6; +const query = /* GraphQL */ ` + query RollDice($dice: Int!, $sides: Int) { + rollDice(numDice: $dice, numSides: $sides) + } +`; fetch('/graphql', { method: 'POST', @@ -131,4 +221,4 @@ fetch('/graphql', { Using `$dice` and `$sides` as variables in GraphQL means we don't have to worry about escaping on the client side. -With basic types and argument passing, you can implement anything you can implement in a REST API. But GraphQL supports even more powerful queries. You can replace multiple API calls with a single API call if you learn how to [define your own object types](/graphql-js/object-types/). +With basic types and argument passing, you can implement anything you can implement in a REST API. But GraphQL supports even more powerful queries. You can replace multiple API calls with a single API call if you learn how to [define your own object types](/object-types/). diff --git a/website/pages/running-an-express-graphql-server.mdx b/website/pages/running-an-express-graphql-server.mdx new file mode 100644 index 0000000000..dbaff0a087 --- /dev/null +++ b/website/pages/running-an-express-graphql-server.mdx @@ -0,0 +1,117 @@ +--- +title: Running an Express GraphQL Server +sidebarTitle: Running Express + GraphQL +--- + +import { Tabs } from 'nextra/components'; + +The simplest way to run a GraphQL API server is to use [Express](https://expressjs.com), a popular web application framework for Node.js. You will need to install two additional dependencies: + +```sh npm2yarn +npm install express graphql-http graphql --save +``` + +Let's modify our “hello world” example so that it's an API server rather than a script that runs a single query. We can use the 'express' module to run a webserver, and instead of executing a query directly with the `graphql` function, we can use the `graphql-http` library to mount a GraphQL API server on the “/graphql” HTTP endpoint: + + + +```javascript +const { buildSchema } = require('graphql'); +const { createHandler } = require('graphql-http/lib/use/express'); +const express = require('express'); + +// Construct a schema, using GraphQL schema language +const schema = buildSchema(`type Query { hello: String } `); + +// The rootValue provides a resolver function for each API endpoint +const rootValue = { + hello() { + return 'Hello world!'; + }, +}; + +const app = express(); + +// Create and use the GraphQL handler. +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); + +// Start the server at port +app.listen(4000); +console.log('Running a GraphQL API server at http://localhost:4000/graphql'); + +```` + + +```javascript +const { GraphQLObjectType, GraphQLSchema } = require('graphql'); +const { createHandler } = require('graphql-http/lib/use/express'); +const express = require('express'); + +// Construct a schema +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + hello: { type: GraphQLString }, + }, + }), +}); + +// The rootValue provides a resolver function for each API endpoint +const rootValue = { + hello() { + return 'Hello world!'; + }, +}; + +const app = express(); + +// Create and use the GraphQL handler. +app.all( + '/graphql', + createHandler({ + schema: schema, + rootValue: root, + }), +); + +// Start the server at port +app.listen(4000); +console.log('Running a GraphQL API server at http://localhost:4000/graphql'); +```` + + + + +You can run this GraphQL server with: + +```sh +node server.js +``` + +## Using GraphiQL + +[GraphiQL](https://github.com/graphql/graphiql) is GraphQL's IDE; a great way of querying and exploring your GraphQL API. +One easy way to add it to your server is via the MIT-licensed [ruru](https://github.com/graphile/crystal/blob/main/grafast/ruru/README.md) package which bundles a prebuilt GraphiQL with some popular enhancements. +To do so, install the `ruru` module with `npm install --save ruru` and then add the following to your `server.js` file, then restart the `node server.js` command: + +```js +const { ruruHTML } = require('ruru/server'); + +// Serve the GraphiQL IDE. +app.get('/', (_req, res) => { + res.type('html'); + res.end(ruruHTML({ endpoint: '/graphql' })); +}); +``` + +If you navigate to [http://localhost:4000](http://localhost:4000), you should see an interface that lets you enter queries; +now you can use the GraphiQL IDE tool to issue GraphQL queries directly in the browser. + +At this point you have learned how to run a GraphQL server. The next step is to learn how to [issue GraphQL queries from client code](/graphql-clients/). diff --git a/website/postcss.config.js b/website/postcss.config.js new file mode 100644 index 0000000000..cdbe50f3a4 --- /dev/null +++ b/website/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + 'tailwindcss/nesting': {}, + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/website/tailwind.config.js b/website/tailwind.config.js new file mode 100644 index 0000000000..4cc2c447a2 --- /dev/null +++ b/website/tailwind.config.js @@ -0,0 +1,41 @@ +import typography from '@tailwindcss/typography'; + +module.exports = { + content: [ + './pages/**/*.{ts,tsx,mdx}', + './icons/**/*.{ts,tsx,mdx}', + './css/**/*.css', + './theme.config.tsx', + ], + theme: { + container: { + center: true, + padding: '1rem', + }, + extend: { + colors: { + primary: '#e10098', + 'conf-black': '#0e031c', + black: '#1b1b1b', + }, + backgroundImage: { + 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', + 'gradient-conic': + 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', + }, + animation: { + scroll: + 'scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite', + }, + keyframes: { + scroll: { + to: { + transform: 'translate(calc(-50% - .5rem))', + }, + }, + }, + }, + }, + plugins: [typography], + darkMode: ['class', 'html[class~="dark"]'], +}; diff --git a/website/theme.config.tsx b/website/theme.config.tsx new file mode 100644 index 0000000000..5d8d5ff3a7 --- /dev/null +++ b/website/theme.config.tsx @@ -0,0 +1,249 @@ +import React from 'react'; +import { DocsThemeConfig, ThemeSwitch, useConfig } from 'nextra-theme-docs'; +import NextLink from 'next/link'; +import { + GraphQLWordmarkLogo, + StackOverflowIcon, + GitHubIcon, + DiscordIcon, + TwitterIcon, +} from './icons/index'; +import { useRouter } from 'next/router'; + +const graphQLLogo = ( + +); + +const classes = { + link: 'hover:underline decoration-from-font [text-underline-position:from-font]', +}; + +function List({ + title, + items, +}: { + title: string; + items: { title: string; url: string }[]; +}) { + return ( +
                              +

                              {title}

                              + {items.map((item) => ( +
                            • + + {item.title} + +
                            • + ))} +
                            + ); +} + +function Footer() { + return ( +
                            +
                            + + {graphQLLogo} + + + + + +
                            +
                            +

                            + Copyright © {new Date().getFullYear()} The GraphQL Foundation. All + rights reserved. +
                            + For web site terms of use, trademark policy and general project + policies please see{' '} + + https://lfprojects.org + +

                            +
                            +
                              + {[ + { url: 'https://github.com/graphql', icon: GitHubIcon }, + { url: 'https://discord.graphql.org', icon: DiscordIcon }, + { url: 'https://x.com/graphql', icon: TwitterIcon }, + { + url: 'http://stackoverflow.com/questions/tagged/graphql', + icon: StackOverflowIcon, + }, + ].map(({ url, icon: Icon }) => ( +
                            • + + + +
                            • + ))} +
                            + + Powered by{' '} + + + + + +
                            +
                            +
                            + ); +} + +const cfg: DocsThemeConfig = { + backgroundColor: { + dark: '27,27,27', + }, + head: function useHead() { + const { frontMatter, title: pageTitle } = useConfig(); + const { asPath } = useRouter(); + + const title = `${pageTitle}${asPath === '/' ? '' : ' | GraphQL'}`; + const { description, canonical, image } = frontMatter; + return ( + <> + {title} + + {description && ( + <> + + + + )} + {canonical && } + {image && } + + + + ); + }, + banner: { + content: ( + <> + 🎬 That's a Wrap for GraphQLConf 2024! • Watch the Videos •{' '} + + Check out the recorded talks and workshops + + + ), + key: 'graphqlconf-2024', + }, + logo: graphQLLogo, + docsRepositoryBase: + 'https://github.com/graphql/graphql-js/tree/16.x.x/website', + color: { + hue: 319, + }, + sidebar: { + defaultMenuCollapseLevel: 1, + }, + footer: { + content: Footer, + }, + navbar: { + extraContent: , + }, + toc: { + backToTop: true, + }, + search: { + placeholder: 'Search…', + }, +}; + +export default cfg; diff --git a/website/tsconfig.json b/website/tsconfig.json new file mode 100644 index 0000000000..dd9c4aa58c --- /dev/null +++ b/website/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "incremental": true, + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ], + "strictNullChecks": true, + "module": "esnext" + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +}