diff --git a/.babelrc-deno.json b/.babelrc-deno.json new file mode 100644 index 0000000000..4b9b17ddad --- /dev/null +++ b/.babelrc-deno.json @@ -0,0 +1,13 @@ +{ + "plugins": [ + "@babel/plugin-transform-flow-strip-types", + ["./resources/add-extension-to-import-paths", { "extension": "js" }], + "./resources/inline-invariant" + ], + "overrides": [ + { + "include": "src/error/GraphQLError.js", + "plugins": [["@babel/plugin-transform-classes", { "loose": false }]] + } + ] +} diff --git a/.babelrc.json b/.babelrc.json index d98d03a0ae..8c98e626b2 100644 --- a/.babelrc.json +++ b/.babelrc.json @@ -1,12 +1,9 @@ { "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]], - "plugins": [ - "./resources/inline-invariant", - "@babel/plugin-transform-flow-strip-types" - ], + "plugins": ["@babel/plugin-transform-flow-strip-types"], "overrides": [ { - "exclude": ["**/__tests__/**/*", "**/__fixtures__/**/*"], + "exclude": ["src/__testUtils__/**/*", "**/__tests__/**/*"], "presets": ["@babel/preset-env"], "plugins": [ ["@babel/plugin-transform-classes", { "loose": true }], @@ -16,11 +13,24 @@ ], "env": { "cjs": { - "presets": [["@babel/preset-env", { "modules": "commonjs" }]] + "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"] + "plugins": [ + [ + "./resources/add-extension-to-import-paths", + { "extension": "mjs" } + ], + "./resources/inline-invariant" + ] } } }, diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..258461b7bf --- /dev/null +++ b/.eslintignore @@ -0,0 +1,13 @@ +# Copied from '.gitignore', please keep it in sync. +/.eslintcache +/node_modules +/coverage +/npmDist +/denoDist +/npm +/deno + +# 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 d0011cd01f..389ceca358 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,73 +1,89 @@ -parser: babel-eslint parserOptions: - sourceType: module + sourceType: script + ecmaVersion: 2020 env: es6: true node: true reportUnusedDisableDirectives: true plugins: - - graphql-internal - - flowtype + - internal-rules + - node + - istanbul - import +settings: + node: + tryExtensions: ['.js', '.json', '.node', '.ts', '.d.ts'] rules: ############################################################################## - # Internal rules located in 'resources/eslint-rules'. - # See './resources/eslint-rules/README.md' + # Internal rules located in 'resources/eslint-internal-rules'. + # See './resources/eslint-internal-rules/README.md' ############################################################################## - graphql-internal/no-dir-import: error + internal-rules/no-dir-import: error ############################################################################## - # `eslint-plugin-flowtype` rule list based on `v4.7.x` - # https://github.com/gajus/eslint-plugin-flowtype#eslint-plugin-flowtype + # `eslint-plugin-istanbul` rule list based on `v0.1.2` + # https://github.com/istanbuljs/eslint-plugin-istanbul#rules ############################################################################## - 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: error - 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: - [error, always, { annotationStyle: line, strict: true }] - 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, identifier, { ignoreTypeDefault: true }] - flowtype/use-flow-type: error + istanbul/no-ignore-file: error + istanbul/prefer-ignore-reason: 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 + ############################################################################## + # `eslint-plugin-node` rule list based on `v11.1.x` + ############################################################################## + + # Possible Errors + # https://github.com/mysticatea/eslint-plugin-node#possible-errors + + node/handle-callback-err: [error, error] + node/no-callback-literal: error + node/no-exports-assign: error + node/no-extraneous-import: error + node/no-extraneous-require: error + node/no-missing-import: error + node/no-missing-require: error + node/no-new-require: error + node/no-path-concat: error + node/no-process-exit: off + node/no-unpublished-bin: error + 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/process-exit-as-throw: error + node/shebang: error + + # Best Practices + # https://github.com/mysticatea/eslint-plugin-node#best-practices + node/no-deprecated-api: error + + # Stylistic Issues + # https://github.com/mysticatea/eslint-plugin-node#stylistic-issues + + node/callback-return: error + node/exports-style: off # TODO consider + node/file-extension-in-import: off # TODO consider + node/global-require: error + node/no-mixed-requires: error + node/no-process-env: off + node/no-restricted-import: off + node/no-restricted-require: off + node/no-sync: error + node/prefer-global/buffer: error + node/prefer-global/console: error + node/prefer-global/process: error + node/prefer-global/text-decoder: error + node/prefer-global/text-encoder: error + node/prefer-global/url-search-params: error + node/prefer-global/url: error + node/prefer-promises/dns: off + node/prefer-promises/fs: off ############################################################################## - # `eslint-plugin-import` rule list based on `v2.20.x` + # `eslint-plugin-import` rule list based on `v2.22.x` ############################################################################## # Static analysis @@ -76,7 +92,11 @@ rules: import/named: error import/default: error import/namespace: error - import/no-restricted-paths: off + import/no-restricted-paths: + - error + - basePath: './' + zones: + - { target: './src', from: 'src/__testUtils__' } import/no-absolute-path: error import/no-dynamic-require: error import/no-internal-modules: off @@ -123,7 +143,7 @@ rules: import/dynamic-import-chunkname: off ############################################################################## - # ESLint builtin rules list based on `v6.8.x` + # ESLint builtin rules list based on `v7.13.x` ############################################################################## # Possible Errors @@ -152,16 +172,20 @@ rules: no-inner-declarations: [error, both] no-invalid-regexp: error no-irregular-whitespace: error + no-loss-of-precision: error no-misleading-character-class: error no-obj-calls: error + no-promise-executor-return: off # TODO no-prototype-builtins: error no-regex-spaces: error no-setter-return: error no-sparse-arrays: error no-template-curly-in-string: error no-unreachable: error + no-unreachable-loop: error no-unsafe-finally: error no-unsafe-negation: error + no-useless-backreference: error require-atomic-updates: error use-isnan: error valid-typeof: error @@ -177,8 +201,9 @@ rules: consistent-return: off curly: error default-case: off + default-case-last: error default-param-last: error - dot-notation: off + dot-notation: error eqeqeq: [error, smart] grouped-accessor-pairs: error guard-for-in: error @@ -201,7 +226,7 @@ rules: no-implicit-coercion: error no-implicit-globals: off no-implied-eval: error - no-invalid-this: off + no-invalid-this: error no-iterator: error no-labels: error no-lone-blocks: error @@ -264,21 +289,6 @@ rules: no-unused-vars: [error, { vars: all, args: all, argsIgnorePattern: '^_' }] no-use-before-define: off - # Node.js and CommonJS - # https://eslint.org/docs/rules/#nodejs-and-commonjs - - callback-return: error - global-require: error - handle-callback-err: [error, error] - no-buffer-constructor: error - no-mixed-requires: error - no-new-require: error - no-path-concat: error - no-process-env: off - no-process-exit: off - no-restricted-modules: off - no-sync: error - # Stylistic Issues # https://eslint.org/docs/rules/#stylistic-issues @@ -288,7 +298,7 @@ rules: func-name-matching: off func-names: off func-style: off - id-blacklist: off + id-denylist: off id-length: off id-match: [error, '^(?:_?[a-zA-Z0-9]*)|[_A-Z0-9]+$'] line-comment-position: off @@ -302,7 +312,7 @@ rules: max-statements: off max-statements-per-line: off multiline-comment-style: off - new-cap: off # TODO + new-cap: error no-array-constructor: error no-bitwise: off no-continue: off @@ -322,7 +332,7 @@ rules: runtime dependencies. Instead, use explicit Promises. no-tabs: error no-ternary: off - no-underscore-dangle: off + no-underscore-dangle: off # TODO no-unneeded-ternary: error one-var: [error, never] operator-assignment: error @@ -342,8 +352,9 @@ rules: no-class-assign: error no-const-assign: error no-dupe-class-members: error - no-duplicate-imports: error + no-duplicate-imports: off # Superseded by `import/no-duplicates` no-new-symbol: error + no-restricted-exports: off no-restricted-imports: off no-this-before-super: error no-useless-computed-key: error @@ -428,21 +439,72 @@ 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' parser: '@typescript-eslint/parser' parserOptions: - tsconfigRootDir: './src/' + sourceType: module project: ['tsconfig.json'] plugins: - '@typescript-eslint' extends: - plugin:import/typescript rules: - flowtype/require-valid-file-annotation: off - flowtype/no-types-missing-file-annotation: off - ########################################################################## - # `@typescript-eslint/eslint-plugin` rule list based on `v2.26.x` + # `@typescript-eslint/eslint-plugin` rule list based on `v4.7.x` ########################################################################## # Supported Rules @@ -450,18 +512,24 @@ overrides: '@typescript-eslint/adjacent-overload-signatures': error '@typescript-eslint/array-type': [error, { default: generic }] '@typescript-eslint/await-thenable': error - '@typescript-eslint/ban-ts-comment': error + '@typescript-eslint/ban-ts-comment': [error, { 'ts-expect-error': false }] + '@typescript-eslint/ban-tslint-comment': error '@typescript-eslint/ban-types': error - '@typescript-eslint/class-literal-property-style': off + '@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/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/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-dynamic-delete': off '@typescript-eslint/no-empty-interface': error '@typescript-eslint/no-explicit-any': off # TODO error @@ -469,6 +537,7 @@ 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-implied-eval': error '@typescript-eslint/no-inferrable-types': [error, { ignoreParameters: true, ignoreProperties: true }] @@ -478,6 +547,7 @@ overrides: '@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-invalid-void-type': error '@typescript-eslint/no-require-imports': error '@typescript-eslint/no-this-alias': error '@typescript-eslint/no-throw-literal': error @@ -487,21 +557,26 @@ overrides: '@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-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-unused-vars-experimental': off '@typescript-eslint/no-var-requires': 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/prefer-function-type': error '@typescript-eslint/prefer-includes': off # TODO switch to error after IE11 drop + '@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-parameter-types': off # TODO consider + '@typescript-eslint/prefer-reduce-type-parameter': error '@typescript-eslint/prefer-regexp-exec': 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 @@ -520,57 +595,108 @@ overrides: # Disable conflicting ESLint rules and enable TS-compatible ones default-param-last: off + dot-notation: off + lines-between-class-members: off no-array-constructor: off no-dupe-class-members: off no-empty-function: off + no-invalid-this: off + no-loop-func: off + no-loss-of-precision: off + no-redeclare: off + no-shadow: off no-unused-expressions: off no-unused-vars: off no-useless-constructor: off require-await: off no-return-await: off '@typescript-eslint/default-param-last': error - '@typescript-eslint/no-dupe-class-members': error + '@typescript-eslint/dot-notation': error + '@typescript-eslint/lines-between-class-members': + [error, always, { exceptAfterSingleLine: true }] '@typescript-eslint/no-array-constructor': error + '@typescript-eslint/no-dupe-class-members': error '@typescript-eslint/no-empty-function': error + '@typescript-eslint/no-invalid-this': error + '@typescript-eslint/no-loop-func': error + '@typescript-eslint/no-loss-of-precision': error + '@typescript-eslint/no-redeclare': error + '@typescript-eslint/no-shadow': error '@typescript-eslint/no-unused-expressions': error '@typescript-eslint/no-unused-vars': - [error, { vars: all, args: all, argsIgnorePattern: '^_' }] + [ + error, + { + vars: all, + args: all, + argsIgnorePattern: '^_', + varsIgnorePattern: '^_T', + }, + ] '@typescript-eslint/no-useless-constructor': error '@typescript-eslint/require-await': error '@typescript-eslint/return-await': error # Disable for JS, Flow and TS + '@typescript-eslint/init-declarations': off '@typescript-eslint/no-magic-numbers': 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 '@typescript-eslint/quotes': off '@typescript-eslint/brace-style': off + '@typescript-eslint/comma-dangle': off '@typescript-eslint/comma-spacing': off '@typescript-eslint/func-call-spacing': off '@typescript-eslint/indent': off + '@typescript-eslint/keyword-spacing': off '@typescript-eslint/member-delimiter-style': off '@typescript-eslint/no-extra-parens': off '@typescript-eslint/no-extra-semi': off '@typescript-eslint/semi': off '@typescript-eslint/space-before-function-paren': off + '@typescript-eslint/space-infix-ops': off '@typescript-eslint/type-annotation-spacing': off - - files: '**/__*__/**' + - files: 'src/**/__*__/**' + rules: + node/no-unpublished-import: [error, { allowModules: ['chai', 'mocha'] }] + import/no-restricted-paths: off + import/no-extraneous-dependencies: [error, { devDependencies: true }] + no-restricted-syntax: off + - files: 'integrationTests/*' rules: - import/no-extraneous-dependencies: off + node/no-unpublished-require: off + node/no-sync: off + import/no-extraneous-dependencies: [error, { devDependencies: true }] import/no-nodejs-modules: off + - files: 'integrationTests/*/**' + rules: + node/no-sync: off + node/no-missing-require: off + import/no-nodejs-modules: off + no-console: off + - files: 'benchmark/**' + rules: + 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/**' - parserOptions: - sourceType: script rules: + node/no-unpublished-import: off + 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: 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 - no-sync: off - global-require: off diff --git a/.flowconfig b/.flowconfig index 76267e7deb..2e0d092df9 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,14 +1,9 @@ [ignore] .* !/src -!/node_modules/chai -!/node_modules/mocha -!/node_modules/iterall [include] -[libs] - [lints] sketchy-null-bool=error sketchy-null-string=error @@ -17,11 +12,10 @@ sketchy-null-mixed=error sketchy-number=error untyped-type-import=error nonstrict-import=off -untyped-import=off +untyped-import=error unclear-type=off deprecated-type=error deprecated-utility=error -dynamic-export=off unsafe-getters-setters=error unnecessary-optional-chain=error unnecessary-invariant=error @@ -29,15 +23,20 @@ signature-verification-failure=error implicit-inexact-object=error ambiguous-object-type=error uninitialized-instance-property=error -unsafe-addition=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] -include_warnings=true +all=true +types_first=false module.use_strict=true babel_loose_array_spread=true -esproposal.optional_chaining=enable -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$DisableFlowOnNegativeTest +experimental.const_params=true +include_warnings=true [version] -^0.121.0 +^0.137.0 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 17bd6cdc41..9b2eef0b2b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -42,7 +42,7 @@ Complete your CLA here: 2. Check out your fork ```sh - git clone git@github.com:yournamehere/graphql-js.git + git clone git@github.com:your_name_here/graphql-js.git ``` 3. Install or Update all dependencies @@ -97,4 +97,4 @@ git push --follow-tags ## License By contributing to graphql-js, you agree that your contributions will be -licensed under its MIT license. +licensed under its [MIT license](../LICENSE). diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..9a6a36b483 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,270 @@ +name: CI +on: [push, pull_request] +env: + NODE_VERSION_USED_FOR_DEVELOPMENT: 14 +jobs: + lint: + name: Lint source files + runs-on: ubuntu-latest + 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 }} + + - 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: Lint ESLint + run: npm run lint + + - name: Lint Flow + run: npm run check + + - name: Lint Prettier + run: npm run prettier:check + + - name: Spellcheck + run: npm run check:spelling + + checkForCommonlyIgnoredFiles: + name: Check for commonly ignored files + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Check if commit contains files that should be ignored + run: | + git clone --depth 1 https://github.com/github/gitignore.git && + cat gitignore/Node.gitignore $(find gitignore/Global -name "*.gitignore" | grep -v ModelSim) > all.gitignore && + if [[ "$(git ls-files -iX all.gitignore)" != "" ]]; then + echo "::error::Please remove these files:" + git ls-files -iX all.gitignore + exit 1 + fi + + integrationTests: + name: Run integration tests + runs-on: ubuntu-latest + 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 }} + + # 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 + + - name: Build NPM package + run: npm run build:npm + + - name: Build Deno package + run: npm run build:deno + + - name: Run Integration Tests + run: npm run check:integrations + + fuzz: + name: Run fuzzing tests + runs-on: ubuntu-latest + 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 }} + + - 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 Tests + run: npm run fuzzonly + + coverage: + name: Measure test coverage + runs-on: ubuntu-latest + 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 }} + + - 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 tests and measure code coverage + run: npm run testonly:cover + + - name: Upload coverage to Codecov + if: ${{ always() }} + uses: codecov/codecov-action@v1 + with: + file: ./coverage/coverage-final.json + fail_ci_if_error: true + + 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] + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Setup Node.js v${{ matrix.node_version_to_setup }} + uses: actions/setup-node@v1 + with: + 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 + + - name: Run Tests + run: npm run testonly + + benchmark: + name: Run benchmark + runs-on: ubuntu-latest + 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/master' + needs: [test, fuzz, lint, checkForCommonlyIgnoredFiles, 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 }} + + - 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: 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 }} + + deploy-to-deno-branch: + name: Deploy to `deno` branch + runs-on: ubuntu-latest + if: | + github.event_name == 'push' && + github.repository == 'graphql/graphql-js' && + github.ref == 'refs/heads/master' + needs: [test, fuzz, lint, checkForCommonlyIgnoredFiles, 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 }} + + - 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: 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 }} diff --git a/.gitignore b/.gitignore index 4186835d32..9e07128cb8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,11 +5,10 @@ # https://help.github.com/articles/ignoring-files/#create-a-global-gitignore # https://www.gitignore.io/ -package-lock.json -.nyc_output -.eslintcache -node_modules -coverage -dist -benchmarkDist -npm +/.eslintcache +/node_modules +/coverage +/npmDist +/denoDist +/npm +/deno diff --git a/.nycflowrc.yml b/.nycflowrc.yml deleted file mode 100644 index 4032fdd014..0000000000 --- a/.nycflowrc.yml +++ /dev/null @@ -1,10 +0,0 @@ -include: - - 'src/' -exclude: - - 'src/polyfills' -clean: true -temp-directory: 'coverage/flow' -report-dir: 'coverage/flow' -skip-full: true -skip-empty: true -reporter: [json, html, text] diff --git a/.nycrc.yml b/.nycrc.yml index b057456271..6856b3bc46 100644 --- a/.nycrc.yml +++ b/.nycrc.yml @@ -3,7 +3,7 @@ include: - 'src/' exclude: - 'src/polyfills' - - '**/*-benchmark.js' + - '**/*-fuzz.js' - '**/*.d.ts' - 'src/validation/rules/ExecutableDefinitions.js' - 'src/validation/rules/LoneSchemaDefinition.js' @@ -13,8 +13,14 @@ exclude: - 'src/validation/rules/UniqueFieldDefinitionNames.js' - 'src/validation/rules/UniqueTypeNames.js' - 'src/validation/rules/UniqueOperationTypes.js' + - 'src/utilities/findDeprecatedUsages.js' clean: true -temp-directory: 'coverage/tests' -report-dir: 'coverage/tests' +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 new file mode 100644 index 0000000000..475f5e22fd --- /dev/null +++ b/.prettierignore @@ -0,0 +1,8 @@ +# Copied from '.gitignore', please keep it in sync. +/.eslintcache +/node_modules +/coverage +/npmDist +/denoDist +/npm +/deno diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 45d6be80c9..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -git: - depth: 5 -language: node_js -cache: yarn - -# https://github.com/nodejs/Release -node_js: - - '13' - - '12' - - '10' - -script: | - if [[ "$(node -pe process.version)" == v12.* ]]; then # Is latest LTS? - npm run test:ci && - bash <(curl -s https://codecov.io/bash) -f coverage/tests/coverage-final.json - else - npm run testonly - fi - -jobs: - include: - - stage: deploy - if: type = push AND branch = master - script: npm run gitpublish - skip_cleanup: true - node_js: '12' - -notifications: - irc: - use_notice: true - on_success: change - on_failure: change - skip_join: true - channels: - - chat.freenode.net#graphql - slack: - secure: G7fzaXoPI1cyyW7dlpQ8oG/ot73n4kE83HgbyK1iEN1YBfodsytVgh0jS+zB3DhhRAotS/VfGVz9Wj2Oo109U5w/FyxdMGuKvFan/0B/aAws1sPxLGWA5230u1wTKQCHAu17+yppFOODUu1ILDXaD2A//Wj5iru9M4NnKc1bO6VHkfBHPTLQLbdPHmorwuSH02Ocbh7K4XOWzXRxM6VrwamEn1KnyXGu2w3QdJUT31OjGEEdf6FUzvjwzFgXPhngCw5+enpwm71ljHDNu8YHhXvHtS4328O5pYQO8np7j653HNEqi+ZUiYEOWpwC8be1xHdvi/s32tPFZiCx28ZmDoCUrY744tpPtE6tzuncmSKB0Y3EjutdXBpxllNr5l5hpX5092G2MlpokFbv85J+E2ALcZYNYeFOqTYTKwTYkxK6B1x4amBNpM+FXgUhloK4BK9OT0Qh5SiQOsM8cZT0h6QP91n+REljtpugW3VbuIxq5OJAi42FYbHBC27pohhq6ohU1euZfobk9a7ZawnjoEUk1EZHXiJzYKY/QqzyB6dwk0ersBl3l3OX/wnjwKTkqc9aTmDWo2L+lHaUCXuCY1+KQXsRicfnH395szTJXQbvcbN0zz188gdz6sawzi5BxndWo0NRwZyOG2YcyUHFQR4bK1rL7Lo6t6rijQ/XMeQ= - -env: - global: - secure: uUjOV39iCLSLtShQfKk9AelIu2PqyKf8dYu4rqVcL5Y9yCHdds1KYysVgCx9XhndrugHNCXWzT/sKDS8voc/NRsfycnvdCIvu+dtBwf9lCHGcMyABFpvsjQfKTGyMCbYNDO8Hd/OQqHCFVj1lh4aNGev8tGqpJoMEDPdQbDKsvMVKWfo9QraXYYK7yh7U2vbidAV+YBj/e3VFfR2UQ+OECHxyxFGxWMbyTF8qRZ7JUsgCaJ82zrx0A7VoEJ6BeXxzhYDPuh3QTON9bXiJpWR/QcsKZNQ7d6Dxf06yo4XQDU9igxe6qst41Hj3IiZzLCyucoPXvoRsbmUcsAVdF4PWq3fnHUmyjRwOMcTjPd2SM4FPJpwnSGZEpstzKSJ3pDzpgRGsF7ai5nGNCes6RCi4AUf96GTjt0JAD+AXwD7mrGlcn4oi0m6r1GcNhDOFsBEgFqz26FXUFQcAqrHzZvsqvG01Cs5pAFMUIEpCyCrkDKClc/LWjJoVInDEVCwGqZk6Qz2XroYjFs25m+aB3ycSIN1qgkTg6szMO76tds4YtL8JDHaAXDbvXAk8YRYbQCAIFQVaIpkp8R1kJa++dP8Q3j/lwAkz+57XJ5KPRlLh7KMqF1joTGKptA0c2vD0sees2RxPrcZGmp6eaOLy3JhQmXfPaRLLpiK+plz6T25f7Y= diff --git a/LICENSE b/LICENSE index cd2262e3a3..7bbf892a04 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 GraphQL Contributors +Copyright (c) GraphQL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 82b748950a..47cce6ad6a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The JavaScript reference implementation for GraphQL, a query language for APIs created by Facebook. [![npm version](https://badge.fury.io/js/graphql.svg)](https://badge.fury.io/js/graphql) -[![Build Status](https://travis-ci.org/graphql/graphql-js.svg?branch=master)](https://travis-ci.org/graphql/graphql-js?branch=master) +[![Build Status](https://github.com/graphql/graphql-js/workflows/CI/badge.svg?branch=master)](https://github.com/graphql/graphql-js/actions?query=branch%3Amaster) [![Coverage Status](https://codecov.io/gh/graphql/graphql-js/branch/master/graph/badge.svg)](https://codecov.io/gh/graphql/graphql-js) See more complete documentation at https://graphql.org/ and @@ -13,7 +13,7 @@ Looking for help? Find resources [from the community](https://graphql.org/commun ## Getting Started -An overview of GraphQL in general is available in the +A general overview of GraphQL is available in the [README](https://github.com/graphql/graphql-spec/blob/master/README.md) for the [Specification for GraphQL](https://github.com/graphql/graphql-spec). That overview describes a simple set of GraphQL examples that exist as [tests](src/__tests__) @@ -24,22 +24,22 @@ through that README and the corresponding tests in parallel. Install GraphQL.js from npm -With yarn: +With npm: ```sh -yarn add graphql +npm install --save graphql ``` -or alternatively using npm: +or using yarn: ```sh -npm install --save graphql +yarn add graphql ``` -GraphQL.js provides two important capabilities: building a type schema, and +GraphQL.js provides two important capabilities: building a type schema and serving queries against that type schema. -First, build a GraphQL type schema which maps to your code base. +First, build a GraphQL type schema which maps to your codebase. ```js import { @@ -64,10 +64,9 @@ var schema = new GraphQLSchema({ }); ``` -This defines a simple schema with one type and one field, that resolves +This defines a simple schema, with one type and one field, that resolves to a fixed value. The `resolve` function can return a value, a promise, -or an array of promises. A more complex example is included in the top -level [tests](src/__tests__) directory. +or an array of promises. A more complex example is included in the top-level [tests](src/__tests__) directory. Then, serve the result of a query against that type schema. @@ -102,7 +101,7 @@ graphql(schema, query).then((result) => { }); ``` -**Note**: Please don't forget to set `NODE_ENV=production` if you are running a production server it will disable some checks that can be useful during development but will significantly improve performance. +**Note**: Please don't forget to set `NODE_ENV=production` if you are running a production server. It will disable some checks that can be useful during development but will significantly improve performance. ### Want to ride the bleeding edge? @@ -118,7 +117,7 @@ npm install graphql@git://github.com/graphql/graphql-js.git#npm ### Using in a Browser -GraphQL.js is a general purpose library and can be used both in a Node server +GraphQL.js is a general-purpose library and can be used both in a Node server and in the browser. As an example, the [GraphiQL](https://github.com/graphql/graphiql/) tool is built with GraphQL.js! @@ -130,8 +129,7 @@ custom build configurations look for `.mjs` files! ### Contributing -We actively welcome pull requests, learn how to -[contribute](https://github.com/graphql/graphql-js/blob/master/.github/CONTRIBUTING.md). +We actively welcome pull requests. Learn how to [contribute](./.github/CONTRIBUTING.md). ### Changelog @@ -139,7 +137,7 @@ Changes are tracked as [GitHub releases](https://github.com/graphql/graphql-js/r ### License -GraphQL.js is [MIT-licensed](https://github.com/graphql/graphql-js/blob/master/LICENSE). +GraphQL.js is [MIT-licensed](./LICENSE). ### Credits diff --git a/resources/benchmark.js b/benchmark/benchmark.js similarity index 52% rename from resources/benchmark.js rename to benchmark/benchmark.js index c8a39255ce..c8da30e1f6 100644 --- a/resources/benchmark.js +++ b/benchmark/benchmark.js @@ -1,22 +1,10 @@ -// @noflow - 'use strict'; const os = require('os'); const fs = require('fs'); const path = require('path'); const assert = require('assert'); - -const { red, green, yellow, cyan, grey } = require('./colors'); -const { - exec, - copyFile, - writeFile, - rmdirRecursive, - mkdirRecursive, - readdirRecursive, -} = require('./utils'); -const { sampleModule } = require('./benchmark-fork'); +const cp = require('child_process'); const NS_PER_SEC = 1e9; const LOCAL = 'local'; @@ -26,67 +14,80 @@ const maxTime = 5; // The minimum sample size required to perform statistical analysis. const minSamples = 5; -function LOCAL_DIR(...paths) { +function localDir(...paths) { return path.join(__dirname, '..', ...paths); } +function exec(command, options = {}) { + const result = cp.execSync(command, { + encoding: 'utf-8', + stdio: ['inherit', 'pipe', 'inherit'], + ...options, + }); + return result && result.trimEnd(); +} + // Build a benchmark-friendly environment for the given revision // and returns path to its 'dist' directory. -function prepareRevision(revision) { - console.log(`🍳 Preparing ${revision}...`); - - if (revision === LOCAL) { - return babelBuild(LOCAL_DIR()); - } - - // Returns the complete git hash for a given git revision reference. - const hash = exec(`git rev-parse "${revision}"`); +function prepareBenchmarkProjects(revisionList) { + const tmpDir = path.join(os.tmpdir(), 'graphql-js-benchmark'); + fs.mkdirSync(tmpDir, { recursive: true }); + + const setupDir = path.join(tmpDir, 'setup'); + fs.rmdirSync(setupDir, { recursive: true }); + fs.mkdirSync(setupDir); + + return revisionList.map((revision) => { + console.log(`🍳 Preparing ${revision}...`); + const projectPath = path.join(setupDir, revision); + fs.rmdirSync(projectPath, { recursive: true }); + fs.mkdirSync(projectPath); + + fs.writeFileSync( + path.join(projectPath, 'package.json'), + '{ "private": true }', + ); + exec('npm --quiet install ' + prepareNPMPackage(revision), { + cwd: projectPath, + }); + exec(`cp -R ${localDir('benchmark')} ${projectPath}`); + + return { revision, projectPath }; + }); + + function prepareNPMPackage(revision) { + if (revision === LOCAL) { + const repoDir = localDir(); + const archivePath = path.join(tmpDir, 'graphql-local.tgz'); + fs.renameSync(buildNPMArchive(repoDir), archivePath); + return archivePath; + } - const dir = path.join(os.tmpdir(), 'graphql-js-benchmark', hash); - rmdirRecursive(dir); - mkdirRecursive(dir); + // Returns the complete git hash for a given git revision reference. + const hash = exec(`git rev-parse "${revision}"`); - exec(`git archive "${hash}" | tar -xC "${dir}"`); - exec('yarn install', { cwd: dir }); + const archivePath = path.join(tmpDir, `graphql-${hash}.tgz`); + if (fs.existsSync(archivePath)) { + return archivePath; + } - for (const file of findFiles(LOCAL_DIR('src'), '*/__tests__/*')) { - const from = LOCAL_DIR('src', file); - const to = path.join(dir, 'src', file); - fs.copyFileSync(from, to); + const repoDir = path.join(tmpDir, hash); + fs.rmdirSync(repoDir, { recursive: true }); + fs.mkdirSync(repoDir); + exec(`git archive "${hash}" | tar -xC "${repoDir}"`); + exec('npm --quiet ci', { cwd: repoDir }); + fs.renameSync(buildNPMArchive(repoDir), archivePath); + fs.rmdirSync(repoDir, { recursive: true }); + return archivePath; } - exec(`cp -R "${LOCAL_DIR()}/src/__fixtures__/" "${dir}/src/__fixtures__/"`); - - return babelBuild(dir); -} -function babelBuild(dir) { - const oldCWD = process.cwd(); - process.chdir(dir); + function buildNPMArchive(repoDir) { + exec('npm --quiet run build:npm', { cwd: repoDir }); - rmdirRecursive('./benchmarkDist'); - mkdirRecursive('./benchmarkDist'); - - const babelPath = path.join(dir, 'node_modules', '@babel', 'core'); - const babel = require(babelPath); - for (const filepath of readdirRecursive('./src')) { - const srcPath = path.join('./src', filepath); - const distPath = path.join('./benchmarkDist', filepath); - - if (filepath.endsWith('.js')) { - const cjs = babel.transformFileSync(srcPath, { envName: 'cjs' }); - writeFile(distPath, cjs.code); - } else { - copyFile(srcPath, distPath); - } + const distDir = path.join(repoDir, 'npmDist'); + const archiveName = exec(`npm --quiet pack ${distDir}`, { cwd: repoDir }); + return path.join(repoDir, archiveName); } - - process.chdir(oldCWD); - return path.join(dir, 'benchmarkDist'); -} - -function findFiles(cwd, pattern) { - const out = exec(`find . -path '${pattern}'`, { cwd }); - return out.split('\n').filter(Boolean); } async function collectSamples(modulePath) { @@ -228,17 +229,14 @@ function maxBy(array, fn) { } // Prepare all revisions and run benchmarks matching a pattern against them. -async function prepareAndRunBenchmarks(benchmarkPatterns, revisions) { - const environments = revisions.map((revision) => ({ - revision, - distPath: prepareRevision(revision), - })); +async function runBenchmarks(benchmarks, revisions) { + const benchmarkProjects = prepareBenchmarkProjects(revisions); - for (const benchmark of matchBenchmarks(benchmarkPatterns)) { + for (const benchmark of benchmarks) { const results = []; - for (let i = 0; i < environments.length; ++i) { - const environment = environments[i]; - const modulePath = path.join(environment.distPath, benchmark); + for (let i = 0; i < benchmarkProjects.length; ++i) { + const { revision, projectPath } = benchmarkProjects[i]; + const modulePath = path.join(projectPath, benchmark); if (i === 0) { const { name } = await sampleModule(modulePath); @@ -249,13 +247,13 @@ async function prepareAndRunBenchmarks(benchmarkPatterns, revisions) { const samples = await collectSamples(modulePath); results.push({ - name: environment.revision, + name: revision, samples, ...computeStats(samples), }); process.stdout.write(' ' + cyan(i + 1) + ' tests completed.\u000D'); } catch (error) { - console.log(' ' + environment.revision + ': ' + red(String(error))); + console.log(' ' + revision + ': ' + red(String(error))); } } console.log('\n'); @@ -265,55 +263,135 @@ async function prepareAndRunBenchmarks(benchmarkPatterns, revisions) { } } -// Find all benchmark tests to be run. -function matchBenchmarks(patterns) { - let benchmarks = findFiles(LOCAL_DIR('src'), '*/__tests__/*-benchmark.js'); - if (patterns.length > 0) { - benchmarks = benchmarks.filter((benchmark) => - patterns.some((pattern) => path.join('src', benchmark).includes(pattern)), - ); - } - - if (benchmarks.length === 0) { - console.warn('No benchmarks matching: ' + patterns.map(bold).join('')); - } - - return benchmarks; -} - function getArguments(argv) { const revsIdx = argv.indexOf('--revs'); const revsArgs = revsIdx === -1 ? [] : argv.slice(revsIdx + 1); - const benchmarkPatterns = revsIdx === -1 ? argv : argv.slice(0, revsIdx); + const specificBenchmarks = revsIdx === -1 ? argv : argv.slice(0, revsIdx); let assumeArgs; let revisions; switch (revsArgs.length) { case 0: - assumeArgs = [...benchmarkPatterns, '--revs', 'local', 'HEAD']; + assumeArgs = [...specificBenchmarks, '--revs', 'local', 'HEAD']; revisions = [LOCAL, 'HEAD']; break; case 1: - assumeArgs = [...benchmarkPatterns, '--revs', 'local', revsArgs[0]]; + assumeArgs = [...specificBenchmarks, '--revs', 'local', revsArgs[0]]; revisions = [LOCAL, revsArgs[0]]; break; default: revisions = revsArgs; break; } + if (assumeArgs) { console.warn( 'Assuming you meant: ' + bold('benchmark ' + assumeArgs.join(' ')), ); } - return { benchmarkPatterns, revisions }; + + return { specificBenchmarks, revisions }; } function bold(str) { return '\u001b[1m' + str + '\u001b[0m'; } +function red(str) { + return '\u001b[31m' + str + '\u001b[0m'; +} + +function green(str) { + return '\u001b[32m' + str + '\u001b[0m'; +} + +function yellow(str) { + return '\u001b[33m' + str + '\u001b[0m'; +} + +function cyan(str) { + return '\u001b[36m' + str + '\u001b[0m'; +} + +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 { benchmarkPatterns, revisions } = getArguments(process.argv.slice(2)); - prepareAndRunBenchmarks(benchmarkPatterns, revisions); + 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'); + + assert(global.gc); + assert(process.send); + const module = require('${modulePath}'); + + clock(7, module.measure); // warm up + global.gc(); + process.nextTick(() => { + const memBaseline = process.memoryUsage().heapUsed; + const clocked = clock(module.count, module.measure); + process.send({ + name: module.name, + clocked: clocked / module.count, + memUsed: (process.memoryUsage().heapUsed - memBaseline) / module.count, + }); + }); + + // Clocks the time taken to execute a test per cycle (secs). + function clock(count, fn) { + const start = process.hrtime.bigint(); + for (let i = 0; i < count; ++i) { + fn(); + } + return Number(process.hrtime.bigint() - start); + } + `; + + return new Promise((resolve, reject) => { + const child = cp.spawn( + process.argv[0], + [ + '--noconcurrent_sweeping', + '--predictable', + '--expose-gc', + '--eval', + sampleCode, + ], + { + stdio: ['inherit', 'inherit', 'inherit', 'ipc'], + env: { NODE_ENV: 'production' }, + }, + ); + + let message; + let error; + + child.on('message', (msg) => (message = msg)); + child.on('error', (e) => (error = e)); + child.on('close', () => { + if (message) { + return resolve(message); + } + reject(error || new Error('Spawn process closed without error')); + }); + }); } diff --git a/benchmark/buildASTSchema-benchmark.js b/benchmark/buildASTSchema-benchmark.js new file mode 100644 index 0000000000..b578d71a7f --- /dev/null +++ b/benchmark/buildASTSchema-benchmark.js @@ -0,0 +1,16 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { buildASTSchema } = require('graphql/utilities/buildASTSchema.js'); + +const { bigSchemaSDL } = require('./fixtures.js'); + +const schemaAST = parse(bigSchemaSDL); + +module.exports = { + name: 'Build Schema from AST', + count: 10, + measure() { + buildASTSchema(schemaAST, { assumeValid: true }); + }, +}; diff --git a/benchmark/buildClientSchema-benchmark.js b/benchmark/buildClientSchema-benchmark.js new file mode 100644 index 0000000000..240c9ca1f1 --- /dev/null +++ b/benchmark/buildClientSchema-benchmark.js @@ -0,0 +1,13 @@ +'use strict'; + +const { buildClientSchema } = require('graphql/utilities/buildClientSchema.js'); + +const { bigSchemaIntrospectionResult } = require('./fixtures.js'); + +module.exports = { + name: 'Build Schema from Introspection', + count: 10, + measure() { + buildClientSchema(bigSchemaIntrospectionResult.data, { assumeValid: true }); + }, +}; diff --git a/benchmark/fixtures.js b/benchmark/fixtures.js new file mode 100644 index 0000000000..d057a80526 --- /dev/null +++ b/benchmark/fixtures.js @@ -0,0 +1,13 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +exports.bigSchemaSDL = fs.readFileSync( + path.join(__dirname, 'github-schema.graphql'), + 'utf8', +); + +exports.bigSchemaIntrospectionResult = JSON.parse( + fs.readFileSync(path.join(__dirname, 'github-schema.json'), 'utf8'), +); diff --git a/src/__fixtures__/github-schema.graphql b/benchmark/github-schema.graphql similarity index 100% rename from src/__fixtures__/github-schema.graphql rename to benchmark/github-schema.graphql diff --git a/src/__fixtures__/github-schema.json b/benchmark/github-schema.json similarity index 100% rename from src/__fixtures__/github-schema.json rename to benchmark/github-schema.json diff --git a/benchmark/introspectionFromSchema-benchmark.js b/benchmark/introspectionFromSchema-benchmark.js new file mode 100644 index 0000000000..125ca9c367 --- /dev/null +++ b/benchmark/introspectionFromSchema-benchmark.js @@ -0,0 +1,21 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { executeSync } = require('graphql/execution/execute.js'); +const { buildSchema } = require('graphql/utilities/buildASTSchema.js'); +const { + getIntrospectionQuery, +} = require('graphql/utilities/getIntrospectionQuery.js'); + +const { bigSchemaSDL } = require('./fixtures.js'); + +const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); +const document = parse(getIntrospectionQuery()); + +module.exports = { + name: 'Execute Introspection Query', + count: 10, + measure() { + executeSync({ schema, document }); + }, +}; diff --git a/benchmark/parser-benchmark.js b/benchmark/parser-benchmark.js new file mode 100644 index 0000000000..7f2e7931eb --- /dev/null +++ b/benchmark/parser-benchmark.js @@ -0,0 +1,16 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { + getIntrospectionQuery, +} = require('graphql/utilities/getIntrospectionQuery.js'); + +const introspectionQuery = getIntrospectionQuery(); + +module.exports = { + name: 'Parse introspection query', + count: 1000, + measure() { + parse(introspectionQuery); + }, +}; diff --git a/benchmark/validateGQL-benchmark.js b/benchmark/validateGQL-benchmark.js new file mode 100644 index 0000000000..cc60a7ade0 --- /dev/null +++ b/benchmark/validateGQL-benchmark.js @@ -0,0 +1,21 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { validate } = require('graphql/validation/validate.js'); +const { buildSchema } = require('graphql/utilities/buildASTSchema.js'); +const { + getIntrospectionQuery, +} = require('graphql/utilities/getIntrospectionQuery.js'); + +const { bigSchemaSDL } = require('./fixtures.js'); + +const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); +const queryAST = parse(getIntrospectionQuery()); + +module.exports = { + name: 'Validate Introspection Query', + count: 50, + measure() { + validate(schema, queryAST); + }, +}; diff --git a/benchmark/validateInvalidGQL-benchmark.js b/benchmark/validateInvalidGQL-benchmark.js new file mode 100644 index 0000000000..1e44b48914 --- /dev/null +++ b/benchmark/validateInvalidGQL-benchmark.js @@ -0,0 +1,30 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { validate } = require('graphql/validation/validate.js'); +const { buildSchema } = require('graphql/utilities/buildASTSchema.js'); + +const { bigSchemaSDL } = require('./fixtures.js'); + +const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); +const queryAST = parse(` + { + unknownField + ... on unknownType { + anotherUnknownField + ...unknownFragment + } + } + + fragment TestFragment on anotherUnknownType { + yetAnotherUnknownField + } +`); + +module.exports = { + name: 'Validate Invalid Query', + count: 50, + measure() { + validate(schema, queryAST); + }, +}; diff --git a/benchmark/validateSDL-benchmark.js b/benchmark/validateSDL-benchmark.js new file mode 100644 index 0000000000..93c80bbc56 --- /dev/null +++ b/benchmark/validateSDL-benchmark.js @@ -0,0 +1,16 @@ +'use strict'; + +const { parse } = require('graphql/language/parser.js'); +const { validateSDL } = require('graphql/validation/validate.js'); + +const { bigSchemaSDL } = require('./fixtures.js'); + +const sdlAST = parse(bigSchemaSDL); + +module.exports = { + name: 'Validate SDL Document', + count: 10, + measure() { + validateSDL(sdlAST); + }, +}; diff --git a/cspell.json b/cspell.json index 58bb085ebd..137edea6f3 100644 --- a/cspell.json +++ b/cspell.json @@ -1,14 +1,37 @@ { "language": "en", "ignorePaths": [ - "src/__fixtures__/github-schema.graphql", - "src/__fixtures__/github-schema.json" + // 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": [ - "jsutils", - "tsutils", - "noflow", - "flowlint", + "graphiql", + "sublinks", + "subcommand", + "transpilation", + "instanceof", + "flowtype", + "noconcurrent", // Different names used inside tests "Skywalker", @@ -24,62 +47,22 @@ "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", - - // TODO: contribute to upstream dictionaries - "ASTs", - "adjacencies", - "bigint", - "bugfixes", - "contravariant", - "dedent", - "deserialized", - "dirent", - "docstring", - "erroring", - "filepath", - "filepaths", - "hardcoded", - "heredoc", - "iteratable", - "lexable", - "lexed", - "lexes", - "lexing", - "memoed", - "memoization", - "memoized", - "memoizes", - "memoizing", - "nullability", - "nullish", - "passthrough", - "polyfilled", - "promisify", - "pubsub", - "punctuator", - "punctuators", - "recurse", - "recursing", - "refetch", - "stateful", - "stringifies", - "subfields", - "subgraphs", - "subtrees", - "subtyped", - "superset", - "undefine", - "unparsed" + "wrds" ] } diff --git a/docs/APIReference-ExpressGraphQL.md b/docs/APIReference-ExpressGraphQL.md index 65703b1b08..eac9f42b0d 100644 --- a/docs/APIReference-ExpressGraphQL.md +++ b/docs/APIReference-ExpressGraphQL.md @@ -10,8 +10,8 @@ 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 +import { graphqlHTTP } from 'express-graphql'; // ES6 +var { graphqlHTTP } = require('express-graphql'); // CommonJS ``` ### graphqlHTTP diff --git a/docs/APIReference-Language.md b/docs/APIReference-Language.md index a3ebab4fc3..4d430c3787 100644 --- a/docs/APIReference-Language.md +++ b/docs/APIReference-Language.md @@ -101,14 +101,20 @@ _Printer_ ```js export class Source { - constructor(body: string, name?: string) + constructor(body: string, name?: string, locationOffset?: Location) +} + +type Location = { + line: number; + column: number; } ``` -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". +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. ### getLocation @@ -142,13 +148,13 @@ export type Token = { ``` Given a Source object, this returns a Lexer for that source. -A Lexer is a function that acts like a generator in that every time +A Lexer is a function that acts as 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 @@ -194,7 +200,7 @@ An enum that describes the different kinds of AST nodes. 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. @@ -230,10 +236,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 +enter/leave visitors at a named key, leading to four permutations of the visitor API: -1. Named visitors triggered when entering a node a specific kind. +1. Named visitors triggered when entering a node of a specific kind. ```js visit(ast, { diff --git a/docs/APIReference-TypeSystem.md b/docs/APIReference-TypeSystem.md index b777db1ad1..8efd840eb6 100644 --- a/docs/APIReference-TypeSystem.md +++ b/docs/APIReference-TypeSystem.md @@ -206,6 +206,7 @@ class GraphQLScalarType { type GraphQLScalarTypeConfig = { name: string; description?: ?string; + specifiedByUrl?: string; serialize: (value: mixed) => ?InternalType; parseValue?: (value: mixed) => ?InternalType; parseLiteral?: (valueAST: Value) => ?InternalType; diff --git a/docs/APIReference-Utilities.md b/docs/APIReference-Utilities.md index a90f386b58..a9455aadd5 100644 --- a/docs/APIReference-Utilities.md +++ b/docs/APIReference-Utilities.md @@ -21,9 +21,9 @@ _Introspection_
  • - -
    var introspectionQuery
    - A GraphQL introspection query containing enough information to reproduce a type system. +
    +
    function getIntrospectionQuery
    + Builds a GraphQL introspection query containing enough information to reproduce a type system.
  • @@ -105,13 +105,33 @@ _Value Validation_ ## Introspection -### introspectionQuery +### getIntrospectionQuery ```js -var introspectionQuery: string; +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; ``` -A GraphQL query that queries a server's introspection system for enough +Build a GraphQL query that queries a server's introspection system for enough information to reproduce that server's type system. ### buildClientSchema @@ -166,8 +186,8 @@ function buildASTSchema( ): GraphQLSchema ``` -This takes the ast of a schema document produced by `parseSchemaIntoAST` in -`graphql/language/schema` and constructs a GraphQLSchema instance which can be +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. diff --git a/docs/Guides-ConstructingTypes.md b/docs/Guides-ConstructingTypes.md index acd1b7ce70..e8737c33e1 100644 --- a/docs/Guides-ConstructingTypes.md +++ b/docs/Guides-ConstructingTypes.md @@ -14,7 +14,7 @@ For example, let's say we are building a simple API that lets you fetch user dat ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var { buildSchema } = require('graphql'); var schema = buildSchema(` @@ -64,7 +64,7 @@ We can implement this same API without using GraphQL schema language: ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var graphql = require('graphql'); // Maps id to User object diff --git a/docs/Tutorial-Authentication.md b/docs/Tutorial-Authentication.md index ac8decd661..28376bc102 100644 --- a/docs/Tutorial-Authentication.md +++ b/docs/Tutorial-Authentication.md @@ -15,7 +15,7 @@ For example, let's say we wanted our server to log the IP address of every reque ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var { buildSchema } = require('graphql'); var schema = buildSchema(` diff --git a/docs/Tutorial-BasicTypes.md b/docs/Tutorial-BasicTypes.md index 30a48d8e13..2367b7d352 100644 --- a/docs/Tutorial-BasicTypes.md +++ b/docs/Tutorial-BasicTypes.md @@ -18,7 +18,7 @@ Each of these types maps straightforwardly to JavaScript, so you can just return ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var { buildSchema } = require('graphql'); // Construct a schema, using GraphQL schema language diff --git a/docs/Tutorial-ExpressGraphQL.md b/docs/Tutorial-ExpressGraphQL.md index a9b3e25dcf..69b49c0a48 100644 --- a/docs/Tutorial-ExpressGraphQL.md +++ b/docs/Tutorial-ExpressGraphQL.md @@ -17,7 +17,7 @@ Let's modify our “hello world” example so that it's an API server rather tha ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var { buildSchema } = require('graphql'); // Construct a schema, using GraphQL schema language diff --git a/docs/Tutorial-Mutations.md b/docs/Tutorial-Mutations.md index e1e30a2480..4b19fc0e38 100644 --- a/docs/Tutorial-Mutations.md +++ b/docs/Tutorial-Mutations.md @@ -73,7 +73,7 @@ Here's some runnable code that implements this schema, keeping the data in memor ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var { buildSchema } = require('graphql'); // Construct a schema, using GraphQL schema language diff --git a/docs/Tutorial-ObjectTypes.md b/docs/Tutorial-ObjectTypes.md index f45ffa73f1..246aa67a51 100644 --- a/docs/Tutorial-ObjectTypes.md +++ b/docs/Tutorial-ObjectTypes.md @@ -74,7 +74,7 @@ Putting this all together, here is some sample code that runs a server with this ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var { buildSchema } = require('graphql'); // Construct a schema, using GraphQL schema language diff --git a/docs/Tutorial-PassingArguments.md b/docs/Tutorial-PassingArguments.md index 9a1ada9f18..df8fda9e27 100644 --- a/docs/Tutorial-PassingArguments.md +++ b/docs/Tutorial-PassingArguments.md @@ -6,7 +6,7 @@ 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, typechecking 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`: +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`: ```graphql type Query { @@ -14,7 +14,7 @@ type Query { } ``` -Instead of hardcoding “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 { @@ -58,7 +58,7 @@ The entire code for a server that hosts this `rollDice` API is: ```js var express = require('express'); -var graphqlHTTP = require('express-graphql'); +var { graphqlHTTP } = require('express-graphql'); var { buildSchema } = require('graphql'); // Construct a schema, using GraphQL schema language diff --git a/flow-typed/core.js b/flow-typed/core.js new file mode 100644 index 0000000000..44ef9c1fd0 --- /dev/null +++ b/flow-typed/core.js @@ -0,0 +1,5 @@ +// 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 new file mode 100644 index 0000000000..aa4cbe8e4f --- /dev/null +++ b/flow-typed/npm/chai_vx.x.x.js @@ -0,0 +1,331 @@ +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 new file mode 100644 index 0000000000..b7c7c13128 --- /dev/null +++ b/flow-typed/npm/mocha_vx.x.x.js @@ -0,0 +1,305 @@ +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/README.md b/integrationTests/README.md new file mode 100644 index 0000000000..706449103a --- /dev/null +++ b/integrationTests/README.md @@ -0,0 +1 @@ +# TBD diff --git a/integrationTests/flow/.flowconfig b/integrationTests/flow/.flowconfig new file mode 100644 index 0000000000..872c3947a6 --- /dev/null +++ b/integrationTests/flow/.flowconfig @@ -0,0 +1,8 @@ +[include] +./index.mjs + +[declarations] +.*/node_modules/.* + +[options] +include_warnings=true diff --git a/integrationTests/flow/index.mjs b/integrationTests/flow/index.mjs new file mode 100644 index 0000000000..ee14390b35 --- /dev/null +++ b/integrationTests/flow/index.mjs @@ -0,0 +1,54 @@ +// @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 new file mode 100644 index 0000000000..8a87590458 --- /dev/null +++ b/integrationTests/flow/package.json @@ -0,0 +1,10 @@ +{ + "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 new file mode 100644 index 0000000000..9ccaddd736 --- /dev/null +++ b/integrationTests/integration-test.js @@ -0,0 +1,49 @@ +'use strict'; + +const os = require('os'); +const fs = require('fs'); +const path = require('path'); +const childProcess = require('child_process'); + +const { describe, it } = require('mocha'); + +function exec(command, options = {}) { + const result = childProcess.execSync(command, { + encoding: 'utf-8', + ...options, + }); + return result != null ? result.trimEnd() : result; +} + +describe('Integration Tests', () => { + const tmpDir = path.join(os.tmpdir(), 'graphql-js-integrationTmp'); + fs.rmdirSync(tmpDir, { recursive: true }); + fs.mkdirSync(tmpDir); + + const distDir = path.resolve('./npmDist'); + const archiveName = exec(`npm --quiet pack ${distDir}`, { cwd: tmpDir }); + fs.renameSync( + path.join(tmpDir, archiveName), + path.join(tmpDir, 'graphql.tgz'), + ); + + function testOnNodeProject(projectName) { + exec(`cp -R ${path.join(__dirname, projectName)} ${tmpDir}`); + + const cwd = path.join(tmpDir, projectName); + exec('npm --quiet install', { cwd, stdio: 'inherit' }); + exec('npm --quiet test', { cwd, stdio: 'inherit' }); + } + + it('Should compile with all supported TS versions', () => { + testOnNodeProject('ts'); + }).timeout(40000); + + it('Should compile with Flow', () => { + testOnNodeProject('flow'); + }).timeout(10000); + + it('Should work on all supported node versions', () => { + testOnNodeProject('node'); + }).timeout(40000); +}); diff --git a/integrationTests/node/index.js b/integrationTests/node/index.js new file mode 100644 index 0000000000..4815fe52e4 --- /dev/null +++ b/integrationTests/node/index.js @@ -0,0 +1,27 @@ +'use strict'; + +const assert = require('assert'); +const { readFileSync } = require('fs'); + +const { version, graphqlSync } = require('graphql'); +const { buildSchema } = require('graphql/utilities'); + +assert.deepStrictEqual( + version, + JSON.parse(readFileSync('./node_modules/graphql/package.json')).version, +); + +const schema = buildSchema('type Query { hello: String }'); + +const result = graphqlSync({ + schema, + source: '{ hello }', + rootValue: { hello: 'world' }, +}); + +assert.deepStrictEqual(result, { + data: { + __proto__: null, + hello: 'world', + }, +}); diff --git a/integrationTests/node/package.json b/integrationTests/node/package.json new file mode 100644 index 0000000000..0b6122b6de --- /dev/null +++ b/integrationTests/node/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "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" + } +} diff --git a/integrationTests/node/test.js b/integrationTests/node/test.js new file mode 100644 index 0000000000..94cc957b47 --- /dev/null +++ b/integrationTests/node/test.js @@ -0,0 +1,17 @@ +'use strict'; + +const path = require('path'); +const childProcess = require('child_process'); + +const { dependencies } = require('./package.json'); + +const nodeVersions = Object.keys(dependencies) + .filter((pkg) => pkg.startsWith('node-')) + .sort((a, b) => b.localeCompare(a)); + +for (const version of nodeVersions) { + console.log(`Testing on ${version} ...`); + + const nodePath = path.join(__dirname, 'node_modules', version, 'bin/node'); + childProcess.execSync(nodePath + ' index.js', { stdio: 'inherit' }); +} diff --git a/integrationTests/ts/index.ts b/integrationTests/ts/index.ts new file mode 100644 index 0000000000..6ef6bea899 --- /dev/null +++ b/integrationTests/ts/index.ts @@ -0,0 +1,138 @@ +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/package.json b/integrationTests/ts/package.json new file mode 100644 index 0000000000..f95cc44556 --- /dev/null +++ b/integrationTests/ts/package.json @@ -0,0 +1,24 @@ +{ + "private": true, + "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" + } +} diff --git a/integrationTests/ts/test.js b/integrationTests/ts/test.js new file mode 100644 index 0000000000..158aee4cf6 --- /dev/null +++ b/integrationTests/ts/test.js @@ -0,0 +1,17 @@ +'use strict'; + +const path = require('path'); +const childProcess = require('child_process'); + +const { dependencies } = require('./package.json'); + +const tsVersions = Object.keys(dependencies) + .filter((pkg) => pkg.startsWith('typescript-')) + .sort((a, b) => b.localeCompare(a)); + +for (const version of tsVersions) { + console.log(`Testing on ${version} ...`); + + const tscPath = path.join(__dirname, 'node_modules', version, 'bin/tsc'); + childProcess.execSync(tscPath, { stdio: 'inherit' }); +} diff --git a/integrationTests/ts/tsconfig.json b/integrationTests/ts/tsconfig.json new file mode 100644 index 0000000000..ea6266120c --- /dev/null +++ b/integrationTests/ts/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": ["es6", "esnext.asynciterable"], + "strict": true, + "noEmit": true, + "types": [] + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..7ced31d739 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5229 @@ +{ + "name": "graphql", + "version": "15.4.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/compat-data": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.5.tgz", + "integrity": "sha512-DTsS7cxrsH3by8nqQSpFSyjSfSYl57D6Cf4q8dW3LK83tBKBDCkfcay1nYkXq1nIHXnpX8WMMb/O25HOy3h1zg==", + "dev": true + }, + "@babel/core": { + "version": "7.12.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", + "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.1", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.1", + "@babel/parser": "^7.12.3", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "dev": true, + "requires": { + "@babel/types": "^7.12.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@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==", + "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/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==", + "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-create-regexp-features-plugin": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.1.tgz", + "integrity": "sha512-rsZ4LGvFTZnzdNZR5HZdmJVuXK8834R5QkF3WvcnBhrlVtF0HSIUC6zbreL9MgjTywhKokn8RIYRiq99+DLAxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", + "regexpu-core": "^4.7.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==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz", + "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.12.5" + } + }, + "@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==", + "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-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@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 + }, + "@babel/helper-regex": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "@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==", + "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-replace-supers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", + "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", + "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==", + "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==", + "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/helpers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", + "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", + "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "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/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==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.5.tgz", + "integrity": "sha512-UiAnkKuOrCyjZ3sYNHlRlfuZJbBHknMQ9VMwVeX97Ofwx7RpD6gS2HfqTCh8KNUQgcOm8IKt103oR4KIjh7Q8g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@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==", + "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/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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz", + "integrity": "sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw==", + "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/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==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@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", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "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/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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", + "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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", + "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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.1.tgz", + "integrity": "sha512-8hAtkmsQb36yMmEtk2JZ9JnVyDSnDOdlB+0nEGzIDLuK4yR3JcEjfuFPYkdEPSh8Id+rAMeBEn+X0iVEyho6Hg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "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==", + "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-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==", + "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-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==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.1.tgz", + "integrity": "sha512-CiUgKQ3AGVk7kveIaPEET1jNDhZZEl1RPMWdTBE1799bdz++SwqDHStmxfCtDfBhQgCl38YRiSnrMuUMZIWSUQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz", + "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/preset-env": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.1.tgz", + "integrity": "sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.12.1", + "@babel/helper-compilation-targets": "^7.12.1", + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-option": "^7.12.1", + "@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.1", + "@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.1", + "@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", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@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.1", + "@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.1", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.1", + "@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.1", + "core-js-compat": "^3.6.2", + "semver": "^5.5.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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/register": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.12.1.tgz", + "integrity": "sha512-XWcmseMIncOjoydKZnWvWi0/5CUCD+ZYKhRwgYlWOrA8fGZ/FjuLRpqtIhLOVD/fvR1b9DQHtZPn68VvhpYf+Q==", + "dev": true, + "requires": { + "find-cache-dir": "^2.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "pirates": "^4.0.0", + "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==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", + "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.5", + "@babel/types": "^7.12.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.1.tgz", + "integrity": "sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "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==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "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==", + "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" + }, + "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-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" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "@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.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.7.0.tgz", + "integrity": "sha512-li9aiSVBBd7kU5VlQlT1AqP0uWGDK6JYKUQ9cVDnOg34VNnd9t4jr0Yqc/bKxJr/tDCPDaB4KzoSFN9fgVxe/Q==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.7.0", + "@typescript-eslint/scope-manager": "4.7.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.7.0.tgz", + "integrity": "sha512-cymzovXAiD4EF+YoHAB5Oh02MpnXjvyaOb+v+BdpY7lsJXZQN34oIETeUwVT2XfV9rSNpXaIcknDLfupO/tUoA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.7.0", + "@typescript-eslint/types": "4.7.0", + "@typescript-eslint/typescript-estree": "4.7.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.7.0.tgz", + "integrity": "sha512-+meGV8bMP1sJHBI2AFq1GeTwofcGiur8LoIr6v+rEmD9knyCqDlrQcFHR0KDDfldHIFDU/enZ53fla6ReF4wRw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.7.0", + "@typescript-eslint/types": "4.7.0", + "@typescript-eslint/typescript-estree": "4.7.0", + "debug": "^4.1.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.7.0.tgz", + "integrity": "sha512-ILITvqwDJYbcDCROj6+Ob0oCKNg3SH46iWcNcTIT9B5aiVssoTYkhKjxOMNzR1F7WSJkik4zmuqve5MdnA0DyA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.7.0", + "@typescript-eslint/visitor-keys": "4.7.0" + } + }, + "@typescript-eslint/types": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.7.0.tgz", + "integrity": "sha512-uLszFe0wExJc+I7q0Z/+BnP7wao/kzX0hB5vJn4LIgrfrMLgnB2UXoReV19lkJQS1a1mHWGGODSxnBx6JQC3Sg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.7.0.tgz", + "integrity": "sha512-5XZRQznD1MfUmxu1t8/j2Af4OxbA7EFU2rbo0No7meb46eHgGkSieFdfV6omiC/DGIBhH9H9gXn7okBbVOm8jw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.7.0", + "@typescript-eslint/visitor-keys": "4.7.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" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.7.0.tgz", + "integrity": "sha512-aDJDWuCRsf1lXOtignlfiPODkzSxxop7D0rZ91L6ZuMlcMCSh0YyK+gAfo5zN/ih6WxMwhoXgJWC3cWQdaKC+A==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.7.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "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==", + "dev": true + }, + "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", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "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==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "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" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "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-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==", + "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-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" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserslist": { + "version": "4.14.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz", + "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001157", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.591", + "escalade": "^3.1.1", + "node-releases": "^1.1.66" + } + }, + "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==", + "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==", + "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 + } + } + }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001157", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001157.tgz", + "integrity": "sha512-gOerH9Wz2IRZ2ZPdMfBvyOi3cjaz4O4dgNwPGzx8EhqAs4+2IL/O+fJsbt+znSigujoZG8bVcIAUM/I/E5K3MA==", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "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", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.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 + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.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 + }, + "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" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "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.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", + "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", + "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==", + "dev": true, + "requires": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.2", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + } + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.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 + } + } + }, + "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==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "core-js-compat": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.7.0.tgz", + "integrity": "sha512-V8yBI3+ZLDVomoWICO6kq/CD28Y4r1M7CWeO4AGpMdMfseu8bkSubBmUPySMGKRTS+su4XQ07zUkAsiu9FCWTg==", + "dev": true, + "requires": { + "browserslist": "^4.14.6", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "cspell": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-4.1.5.tgz", + "integrity": "sha512-KIVZzQAMtSVsYGeFP5ljXPgbMor1jR49sVkSEHH2MdGFegTyMJZEVkgcwu7pTS0VRI+6O2k06/K3AKOJeK4WSg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "commander": "^6.1.0", + "comment-json": "^4.0.6", + "cspell-glob": "^0.1.21", + "cspell-lib": "^4.3.2", + "fs-extra": "^9.0.1", + "gensequence": "^3.1.1", + "get-stdin": "^8.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "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" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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 + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cspell-dict-aws": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/cspell-dict-aws/-/cspell-dict-aws-1.0.9.tgz", + "integrity": "sha512-DrSXcDEcPK0flggRzP7PgmMcqOKO3TsEv5pClK8MsCHN1GcJB3+FyT683BZu0gcO4RQkj4CjEi2Q5m++fZ30Cg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-bash": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cspell-dict-bash/-/cspell-dict-bash-1.0.7.tgz", + "integrity": "sha512-u1TFhmCUNZq86lfGFXCpnKHie8Zm3aarGHBu9/cBZC/NVjXp/6S32EUdiNjJm9t+Rlfb244u2ITTKvLPp/IE/A==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-companies": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/cspell-dict-companies/-/cspell-dict-companies-1.0.31.tgz", + "integrity": "sha512-DHn7umIg/Zz79f58PHyTmvEO01UFZmG0226Dgi6bA/haGUV/zR0P72cPLMEsoTUUSzsfkmcQ/8k2lHNEwriLaQ==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-cpp": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/cspell-dict-cpp/-/cspell-dict-cpp-1.1.33.tgz", + "integrity": "sha512-wCvVCSQl6k3884oEcpGv77l/B1k2dRl2Koo3xrB7tAADg9n4euuk7BBwN681vtHJjJPQXBqW59qeSCwD14y8sw==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-cryptocurrencies": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cspell-dict-cryptocurrencies/-/cspell-dict-cryptocurrencies-1.0.6.tgz", + "integrity": "sha512-JAjP6CkVsMH8j2K0s6DozAgk7tBfJ2ixLGy5uOhn7/gx+sIf327p9GZOtlRLzAjN3xc2/nzjJ0Li7zGCFlh5cA==", + "dev": true, + "requires": { + "configstore": "^5.0.0" + } + }, + "cspell-dict-csharp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cspell-dict-csharp/-/cspell-dict-csharp-1.0.6.tgz", + "integrity": "sha512-j/no5CTqhmLh9D23SgtYSS4Nr/k82yOn/+NjIqr6mE2Z57w4vgDxLmfiE7MocDvZGczBkAiHtOgrXLDkOzIkSA==", + "dev": true, + "requires": { + "configstore": "^5.0.0" + } + }, + "cspell-dict-css": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cspell-dict-css/-/cspell-dict-css-1.0.6.tgz", + "integrity": "sha512-Io1X4PMdOpY7NVL0fu9uw1NQu9VF4I9ONI1L7t/5Hu19WcljmSTJL7rxKlwqUc4qQ91ICnZwPJ5lztNfcWYe+w==", + "dev": true, + "requires": { + "configstore": "^5.0.0" + } + }, + "cspell-dict-django": { + "version": "1.0.21", + "resolved": "https://registry.npmjs.org/cspell-dict-django/-/cspell-dict-django-1.0.21.tgz", + "integrity": "sha512-wUlSbFC5CDYw+2+oGkgn/hI356LK2Q/K6h6GOBHTKGCNm0K6Pqrb0/LUKSC2CmZ/FvnAbuz3A6298ZVzQ5INAg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-dotnet": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/cspell-dict-dotnet/-/cspell-dict-dotnet-1.0.20.tgz", + "integrity": "sha512-+h73Kvr6/w+jRp/6yHDqkV0lIr4HaVfDwVGqbVeefO+VkAass94CYAuu78HvmgvwovsyEpym0JJDMnftZA4o5A==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-elixir": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/cspell-dict-elixir/-/cspell-dict-elixir-1.0.19.tgz", + "integrity": "sha512-1NtCgvykvAvzXKunQvaZ8UPTkgPFnYyu5thfayWgJXv1PkHtM2TlrwLqypkskj1z8uWDTtQqHH2DES8OOb2Qeg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-en-gb": { + "version": "1.1.24", + "resolved": "https://registry.npmjs.org/cspell-dict-en-gb/-/cspell-dict-en-gb-1.1.24.tgz", + "integrity": "sha512-fF+doyWNV039760WY08aYcTFfLyPo6BSwXN8gWsPWAc17f0uKI2EGEhF8IrR/kTIqdwyt9tRiZdYNZM7suTPKg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-en_us": { + "version": "1.2.34", + "resolved": "https://registry.npmjs.org/cspell-dict-en_us/-/cspell-dict-en_us-1.2.34.tgz", + "integrity": "sha512-BCiAotkU19/a/FJrhfs3C8c16k6QPGb+KIpQ/sJZQFVTI69nxgGvZ3yidBWS+fo1Q4UDx3atiNEE/cmcY6uZAw==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-filetypes": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cspell-dict-filetypes/-/cspell-dict-filetypes-1.1.1.tgz", + "integrity": "sha512-X313greGPD/2orACD+x86W6rS+C99voSkm4wwbg6ZxmTGPlNV+hTLmY1jgHsjrE3nzL2Uz1//+N+BE6kzQKguQ==", + "dev": true, + "requires": { + "configstore": "^5.0.0" + } + }, + "cspell-dict-fonts": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/cspell-dict-fonts/-/cspell-dict-fonts-1.0.9.tgz", + "integrity": "sha512-tm1VxbWEl08p6TcTZqkB3RbIDJjEHgR4Hs0OmGnX8rASgOw1ogcWWMmTCjE+mxcxmY5zcf0F9Vn8BmEvIwdqog==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-fullstack": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/cspell-dict-fullstack/-/cspell-dict-fullstack-1.0.32.tgz", + "integrity": "sha512-rC0ae/iDI7cYsxNbYjSgrP8s4wye5NxLHsJSR4GBFO5tlDejHPCVzQO04bRcrrz+vkYk74rVQ0nJ2s67dgXv1g==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-golang": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/cspell-dict-golang/-/cspell-dict-golang-1.1.20.tgz", + "integrity": "sha512-9pdJgWTH5TZpZoxcMksJ2dS3EyD0Ur5sHCEMVnDEfA3EU7dZSiNB+uQQET5aGJGupmSJzLrs0Kc9upS1BZzq1w==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-haskell": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/cspell-dict-haskell/-/cspell-dict-haskell-1.0.8.tgz", + "integrity": "sha512-JnTbTX4kZGtV7w2wFNWeR+2JlbE/PW7IDeYjJFG+sX9RXcV32MUM4WkV8L4Ucx7GQpSiJOXp1gVyqWrZOvr3Hg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-html": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cspell-dict-html/-/cspell-dict-html-1.1.1.tgz", + "integrity": "sha512-v2Lu7M3K7QcW/2A6PCI04IOW/w6MeuuoukYuFxaBKtHW/PWjhjO0PJaGf/XAtccGed+U+2ppSGLL57YREwPMnw==", + "dev": true, + "requires": { + "configstore": "^5.0.0" + } + }, + "cspell-dict-html-symbol-entities": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/cspell-dict-html-symbol-entities/-/cspell-dict-html-symbol-entities-1.0.19.tgz", + "integrity": "sha512-+L2whNDxODc8F3Pjomm6cr+T2rWtC24Aiemkt9ZWe1Jh8BnTQeYMF1oWgMTmiuEPF5rEGlhXADbNfyrSNJI11Q==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-java": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/cspell-dict-java/-/cspell-dict-java-1.0.18.tgz", + "integrity": "sha512-wy8BXuV0g4/OHdrOyIpzQL3DfjLRHKwA7S6CCHTAe3EWqLzE3HCOIgfyat/6gxJu8K8GXJ2A3IqFnIXy+wLB1Q==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-latex": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/cspell-dict-latex/-/cspell-dict-latex-1.0.19.tgz", + "integrity": "sha512-wjFkbEMCrNANN1XZiBn45yngrqCOkwD7Mha4Un7J1FbYI6fVGX1/+TCcwhMeTvJ+mhOo8VIZUazSm8+pPuOJqQ==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-lorem-ipsum": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/cspell-dict-lorem-ipsum/-/cspell-dict-lorem-ipsum-1.0.18.tgz", + "integrity": "sha512-fTTEhFktvYG1l6x/pss/i/2DX3XdYk/cLUGUpIjvOe6KpfX7Wk6rnYNyazK3fR2CteRrktsvCPbOqroHYHmfYQ==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-lua": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/cspell-dict-lua/-/cspell-dict-lua-1.0.12.tgz", + "integrity": "sha512-UmXMehOeWXNB7rzZopx0MO1bf8OXsT9ttSfAKklJWZHJrb6/qbGbJ5RDYNuyv7xZvpoMKNZcRJvxup1p3u0aeg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-node": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/cspell-dict-node/-/cspell-dict-node-1.0.5.tgz", + "integrity": "sha512-oNUO0QHm7N/sqWvgh1RIJf/rOlCFfyBGRmK2ecr9lBtt8DhZ+/BU9RM/ZzVuLY69YdZH0Ghjt4+9LGYpd+x3/w==", + "dev": true, + "requires": { + "configstore": "^5.0.0" + } + }, + "cspell-dict-npm": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cspell-dict-npm/-/cspell-dict-npm-1.0.6.tgz", + "integrity": "sha512-nyRUfFQIOgMcmkKZeZuNTVUaJj8mozZXYtd+O3f+SRzEj3zhzSeubenoBfQsEg5naNi3bqEsqKjej83bopRdaQ==", + "dev": true, + "requires": { + "configstore": "^5.0.0" + } + }, + "cspell-dict-php": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/cspell-dict-php/-/cspell-dict-php-1.0.19.tgz", + "integrity": "sha512-3LSHgtOFVO0lnUIMnOVWeX/rPoK/trOo6TVEIyottKCdB58SCf1/E/Vw+EhLDolvgvVg5qqjTBf4sx8OXI/hCg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-powershell": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/cspell-dict-powershell/-/cspell-dict-powershell-1.0.10.tgz", + "integrity": "sha512-BwY5UiqwIaHz5WjoXnIp53y6xKCbbihewWTYRZjRsYl0MvfiKnZ1wUQWa8DW/W5gKs+OifYSulgmLWy6N4pYug==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-python": { + "version": "1.0.27", + "resolved": "https://registry.npmjs.org/cspell-dict-python/-/cspell-dict-python-1.0.27.tgz", + "integrity": "sha512-VHGa7O9RhJd3Ke2eDmMbzzoU6mDsoXPN24YrfXzcJ3OVEPC2giR42KQIn3Iq2JzEMRBQuOMloSlf4w+0KtPOOg==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-ruby": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/cspell-dict-ruby/-/cspell-dict-ruby-1.0.8.tgz", + "integrity": "sha512-Z/OJce6A5XbwOM2LL8HUkJP8wPNCKRNf2SzyfHqPTUYHfPpyE7MWFLTKxiZWZ6h9J/tfUyjFnyoAD3GxpjFQ3Q==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-rust": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/cspell-dict-rust/-/cspell-dict-rust-1.0.18.tgz", + "integrity": "sha512-Jolr/EDhRYHWedTJ6lZmAozi2uojzv3dCyBvkOB0j6RftlVH0Y6NlPCy593KRLgDES3kmtQCXIJCNj1orIj0PA==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-scala": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/cspell-dict-scala/-/cspell-dict-scala-1.0.17.tgz", + "integrity": "sha512-ULwdZtIRxxJ8SXxfCbteMstKqs+9HIZC25u2oWwLZmK6fdOGcVE4Z/19tz3vEXeGHOg6rqQVcjAcM5BdaNSHsA==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-software-terms": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/cspell-dict-software-terms/-/cspell-dict-software-terms-1.0.19.tgz", + "integrity": "sha512-Q1QSDZ63kkStP1rUgGw9fjfXZ6gyinRoJKNX3nu7o7W/D6u2+ZOz7UMo/Vahu7+zqVKZ/7mxtNjJcbVhhPBMgA==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-dict-typescript": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/cspell-dict-typescript/-/cspell-dict-typescript-1.0.12.tgz", + "integrity": "sha512-EvqdZEbsmEdCR3svx5/HqGHZdYipg31BZeXKJ63mQ3+/cf3RCOMAbKDuvyGcJFpMS87LUr5vBA5sj0Aiaz3MLQ==", + "dev": true, + "requires": { + "configstore": "^5.0.1" + } + }, + "cspell-glob": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-0.1.21.tgz", + "integrity": "sha512-+xwxxB0QZRKKgehZP0Jp48mBKiYa3RkGb0XgxcBrEZr9u0GBLOYUDi6iDox9VR+/rihvUvQKt8tTRGsMyNKe0A==", + "dev": true, + "requires": { + "micromatch": "^4.0.2" + } + }, + "cspell-io": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-4.1.2.tgz", + "integrity": "sha512-FLLojKoCweQPYJBsze9KS9wNI8Cvvp84Zt/pwgNdkiqxPADZEsymIZ8U4xFdL3L+/k+LT2KhJZzxjeTI6/zsNA==", + "dev": true, + "requires": { + "iconv-lite": "^0.6.2", + "iterable-to-stream": "^1.0.1" + } + }, + "cspell-lib": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-4.3.2.tgz", + "integrity": "sha512-d794ObE18mVblT6DSgvvaFaonkvNv4+HmBnR6IALZxd0AsS8AGxZ33t4o9mgcymiATvAzrZvG0u2zL0/onhNhw==", + "dev": true, + "requires": { + "comment-json": "^4.1.0", + "configstore": "^5.0.1", + "cspell-dict-aws": "^1.0.9", + "cspell-dict-bash": "^1.0.7", + "cspell-dict-companies": "^1.0.31", + "cspell-dict-cpp": "^1.1.33", + "cspell-dict-cryptocurrencies": "^1.0.6", + "cspell-dict-csharp": "^1.0.6", + "cspell-dict-css": "^1.0.6", + "cspell-dict-django": "^1.0.21", + "cspell-dict-dotnet": "^1.0.20", + "cspell-dict-elixir": "^1.0.19", + "cspell-dict-en-gb": "^1.1.24", + "cspell-dict-en_us": "^1.2.34", + "cspell-dict-filetypes": "^1.1.1", + "cspell-dict-fonts": "^1.0.9", + "cspell-dict-fullstack": "^1.0.32", + "cspell-dict-golang": "^1.1.20", + "cspell-dict-haskell": "^1.0.8", + "cspell-dict-html": "^1.1.1", + "cspell-dict-html-symbol-entities": "^1.0.19", + "cspell-dict-java": "^1.0.18", + "cspell-dict-latex": "^1.0.19", + "cspell-dict-lorem-ipsum": "^1.0.18", + "cspell-dict-lua": "^1.0.12", + "cspell-dict-node": "^1.0.5", + "cspell-dict-npm": "^1.0.6", + "cspell-dict-php": "^1.0.19", + "cspell-dict-powershell": "^1.0.10", + "cspell-dict-python": "^1.0.27", + "cspell-dict-ruby": "^1.0.8", + "cspell-dict-rust": "^1.0.18", + "cspell-dict-scala": "^1.0.17", + "cspell-dict-software-terms": "^1.0.19", + "cspell-dict-typescript": "^1.0.12", + "cspell-io": "^4.1.2", + "cspell-trie-lib": "^4.2.2", + "cspell-util-bundle": "^4.1.4", + "fs-extra": "^9.0.1", + "gensequence": "^3.1.1", + "minimatch": "^3.0.4", + "resolve-from": "^5.0.0", + "vscode-uri": "^2.1.2" + } + }, + "cspell-trie-lib": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-4.2.2.tgz", + "integrity": "sha512-FKwubuKs7XhFIAZN8Twh4RUSKc1h2X+EHsaSu8Y4E9QIcz5vBKooejCC3HTCgTzARXbX4pw0HazehSDqjraE+g==", + "dev": true, + "requires": { + "gensequence": "^3.1.1" + } + }, + "cspell-util-bundle": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/cspell-util-bundle/-/cspell-util-bundle-4.1.4.tgz", + "integrity": "sha512-97TZTl3lqrKYVu63mf9FdekbqH6CYHRka4nUbRN0mm9bOv4L68ZE2k/DwcRuqWz7Rrc190oKOWV7USVZutgAeQ==", + "dev": true + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "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=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "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=", + "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" + }, + "dependencies": { + "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==", + "dev": true + } + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.592", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.592.tgz", + "integrity": "sha512-kGNowksvqQiPb1pUSQKpd8JFoGPLxYOwduNRCqCxGh/2Q1qE2JdmwouCW41lUzDxOb/2RIV4lR0tVIfboWlO9A==", + "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 + }, + "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", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "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", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.13.0.tgz", + "integrity": "sha512-uCORMuOO8tUzJmsdRtrvcGq5qposf7Rw0LwkTJkoDbOycVQtQjmnhZSuLQnozLE4TmAzlMVV45eCHmQ1OpDKUQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "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.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "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", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "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" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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 + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "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 + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "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==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "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 + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "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" + } + }, + "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==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "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" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-internal-rules": { + "version": "file:resources/eslint-internal-rules", + "dev": true + }, + "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 + }, + "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": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "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" + }, + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "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 + } + } + }, + "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 + }, + "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==", + "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": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "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==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", + "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "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" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flow-bin": { + "version": "0.137.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.137.0.tgz", + "integrity": "sha512-ytwUn68fPKK/VWVpCxJ4KNeNIjCC/uX0Ll6Z1E98sOXfMknB000WtgQjKYDdO6tOR8mvXBE0adzjgCrChVympw==", + "dev": true + }, + "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, + "requires": { + "cross-spawn": "^7.0.0", + "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.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gensequence": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-3.1.1.tgz", + "integrity": "sha512-ys3h0hiteRwmY6BsvSttPmkhC0vEQHPJduANBRtH/dlDPZ0UBIb/dXy80IcckXyuQ6LKg+PloRqvGER9IS7F7g==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "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 + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "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 + }, + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "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", + "slash": "^3.0.0" + } + }, + "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==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "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==", + "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==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "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": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "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", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "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-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, + "requires": { + "binary-extensions": "^2.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==", + "dev": true + }, + "is-core-module": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", + "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "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 + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "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 + }, + "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==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "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-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 + }, + "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==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "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 + } + } + }, + "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==", + "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" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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==", + "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==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-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==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "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" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "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 + } + } + }, + "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" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "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=", + "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==", + "dev": true, + "requires": { + "chalk": "^4.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" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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 + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "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==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", + "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", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "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", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.2", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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 + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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 + }, + "nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "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.66", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.66.tgz", + "integrity": "sha512-JHEQ1iWPGK+38VLB2H9ef2otU4l8s3yAMt9Xf934r6+ojCYDMHPMqvCc9TnzfeFSP1QEOeU6YZEd3+De0LTCgg==", + "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 + }, + "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 + }, + "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" + } + }, + "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 + }, + "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-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" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "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" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "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==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "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-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "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" + } + }, + "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==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.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 + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "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" + } + }, + "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" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", + "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==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, + "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==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "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 + } + } + }, + "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==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "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==", + "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==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "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" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "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", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "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==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "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 + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "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==", + "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==", + "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 + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "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": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "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==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "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 + } + } + }, + "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" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "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.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "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": "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" + }, + "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 + }, + "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" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", + "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", + "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.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 + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "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.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "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", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", + "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", + "dev": true + }, + "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==", + "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==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "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==", + "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==", + "dev": true + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "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==", + "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==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vscode-uri": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz", + "integrity": "sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-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==", + "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 + }, + "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" + } + } + } + }, + "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 + }, + "workerpool": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", + "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "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 + }, + "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", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.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": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "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" + } + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "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 + } + } + } + } +} diff --git a/package.json b/package.json index 7ef13341fe..f4053830b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "graphql", - "version": "15.0.0", + "version": "15.4.0", "description": "A Query Language and Runtime which can target any service.", "license": "MIT", "private": true, @@ -21,47 +21,52 @@ "graphql-js" ], "engines": { + "node": ">= 14.2" + }, + "engines_on_npm": { "node": ">= 10.x" }, "scripts": { - "test": "npm run prettier:check && npm run lint && npm run check && npm run testonly && npm run check:ts && npm run check:spelling", - "test:ci": "yarn check --integrity && npm run prettier:check && npm run lint -- --no-cache && npm run check && npm run testonly:cover && npm run check:ts && npm run check:spelling && npm run build", + "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", + "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", - "lint": "eslint --cache --ext .js,.ts src resources", - "benchmark": "node --noconcurrent_sweeping --expose-gc --predictable ./resources/benchmark.js", - "prettier": "prettier --ignore-path .gitignore --write --list-different \"**/*.{js,ts,md,json,yml}\"", - "prettier:check": "prettier --ignore-path .gitignore --check \"**/*.{js,ts,md,json,yml}\"", - "check": "flow check", - "check:ts": "dtslint src", - "check:cover": "node resources/check-cover.js && nyc report --nycrc-path .nycflowrc.yml", - "check:spelling": "cspell \"./{src/**/,resources**/,}*.{js,ts,md,graphql}\"", - "build": "node resources/build.js", - "changelog": "node resources/gen-changelog.js", - "preversion": ". ./resources/checkgit.sh && yarn check --integrity", - "version": "node resources/gen-version.js && npm test && git add src/version.js", - "gitpublish": ". ./resources/gitpublish.sh" + "prettier": "prettier --write --list-different .", + "prettier:check": "prettier --check .", + "check:spelling": "cspell '**/*'", + "check:integrations": "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" }, "dependencies": {}, "devDependencies": { - "@babel/core": "7.9.0", - "@babel/plugin-transform-flow-strip-types": "7.9.0", - "@babel/preset-env": "7.9.0", - "@babel/register": "7.9.0", - "@typescript-eslint/eslint-plugin": "2.26.0", - "@typescript-eslint/parser": "2.26.0", + "@babel/core": "7.12.3", + "@babel/plugin-transform-flow-strip-types": "7.12.1", + "@babel/preset-env": "7.12.1", + "@babel/register": "7.12.1", + "@typescript-eslint/eslint-plugin": "4.7.0", + "@typescript-eslint/parser": "4.7.0", "babel-eslint": "10.1.0", "chai": "4.2.0", - "cspell": "4.0.55", - "dtslint": "3.4.1", - "eslint": "6.8.0", - "eslint-plugin-flowtype": "4.7.0", - "eslint-plugin-graphql-internal": "link:./resources/eslint-rules", - "eslint-plugin-import": "2.20.2", - "flow-bin": "0.121.0", - "mocha": "7.1.1", - "nyc": "15.0.0", - "prettier": "2.0.2", - "typescript": "^3.8.3" + "cspell": "4.1.5", + "eslint": "7.13.0", + "eslint-plugin-flowtype": "5.2.0", + "eslint-plugin-import": "2.22.1", + "eslint-plugin-internal-rules": "file:./resources/eslint-internal-rules", + "eslint-plugin-istanbul": "0.1.2", + "eslint-plugin-node": "11.1.0", + "flow-bin": "0.137.0", + "mocha": "8.2.1", + "nyc": "15.1.0", + "prettier": "2.1.2", + "typescript": "4.0.5" } } diff --git a/resources/add-extension-to-import-paths.js b/resources/add-extension-to-import-paths.js index cfa6ae62d6..3ec22d9dcc 100644 --- a/resources/add-extension-to-import-paths.js +++ b/resources/add-extension-to-import-paths.js @@ -1,5 +1,3 @@ -// @noflow - 'use strict'; /** @@ -16,7 +14,7 @@ * export { foo } from './bar.mjs'; * */ -module.exports = function addExtensionToImportPaths(context) { +module.exports = function addExtensionToImportPaths(context, { extension }) { const { types } = context; return { @@ -34,10 +32,8 @@ module.exports = function addExtensionToImportPaths(context) { const source = path.node.source.value; if (source.startsWith('./') || source.startsWith('../')) { - if (!source.endsWith('.mjs')) { - const newSourceNode = types.stringLiteral(source + '.mjs'); - path.get('source').replaceWith(newSourceNode); - } + const newSourceNode = types.stringLiteral(source + '.' + extension); + path.get('source').replaceWith(newSourceNode); } } }; diff --git a/resources/benchmark-fork.js b/resources/benchmark-fork.js deleted file mode 100644 index 9a0abfe931..0000000000 --- a/resources/benchmark-fork.js +++ /dev/null @@ -1,60 +0,0 @@ -// @noflow - -'use strict'; - -const assert = require('assert'); -const cp = require('child_process'); - -// Clocks the time taken to execute a test per cycle (secs). -function clock(count, fn) { - const start = process.hrtime.bigint(); - for (let i = 0; i < count; ++i) { - fn(); - } - return Number(process.hrtime.bigint() - start); -} - -if (require.main === module) { - const modulePath = process.env.BENCHMARK_MODULE_PATH; - assert(typeof modulePath === 'string'); - assert(process.send); - const module = require(modulePath); - - clock(7, module.measure); // warm up - global.gc(); - process.nextTick(() => { - const memBaseline = process.memoryUsage().heapUsed; - const clocked = clock(module.count, module.measure); - process.send({ - name: module.name, - clocked: clocked / module.count, - memUsed: (process.memoryUsage().heapUsed - memBaseline) / module.count, - }); - }); -} - -function sampleModule(modulePath) { - return new Promise((resolve, reject) => { - const env = { - NODE_ENV: 'production', - BENCHMARK_MODULE_PATH: modulePath, - }; - const child = cp.fork(__filename, { env }); - let message; - let error; - - child.on('message', (msg) => (message = msg)); - child.on('error', (e) => (error = e)); - child.on('close', () => { - if (message) { - return resolve(message); - } - reject(error || new Error('Forked process closed without error')); - }); - }).then((result) => { - global.gc(); - return result; - }); -} - -module.exports = { sampleModule }; diff --git a/resources/build-deno.js b/resources/build-deno.js new file mode 100644 index 0000000000..0c63c06996 --- /dev/null +++ b/resources/build-deno.js @@ -0,0 +1,33 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const babel = require('@babel/core'); + +const { rmdirRecursive, readdirRecursive, showDirStats } = require('./utils'); + +if (require.main === module) { + rmdirRecursive('./denoDist'); + fs.mkdirSync('./denoDist'); + + const srcFiles = readdirRecursive('./src', { ignoreDir: /^__.*__$/ }); + for (const filepath of srcFiles) { + const srcPath = path.join('./src', filepath); + const destPath = path.join('./denoDist', filepath); + + fs.mkdirSync(path.dirname(destPath), { recursive: true }); + if (filepath.endsWith('.js')) { + 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); + } + } + + fs.copyFileSync('./LICENSE', './denoDist/LICENSE'); + fs.copyFileSync('./README.md', './denoDist/README.md'); + + showDirStats('./denoDist'); +} diff --git a/resources/build-npm.js b/resources/build-npm.js new file mode 100644 index 0000000000..b2cd83aade --- /dev/null +++ b/resources/build-npm.js @@ -0,0 +1,81 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const assert = require('assert'); + +const babel = require('@babel/core'); + +const { rmdirRecursive, readdirRecursive, showDirStats } = require('./utils'); + +if (require.main === module) { + rmdirRecursive('./npmDist'); + fs.mkdirSync('./npmDist'); + + 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); + + const cjs = babelBuild(srcPath, { envName: 'cjs' }); + fs.writeFileSync(destPath, cjs); + + const mjs = babelBuild(srcPath, { envName: 'mjs' }); + fs.writeFileSync(destPath.replace(/\.js$/, '.mjs'), mjs); + } else if (filepath.endsWith('.d.ts')) { + fs.copyFileSync(srcPath, destPath); + } + } + + 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), + ); + + showDirStats('./npmDist'); +} + +function babelBuild(srcPath, options) { + return babel.transformFileSync(srcPath, options).code + '\n'; +} + +function buildPackageJSON() { + const packageJSON = require('../package.json'); + delete packageJSON.private; + delete packageJSON.scripts; + delete packageJSON.devDependencies; + + packageJSON.engines = packageJSON.engines_on_npm; + delete packageJSON.engines_on_npm; + + const { version } = packageJSON; + const versionMatch = /^\d+\.\d+\.\d+-?(?.*)?$/.exec(version); + if (!versionMatch) { + throw new Error('Version does not match semver spec: ' + version); + } + + const { preReleaseTag } = versionMatch.groups; + + if (preReleaseTag != null) { + const [tag] = preReleaseTag.split('.'); + assert( + tag.startsWith('experimental-') || ['alpha', 'beta', 'rc'].includes(tag), + `"${tag}" tag is supported.`, + ); + + assert(!packageJSON.publishConfig, 'Can not override "publishConfig".'); + packageJSON.publishConfig = { tag: tag || 'latest' }; + } + + return packageJSON; +} diff --git a/resources/build.js b/resources/build.js deleted file mode 100644 index f21020f994..0000000000 --- a/resources/build.js +++ /dev/null @@ -1,124 +0,0 @@ -// @noflow - -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const assert = require('assert'); - -const babel = require('@babel/core'); - -const { - copyFile, - writeFile, - rmdirRecursive, - mkdirRecursive, - readdirRecursive, - parseSemver, -} = require('./utils'); - -if (require.main === module) { - rmdirRecursive('./dist'); - mkdirRecursive('./dist'); - - copyFile('./LICENSE', './dist/LICENSE'); - copyFile('./README.md', './dist/README.md'); - - const srcFiles = readdirRecursive('./src', { ignoreDir: /^__.*__$/ }); - for (const filepath of srcFiles) { - if (filepath.endsWith('.js')) { - buildJSFile(filepath); - } else if (filepath.endsWith('.d.ts')) { - const srcPath = path.join('./src', filepath); - const destPath = path.join('./dist', filepath); - - copyFile(srcPath, destPath); - } - } - - const packageJSON = buildPackageJSON(); - assert( - packageJSON.version === require('../dist/version').version, - 'Version in package.json and version.js should match', - ); - - writeFile('./dist/package.json', JSON.stringify(packageJSON, null, 2)); - showStats(); -} - -function showStats() { - const fileTypes = {}; - let totalSize = 0; - - for (const filepath of readdirRecursive('./dist')) { - const name = filepath.split(path.sep).pop(); - const [base, ...splitExt] = name.split('.'); - const ext = splitExt.join('.'); - - const filetype = ext ? '*.' + ext : base; - fileTypes[filetype] = fileTypes[filetype] || { filepaths: [], size: 0 }; - - const { size } = fs.lstatSync(path.join('./dist', filepath)); - totalSize += size; - fileTypes[filetype].size += size; - fileTypes[filetype].filepaths.push(filepath); - } - - let stats = []; - for (const [filetype, typeStats] of Object.entries(fileTypes)) { - const numFiles = typeStats.filepaths.length; - - if (numFiles > 1) { - stats.push([filetype + ' x' + numFiles, typeStats.size]); - } else { - stats.push([typeStats.filepaths[0], typeStats.size]); - } - } - stats.sort((a, b) => b[1] - a[1]); - stats = stats.map(([type, size]) => [type, (size / 1024).toFixed(2) + ' KB']); - - const typeMaxLength = Math.max(...stats.map((x) => x[0].length)); - const sizeMaxLength = Math.max(...stats.map((x) => x[1].length)); - for (const [type, size] of stats) { - console.log( - type.padStart(typeMaxLength) + ' | ' + size.padStart(sizeMaxLength), - ); - } - - console.log('-'.repeat(typeMaxLength + 3 + sizeMaxLength)); - const totalMB = (totalSize / 1024 / 1024).toFixed(2) + ' MB'; - console.log( - 'Total'.padStart(typeMaxLength) + ' | ' + totalMB.padStart(sizeMaxLength), - ); -} - -function babelBuild(srcPath, envName) { - return babel.transformFileSync(srcPath, { envName }).code + '\n'; -} - -function buildJSFile(filepath) { - const srcPath = path.join('./src', filepath); - const destPath = path.join('./dist', filepath); - - copyFile(srcPath, destPath + '.flow'); - writeFile(destPath, babelBuild(srcPath, 'cjs')); - writeFile(destPath.replace(/\.js$/, '.mjs'), babelBuild(srcPath, 'mjs')); -} - -function buildPackageJSON() { - const packageJSON = require('../package.json'); - delete packageJSON.private; - delete packageJSON.scripts; - delete packageJSON.devDependencies; - - const { preReleaseTag } = parseSemver(packageJSON.version); - if (preReleaseTag != null) { - const [tag] = preReleaseTag.split('.'); - assert(['alpha', 'beta', 'rc'].includes(tag), `"${tag}" tag is supported.`); - - assert(!packageJSON.publishConfig, 'Can not override "publishConfig".'); - packageJSON.publishConfig = { tag: tag || 'latest' }; - } - - return packageJSON; -} diff --git a/resources/check-cover.js b/resources/check-cover.js deleted file mode 100644 index 42a30e4eee..0000000000 --- a/resources/check-cover.js +++ /dev/null @@ -1,88 +0,0 @@ -// @noflow - -'use strict'; - -const path = require('path'); - -const { - exec, - execAsync, - writeFile, - rmdirRecursive, - readdirRecursive, -} = require('./utils'); - -rmdirRecursive('./coverage/flow'); -getFullCoverage() - .then((fullCoverage) => - writeFile( - './coverage/flow/full-coverage.json', - JSON.stringify(fullCoverage), - ), - ) - .catch((error) => { - console.error(error.stack); - process.exit(1); - }); - -async function getFullCoverage() { - const fullCoverage = {}; - - exec('flow start --quiet'); - try { - exec('flow check', { stdio: 'inherit' }); - - // TODO: measure coverage for all files. ATM missing types for chai & mocha - const files = readdirRecursive('./src', { ignoreDir: /^__.*__$/ }) - .filter((filepath) => filepath.endsWith('.js')) - .map((filepath) => path.join('src/', filepath)); - - await Promise.all(files.map(getCoverage)).then((coverages) => { - for (const coverage of coverages) { - fullCoverage[coverage.path] = coverage; - } - }); - } finally { - exec('flow stop --quiet'); - } - return fullCoverage; -} - -async function getCoverage(filepath) { - const json = await execAsync(`flow coverage --json ${filepath}`); - const flowExpressions = JSON.parse(json).expressions; - - const s = {}; - const statementMap = {}; - let id = 0; - for (const coveredExp of flowExpressions.covered_locs) { - s[id] = 1; - statementMap[id] = covertLocation(coveredExp); - ++id; - } - - for (const uncoveredExp of flowExpressions.uncovered_locs) { - s[id] = 0; - statementMap[id] = covertLocation(uncoveredExp); - ++id; - } - - // istanbul format, see: - // https://github.com/gotwarlost/istanbul/blob/master/coverage.json.md - return { - path: filepath, - b: {}, - branchMap: {}, - f: {}, - fnMap: {}, - s, - statementMap, - }; -} - -function covertLocation(flow) { - return { - start: { line: flow.start.line, column: flow.start.column - 1 }, - end: { line: flow.end.line, column: flow.end.column - 1 }, - }; -} diff --git a/resources/check-cycles.js b/resources/check-cycles.js index 420652fd93..e5f0385d5f 100644 --- a/resources/check-cycles.js +++ b/resources/check-cycles.js @@ -1,5 +1,3 @@ -// @noflow - 'use strict'; const os = require('os'); @@ -12,7 +10,7 @@ const { exec } = require('./utils'); const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'flow-dep-graph')); const tmpFile = path.join(tmpDir, 'out.dot'); -exec(`yarn flow graph dep-graph --quiet --strip-root --out ${tmpFile}`); +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); diff --git a/resources/checkgit.sh b/resources/checkgit.sh index a080b42566..f8e942bc8e 100644 --- a/resources/checkgit.sh +++ b/resources/checkgit.sh @@ -13,18 +13,18 @@ git fetch; if [[ $? -ne 0 ]]; then exit 1; fi; # Extract useful information. -GITBRANCH=$(git branch -v 2> /dev/null | sed '/^[^*]/d'); -GITBRANCHNAME=$(echo "$GITBRANCH" | sed 's/* \([A-Za-z0-9_\-]*\).*/\1/'); -GITBRANCHSYNC=$(echo "$GITBRANCH" | sed 's/* [^[]*.\([^]]*\).*/\1/'); +GIT_BRANCH=$(git branch -v 2> /dev/null | sed '/^[^*]/d'); +GIT_BRANCH_NAME=$(echo "$GIT_BRANCH" | sed 's/* \([A-Za-z0-9_\-]*\).*/\1/'); +GIT_BRANCH_SYNC=$(echo "$GIT_BRANCH" | sed 's/* [^[]*.\([^]]*\).*/\1/'); # Check if master is checked out -if [ "$GITBRANCHNAME" != "master" ]; then - read -p "Git not on master but $GITBRANCHNAME. Continue? (y|N) " yn; +if [ "$GIT_BRANCH_NAME" != "master" ]; then + read -p "Git not on master but $GIT_BRANCH_NAME. Continue? (y|N) " yn; if [ "$yn" != "y" ]; then exit 1; fi; fi; # Check if branch is synced with remote -if [ "$GITBRANCHSYNC" != "" ]; then - read -p "Git not up to date but $GITBRANCHSYNC. Continue? (y|N) " yn; +if [ "$GIT_BRANCH_SYNC" != "" ]; then + read -p "Git not up to date but $GIT_BRANCH_SYNC. Continue? (y|N) " yn; if [ "$yn" != "y" ]; then exit 1; fi; fi; diff --git a/resources/colors.js b/resources/colors.js deleted file mode 100644 index a9ce45a698..0000000000 --- a/resources/colors.js +++ /dev/null @@ -1,31 +0,0 @@ -// @noflow - -'use strict'; - -function red(str) { - return '\u001b[31m' + str + '\u001b[0m'; -} - -function green(str) { - return '\u001b[32m' + str + '\u001b[0m'; -} - -function yellow(str) { - return '\u001b[33m' + str + '\u001b[0m'; -} - -function cyan(str) { - return '\u001b[36m' + str + '\u001b[0m'; -} - -function grey(str) { - return '\u001b[90m' + str + '\u001b[0m'; -} - -module.exports = { - red, - green, - yellow, - cyan, - grey, -}; diff --git a/resources/eslint-rules/README.md b/resources/eslint-internal-rules/README.md similarity index 70% rename from resources/eslint-rules/README.md rename to resources/eslint-internal-rules/README.md index fd8a496025..cec9e87c9b 100644 --- a/resources/eslint-rules/README.md +++ b/resources/eslint-internal-rules/README.md @@ -3,4 +3,4 @@ This is a dummy npm package that allows us to treat it as an `eslint-plugin-graphql-internal`. It's not actually published, nor are the rules here useful for users of graphql. -**If you modify this rule, you must re-run `yarn` for it to take effect.** +**If you modify this rule, you must re-run `npm install` for it to take effect.** diff --git a/resources/eslint-rules/index.js b/resources/eslint-internal-rules/index.js similarity index 89% rename from resources/eslint-rules/index.js rename to resources/eslint-internal-rules/index.js index b8370f5772..dcb9e34965 100644 --- a/resources/eslint-rules/index.js +++ b/resources/eslint-internal-rules/index.js @@ -1,5 +1,3 @@ -// @noflow - 'use strict'; module.exports = { diff --git a/resources/eslint-rules/no-dir-import.js b/resources/eslint-internal-rules/no-dir-import.js similarity index 85% rename from resources/eslint-rules/no-dir-import.js rename to resources/eslint-internal-rules/no-dir-import.js index 45ab9d19f3..156a4e9741 100644 --- a/resources/eslint-rules/no-dir-import.js +++ b/resources/eslint-internal-rules/no-dir-import.js @@ -1,5 +1,3 @@ -// @noflow - 'use strict'; const fs = require('fs'); @@ -7,11 +5,11 @@ const path = require('path'); module.exports = function (context) { return { - ImportDeclaration: checkImporPath, - ExportNamedDeclaration: checkImporPath, + ImportDeclaration: checkImportPath, + ExportNamedDeclaration: checkImportPath, }; - function checkImporPath(node) { + function checkImportPath(node) { const { source } = node; // bail if the declaration doesn't have a source, e.g. "export { foo };" diff --git a/resources/eslint-rules/package.json b/resources/eslint-internal-rules/package.json similarity index 100% rename from resources/eslint-rules/package.json rename to resources/eslint-internal-rules/package.json diff --git a/resources/gen-changelog.js b/resources/gen-changelog.js index 19e8bfda85..48a3cf366a 100644 --- a/resources/gen-changelog.js +++ b/resources/gen-changelog.js @@ -1,5 +1,3 @@ -// @noflow - 'use strict'; const util = require('util'); @@ -37,7 +35,7 @@ const labelsConfig = { fold: true, }, }; -const GH_TOKEN = process.env['GH_TOKEN']; +const { GH_TOKEN } = process.env; if (!GH_TOKEN) { console.error('Must provide GH_TOKEN as environment variable!'); @@ -49,18 +47,21 @@ if (!packageJSON.repository || typeof packageJSON.repository.url !== 'string') { process.exit(1); } -const repoURLMatch = /https:\/\/github.com\/([^/]+)\/([^/]+).git/.exec( +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); } -const [, githubOrg, githubRepo] = repoURLMatch; +const { githubOrg, githubRepo } = repoURLMatch.groups; getChangeLog() .then((changelog) => process.stdout.write(changelog)) - .catch((error) => console.error(error)); + .catch((error) => { + console.error(error); + process.exit(1); + }); function getChangeLog() { const { version } = packageJSON; @@ -274,9 +275,9 @@ function commitsInfoToPRs(commits) { (pr) => pr.repository.nameWithOwner === `${githubOrg}/${githubRepo}`, ); if (associatedPRs.length === 0) { - const match = / \(#([0-9]+)\)$/m.exec(commit.message); + const match = / \(#(?[0-9]+)\)$/m.exec(commit.message); if (match) { - prs[parseInt(match[1], 10)] = true; + prs[parseInt(match.groups.prNumber, 10)] = true; continue; } throw new Error( diff --git a/resources/gen-version.js b/resources/gen-version.js index 1908f15d35..0141ff3597 100644 --- a/resources/gen-version.js +++ b/resources/gen-version.js @@ -1,17 +1,19 @@ -// @noflow - 'use strict'; +const fs = require('fs'); + const { version } = require('../package.json'); -const { writeFile, parseSemver } = require('./utils'); +const versionMatch = /^(\d+)\.(\d+)\.(\d+)-?(.*)?$/.exec(version); +if (!versionMatch) { + throw new Error('Version does not match semver spec: ' + version); +} -const { major, minor, patch, preReleaseTag } = parseSemver(version); -const body = `// @flow strict +const [, major, minor, patch, preReleaseTag] = versionMatch; -/** +const body = `/** * Note: This file is autogenerated using "resources/gen-version.js" script and - * automatically updated by "yarn version" command. + * automatically updated by "npm version" command. */ /** @@ -31,5 +33,5 @@ export const versionInfo = Object.freeze({ `; if (require.main === module) { - writeFile('./src/version.js', body); + fs.writeFileSync('./src/version.js', body); } diff --git a/resources/gitpublish.sh b/resources/gitpublish.sh old mode 100644 new mode 100755 index 29286d4882..8f6214d2f2 --- a/resources/gitpublish.sh +++ b/resources/gitpublish.sh @@ -1,41 +1,62 @@ -#!/bin/sh +#!/bin/bash -# Exit immediately if any subcommand terminated -trap "exit 1" ERR - -# This script maintains a git branch which mirrors master but in a form that -# what will eventually be deployed to npm, allowing npm dependencies to use: +# This script maintains a git branch which mirrors master 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" +# "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; -# Build -npm run build +if [ ! -d $DIST_DIR ]; then + echo "Directory '${DIST_DIR}' does not exist!" + exit 1; +fi; -# Create empty npm directory -rm -rf npm -git clone -b npm "https://${GH_TOKEN}@github.com/graphql/graphql-js.git" npm +# 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 npm/**/* -rm -rf npm/* +rm -rf $BRANCH/**/* +rm -rf $BRANCH/* # Copy over necessary files -cp -r dist/* npm/ +cp -r $DIST_DIR/* $BRANCH/ # Reference current commit -HEADREV=`git rev-parse HEAD` -echo $HEADREV +HEAD_REV=`git rev-parse HEAD` +echo $HEAD_REV # Deploy -cd npm -git config user.name "Travis CI" -git config user.email "github@fb.com" +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 $HEADREV to NPM branch" + 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 682d24e276..c17367c8e0 100644 --- a/resources/inline-invariant.js +++ b/resources/inline-invariant.js @@ -1,5 +1,3 @@ -// @noflow - 'use strict'; /** @@ -21,7 +19,6 @@ module.exports = function inlineInvariant(context) { (%%cond%%) || devAssert(0, %%args%%) `); - const t = context.types; return { visitor: { CallExpression(path) { @@ -40,13 +37,7 @@ module.exports = function inlineInvariant(context) { if (calleeName === 'invariant') { const [cond, args] = node.arguments; - // Check if it is unreachable invariant: "invariant(false, ...)" - if (cond.type === 'BooleanLiteral' && cond.value === false) { - addIstanbulIgnoreElse(path); - } else { - path.replaceWith(invariantTemplate({ cond, args })); - } - path.addComment('leading', ' istanbul ignore next '); + path.replaceWith(invariantTemplate({ cond, args })); } else if (calleeName === 'devAssert') { const [cond, args] = node.arguments; path.replaceWith(assertTemplate({ cond, args })); @@ -54,17 +45,4 @@ module.exports = function inlineInvariant(context) { }, }, }; - - function addIstanbulIgnoreElse(path) { - const parentStatement = path.getStatementParent(); - const previousStatement = - parentStatement.container[parentStatement.key - 1]; - if ( - previousStatement != null && - previousStatement.type === 'IfStatement' && - previousStatement.alternate == null - ) { - t.addComment(previousStatement, 'leading', ' istanbul ignore else '); - } - } }; diff --git a/resources/utils.js b/resources/utils.js index 3c64785d7f..d3593816f4 100644 --- a/resources/utils.js +++ b/resources/utils.js @@ -1,5 +1,3 @@ -// @noflow - 'use strict'; const fs = require('fs'); @@ -34,10 +32,6 @@ function removeTrailingNewLine(str) { return str.split('\n').slice(0, -1).join('\n'); } -function mkdirRecursive(dirPath) { - fs.mkdirSync(dirPath, { recursive: true }); -} - function rmdirRecursive(dirPath) { if (fs.existsSync(dirPath)) { for (const dirent of fs.readdirSync(dirPath, { withFileTypes: true })) { @@ -73,33 +67,56 @@ function readdirRecursive(dirPath, opts = {}) { return result; } -function writeFile(destPath, data) { - mkdirRecursive(path.dirname(destPath)); - fs.writeFileSync(destPath, data); -} +function showDirStats(dirPath) { + const fileTypes = {}; + let totalSize = 0; -function copyFile(srcPath, destPath) { - mkdirRecursive(path.dirname(destPath)); - fs.copyFileSync(srcPath, destPath); -} + for (const filepath of readdirRecursive(dirPath)) { + const name = filepath.split(path.sep).pop(); + const [base, ...splitExt] = name.split('.'); + const ext = splitExt.join('.'); + + const filetype = ext ? '*.' + ext : base; + fileTypes[filetype] = fileTypes[filetype] || { filepaths: [], size: 0 }; -function parseSemver(version) { - const match = /^(\d+)\.(\d+)\.(\d+)-?(.*)?$/.exec(version); - if (!match) { - throw new Error('Version does not match semver spec: ' + version); + const { size } = fs.lstatSync(path.join(dirPath, filepath)); + totalSize += size; + fileTypes[filetype].size += size; + fileTypes[filetype].filepaths.push(filepath); + } + + let stats = []; + for (const [filetype, typeStats] of Object.entries(fileTypes)) { + const numFiles = typeStats.filepaths.length; + + if (numFiles > 1) { + stats.push([filetype + ' x' + numFiles, typeStats.size]); + } else { + stats.push([typeStats.filepaths[0], typeStats.size]); + } + } + stats.sort((a, b) => b[1] - a[1]); + stats = stats.map(([type, size]) => [type, (size / 1024).toFixed(2) + ' KB']); + + const typeMaxLength = Math.max(...stats.map((x) => x[0].length)); + const sizeMaxLength = Math.max(...stats.map((x) => x[1].length)); + for (const [type, size] of stats) { + console.log( + type.padStart(typeMaxLength) + ' | ' + size.padStart(sizeMaxLength), + ); } - const [, major, minor, patch, preReleaseTag] = match; - return { major, minor, patch, preReleaseTag }; + console.log('-'.repeat(typeMaxLength + 3 + sizeMaxLength)); + const totalMB = (totalSize / 1024 / 1024).toFixed(2) + ' MB'; + console.log( + 'Total'.padStart(typeMaxLength) + ' | ' + totalMB.padStart(sizeMaxLength), + ); } module.exports = { exec, execAsync, - copyFile, - writeFile, rmdirRecursive, - mkdirRecursive, readdirRecursive, - parseSemver, + showDirStats, }; diff --git a/src/__fixtures__/index.js b/src/__fixtures__/index.js deleted file mode 100644 index 460bee30f0..0000000000 --- a/src/__fixtures__/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// @flow strict - -import { join } from 'path'; -import { readFileSync } from 'fs'; - -function readLocalFile(filename: string): string { - return readFileSync(join(__dirname, filename), 'utf8'); -} - -export const bigSchemaSDL: string = readLocalFile('github-schema.graphql'); -export const bigSchemaIntrospectionResult: any = JSON.parse( - readLocalFile('github-schema.json'), -); - -export const kitchenSinkSDL: string = readLocalFile( - 'schema-kitchen-sink.graphql', -); -export const kitchenSinkQuery: string = readLocalFile('kitchen-sink.graphql'); diff --git a/src/jsutils/__tests__/dedent-test.js b/src/__testUtils__/__tests__/dedent-test.js similarity index 99% rename from src/jsutils/__tests__/dedent-test.js rename to src/__testUtils__/__tests__/dedent-test.js index 192af3c8de..9ee2440bce 100644 --- a/src/jsutils/__tests__/dedent-test.js +++ b/src/__testUtils__/__tests__/dedent-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/__testUtils__/__tests__/genFuzzStrings-test.js b/src/__testUtils__/__tests__/genFuzzStrings-test.js new file mode 100644 index 0000000000..75da1b63cc --- /dev/null +++ b/src/__testUtils__/__tests__/genFuzzStrings-test.js @@ -0,0 +1,83 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import genFuzzStrings from '../genFuzzStrings'; + +function expectFuzzStrings(options: {| + allowedChars: Array, + maxLength: number, +|}) { + return expect(Array.from(genFuzzStrings(options))); +} + +describe('genFuzzStrings', () => { + it('always provide empty string', () => { + expectFuzzStrings({ allowedChars: [], maxLength: 0 }).to.deep.equal(['']); + expectFuzzStrings({ allowedChars: [], maxLength: 1 }).to.deep.equal(['']); + expectFuzzStrings({ allowedChars: ['a'], maxLength: 0 }).to.deep.equal([ + '', + ]); + }); + + it('generate strings with single character', () => { + expectFuzzStrings({ allowedChars: ['a'], maxLength: 1 }).to.deep.equal([ + '', + 'a', + ]); + + expectFuzzStrings({ + allowedChars: ['a', 'b', 'c'], + maxLength: 1, + }).to.deep.equal(['', 'a', 'b', 'c']); + }); + + it('generate strings with multiple character', () => { + expectFuzzStrings({ allowedChars: ['a'], maxLength: 2 }).to.deep.equal([ + '', + 'a', + 'aa', + ]); + + expectFuzzStrings({ + allowedChars: ['a', 'b', 'c'], + maxLength: 2, + }).to.deep.equal([ + '', + 'a', + 'b', + 'c', + 'aa', + 'ab', + 'ac', + 'ba', + 'bb', + 'bc', + 'ca', + 'cb', + 'cc', + ]); + }); + + it('generate strings longer than possible number of characters', () => { + expectFuzzStrings({ + allowedChars: ['a', 'b'], + maxLength: 3, + }).to.deep.equal([ + '', + 'a', + 'b', + 'aa', + 'ab', + 'ba', + 'bb', + 'aaa', + 'aab', + 'aba', + 'abb', + 'baa', + 'bab', + 'bba', + 'bbb', + ]); + }); +}); diff --git a/src/__testUtils__/__tests__/inspectStr-test.js b/src/__testUtils__/__tests__/inspectStr-test.js new file mode 100644 index 0000000000..b31e59b159 --- /dev/null +++ b/src/__testUtils__/__tests__/inspectStr-test.js @@ -0,0 +1,19 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import inspectStr from '../inspectStr'; + +describe('inspectStr', () => { + it('handles null and undefined values', () => { + expect(inspectStr(null)).to.equal('null'); + expect(inspectStr(undefined)).to.equal('null'); + }); + + it('correctly print various strings', () => { + expect(inspectStr('')).to.equal('``'); + expect(inspectStr('a')).to.equal('`a`'); + expect(inspectStr('"')).to.equal('`"`'); + expect(inspectStr("'")).to.equal("`'`"); + expect(inspectStr('\\"')).to.equal('`\\"`'); + }); +}); diff --git a/src/__testUtils__/__tests__/resolveOnNextTick-test.js b/src/__testUtils__/__tests__/resolveOnNextTick-test.js new file mode 100644 index 0000000000..5d51eb8aa8 --- /dev/null +++ b/src/__testUtils__/__tests__/resolveOnNextTick-test.js @@ -0,0 +1,21 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import resolveOnNextTick from '../resolveOnNextTick'; + +describe('resolveOnNextTick', () => { + it('resolves promise on the next tick', async () => { + const output = []; + + const promise1 = resolveOnNextTick().then(() => { + output.push('second'); + }); + const promise2 = resolveOnNextTick().then(() => { + output.push('third'); + }); + output.push('first'); + + await Promise.all([promise1, promise2]); + expect(output).to.deep.equal(['first', 'second', 'third']); + }); +}); diff --git a/src/jsutils/dedent.js b/src/__testUtils__/dedent.js similarity index 91% rename from src/jsutils/dedent.js rename to src/__testUtils__/dedent.js index a34a23aece..c4b8e8da7b 100644 --- a/src/jsutils/dedent.js +++ b/src/__testUtils__/dedent.js @@ -1,5 +1,3 @@ -// @flow strict - /** * An ES6 string tag that fixes indentation. Also removes leading newlines * and trailing spaces and tabs, but keeps trailing newlines. @@ -21,7 +19,7 @@ export default function dedent( for (let i = 0; i < strings.length; ++i) { str += strings[i]; if (i < values.length) { - /* istanbul ignore next (ignore else inside Babel generated code) */ + // istanbul ignore next (Ignore else inside Babel generated code) const value = values[i]; str += value; // interpolation diff --git a/src/__testUtils__/genFuzzStrings.js b/src/__testUtils__/genFuzzStrings.js new file mode 100644 index 0000000000..4ead99080c --- /dev/null +++ b/src/__testUtils__/genFuzzStrings.js @@ -0,0 +1,29 @@ +/** + * Generator that produces all possible combinations of allowed characters. + */ +export default function* genFuzzStrings(options: {| + allowedChars: Array, + maxLength: number, +|}): Generator { + const { allowedChars, maxLength } = options; + const numAllowedChars = allowedChars.length; + + let numCombinations = 0; + for (let length = 1; length <= maxLength; ++length) { + numCombinations += numAllowedChars ** length; + } + + yield ''; // special case for empty string + for (let combination = 0; combination < numCombinations; ++combination) { + let permutation = ''; + + let leftOver = combination; + while (leftOver >= 0) { + const reminder = leftOver % numAllowedChars; + permutation = allowedChars[reminder] + permutation; + leftOver = (leftOver - reminder) / numAllowedChars - 1; + } + + yield permutation; + } +} diff --git a/src/__testUtils__/inspectStr.js b/src/__testUtils__/inspectStr.js new file mode 100644 index 0000000000..a99a28150a --- /dev/null +++ b/src/__testUtils__/inspectStr.js @@ -0,0 +1,12 @@ +/** + * Special inspect function to produce readable string literal for error messages in tests + */ +export default function inspectStr(str: ?string): string { + if (str == null) { + return 'null'; + } + return JSON.stringify(str) + .replace(/^"|"$/g, '`') + .replace(/\\"/g, '"') + .replace(/\\\\/g, '\\'); +} diff --git a/src/__fixtures__/kitchen-sink.graphql b/src/__testUtils__/kitchenSinkQuery.js similarity index 89% rename from src/__fixtures__/kitchen-sink.graphql rename to src/__testUtils__/kitchenSinkQuery.js index 543307bb8a..2ccdc9dc92 100644 --- a/src/__fixtures__/kitchen-sink.graphql +++ b/src/__testUtils__/kitchenSinkQuery.js @@ -1,3 +1,5 @@ +// $FlowFixMe[incompatible-call] +const kitchenSinkQuery: string = String.raw` query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { whoever123is: node(id: [123, 456]) { id @@ -62,3 +64,6 @@ fragment frag on Friend @onFragmentDefinition { query { __typename } +`; + +export default kitchenSinkQuery; diff --git a/src/__fixtures__/schema-kitchen-sink.graphql b/src/__testUtils__/kitchenSinkSDL.js similarity index 81% rename from src/__fixtures__/schema-kitchen-sink.graphql rename to src/__testUtils__/kitchenSinkSDL.js index 8ec1f2d8a6..7b171ac027 100644 --- a/src/__fixtures__/schema-kitchen-sink.graphql +++ b/src/__testUtils__/kitchenSinkSDL.js @@ -1,3 +1,4 @@ +const kitchenSinkSDL: string = ` """This is a description of the schema as a whole.""" schema { query: QueryType @@ -6,21 +7,21 @@ schema { """ This is a description -of the `Foo` type. +of the \`Foo\` type. """ type Foo implements Bar & Baz & Two { - "Description of the `one` field." + "Description of the \`one\` field." one: Type """ - This is a description of the `two` field. + This is a description of the \`two\` field. """ two( """ - This is a description of the `argument` argument. + This is a description of the \`argument\` argument. """ argument: InputType! ): Type - """This is a description of the `three` field.""" + """This is a description of the \`three\` field.""" three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String @@ -86,14 +87,14 @@ extend scalar CustomScalar @onScalar enum Site { """ - This is a description of the `DESKTOP` value + This is a description of the \`DESKTOP\` value """ DESKTOP - """This is a description of the `MOBILE` value""" + """This is a description of the \`MOBILE\` value""" MOBILE - "This is a description of the `WEB` value" + "This is a description of the \`WEB\` value" WEB } @@ -128,10 +129,10 @@ extend input InputType { extend input InputType @onInputObject """ -This is a description of the `@skip` directive +This is a description of the \`@skip\` directive """ directive @skip( - """This is a description of the `if` argument""" + """This is a description of the \`if\` argument""" if: Boolean! @onArgumentDefinition ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT @@ -154,3 +155,6 @@ extend schema @onSchema extend schema @onSchema { subscription: SubscriptionType } +`; + +export default kitchenSinkSDL; diff --git a/src/__testUtils__/resolveOnNextTick.js b/src/__testUtils__/resolveOnNextTick.js new file mode 100644 index 0000000000..b27ba839b2 --- /dev/null +++ b/src/__testUtils__/resolveOnNextTick.js @@ -0,0 +1,3 @@ +export default function resolveOnNextTick(): Promise { + return Promise.resolve(undefined); +} diff --git a/src/__tests__/starWarsData.js b/src/__tests__/starWarsData.js index 5144f3735e..7e1917b8bd 100644 --- a/src/__tests__/starWarsData.js +++ b/src/__tests__/starWarsData.js @@ -1,4 +1,32 @@ -// @flow strict +/** + * 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 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, +|}; /** * This defines a basic set of data for our Star Wars Schema. @@ -8,7 +36,7 @@ * JSON objects in a more complex demo. */ -const luke = { +const luke: Human = { type: 'Human', id: '1000', name: 'Luke Skywalker', @@ -17,7 +45,7 @@ const luke = { homePlanet: 'Tatooine', }; -const vader = { +const vader: Human = { type: 'Human', id: '1001', name: 'Darth Vader', @@ -26,7 +54,7 @@ const vader = { homePlanet: 'Tatooine', }; -const han = { +const han: Human = { type: 'Human', id: '1002', name: 'Han Solo', @@ -34,7 +62,7 @@ const han = { appearsIn: [4, 5, 6], }; -const leia = { +const leia: Human = { type: 'Human', id: '1003', name: 'Leia Organa', @@ -43,7 +71,7 @@ const leia = { homePlanet: 'Alderaan', }; -const tarkin = { +const tarkin: Human = { type: 'Human', id: '1004', name: 'Wilhuff Tarkin', @@ -51,15 +79,15 @@ const tarkin = { appearsIn: [4], }; -const humanData = { - '1000': luke, - '1001': vader, - '1002': han, - '1003': leia, - '1004': tarkin, +const humanData: {| [id: string]: Human |} = { + [luke.id]: luke, + [vader.id]: vader, + [han.id]: han, + [leia.id]: leia, + [tarkin.id]: tarkin, }; -const threepio = { +const threepio: Droid = { type: 'Droid', id: '2000', name: 'C-3PO', @@ -68,7 +96,7 @@ const threepio = { primaryFunction: 'Protocol', }; -const artoo = { +const artoo: Droid = { type: 'Droid', id: '2001', name: 'R2-D2', @@ -77,45 +105,15 @@ const artoo = { primaryFunction: 'Astromech', }; -const droidData = { - '2000': threepio, - '2001': artoo, +const droidData: {| [id: string]: Droid |} = { + [threepio.id]: threepio, + [artoo.id]: artoo, }; -/** - * These are Flow 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 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, -|}; - /** * Helper function to get a character by ID. */ -function getCharacter(id) { +function getCharacter(id: string): Promise { // Returning a promise just to illustrate that GraphQL.js supports it. return Promise.resolve(humanData[id] ?? droidData[id]); } @@ -123,7 +121,9 @@ function getCharacter(id) { /** * Allows us to query for a character's friends. */ -export function getFriends(character: Character): Array> { +export function getFriends( + character: Character, +): Array> { // Notice that GraphQL accepts Arrays of Promises. return character.friends.map((id) => getCharacter(id)); } @@ -143,13 +143,13 @@ export function getHero(episode: number): Character { /** * Allows us to query for the human with the given id. */ -export function getHuman(id: string): Human { +export function getHuman(id: string): Human | null { return humanData[id]; } /** * Allows us to query for the droid with the given id. */ -export function getDroid(id: string): Droid { +export function getDroid(id: string): Droid | null { return droidData[id]; } diff --git a/src/__tests__/starWarsIntrospection-test.js b/src/__tests__/starWarsIntrospection-test.js index 8db0c324c6..d637787c4a 100644 --- a/src/__tests__/starWarsIntrospection-test.js +++ b/src/__tests__/starWarsIntrospection-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -7,7 +5,7 @@ import { graphqlSync } from '../graphql'; import { StarWarsSchema } from './starWarsSchema'; -function queryStarWars(source) { +function queryStarWars(source: string) { const result = graphqlSync({ schema: StarWarsSchema, source }); expect(Object.keys(result)).to.deep.equal(['data']); return result.data; diff --git a/src/__tests__/starWarsQuery-test.js b/src/__tests__/starWarsQuery-test.js index fd14017293..8b8ef8a56e 100644 --- a/src/__tests__/starWarsQuery-test.js +++ b/src/__tests__/starWarsQuery-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/__tests__/starWarsSchema.js b/src/__tests__/starWarsSchema.js index 78a95647d3..e06c2cef71 100644 --- a/src/__tests__/starWarsSchema.js +++ b/src/__tests__/starWarsSchema.js @@ -1,5 +1,3 @@ -// @flow strict - import invariant from '../jsutils/invariant'; import { GraphQLSchema } from '../type/schema'; @@ -105,7 +103,7 @@ const characterInterface = new GraphQLInterfaceType({ description: 'A character in the Star Wars Trilogy', fields: () => ({ id: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), description: 'The id of the character.', }, name: { @@ -113,12 +111,12 @@ const characterInterface = new GraphQLInterfaceType({ description: 'The name of the character.', }, friends: { - type: GraphQLList(characterInterface), + type: new GraphQLList(characterInterface), description: 'The friends of the character, or an empty list if they have none.', }, appearsIn: { - type: GraphQLList(episodeEnum), + type: new GraphQLList(episodeEnum), description: 'Which movies they appear in.', }, secretBackstory: { @@ -127,14 +125,14 @@ const characterInterface = new GraphQLInterfaceType({ }, }), resolveType(character) { - if (character.type === 'Human') { - return humanType; - } - if (character.type === 'Droid') { - return droidType; + switch (character.type) { + case 'Human': + return humanType.name; + case 'Droid': + return droidType.name; } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false); }, }); @@ -156,7 +154,7 @@ const humanType = new GraphQLObjectType({ description: 'A humanoid creature in the Star Wars universe.', fields: () => ({ id: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), description: 'The id of the human.', }, name: { @@ -164,13 +162,13 @@ const humanType = new GraphQLObjectType({ description: 'The name of the human.', }, friends: { - type: GraphQLList(characterInterface), + type: new GraphQLList(characterInterface), description: 'The friends of the human, or an empty list if they have none.', resolve: (human) => getFriends(human), }, appearsIn: { - type: GraphQLList(episodeEnum), + type: new GraphQLList(episodeEnum), description: 'Which movies they appear in.', }, homePlanet: { @@ -206,7 +204,7 @@ const droidType = new GraphQLObjectType({ description: 'A mechanical creature in the Star Wars universe.', fields: () => ({ id: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), description: 'The id of the droid.', }, name: { @@ -214,13 +212,13 @@ const droidType = new GraphQLObjectType({ description: 'The name of the droid.', }, friends: { - type: GraphQLList(characterInterface), + type: new GraphQLList(characterInterface), description: 'The friends of the droid, or an empty list if they have none.', resolve: (droid) => getFriends(droid), }, appearsIn: { - type: GraphQLList(episodeEnum), + type: new GraphQLList(episodeEnum), description: 'Which movies they appear in.', }, secretBackstory: { @@ -271,7 +269,7 @@ const queryType = new GraphQLObjectType({ args: { id: { description: 'id of the human', - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), }, }, resolve: (_source, { id }) => getHuman(id), @@ -281,7 +279,7 @@ const queryType = new GraphQLObjectType({ args: { id: { description: 'id of the droid', - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), }, }, resolve: (_source, { id }) => getDroid(id), diff --git a/src/__tests__/starWarsValidation-test.js b/src/__tests__/starWarsValidation-test.js index e746b60688..65e6c7f666 100644 --- a/src/__tests__/starWarsValidation-test.js +++ b/src/__tests__/starWarsValidation-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -13,7 +11,7 @@ import { StarWarsSchema } from './starWarsSchema'; /** * Helper function to test a query and the expected response. */ -function validationErrors(query) { +function validationErrors(query: string) { const source = new Source(query, 'StarWars.graphql'); const ast = parse(source); return validate(StarWarsSchema, ast); diff --git a/src/__tests__/version-test.js b/src/__tests__/version-test.js index b6fde05200..ffa8d981e6 100644 --- a/src/__tests__/version-test.js +++ b/src/__tests__/version-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -8,7 +6,9 @@ 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)\.\d+)?$/); + expect(version).to.match( + /^\d+\.\d+\.\d(-(alpha|beta|rc|(experimental-[\w-]+))\.\d+)?$/, + ); }); it('versionInfo', () => { @@ -26,14 +26,14 @@ describe('Version', () => { expect(minor).to.be.a('number'); expect(patch).to.be.a('number'); - /* istanbul ignore next (Can't be verified on all versions) */ + // 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) */ + // istanbul ignore next (Can't be verified on all versions) (preReleaseTag !== null ? '-' + preReleaseTag : ''), ).to.equal(version); }); diff --git a/src/error/GraphQLError.d.ts b/src/error/GraphQLError.d.ts index d8886a181e..99001fd26f 100644 --- a/src/error/GraphQLError.d.ts +++ b/src/error/GraphQLError.d.ts @@ -1,4 +1,4 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; import { ASTNode } from '../language/ast'; import { Source } from '../language/source'; @@ -13,7 +13,7 @@ import { SourceLocation } from '../language/location'; export class GraphQLError extends Error { constructor( message: string, - nodes?: ReadonlyArray | ASTNode | undefined, + nodes?: Maybe | ASTNode>, source?: Maybe, positions?: Maybe>, path?: Maybe>, diff --git a/src/error/GraphQLError.js b/src/error/GraphQLError.js index d3af8d2cf7..8e214ee2d4 100644 --- a/src/error/GraphQLError.js +++ b/src/error/GraphQLError.js @@ -1,14 +1,13 @@ -// @flow strict - // 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, getLocation } from '../language/location'; +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'; /** @@ -196,7 +195,7 @@ export class GraphQLError extends Error { return; } - /* istanbul ignore next (See: https://github.com/graphql/graphql-js/issues/2317) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') if (Error.captureStackTrace) { Error.captureStackTrace(this, GraphQLError); } else { @@ -213,7 +212,7 @@ export class GraphQLError extends Error { } // FIXME: workaround to not break chai comparisons, should be remove in v16 - // $FlowFixMe Flow doesn't support computed properties yet + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG](): string { return 'Object'; } diff --git a/src/error/__tests__/GraphQLError-test.js b/src/error/__tests__/GraphQLError-test.js index deba78b437..b72d31b174 100644 --- a/src/error/__tests__/GraphQLError-test.js +++ b/src/error/__tests__/GraphQLError-test.js @@ -1,9 +1,8 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; + import invariant from '../../jsutils/invariant'; import { Kind } from '../../language/kinds'; diff --git a/src/error/__tests__/formatError-test.js b/src/error/__tests__/formatError-test.js index f1638804b0..d6c8e17e8d 100644 --- a/src/error/__tests__/formatError-test.js +++ b/src/error/__tests__/formatError-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -8,7 +6,7 @@ import { GraphQLError } from '../GraphQLError'; describe('formatError: default error formatter', () => { it('uses default message', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] const e = new GraphQLError(); expect(formatError(e)).to.deep.equal({ @@ -47,12 +45,12 @@ describe('formatError: default error formatter', () => { }); it('rejects null and undefined errors', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => formatError(undefined)).to.throw( 'Received null or undefined error.', ); - // $DisableFlowOnNegativeTest + // $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 index d30cb6ed72..3de473b4c9 100644 --- a/src/error/__tests__/locatedError-test.js +++ b/src/error/__tests__/locatedError-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/error/formatError.js b/src/error/formatError.js index 8bb4c5b8f6..d73cc897b0 100644 --- a/src/error/formatError.js +++ b/src/error/formatError.js @@ -1,10 +1,8 @@ -// @flow strict - import devAssert from '../jsutils/devAssert'; -import { type SourceLocation } from '../language/location'; +import type { SourceLocation } from '../language/location'; -import { type GraphQLError } from './GraphQLError'; +import type { GraphQLError } from './GraphQLError'; /** * Given a GraphQLError, format it according to the rules described by the diff --git a/src/error/index.js b/src/error/index.js index c920bfc188..914a6dbe46 100644 --- a/src/error/index.js +++ b/src/error/index.js @@ -1,5 +1,3 @@ -// @flow strict - export { GraphQLError, printError } from './GraphQLError'; export { syntaxError } from './syntaxError'; diff --git a/src/error/locatedError.d.ts b/src/error/locatedError.d.ts index 5e9d02dffc..8693757094 100644 --- a/src/error/locatedError.d.ts +++ b/src/error/locatedError.d.ts @@ -1,16 +1,16 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; import { ASTNode } from '../language/ast'; import { GraphQLError } from './GraphQLError'; /** - * Given an arbitrary Error, presumably thrown while attempting to execute a + * 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( - originalError: Error | GraphQLError, + rawOriginalError: any, nodes: ASTNode | ReadonlyArray | undefined, path?: Maybe>, ): GraphQLError; diff --git a/src/error/locatedError.js b/src/error/locatedError.js index ceb5426e22..1b7c335070 100644 --- a/src/error/locatedError.js +++ b/src/error/locatedError.js @@ -1,21 +1,26 @@ -// @flow strict +import inspect from '../jsutils/inspect'; -import { type ASTNode } from '../language/ast'; +import type { ASTNode } from '../language/ast'; import { GraphQLError } from './GraphQLError'; /** - * Given an arbitrary Error, presumably thrown while attempting to execute a + * 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( - originalError: Error | GraphQLError, + rawOriginalError: mixed, nodes: ASTNode | $ReadOnlyArray | void | null, path?: ?$ReadOnlyArray, ): GraphQLError { - // Note: this uses a brand-check to support GraphQL errors originating from - // other contexts. + // 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); } diff --git a/src/error/syntaxError.js b/src/error/syntaxError.js index c5eeb1d9c0..21a2dc18e4 100644 --- a/src/error/syntaxError.js +++ b/src/error/syntaxError.js @@ -1,6 +1,4 @@ -// @flow strict - -import { type Source } from '../language/source'; +import type { Source } from '../language/source'; import { GraphQLError } from './GraphQLError'; diff --git a/src/execution/__tests__/abstract-promise-test.js b/src/execution/__tests__/abstract-promise-test.js deleted file mode 100644 index 6f58497225..0000000000 --- a/src/execution/__tests__/abstract-promise-test.js +++ /dev/null @@ -1,635 +0,0 @@ -// @flow strict - -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import invariant from '../../jsutils/invariant'; - -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString, GraphQLBoolean } from '../../type/scalars'; -import { - GraphQLList, - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, -} from '../../type/definition'; - -import { graphql } from '../../graphql'; - -class Dog { - name: string; - woofs: boolean; - - constructor(name, woofs) { - this.name = name; - this.woofs = woofs; - } -} - -class Cat { - name: string; - meows: boolean; - - constructor(name, meows) { - this.name = name; - this.meows = meows; - } -} - -class Human { - name: string; - - constructor(name) { - this.name = name; - } -} - -describe('Execute: Handles execution of abstract types with promises', () => { - it('isTypeOf used to resolve runtime type for Interface', async () => { - const PetType = new GraphQLInterfaceType({ - name: 'Pet', - fields: { - name: { type: GraphQLString }, - }, - }); - - const DogType = new GraphQLObjectType({ - name: 'Dog', - interfaces: [PetType], - isTypeOf: (obj) => Promise.resolve(obj instanceof Dog), - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); - - const CatType = new GraphQLObjectType({ - name: 'Cat', - interfaces: [PetType], - isTypeOf: (obj) => Promise.resolve(obj instanceof Cat), - fields: { - name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return [new Dog('Odie', true), new Cat('Garfield', false)]; - }, - }, - }, - }), - types: [CatType, DogType], - }); - - const source = ` - { - pets { - name - ... on Dog { - woofs - } - ... on Cat { - meows - } - } - } - `; - - const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ - data: { - pets: [ - { - name: 'Odie', - woofs: true, - }, - { - name: 'Garfield', - meows: false, - }, - ], - }, - }); - }); - - it('isTypeOf can be rejected', async () => { - const PetType = new GraphQLInterfaceType({ - name: 'Pet', - fields: { - name: { type: GraphQLString }, - }, - }); - - const DogType = new GraphQLObjectType({ - name: 'Dog', - interfaces: [PetType], - isTypeOf: () => Promise.reject(new Error('We are testing this error')), - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); - - const CatType = new GraphQLObjectType({ - name: 'Cat', - interfaces: [PetType], - isTypeOf: (obj) => Promise.resolve(obj instanceof Cat), - fields: { - name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return [new Dog('Odie', true), new Cat('Garfield', false)]; - }, - }, - }, - }), - types: [CatType, DogType], - }); - - const source = ` - { - pets { - name - ... on Dog { - woofs - } - ... on Cat { - meows - } - } - } - `; - - const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ - data: { - pets: [null, null], - }, - errors: [ - { - message: 'We are testing this error', - locations: [{ line: 3, column: 9 }], - path: ['pets', 0], - }, - { - message: 'We are testing this error', - locations: [{ line: 3, column: 9 }], - path: ['pets', 1], - }, - ], - }); - }); - - it('isTypeOf used to resolve runtime type for Union', async () => { - const DogType = new GraphQLObjectType({ - name: 'Dog', - isTypeOf: (obj) => Promise.resolve(obj instanceof Dog), - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); - - const CatType = new GraphQLObjectType({ - name: 'Cat', - isTypeOf: (obj) => Promise.resolve(obj instanceof Cat), - 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', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return [new Dog('Odie', true), new Cat('Garfield', false)]; - }, - }, - }, - }), - }); - - const source = ` - { - pets { - ... on Dog { - name - woofs - } - ... on Cat { - name - meows - } - } - } - `; - - const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ - data: { - pets: [ - { - name: 'Odie', - woofs: true, - }, - { - name: 'Garfield', - meows: false, - }, - ], - }, - }); - }); - - it('resolveType on Interface yields useful error', async () => { - const PetType = new GraphQLInterfaceType({ - name: 'Pet', - resolveType(obj) { - if (obj instanceof Dog) { - return Promise.resolve(DogType); - } - if (obj instanceof Cat) { - return Promise.resolve(CatType); - } - if (obj instanceof Human) { - return Promise.resolve(HumanType); - } - - // Not reachable. All possible types have been considered. - invariant(false); - }, - fields: { - name: { type: GraphQLString }, - }, - }); - - const HumanType = new GraphQLObjectType({ - name: 'Human', - fields: { - name: { type: GraphQLString }, - }, - }); - - const DogType = new GraphQLObjectType({ - name: 'Dog', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); - - const CatType = new GraphQLObjectType({ - name: 'Cat', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return Promise.resolve([ - new Dog('Odie', true), - new Cat('Garfield', false), - new Human('Jon'), - ]); - }, - }, - }, - }), - types: [CatType, DogType], - }); - - const source = ` - { - pets { - name - ... on Dog { - woofs - } - ... on Cat { - meows - } - } - } - `; - - const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ - data: { - pets: [ - { - name: 'Odie', - woofs: true, - }, - { - name: 'Garfield', - meows: false, - }, - null, - ], - }, - errors: [ - { - message: - 'Runtime Object type "Human" is not a possible type for "Pet".', - locations: [{ line: 3, column: 9 }], - path: ['pets', 2], - }, - ], - }); - }); - - it('resolveType on Union yields useful error', async () => { - const HumanType = new GraphQLObjectType({ - name: 'Human', - fields: { - name: { type: GraphQLString }, - }, - }); - - const DogType = new GraphQLObjectType({ - name: 'Dog', - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); - - const CatType = new GraphQLObjectType({ - name: 'Cat', - fields: { - name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - }, - }); - - const PetType = new GraphQLUnionType({ - name: 'Pet', - resolveType(obj) { - if (obj instanceof Dog) { - return Promise.resolve(DogType); - } - if (obj instanceof Cat) { - return Promise.resolve(CatType); - } - if (obj instanceof Human) { - return Promise.resolve(HumanType); - } - - // Not reachable. All possible types have been considered. - invariant(false); - }, - types: [DogType, CatType], - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return [ - new Dog('Odie', true), - new Cat('Garfield', false), - new Human('Jon'), - ]; - }, - }, - }, - }), - }); - - const source = ` - { - pets { - ... on Dog { - name - woofs - } - ... on Cat { - name - meows - } - } - } - `; - - const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ - data: { - pets: [ - { - name: 'Odie', - woofs: true, - }, - { - name: 'Garfield', - meows: false, - }, - null, - ], - }, - errors: [ - { - message: - 'Runtime Object type "Human" is not a possible type for "Pet".', - locations: [{ line: 3, column: 9 }], - path: ['pets', 2], - }, - ], - }); - }); - - it('resolveType allows resolving with type name', async () => { - const PetType = new GraphQLInterfaceType({ - name: 'Pet', - resolveType(obj) { - if (obj instanceof Dog) { - return Promise.resolve('Dog'); - } - if (obj instanceof Cat) { - return Promise.resolve('Cat'); - } - - // Not reachable. All possible types have been considered. - invariant(false); - }, - fields: { - name: { type: GraphQLString }, - }, - }); - - const DogType = new GraphQLObjectType({ - name: 'Dog', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); - - const CatType = new GraphQLObjectType({ - name: 'Cat', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return [new Dog('Odie', true), new Cat('Garfield', false)]; - }, - }, - }, - }), - types: [CatType, DogType], - }); - - const source = ` - { - pets { - name - ... on Dog { - woofs - } - ... on Cat { - meows - } - } - } - `; - - const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ - data: { - pets: [ - { - name: 'Odie', - woofs: true, - }, - { - name: 'Garfield', - meows: false, - }, - ], - }, - }); - }); - - it('resolveType can be caught', async () => { - const PetType = new GraphQLInterfaceType({ - name: 'Pet', - resolveType: () => Promise.reject(new Error('We are testing this error')), - fields: { - name: { type: GraphQLString }, - }, - }); - - const DogType = new GraphQLObjectType({ - name: 'Dog', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); - - const CatType = new GraphQLObjectType({ - name: 'Cat', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return [new Dog('Odie', true), new Cat('Garfield', false)]; - }, - }, - }, - }), - types: [CatType, DogType], - }); - - const source = ` - { - pets { - name - ... on Dog { - woofs - } - ... on Cat { - meows - } - } - } - `; - - const result = await graphql({ schema, source }); - expect(result).to.deep.equal({ - data: { - pets: [null, null], - }, - errors: [ - { - message: 'We are testing this error', - locations: [{ line: 3, column: 9 }], - path: ['pets', 0], - }, - { - message: 'We are testing this error', - locations: [{ line: 3, column: 9 }], - path: ['pets', 1], - }, - ], - }); - }); -}); diff --git a/src/execution/__tests__/abstract-test.js b/src/execution/__tests__/abstract-test.js index 10b07c6d6b..1d8bbeaab0 100644 --- a/src/execution/__tests__/abstract-test.js +++ b/src/execution/__tests__/abstract-test.js @@ -1,10 +1,10 @@ -// @flow strict - 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 { @@ -14,13 +14,39 @@ import { GraphQLUnionType, } from '../../type/definition'; -import { graphqlSync } from '../../graphql'; +import { buildSchema } from '../../utilities/buildASTSchema'; + +import { executeSync, execute } from '../execute'; + +async function executeQuery(args: {| + schema: GraphQLSchema, + query: string, + rootValue?: mixed, +|}) { + const { schema, query, rootValue } = args; + const document = parse(query); + const result = executeSync({ + schema, + document, + rootValue, + contextValue: { async: false }, + }); + const asyncResult = await execute({ + schema, + document, + rootValue, + contextValue: { async: true }, + }); + + expect(result).to.deep.equal(asyncResult); + return result; +} class Dog { name: string; woofs: boolean; - constructor(name, woofs) { + constructor(name: string, woofs: boolean) { this.name = name; this.woofs = woofs; } @@ -30,22 +56,14 @@ class Cat { name: string; meows: boolean; - constructor(name, meows) { + constructor(name: string, meows: boolean) { this.name = name; this.meows = meows; } } -class Human { - name: string; - - constructor(name) { - this.name = name; - } -} - describe('Execute: Handles execution of abstract types', () => { - it('isTypeOf used to resolve runtime type for Interface', () => { + it('isTypeOf used to resolve runtime type for Interface', async () => { const PetType = new GraphQLInterfaceType({ name: 'Pet', fields: { @@ -56,7 +74,10 @@ describe('Execute: Handles execution of abstract types', () => { const DogType = new GraphQLObjectType({ name: 'Dog', interfaces: [PetType], - isTypeOf: (obj) => obj instanceof Dog, + isTypeOf(obj, context) { + const isDog = obj instanceof Dog; + return context.async ? Promise.resolve(isDog) : isDog; + }, fields: { name: { type: GraphQLString }, woofs: { type: GraphQLBoolean }, @@ -66,7 +87,10 @@ describe('Execute: Handles execution of abstract types', () => { const CatType = new GraphQLObjectType({ name: 'Cat', interfaces: [PetType], - isTypeOf: (obj) => obj instanceof Cat, + isTypeOf(obj, context) { + const isCat = obj instanceof Cat; + return context.async ? Promise.resolve(isCat) : isCat; + }, fields: { name: { type: GraphQLString }, meows: { type: GraphQLBoolean }, @@ -78,7 +102,7 @@ describe('Execute: Handles execution of abstract types', () => { name: 'Query', fields: { pets: { - type: GraphQLList(PetType), + type: new GraphQLList(PetType), resolve() { return [new Dog('Odie', true), new Cat('Garfield', false)]; }, @@ -102,9 +126,7 @@ describe('Execute: Handles execution of abstract types', () => { } `; - const result = graphqlSync({ schema, source: query }); - - expect(result).to.deep.equal({ + expect(await executeQuery({ schema, query })).to.deep.equal({ data: { pets: [ { @@ -120,10 +142,95 @@ describe('Execute: Handles execution of abstract types', () => { }); }); - it('isTypeOf used to resolve runtime type for Union', () => { + it('isTypeOf can throw', async () => { + const PetType = new GraphQLInterfaceType({ + name: 'Pet', + fields: { + name: { type: GraphQLString }, + }, + }); + + const DogType = new GraphQLObjectType({ + name: 'Dog', + interfaces: [PetType], + isTypeOf(_source, context) { + const error = new Error('We are testing this error'); + if (context.async) { + return Promise.reject(error); + } + throw error; + }, + fields: { + name: { type: GraphQLString }, + woofs: { type: GraphQLBoolean }, + }, + }); + + const CatType = new GraphQLObjectType({ + name: 'Cat', + interfaces: [PetType], + isTypeOf: undefined, + fields: { + name: { type: GraphQLString }, + meows: { type: GraphQLBoolean }, + }, + }); + + 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)]; + }, + }, + }, + }), + types: [DogType, CatType], + }); + + const query = ` + { + pets { + name + ... on Dog { + woofs + } + ... on Cat { + meows + } + } + } + `; + + expect(await executeQuery({ schema, query })).to.deep.equal({ + data: { + pets: [null, null], + }, + errors: [ + { + message: 'We are testing this error', + locations: [{ line: 3, column: 9 }], + path: ['pets', 0], + }, + { + message: 'We are testing this error', + locations: [{ line: 3, column: 9 }], + path: ['pets', 1], + }, + ], + }); + }); + + it('isTypeOf used to resolve runtime type for Union', async () => { const DogType = new GraphQLObjectType({ name: 'Dog', - isTypeOf: (obj) => obj instanceof Dog, + isTypeOf(obj, context) { + const isDog = obj instanceof Dog; + return context.async ? Promise.resolve(isDog) : isDog; + }, fields: { name: { type: GraphQLString }, woofs: { type: GraphQLBoolean }, @@ -132,7 +239,10 @@ describe('Execute: Handles execution of abstract types', () => { const CatType = new GraphQLObjectType({ name: 'Cat', - isTypeOf: (obj) => obj instanceof Cat, + isTypeOf(obj, context) { + const isCat = obj instanceof Cat; + return context.async ? Promise.resolve(isCat) : isCat; + }, fields: { name: { type: GraphQLString }, meows: { type: GraphQLBoolean }, @@ -149,7 +259,7 @@ describe('Execute: Handles execution of abstract types', () => { name: 'Query', fields: { pets: { - type: GraphQLList(PetType), + type: new GraphQLList(PetType), resolve() { return [new Dog('Odie', true), new Cat('Garfield', false)]; }, @@ -171,9 +281,7 @@ describe('Execute: Handles execution of abstract types', () => { } }`; - const result = graphqlSync({ schema, source: query }); - - expect(result).to.deep.equal({ + expect(await executeQuery({ schema, query })).to.deep.equal({ data: { pets: [ { @@ -189,21 +297,19 @@ describe('Execute: Handles execution of abstract types', () => { }); }); - it('resolveType on Interface yields useful error', () => { + it('deprecated(will be removed in v16.0.0): resolveType allows resolving with type object', async () => { const PetType = new GraphQLInterfaceType({ name: 'Pet', - resolveType(obj) { + resolveType(obj, context) { if (obj instanceof Dog) { - return DogType; + return context.async ? Promise.resolve(DogType) : DogType; } + // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (obj instanceof Cat) { - return CatType; - } - if (obj instanceof Human) { - return HumanType; + return context.async ? Promise.resolve(CatType) : CatType; } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false); }, fields: { @@ -211,13 +317,6 @@ describe('Execute: Handles execution of abstract types', () => { }, }); - const HumanType = new GraphQLObjectType({ - name: 'Human', - fields: { - name: { type: GraphQLString }, - }, - }); - const DogType = new GraphQLObjectType({ name: 'Dog', interfaces: [PetType], @@ -241,13 +340,9 @@ describe('Execute: Handles execution of abstract types', () => { name: 'Query', fields: { pets: { - type: GraphQLList(PetType), + type: new GraphQLList(PetType), resolve() { - return [ - new Dog('Odie', true), - new Cat('Garfield', false), - new Human('Jon'), - ]; + return [new Dog('Odie', true), new Cat('Garfield', false)]; }, }, }, @@ -269,9 +364,7 @@ describe('Execute: Handles execution of abstract types', () => { } `; - const result = graphqlSync({ schema, source: query }); - - expect(result).to.deep.equal({ + expect(await executeQuery({ schema, query })).to.deep.equal({ data: { pets: [ { @@ -282,23 +375,21 @@ describe('Execute: Handles execution of abstract types', () => { name: 'Garfield', meows: false, }, - null, ], }, - errors: [ - { - message: - 'Runtime Object type "Human" is not a possible type for "Pet".', - locations: [{ line: 3, column: 9 }], - path: ['pets', 2], - }, - ], }); }); - it('resolveType on Union yields useful error', () => { - const HumanType = new GraphQLObjectType({ - name: 'Human', + it('resolveType can throw', async () => { + const PetType = new GraphQLInterfaceType({ + name: 'Pet', + resolveType(_source, context) { + const error = new Error('We are testing this error'); + if (context.async) { + return Promise.reject(error); + } + throw error; + }, fields: { name: { type: GraphQLString }, }, @@ -306,6 +397,7 @@ describe('Execute: Handles execution of abstract types', () => { const DogType = new GraphQLObjectType({ name: 'Dog', + interfaces: [PetType], fields: { name: { type: GraphQLString }, woofs: { type: GraphQLBoolean }, @@ -314,226 +406,145 @@ describe('Execute: Handles execution of abstract types', () => { const CatType = new GraphQLObjectType({ name: 'Cat', + interfaces: [PetType], fields: { name: { type: GraphQLString }, meows: { type: GraphQLBoolean }, }, }); - const PetType = new GraphQLUnionType({ - name: 'Pet', - resolveType(obj) { - if (obj instanceof Dog) { - return DogType; - } - if (obj instanceof Cat) { - return CatType; - } - if (obj instanceof Human) { - return HumanType; - } - - // Not reachable. All possible types have been considered. - invariant(false); - }, - types: [DogType, CatType], - }); - const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { pets: { - type: GraphQLList(PetType), + type: new GraphQLList(PetType), resolve() { - return [ - new Dog('Odie', true), - new Cat('Garfield', false), - new Human('Jon'), - ]; + return [new Dog('Odie', true), new Cat('Garfield', false)]; }, }, }, }), + types: [CatType, DogType], }); const query = ` { pets { + name ... on Dog { - name woofs } ... on Cat { - name meows } } } `; - const result = graphqlSync({ schema, source: query }); - - expect(result).to.deep.equal({ + expect(await executeQuery({ schema, query })).to.deep.equal({ data: { - pets: [ - { - name: 'Odie', - woofs: true, - }, - { - name: 'Garfield', - meows: false, - }, - null, - ], + pets: [null, null], }, errors: [ { - message: - 'Runtime Object type "Human" is not a possible type for "Pet".', + message: 'We are testing this error', locations: [{ line: 3, column: 9 }], - path: ['pets', 2], + path: ['pets', 0], }, - ], - }); - }); - - it('returning invalid value from resolveType yields useful error', () => { - const fooInterface = new GraphQLInterfaceType({ - name: 'FooInterface', - fields: { bar: { type: GraphQLString } }, - // $DisableFlowOnNegativeTest - resolveType() { - return []; - }, - }); - - const fooObject = new GraphQLObjectType({ - name: 'FooObject', - fields: { bar: { type: GraphQLString } }, - interfaces: [fooInterface], - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - foo: { - type: fooInterface, - resolve: () => 'dummy', - }, - }, - }), - types: [fooObject], - }); - - const result = graphqlSync({ schema, source: '{ foo { bar } }' }); - - expect(result).to.deep.equal({ - data: { foo: null }, - errors: [ { - message: - 'Abstract type "FooInterface" must resolve to an Object type at runtime for field "Query.foo" with value "dummy", received "[]". Either the "FooInterface" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.', - locations: [{ line: 1, column: 3 }], - path: ['foo'], + message: 'We are testing this error', + locations: [{ line: 3, column: 9 }], + path: ['pets', 1], }, ], }); }); - it('missing both resolveType and isTypeOf yields useful error', () => { - const fooInterface = new GraphQLInterfaceType({ - name: 'FooInterface', - fields: { bar: { type: GraphQLString } }, - }); + it('resolve Union type using __typename on source object', async () => { + const schema = buildSchema(` + type Query { + pets: [Pet] + } - const fooObject = new GraphQLObjectType({ - name: 'FooObject', - fields: { bar: { type: GraphQLString } }, - interfaces: [fooInterface], - }); + union Pet = Cat | Dog - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - foo: { - type: fooInterface, - resolve: () => 'dummy', - }, - }, - }), - types: [fooObject], - }); + type Cat { + name: String + meows: Boolean + } - const result = graphqlSync({ schema, source: '{ foo { bar } }' }); + type Dog { + name: String + woofs: Boolean + } + `); - expect(result).to.deep.equal({ - data: { foo: null }, - errors: [ + const query = ` + { + pets { + name + ... on Dog { + woofs + } + ... on Cat { + meows + } + } + } + `; + + const rootValue = { + pets: [ { - message: - 'Abstract type "FooInterface" must resolve to an Object type at runtime for field "Query.foo" with value "dummy", received "undefined". Either the "FooInterface" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.', - locations: [{ line: 1, column: 3 }], - path: ['foo'], + __typename: 'Dog', + name: 'Odie', + woofs: true, + }, + { + __typename: 'Cat', + name: 'Garfield', + meows: false, }, ], - }); - }); - - it('resolveType allows resolving with type name', () => { - const PetType = new GraphQLInterfaceType({ - name: 'Pet', - resolveType(obj) { - if (obj instanceof Dog) { - return 'Dog'; - } - if (obj instanceof Cat) { - return 'Cat'; - } + }; - // Not reachable. All possible types have been considered. - invariant(false); - }, - fields: { - name: { type: GraphQLString }, + expect(await executeQuery({ schema, query, rootValue })).to.deep.equal({ + data: { + pets: [ + { + name: 'Odie', + woofs: true, + }, + { + name: 'Garfield', + meows: false, + }, + ], }, }); + }); - const DogType = new GraphQLObjectType({ - name: 'Dog', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - woofs: { type: GraphQLBoolean }, - }, - }); + it('resolve Interface type using __typename on source object', async () => { + const schema = buildSchema(` + type Query { + pets: [Pet] + } - const CatType = new GraphQLObjectType({ - name: 'Cat', - interfaces: [PetType], - fields: { - name: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - }, - }); + interface Pet { + name: String + } - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - pets: { - type: GraphQLList(PetType), - resolve() { - return [new Dog('Odie', true), new Cat('Garfield', false)]; - }, - }, - }, - }), - types: [CatType, DogType], - }); + type Cat implements Pet { + name: String + meows: Boolean + } + + type Dog implements Pet { + name: String + woofs: Boolean + } + `); const query = ` { @@ -549,9 +560,22 @@ describe('Execute: Handles execution of abstract types', () => { } `; - const result = graphqlSync({ schema, source: query }); + const rootValue = { + pets: [ + { + __typename: 'Dog', + name: 'Odie', + woofs: true, + }, + { + __typename: 'Cat', + name: 'Garfield', + meows: false, + }, + ], + }; - expect(result).to.deep.equal({ + expect(await executeQuery({ schema, query, rootValue })).to.deep.equal({ data: { pets: [ { @@ -566,4 +590,73 @@ describe('Execute: Handles execution of abstract types', () => { }, }); }); + + it('resolveType on Interface yields useful error', () => { + const schema = buildSchema(` + type Query { + pet: Pet + } + + interface Pet { + name: String + } + + type Cat implements Pet { + name: String + } + + type Dog implements Pet { + name: String + } + `); + + const document = parse(` + { + pet { + name + } + } + `); + + function expectError({ forTypeName }: {| forTypeName: mixed |}) { + const rootValue = { pet: { __typename: forTypeName } }; + const result = executeSync({ schema, document, rootValue }); + return { + toEqual(message: string) { + expect(result).to.deep.equal({ + data: { pet: null }, + errors: [ + { + message, + locations: [{ line: 3, column: 9 }], + path: ['pet'], + }, + ], + }); + }, + }; + } + + expectError({ forTypeName: undefined }).toEqual( + '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.', + ); + + expectError({ forTypeName: 'Human' }).toEqual( + 'Abstract type "Pet" was resolve to a type "Human" that does not exist inside schema.', + ); + + expectError({ forTypeName: 'String' }).toEqual( + 'Abstract type "Pet" was resolve to a non-object type "String".', + ); + + expectError({ forTypeName: '__Schema' }).toEqual( + 'Runtime Object type "__Schema" is not a possible type for "Pet".', + ); + + // FIXME: workaround since we can't inject resolveType into SDL + (schema.getType('Pet'): any).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 "[]".', + ); + }); }); diff --git a/src/execution/__tests__/directives-test.js b/src/execution/__tests__/directives-test.js index 810cd51b68..92c8fb9c5f 100644 --- a/src/execution/__tests__/directives-test.js +++ b/src/execution/__tests__/directives-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -9,7 +7,7 @@ import { GraphQLSchema } from '../../type/schema'; import { GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; -import { execute } from '../execute'; +import { executeSync } from '../execute'; const schema = new GraphQLSchema({ query: new GraphQLObjectType({ @@ -30,9 +28,9 @@ const rootValue = { }, }; -function executeTestQuery(query) { +function executeTestQuery(query: string) { const document = parse(query); - return execute({ schema, document, rootValue }); + return executeSync({ schema, document, rootValue }); } describe('Execute: handles directives', () => { diff --git a/src/execution/__tests__/executor-test.js b/src/execution/__tests__/executor-test.js index ef5d02076e..aa9427ffc4 100644 --- a/src/execution/__tests__/executor-test.js +++ b/src/execution/__tests__/executor-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -17,9 +15,10 @@ import { GraphQLScalarType, GraphQLInterfaceType, GraphQLObjectType, + GraphQLUnionType, } from '../../type/definition'; -import { execute } from '../execute'; +import { execute, executeSync } from '../execute'; describe('Execute: Handles basic execution tasks', () => { it('throws if no document is provided', () => { @@ -32,15 +31,15 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - // $DisableFlowOnNegativeTest - expect(() => execute({ schema })).to.throw('Must provide document.'); + // $FlowExpectedError[prop-missing] + expect(() => executeSync({ schema })).to.throw('Must provide document.'); }); it('throws if no schema is provided', () => { const document = parse('{ field }'); - // $DisableFlowOnNegativeTest - expect(() => execute({ document })).to.throw( + // $FlowExpectedError[prop-missing] + expect(() => executeSync({ document })).to.throw( 'Expected undefined to be a GraphQL schema.', ); }); @@ -64,8 +63,8 @@ describe('Execute: Handles basic execution tasks', () => { `); const variableValues = '{ "a": 1 }'; - // $DisableFlowOnNegativeTest - expect(() => execute({ schema, document, variableValues })).to.throw( + // $FlowExpectedError[incompatible-call] + 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.', ); }); @@ -103,7 +102,7 @@ describe('Execute: Handles basic execution tasks', () => { e: () => 'Egg', f: 'Fish', // Called only by DataType::pic static resolver - pic: (size) => 'Pic of size: ' + size, + pic: (size: number) => 'Pic of size: ' + size, deep: () => deepData, promise: promiseData, }; @@ -116,11 +115,7 @@ describe('Execute: Handles basic execution tasks', () => { }; function promiseData() { - return new Promise((resolve) => { - process.nextTick(() => { - resolve(data); - }); - }); + return Promise.resolve(data); } const DataType = new GraphQLObjectType({ @@ -147,8 +142,8 @@ describe('Execute: Handles basic execution tasks', () => { fields: { a: { type: GraphQLString }, b: { type: GraphQLString }, - c: { type: GraphQLList(GraphQLString) }, - deeper: { type: GraphQLList(DataType) }, + c: { type: new GraphQLList(GraphQLString) }, + deeper: { type: new GraphQLList(DataType) }, }, }); @@ -239,7 +234,7 @@ describe('Execute: Handles basic execution tasks', () => { } `); - const result = execute({ schema, document }); + const result = executeSync({ schema, document }); expect(result).to.deep.equal({ data: { a: 'Apple', @@ -276,7 +271,7 @@ describe('Execute: Handles basic execution tasks', () => { const rootValue = { root: 'val' }; const variableValues = { var: 'abc' }; - execute({ schema, document, rootValue, variableValues }); + executeSync({ schema, document, rootValue, variableValues }); expect(resolvedInfo).to.have.all.keys( 'fieldName', @@ -306,11 +301,70 @@ describe('Execute: Handles basic execution tasks', () => { const field = operation.selectionSet.selections[0]; expect(resolvedInfo).to.deep.include({ fieldNodes: [field], - path: { prev: undefined, key: 'result' }, + path: { prev: undefined, key: 'result', typename: 'Test' }, variableValues: { var: 'abc' }, }); }); + it('populates path correctly with complex types', () => { + let path; + const someObject = new GraphQLObjectType({ + name: 'SomeObject', + fields: { + test: { + type: GraphQLString, + resolve(_val, _args, _ctx, info) { + path = info.path; + }, + }, + }, + }); + const someUnion = new GraphQLUnionType({ + name: 'SomeUnion', + types: [someObject], + resolveType() { + return 'SomeObject'; + }, + }); + const testType = new GraphQLObjectType({ + name: 'SomeQuery', + fields: { + test: { + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(someUnion)), + ), + }, + }, + }); + const schema = new GraphQLSchema({ query: testType }); + const rootValue = { test: [{}] }; + const document = parse(` + query { + l1: test { + ... on SomeObject { + l2: test + } + } + } + `); + + executeSync({ schema, document, rootValue }); + + expect(path).to.deep.equal({ + key: 'l2', + typename: 'SomeObject', + prev: { + key: 0, + typename: undefined, + prev: { + key: 'l1', + typename: 'SomeQuery', + prev: undefined, + }, + }, + }); + }); + it('threads root value context correctly', () => { let resolvedRootValue; const schema = new GraphQLSchema({ @@ -330,7 +384,7 @@ describe('Execute: Handles basic execution tasks', () => { const document = parse('query Example { a }'); const rootValue = { contextThing: 'thing' }; - execute({ schema, document, rootValue }); + executeSync({ schema, document, rootValue }); expect(resolvedRootValue).to.equal(rootValue); }); @@ -360,7 +414,7 @@ describe('Execute: Handles basic execution tasks', () => { } `); - execute({ schema, document }); + executeSync({ schema, document }); expect(resolvedArgs).to.deep.equal({ numArg: 123, stringArg: 'foo' }); }); @@ -373,7 +427,7 @@ describe('Execute: Handles basic execution tasks', () => { syncError: { type: GraphQLString }, syncRawError: { type: GraphQLString }, syncReturnError: { type: GraphQLString }, - syncReturnErrorList: { type: GraphQLList(GraphQLString) }, + syncReturnErrorList: { type: new GraphQLList(GraphQLString) }, async: { type: GraphQLString }, asyncReject: { type: GraphQLString }, asyncRejectWithExtensions: { type: GraphQLString }, @@ -554,7 +608,7 @@ describe('Execute: Handles basic execution tasks', () => { name: 'Query', fields: { foods: { - type: GraphQLList( + type: new GraphQLList( new GraphQLObjectType({ name: 'Food', fields: { @@ -601,11 +655,11 @@ describe('Execute: Handles basic execution tasks', () => { resolve: () => ({}), }, nonNullA: { - type: GraphQLNonNull(A), + type: new GraphQLNonNull(A), resolve: () => ({}), }, throws: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), resolve: () => { throw new Error('Catch me if you can'); }, @@ -638,7 +692,7 @@ describe('Execute: Handles basic execution tasks', () => { } `); - const result = execute({ schema, document }); + const result = executeSync({ schema, document }); expect(result).to.deep.equal({ data: { nullableA: { @@ -667,7 +721,7 @@ describe('Execute: Handles basic execution tasks', () => { const document = parse('{ a }'); const rootValue = { a: 'b' }; - const result = execute({ schema, document, rootValue }); + const result = executeSync({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { a: 'b' } }); }); @@ -683,7 +737,7 @@ describe('Execute: Handles basic execution tasks', () => { const document = parse('query Example { a }'); const rootValue = { a: 'b' }; - const result = execute({ schema, document, rootValue }); + const result = executeSync({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { a: 'b' } }); }); @@ -704,7 +758,7 @@ describe('Execute: Handles basic execution tasks', () => { const rootValue = { a: 'b' }; const operationName = 'OtherExample'; - const result = execute({ schema, document, rootValue, operationName }); + const result = executeSync({ schema, document, rootValue, operationName }); expect(result).to.deep.equal({ data: { second: 'b' } }); }); @@ -720,7 +774,7 @@ describe('Execute: Handles basic execution tasks', () => { const document = parse('fragment Example on Type { a }'); const rootValue = { a: 'b' }; - const result = execute({ schema, document, rootValue }); + const result = executeSync({ schema, document, rootValue }); expect(result).to.deep.equal({ errors: [{ message: 'Must provide an operation.' }], }); @@ -740,7 +794,7 @@ describe('Execute: Handles basic execution tasks', () => { query OtherExample { a } `); - const result = execute({ schema, document }); + const result = executeSync({ schema, document }); expect(result).to.deep.equal({ errors: [ { @@ -766,7 +820,7 @@ describe('Execute: Handles basic execution tasks', () => { `); const operationName = 'UnknownExample'; - const result = execute({ schema, document, operationName }); + const result = executeSync({ schema, document, operationName }); expect(result).to.deep.equal({ errors: [{ message: 'Unknown operation named "UnknownExample".' }], }); @@ -784,7 +838,7 @@ describe('Execute: Handles basic execution tasks', () => { const document = parse('{ a }'); const operationName = ''; - const result = execute({ schema, document, operationName }); + const result = executeSync({ schema, document, operationName }); expect(result).to.deep.equal({ errors: [{ message: 'Unknown operation named "".' }], }); @@ -819,7 +873,7 @@ describe('Execute: Handles basic execution tasks', () => { const rootValue = { a: 'b', c: 'd' }; const operationName = 'Q'; - const result = execute({ schema, document, rootValue, operationName }); + const result = executeSync({ schema, document, rootValue, operationName }); expect(result).to.deep.equal({ data: { a: 'b' } }); }); @@ -845,7 +899,7 @@ describe('Execute: Handles basic execution tasks', () => { const rootValue = { a: 'b', c: 'd' }; const operationName = 'M'; - const result = execute({ schema, document, rootValue, operationName }); + const result = executeSync({ schema, document, rootValue, operationName }); expect(result).to.deep.equal({ data: { c: 'd' } }); }); @@ -871,7 +925,7 @@ describe('Execute: Handles basic execution tasks', () => { const rootValue = { a: 'b', c: 'd' }; const operationName = 'S'; - const result = execute({ schema, document, rootValue, operationName }); + const result = executeSync({ schema, document, rootValue, operationName }); expect(result).to.deep.equal({ data: { a: 'b' } }); }); @@ -926,7 +980,7 @@ describe('Execute: Handles basic execution tasks', () => { `); const rootValue = { a: 'b' }; - const result = execute({ schema, document, rootValue }); + const result = executeSync({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { a: 'b' }, }); @@ -950,7 +1004,7 @@ describe('Execute: Handles basic execution tasks', () => { const document = parse('{ a }'); const rootValue = { a: { b: 'c' } }; - const result = execute({ schema, document, rootValue }); + const result = executeSync({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { a: {} }, }); @@ -967,7 +1021,7 @@ describe('Execute: Handles basic execution tasks', () => { }); const document = parse('{ thisIsIllegalDoNotIncludeMe }'); - const result = execute({ schema, document }); + const result = executeSync({ schema, document }); expect(result).to.deep.equal({ data: {}, }); @@ -994,7 +1048,7 @@ describe('Execute: Handles basic execution tasks', () => { }); const document = parse('{ field(a: true, c: false, e: 0) }'); - const result = execute({ schema, document }); + const result = executeSync({ schema, document }); expect(result).to.deep.equal({ data: { field: '{ a: true, c: false, e: 0 }', @@ -1006,7 +1060,7 @@ describe('Execute: Handles basic execution tasks', () => { class Special { value: string; - constructor(value) { + constructor(value: string) { this.value = value; } } @@ -1014,7 +1068,7 @@ describe('Execute: Handles basic execution tasks', () => { class NotSpecial { value: string; - constructor(value) { + constructor(value: string) { this.value = value; } } @@ -1032,7 +1086,7 @@ describe('Execute: Handles basic execution tasks', () => { query: new GraphQLObjectType({ name: 'Query', fields: { - specials: { type: GraphQLList(SpecialType) }, + specials: { type: new GraphQLList(SpecialType) }, }, }), }); @@ -1042,7 +1096,7 @@ describe('Execute: Handles basic execution tasks', () => { specials: [new Special('foo'), new NotSpecial('bar')], }; - const result = execute({ schema, document, rootValue }); + const result = executeSync({ schema, document, rootValue }); expect(result).to.deep.equal({ data: { specials: [{ value: 'foo' }, null], @@ -1086,7 +1140,7 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - const result = execute({ schema, document: parse('{ customScalar }') }); + const result = executeSync({ schema, document: parse('{ customScalar }') }); expect(result).to.deep.equal({ data: { customScalar: null }, errors: [ @@ -1116,7 +1170,7 @@ describe('Execute: Handles basic execution tasks', () => { type Query { bar: String } `); - const result = execute({ schema, document }); + const result = executeSync({ schema, document }); expect(result).to.deep.equal({ data: { foo: null } }); }); @@ -1131,12 +1185,15 @@ describe('Execute: Handles basic execution tasks', () => { }); const document = parse('{ foo }'); - function fieldResolver(_source, _args, _context, info) { - // For the purposes of test, just return the name of the field! - return info.fieldName; - } + const result = executeSync({ + schema, + document, + fieldResolver(_source, _args, _context, info) { + // For the purposes of test, just return the name of the field! + return info.fieldName; + }, + }); - const result = execute({ schema, document, fieldResolver }); expect(result).to.deep.equal({ data: { foo: 'foo' } }); }); @@ -1168,16 +1225,20 @@ describe('Execute: Handles basic execution tasks', () => { types: [fooObject], }); - let possibleTypes; - function typeResolver(_source, _context, info, abstractType) { - // Resolver should be able to figure out all possible types on its own - possibleTypes = info.schema.getPossibleTypes(abstractType); + const rootValue = { foo: { bar: 'bar' } }; - return 'FooObject'; - } + let possibleTypes; + const result = executeSync({ + schema, + document, + rootValue, + typeResolver(_source, _context, info, abstractType) { + // Resolver should be able to figure out all possible types on its own + possibleTypes = info.schema.getPossibleTypes(abstractType); - const rootValue = { foo: { bar: 'bar' } }; - const result = execute({ schema, document, rootValue, typeResolver }); + return 'FooObject'; + }, + }); expect(result).to.deep.equal({ data: { foo: { bar: 'bar' } } }); expect(possibleTypes).to.deep.equal([fooObject]); diff --git a/src/execution/__tests__/lists-test.js b/src/execution/__tests__/lists-test.js index c665c9f9ec..926802a51b 100644 --- a/src/execution/__tests__/lists-test.js +++ b/src/execution/__tests__/lists-test.js @@ -1,539 +1,223 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString, GraphQLInt } from '../../type/scalars'; -import { - GraphQLList, - GraphQLNonNull, - GraphQLObjectType, -} from '../../type/definition'; - -import { execute } from '../execute'; - -// resolved() is shorthand for Promise.resolve() -const resolved = Promise.resolve.bind(Promise); - -// rejected() is shorthand for Promise.reject() -const rejected = Promise.reject.bind(Promise); +import { buildSchema } from '../../utilities/buildASTSchema'; -/** - * This function creates a test case passed to "it", there's a time delay - * between when the test is created and when the test is run, so if testData - * contains a rejection, testData should be a function that returns that - * rejection so as not to trigger the "unhandled rejection" error watcher. - */ -function check(testType, testData, expected) { - return async () => { - const data = { test: testData }; +import { execute, executeSync } from '../execute'; - const dataType = new GraphQLObjectType({ - name: 'DataType', - fields: () => ({ - test: { type: testType }, - nest: { type: dataType, resolve: () => data }, - }), +describe('Execute: Accepts any iterable as list value', () => { + function complete(rootValue: mixed) { + return executeSync({ + schema: buildSchema('type Query { listField: [String] }'), + document: parse('{ listField }'), + rootValue, }); + } + + it('Accepts a Set as a List value', () => { + const listField = new Set(['apple', 'banana', 'apple', 'coconut']); - const response = await execute({ - schema: new GraphQLSchema({ query: dataType }), - document: parse('{ nest { test } }'), - contextValue: { test: testData }, + expect(complete({ listField })).to.deep.equal({ + data: { listField: ['apple', 'banana', 'coconut'] }, }); - expect(response).to.deep.equal(expected); - }; -} + }); -describe('Execute: Accepts any iterable as list value', () => { - it( - 'Accepts a Set as a List value', - check( - GraphQLList(GraphQLString), - new Set(['apple', 'banana', 'apple', 'coconut']), - { data: { nest: { test: ['apple', 'banana', 'coconut'] } } }, - ), - ); + it('Accepts an Generator function as a List value', () => { + function* listField() { + yield 'one'; + yield 2; + yield true; + } - function* yieldItems() { - yield 'one'; - yield 2; - yield true; - } + expect(complete({ listField })).to.deep.equal({ + data: { listField: ['one', '2', 'true'] }, + }); + }); - it( - 'Accepts an Generator function as a List value', - check(GraphQLList(GraphQLString), yieldItems(), { - data: { nest: { test: ['one', '2', 'true'] } }, - }), - ); + it('Accepts function arguments as a List value', () => { + function getArgs(...args: Array) { + return args; + } + const listField = getArgs('one', 'two'); - function getArgs(...args) { - return args; - } + expect(complete({ listField })).to.deep.equal({ + data: { listField: ['one', 'two'] }, + }); + }); - it( - 'Accepts function arguments as a List value', - check(GraphQLList(GraphQLString), getArgs('one', 'two'), { - data: { nest: { test: ['one', 'two'] } }, - }), - ); + it('Does not accept (Iterable) String-literal as a List value', () => { + const listField = 'Singular'; - it( - 'Does not accept (Iterable) String-literal as a List value', - check(GraphQLList(GraphQLString), 'Singular', { - data: { nest: { test: null } }, + expect(complete({ listField })).to.deep.equal({ + data: { listField: null }, errors: [ { message: - 'Expected Iterable, but did not find one for field "DataType.test".', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], + 'Expected Iterable, but did not find one for field "Query.listField".', + locations: [{ line: 1, column: 3 }], + path: ['listField'], }, ], - }), - ); + }); + }); }); describe('Execute: Handles list nullability', () => { - describe('[T]', () => { - const type = GraphQLList(GraphQLInt); + async function complete(args: {| listField: mixed, 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); + if (Array.isArray(listField)) { + const listOfPromises = listField.map(promisify); + + // Array> === Array + expect(await executeQuery(listOfPromises)).to.deep.equal(result); + // Promise>> === Array + expect(await executeQuery(promisify(listOfPromises))).to.deep.equal( + result, + ); + } + return result; + + function executeQuery(listValue: mixed) { + return execute({ schema, document, rootValue: { listField: listValue } }); + } + + function promisify(value: mixed): Promise { + return value instanceof Error + ? Promise.reject(value) + : Promise.resolve(value); + } + } - describe('Array', () => { - it( - 'Contains values', - check(type, [1, 2], { data: { nest: { test: [1, 2] } } }), - ); + it('Contains values', async () => { + const listField = [1, 2]; - it( - 'Contains null', - check(type, [1, null, 2], { data: { nest: { test: [1, null, 2] } } }), - ); - - it('Returns null', check(type, null, { data: { nest: { test: null } } })); + expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ + data: { listField: [1, 2] }, }); - - describe('Promise>', () => { - it( - 'Contains values', - check(type, resolved([1, 2]), { data: { nest: { test: [1, 2] } } }), - ); - - it( - 'Contains null', - check(type, resolved([1, null, 2]), { - data: { nest: { test: [1, null, 2] } }, - }), - ); - - it( - 'Returns null', - check(type, resolved(null), { data: { nest: { test: null } } }), - ); - - it( - 'Rejected', - check(type, () => rejected(new Error('bad')), { - data: { nest: { test: null } }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); + expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + data: { listField: [1, 2] }, }); - - describe('Array>', () => { - it( - 'Contains values', - check(type, [resolved(1), resolved(2)], { - data: { nest: { test: [1, 2] } }, - }), - ); - - it( - 'Contains null', - check(type, [resolved(1), resolved(null), resolved(2)], { - data: { nest: { test: [1, null, 2] } }, - }), - ); - - it( - 'Contains reject', - check( - type, - () => [resolved(1), rejected(new Error('bad')), resolved(2)], - { - data: { nest: { test: [1, null, 2] } }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }, - ), - ); + expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + data: { listField: [1, 2] }, + }); + expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + data: { listField: [1, 2] }, }); }); - describe('[T]!', () => { - const type = GraphQLNonNull(GraphQLList(GraphQLInt)); - - describe('Array', () => { - it( - 'Contains values', - check(type, [1, 2], { data: { nest: { test: [1, 2] } } }), - ); - - it( - 'Contains null', - check(type, [1, null, 2], { data: { nest: { test: [1, null, 2] } } }), - ); - - it( - 'Returns null', - check(type, null, { - data: { nest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); + it('Contains null', async () => { + const listField = [1, null, 2]; + const errors = [ + { + message: 'Cannot return null for non-nullable field Query.listField.', + locations: [{ line: 1, column: 3 }], + path: ['listField', 1], + }, + ]; + + expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ + data: { listField: [1, null, 2] }, }); - - describe('Promise>', () => { - it( - 'Contains values', - check(type, resolved([1, 2]), { data: { nest: { test: [1, 2] } } }), - ); - - it( - 'Contains null', - check(type, resolved([1, null, 2]), { - data: { nest: { test: [1, null, 2] } }, - }), - ); - - it( - 'Returns null', - check(type, resolved(null), { - data: { nest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); - - it( - 'Rejected', - check(type, () => rejected(new Error('bad')), { - data: { nest: null }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); + expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + data: { listField: [1, null, 2] }, }); - - describe('Array>', () => { - it( - 'Contains values', - check(type, [resolved(1), resolved(2)], { - data: { nest: { test: [1, 2] } }, - }), - ); - - it( - 'Contains null', - check(type, [resolved(1), resolved(null), resolved(2)], { - data: { nest: { test: [1, null, 2] } }, - }), - ); - - it( - 'Contains reject', - check( - type, - () => [resolved(1), rejected(new Error('bad')), resolved(2)], - { - data: { nest: { test: [1, null, 2] } }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }, - ), - ); + expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + data: { listField: null }, + errors, + }); + expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + data: null, + errors, }); }); - describe('[T!]', () => { - const type = GraphQLList(GraphQLNonNull(GraphQLInt)); - - describe('Array', () => { - it( - 'Contains values', - check(type, [1, 2], { data: { nest: { test: [1, 2] } } }), - ); - - it( - 'Contains null', - check(type, [1, null, 2], { - data: { nest: { test: null } }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }), - ); - - it('Returns null', check(type, null, { data: { nest: { test: null } } })); + it('Returns null', async () => { + const listField = null; + const errors = [ + { + message: 'Cannot return null for non-nullable field Query.listField.', + locations: [{ line: 1, column: 3 }], + path: ['listField'], + }, + ]; + + expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ + data: { listField: null }, }); - - describe('Promise>', () => { - it( - 'Contains values', - check(type, resolved([1, 2]), { data: { nest: { test: [1, 2] } } }), - ); - - it( - 'Contains null', - check(type, resolved([1, null, 2]), { - data: { nest: { test: null } }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }), - ); - - it( - 'Returns null', - check(type, resolved(null), { data: { nest: { test: null } } }), - ); - - it( - 'Rejected', - check(type, () => rejected(new Error('bad')), { - data: { nest: { test: null } }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); + expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + data: null, + errors, }); - - describe('Array>', () => { - it( - 'Contains values', - check(type, [resolved(1), resolved(2)], { - data: { nest: { test: [1, 2] } }, - }), - ); - - it( - 'Contains null', - check(type, [resolved(1), resolved(null), resolved(2)], { - data: { nest: { test: null } }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }), - ); - - it( - 'Contains reject', - check( - type, - () => [resolved(1), rejected(new Error('bad')), resolved(2)], - { - data: { nest: { test: null } }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }, - ), - ); + expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + data: { listField: null }, + }); + expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + data: null, + errors, }); }); - describe('[T!]!', () => { - const type = GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLInt))); - - describe('Array', () => { - it( - 'Contains values', - check(type, [1, 2], { data: { nest: { test: [1, 2] } } }), - ); - - it( - 'Contains null', - check(type, [1, null, 2], { - data: { nest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }), - ); - - it( - 'Returns null', - check(type, null, { - data: { nest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); + it('Contains error', async () => { + const listField = [1, new Error('bad'), 2]; + const errors = [ + { + message: 'bad', + locations: [{ line: 1, column: 3 }], + path: ['listField', 1], + }, + ]; + + expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ + data: { listField: [1, null, 2] }, + errors, }); - - describe('Promise>', () => { - it( - 'Contains values', - check(type, resolved([1, 2]), { data: { nest: { test: [1, 2] } } }), - ); - - it( - 'Contains null', - check(type, resolved([1, null, 2]), { - data: { nest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }), - ); - - it( - 'Returns null', - check(type, resolved(null), { - data: { nest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); - - it( - 'Rejected', - check(type, () => rejected(new Error('bad')), { - data: { nest: null }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test'], - }, - ], - }), - ); + expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + data: { listField: [1, null, 2] }, + errors, }); + expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + data: { listField: null }, + errors, + }); + expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + data: null, + errors, + }); + }); - describe('Array>', () => { - it( - 'Contains values', - check(type, [resolved(1), resolved(2)], { - data: { nest: { test: [1, 2] } }, - }), - ); - - it( - 'Contains null', - check(type, [resolved(1), resolved(null), resolved(2)], { - data: { nest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.test.', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }), - ); - - it( - 'Contains reject', - check( - type, - () => [resolved(1), rejected(new Error('bad')), resolved(2)], - { - data: { nest: null }, - errors: [ - { - message: 'bad', - locations: [{ line: 1, column: 10 }], - path: ['nest', 'test', 1], - }, - ], - }, - ), - ); + it('Results in error', async () => { + const listField = new Error('bad'); + const errors = [ + { + message: 'bad', + locations: [{ line: 1, column: 3 }], + path: ['listField'], + }, + ]; + + expect(await complete({ listField, as: '[Int]' })).to.deep.equal({ + data: { listField: null }, + errors, + }); + expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({ + data: null, + errors, + }); + expect(await complete({ listField, as: '[Int!]' })).to.deep.equal({ + data: { listField: null }, + errors, + }); + expect(await complete({ listField, as: '[Int!]!' })).to.deep.equal({ + data: null, + errors, }); }); }); diff --git a/src/execution/__tests__/mutations-test.js b/src/execution/__tests__/mutations-test.js index 63b2411394..c9c51296bf 100644 --- a/src/execution/__tests__/mutations-test.js +++ b/src/execution/__tests__/mutations-test.js @@ -1,15 +1,15 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import resolveOnNextTick from '../../__testUtils__/resolveOnNextTick'; + import { parse } from '../../language/parser'; import { GraphQLInt } from '../../type/scalars'; import { GraphQLSchema } from '../../type/schema'; import { GraphQLObjectType } from '../../type/definition'; -import { execute } from '../execute'; +import { execute, executeSync } from '../execute'; class NumberHolder { theNumber: number; @@ -31,24 +31,18 @@ class Root { return this.numberHolder; } - promiseToChangeTheNumber(newNumber: number): Promise { - return new Promise((resolve) => { - process.nextTick(() => { - resolve(this.immediatelyChangeTheNumber(newNumber)); - }); - }); + async promiseToChangeTheNumber(newNumber: number): Promise { + await resolveOnNextTick(); + return this.immediatelyChangeTheNumber(newNumber); } failToChangeTheNumber(): NumberHolder { throw new Error('Cannot change the number'); } - promiseAndFailToChangeTheNumber(): Promise { - return new Promise((_resolve, reject) => { - process.nextTick(() => { - reject(new Error('Cannot change the number')); - }); - }); + async promiseAndFailToChangeTheNumber(): Promise { + await resolveOnNextTick(); + throw new Error('Cannot change the number'); } } @@ -140,7 +134,7 @@ describe('Execute: Handles mutation execution ordering', () => { it('does not include illegal mutation fields in output', () => { const document = parse('mutation { thisIsIllegalDoNotIncludeMe }'); - const result = execute({ schema, document }); + const result = executeSync({ schema, document }); expect(result).to.deep.equal({ data: {}, }); diff --git a/src/execution/__tests__/nonnull-test.js b/src/execution/__tests__/nonnull-test.js index 3312a1b275..4eb38f12b6 100644 --- a/src/execution/__tests__/nonnull-test.js +++ b/src/execution/__tests__/nonnull-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -11,7 +9,8 @@ import { GraphQLNonNull, GraphQLObjectType } from '../../type/definition'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { execute } from '../execute'; +import type { ExecutionResult } from '../execute'; +import { execute, executeSync } from '../execute'; const syncError = new Error('sync'); const syncNonNullError = new Error('syncNonNull'); @@ -105,24 +104,33 @@ const schema = buildSchema(` } `); -function executeQuery(query, rootValue) { +function executeQuery( + query: string, + rootValue: mixed, +): ExecutionResult | Promise { return execute({ schema, document: parse(query), rootValue }); } +function patch(str: string): string { + return str + .replace(/\bsync\b/g, 'promise') + .replace(/\bsyncNonNull\b/g, 'promiseNonNull'); +} + // avoids also doing any nests -function patch(data) { - return JSON.parse( - JSON.stringify(data) - .replace(/\bsync\b/g, 'promise') - .replace(/\bsyncNonNull\b/g, 'promiseNonNull'), - ); +function patchData(data: ExecutionResult): ExecutionResult { + return JSON.parse(patch(JSON.stringify(data))); } -async function executeSyncAndAsync(query, rootValue) { - const syncResult = await executeQuery(query, rootValue); - const asyncResult = await executeQuery(patch(query), rootValue); +async function executeSyncAndAsync(query: string, rootValue: mixed) { + const syncResult = executeSync({ schema, document: parse(query), rootValue }); + const asyncResult = await execute({ + schema, + document: parse(patch(query)), + rootValue, + }); - expect(asyncResult).to.deep.equal(patch(syncResult)); + expect(asyncResult).to.deep.equal(patchData(syncResult)); return syncResult; } @@ -156,7 +164,7 @@ describe('Execute: handles non-nullable types', () => { }); }); - describe('nulls a synchronously returned object that contains a non-nullable field', () => { + describe('nulls a returned object that contains a non-nullable field', () => { const query = ` { syncNest { @@ -195,45 +203,6 @@ describe('Execute: handles non-nullable types', () => { }); }); - describe('nulls an object returned in a promise that contains a non-nullable field', () => { - const query = ` - { - promiseNest { - syncNonNull, - } - } - `; - - it('that returns null', async () => { - const result = await executeSyncAndAsync(query, nullingData); - expect(result).to.deep.equal({ - data: { promiseNest: null }, - errors: [ - { - message: - 'Cannot return null for non-nullable field DataType.syncNonNull.', - path: ['promiseNest', 'syncNonNull'], - locations: [{ line: 4, column: 11 }], - }, - ], - }); - }); - - it('that throws', async () => { - const result = await executeSyncAndAsync(query, throwingData); - expect(result).to.deep.equal({ - data: { promiseNest: null }, - errors: [ - { - message: syncNonNullError.message, - path: ['promiseNest', 'syncNonNull'], - locations: [{ line: 4, column: 11 }], - }, - ], - }); - }); - }); - describe('nulls a complex tree of nullable fields, each', () => { const query = ` { @@ -562,7 +531,7 @@ describe('Execute: handles non-nullable types', () => { type: GraphQLString, args: { cannotBeNull: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), }, }, resolve: (_, args) => 'Passed: ' + String(args.cannotBeNull), @@ -572,7 +541,7 @@ describe('Execute: handles non-nullable types', () => { }); it('succeeds when passed non-null literal value', () => { - const result = execute({ + const result = executeSync({ schema: schemaWithNonNullArg, document: parse(` query { @@ -589,7 +558,7 @@ describe('Execute: handles non-nullable types', () => { }); it('succeeds when passed non-null variable value', () => { - const result = execute({ + const result = executeSync({ schema: schemaWithNonNullArg, document: parse(` query ($testVar: String!) { @@ -609,7 +578,7 @@ describe('Execute: handles non-nullable types', () => { }); it('succeeds when missing variable has default value', () => { - const result = execute({ + const result = executeSync({ schema: schemaWithNonNullArg, document: parse(` query ($testVar: String = "default value") { @@ -631,7 +600,7 @@ describe('Execute: handles non-nullable types', () => { it('field error when missing non-null arg', () => { // Note: validation should identify this issue first (missing args rule) // however execution should still protect against this. - const result = execute({ + const result = executeSync({ schema: schemaWithNonNullArg, document: parse(` query { @@ -658,7 +627,7 @@ describe('Execute: handles non-nullable types', () => { it('field error when non-null arg provided null', () => { // Note: validation should identify this issue first (values of correct // type rule) however execution should still protect against this. - const result = execute({ + const result = executeSync({ schema: schemaWithNonNullArg, document: parse(` query { @@ -685,7 +654,7 @@ describe('Execute: handles non-nullable types', () => { it('field error when non-null arg not provided variable value', () => { // Note: validation should identify this issue first (variables in allowed // position rule) however execution should still protect against this. - const result = execute({ + const result = executeSync({ schema: schemaWithNonNullArg, document: parse(` query ($testVar: String) { @@ -713,7 +682,7 @@ describe('Execute: handles non-nullable types', () => { }); it('field error when non-null arg provided variable with explicit null value', () => { - const result = execute({ + const result = executeSync({ schema: schemaWithNonNullArg, document: parse(` query ($testVar: String = "default value") { diff --git a/src/execution/__tests__/resolve-test.js b/src/execution/__tests__/resolve-test.js index cd1f13b8fb..afe911e7bc 100644 --- a/src/execution/__tests__/resolve-test.js +++ b/src/execution/__tests__/resolve-test.js @@ -1,16 +1,17 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import { parse } from '../../language/parser'; + +import type { GraphQLFieldConfig } from '../../type/definition'; import { GraphQLSchema } from '../../type/schema'; -import { GraphQLObjectType } from '../../type/definition'; import { GraphQLInt, GraphQLString } from '../../type/scalars'; +import { GraphQLObjectType } from '../../type/definition'; -import { graphqlSync } from '../../graphql'; +import { executeSync } from '../execute'; describe('Execute: resolve function', () => { - function testSchema(testField) { + function testSchema(testField: GraphQLFieldConfig) { return new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', @@ -22,9 +23,9 @@ describe('Execute: resolve function', () => { } it('default function accesses properties', () => { - const result = graphqlSync({ + const result = executeSync({ schema: testSchema({ type: GraphQLString }), - source: '{ test }', + document: parse('{ test }'), rootValue: { test: 'testValue' }, }); @@ -43,9 +44,9 @@ describe('Execute: resolve function', () => { }, }; - const result = graphqlSync({ + const result = executeSync({ schema: testSchema({ type: GraphQLString }), - source: '{ test }', + document: parse('{ test }'), rootValue, }); expect(result).to.deep.equal({ @@ -59,12 +60,12 @@ describe('Execute: resolve function', () => { class Adder { _num: number; - constructor(num) { + constructor(num: number) { this._num = num; } - test({ addend1 }, context) { - return this._num + addend1 + context.addend2; + test(args: {| addend1: number |}, context: {| addend2: number |}) { + return this._num + args.addend1 + context.addend2; } } const rootValue = new Adder(700); @@ -76,9 +77,9 @@ describe('Execute: resolve function', () => { }, }); const contextValue = { addend2: 9 }; - const source = '{ test(addend1: 80) }'; + const document = parse('{ test(addend1: 80) }'); - const result = graphqlSync({ schema, source, rootValue, contextValue }); + const result = executeSync({ schema, document, rootValue, contextValue }); expect(result).to.deep.equal({ data: { test: 789 }, }); @@ -94,30 +95,31 @@ describe('Execute: resolve function', () => { resolve: (source, args) => JSON.stringify([source, args]), }); - function execute(source, rootValue, contextValue) { - return graphqlSync({ schema, source, rootValue, contextValue }); + function executeQuery(query: string, rootValue?: mixed) { + const document = parse(query); + return executeSync({ schema, document, rootValue }); } - expect(execute('{ test }')).to.deep.equal({ + expect(executeQuery('{ test }')).to.deep.equal({ data: { test: '[null,{}]', }, }); - expect(execute('{ test }', 'Source!')).to.deep.equal({ + expect(executeQuery('{ test }', 'Source!')).to.deep.equal({ data: { test: '["Source!",{}]', }, }); - expect(execute('{ test(aStr: "String!") }', 'Source!')).to.deep.equal({ + expect(executeQuery('{ test(aStr: "String!") }', 'Source!')).to.deep.equal({ data: { test: '["Source!",{"aStr":"String!"}]', }, }); expect( - execute('{ test(aInt: -123, aStr: "String!") }', 'Source!'), + executeQuery('{ test(aInt: -123, aStr: "String!") }', 'Source!'), ).to.deep.equal({ data: { test: '["Source!",{"aStr":"String!","aInt":-123}]', diff --git a/src/execution/__tests__/schema-test.js b/src/execution/__tests__/schema-test.js index 7c8115ce9c..7da7849c5a 100644 --- a/src/execution/__tests__/schema-test.js +++ b/src/execution/__tests__/schema-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -18,7 +16,7 @@ import { GraphQLBoolean, } from '../../type/scalars'; -import { execute } from '../execute'; +import { executeSync } from '../execute'; describe('Execute: Handles execution with a complex schema', () => { it('executes using a schema', () => { @@ -48,12 +46,12 @@ describe('Execute: Handles execution with a complex schema', () => { const BlogArticle = new GraphQLObjectType({ name: 'Article', fields: { - id: { type: GraphQLNonNull(GraphQLString) }, + id: { type: new GraphQLNonNull(GraphQLString) }, isPublished: { type: GraphQLBoolean }, author: { type: BlogAuthor }, title: { type: GraphQLString }, body: { type: GraphQLString }, - keywords: { type: GraphQLList(GraphQLString) }, + keywords: { type: new GraphQLList(GraphQLString) }, }, }); @@ -66,7 +64,7 @@ describe('Execute: Handles execution with a complex schema', () => { resolve: (_, { id }) => article(id), }, feed: { - type: GraphQLList(BlogArticle), + type: new GraphQLList(BlogArticle), resolve: () => [ article(1), article(2), @@ -87,14 +85,14 @@ describe('Execute: Handles execution with a complex schema', () => { query: BlogQuery, }); - function article(id) { + function article(id: number) { return { id, isPublished: true, author: { id: 123, name: 'John Smith', - pic: (width, height) => getPic(123, width, height), + pic: (width: number, height: number) => getPic(123, width, height), recentArticle: () => article(1), }, title: 'My Article ' + id, @@ -104,7 +102,7 @@ describe('Execute: Handles execution with a complex schema', () => { }; } - function getPic(uid, width, height) { + function getPic(uid: number, width: number, height: number) { return { url: `cdn://${uid}`, width: `${width}`, @@ -148,7 +146,7 @@ describe('Execute: Handles execution with a complex schema', () => { // Note: this is intentionally not validating to ensure appropriate // behavior occurs when executing an invalid query. - expect(execute({ schema: BlogSchema, document })).to.deep.equal({ + expect(executeSync({ schema: BlogSchema, document })).to.deep.equal({ data: { feed: [ { id: '1', title: 'My Article 1' }, diff --git a/src/execution/__tests__/sync-test.js b/src/execution/__tests__/sync-test.js index 4c12f1fb24..184a259b69 100644 --- a/src/execution/__tests__/sync-test.js +++ b/src/execution/__tests__/sync-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -13,7 +11,7 @@ import { GraphQLObjectType } from '../../type/definition'; import { graphqlSync } from '../../graphql'; -import { execute } from '../execute'; +import { execute, executeSync } from '../execute'; describe('Execute: synchronously when possible', () => { const schema = new GraphQLSchema({ @@ -92,6 +90,29 @@ describe('Execute: synchronously when possible', () => { }); }); + describe('executeSync', () => { + it('does not return a Promise for sync execution', () => { + const doc = 'query Example { syncField }'; + const result = executeSync({ + schema, + document: parse(doc), + rootValue: 'rootValue', + }); + expect(result).to.deep.equal({ data: { syncField: 'rootValue' } }); + }); + + it('throws if encountering async execution', () => { + const doc = 'query Example { syncField, asyncField }'; + expect(() => { + executeSync({ + schema, + document: parse(doc), + rootValue: 'rootValue', + }); + }).to.throw('GraphQL execution failed to complete synchronously.'); + }); + }); + describe('graphqlSync', () => { it('report errors raised during schema validation', () => { const badSchema = new GraphQLSchema({}); diff --git a/src/execution/__tests__/union-interface-test.js b/src/execution/__tests__/union-interface-test.js index 39e2518a4f..1d750d273d 100644 --- a/src/execution/__tests__/union-interface-test.js +++ b/src/execution/__tests__/union-interface-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -11,25 +9,23 @@ import { GraphQLSchema } from '../../type/schema'; import { GraphQLString, GraphQLBoolean } from '../../type/scalars'; import { GraphQLList, + GraphQLUnionType, GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, } from '../../type/definition'; -import { execute } from '../execute'; +import { executeSync } from '../execute'; class Dog { name: string; barks: boolean; - mother: ?Dog; - father: ?Dog; + mother: Dog | void; + father: Dog | void; progeny: Array; - constructor(name, barks) { + constructor(name: string, barks: boolean) { this.name = name; this.barks = barks; - this.mother = null; - this.father = null; this.progeny = []; } } @@ -37,25 +33,27 @@ class Dog { class Cat { name: string; meows: boolean; - mother: ?Cat; - father: ?Cat; + mother: Cat | void; + father: Cat | void; progeny: Array; - constructor(name, meows) { + constructor(name: string, meows: boolean) { this.name = name; this.meows = meows; - this.mother = null; - this.father = null; this.progeny = []; } } class Person { name: string; - pets: ?Array; - friends: ?Array; - - constructor(name, pets, friends) { + pets: Array | void; + friends: Array | void; + + constructor( + name: string, + pets?: Array, + friends?: Array | void, + ) { this.name = name; this.pets = pets; this.friends = friends; @@ -72,7 +70,7 @@ const NamedType = new GraphQLInterfaceType({ const LifeType = new GraphQLInterfaceType({ name: 'Life', fields: () => ({ - progeny: { type: GraphQLList(LifeType) }, + progeny: { type: new GraphQLList(LifeType) }, }), }); @@ -80,7 +78,7 @@ const MammalType = new GraphQLInterfaceType({ name: 'Mammal', interfaces: [LifeType], fields: () => ({ - progeny: { type: GraphQLList(MammalType) }, + progeny: { type: new GraphQLList(MammalType) }, mother: { type: MammalType }, father: { type: MammalType }, }), @@ -92,7 +90,7 @@ const DogType = new GraphQLObjectType({ fields: () => ({ name: { type: GraphQLString }, barks: { type: GraphQLBoolean }, - progeny: { type: GraphQLList(DogType) }, + progeny: { type: new GraphQLList(DogType) }, mother: { type: DogType }, father: { type: DogType }, }), @@ -105,7 +103,7 @@ const CatType = new GraphQLObjectType({ fields: () => ({ name: { type: GraphQLString }, meows: { type: GraphQLBoolean }, - progeny: { type: GraphQLList(CatType) }, + progeny: { type: new GraphQLList(CatType) }, mother: { type: CatType }, father: { type: CatType }, }), @@ -117,13 +115,14 @@ const PetType = new GraphQLUnionType({ types: [DogType, CatType], resolveType(value) { if (value instanceof Dog) { - return DogType; + return DogType.name; } + // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (value instanceof Cat) { - return CatType; + return CatType.name; } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false); }, }); @@ -133,9 +132,9 @@ const PersonType = new GraphQLObjectType({ interfaces: [NamedType, MammalType, LifeType], fields: () => ({ name: { type: GraphQLString }, - pets: { type: GraphQLList(PetType) }, - friends: { type: GraphQLList(NamedType) }, - progeny: { type: GraphQLList(PersonType) }, + pets: { type: new GraphQLList(PetType) }, + friends: { type: new GraphQLList(NamedType) }, + progeny: { type: new GraphQLList(PersonType) }, mother: { type: PersonType }, father: { type: PersonType }, }), @@ -192,7 +191,7 @@ describe('Execute: Union and intersection types', () => { } `); - expect(execute({ schema, document })).to.deep.equal({ + expect(executeSync({ schema, document })).to.deep.equal({ data: { Named: { kind: 'INTERFACE', @@ -240,7 +239,7 @@ describe('Execute: Union and intersection types', () => { } `); - expect(execute({ schema, document, rootValue: john })).to.deep.equal({ + expect(executeSync({ schema, document, rootValue: john })).to.deep.equal({ data: { __typename: 'Person', name: 'John', @@ -280,7 +279,7 @@ describe('Execute: Union and intersection types', () => { } `); - expect(execute({ schema, document, rootValue: john })).to.deep.equal({ + expect(executeSync({ schema, document, rootValue: john })).to.deep.equal({ data: { __typename: 'Person', name: 'John', @@ -315,7 +314,7 @@ describe('Execute: Union and intersection types', () => { } `); - expect(execute({ schema, document, rootValue: john })).to.deep.equal({ + expect(executeSync({ schema, document, rootValue: john })).to.deep.equal({ data: { __typename: 'Person', name: 'John', @@ -360,7 +359,7 @@ describe('Execute: Union and intersection types', () => { } `); - expect(execute({ schema, document, rootValue: john })).to.deep.equal({ + expect(executeSync({ schema, document, rootValue: john })).to.deep.equal({ data: { __typename: 'Person', name: 'John', @@ -403,7 +402,7 @@ describe('Execute: Union and intersection types', () => { } `); - expect(execute({ schema, document, rootValue: john })).to.deep.equal({ + expect(executeSync({ schema, document, rootValue: john })).to.deep.equal({ data: { __typename: 'Person', name: 'John', @@ -468,7 +467,7 @@ describe('Execute: Union and intersection types', () => { } `); - expect(execute({ schema, document, rootValue: john })).to.deep.equal({ + expect(executeSync({ schema, document, rootValue: john })).to.deep.equal({ data: { __typename: 'Person', name: 'John', @@ -515,7 +514,7 @@ describe('Execute: Union and intersection types', () => { encounteredContext = context; encounteredSchema = info.schema; encounteredRootValue = info.rootValue; - return PersonType2; + return PersonType2.name; }, }); @@ -524,7 +523,7 @@ describe('Execute: Union and intersection types', () => { interfaces: [NamedType2], fields: { name: { type: GraphQLString }, - friends: { type: GraphQLList(NamedType2) }, + friends: { type: new GraphQLList(NamedType2) }, }, }); const schema2 = new GraphQLSchema({ query: PersonType2 }); @@ -532,7 +531,7 @@ describe('Execute: Union and intersection types', () => { const rootValue = new Person('John', [], [liz]); const contextValue = { authToken: '123abc' }; - const result = execute({ + const result = executeSync({ schema: schema2, document, rootValue, diff --git a/src/execution/__tests__/variables-test.js b/src/execution/__tests__/variables-test.js index f0ce6253a5..9f637dd7ed 100644 --- a/src/execution/__tests__/variables-test.js +++ b/src/execution/__tests__/variables-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -9,6 +7,7 @@ import invariant from '../../jsutils/invariant'; 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 { @@ -20,7 +19,7 @@ import { GraphQLEnumType, } from '../../type/definition'; -import { execute } from '../execute'; +import { executeSync } from '../execute'; import { getVariableValues } from '../values'; const TestComplexScalar = new GraphQLScalarType({ @@ -39,8 +38,8 @@ const TestInputObject = new GraphQLInputObjectType({ name: 'TestInputObject', fields: { a: { type: GraphQLString }, - b: { type: GraphQLList(GraphQLString) }, - c: { type: GraphQLNonNull(GraphQLString) }, + b: { type: new GraphQLList(GraphQLString) }, + c: { type: new GraphQLNonNull(GraphQLString) }, d: { type: TestComplexScalar }, }, }); @@ -48,8 +47,8 @@ const TestInputObject = new GraphQLInputObjectType({ const TestNestedInputObject = new GraphQLInputObjectType({ name: 'TestNestedInputObject', fields: { - na: { type: GraphQLNonNull(TestInputObject) }, - nb: { type: GraphQLNonNull(GraphQLString) }, + na: { type: new GraphQLNonNull(TestInputObject) }, + nb: { type: new GraphQLNonNull(GraphQLString) }, }, }); @@ -65,7 +64,7 @@ const TestEnum = new GraphQLEnumType({ }, }); -function fieldWithInputArg(inputArg) { +function fieldWithInputArg(inputArg: GraphQLArgumentConfig) { return { type: GraphQLString, args: { input: inputArg }, @@ -82,43 +81,48 @@ const TestType = new GraphQLObjectType({ fields: { fieldWithEnumInput: fieldWithInputArg({ type: TestEnum }), fieldWithNonNullableEnumInput: fieldWithInputArg({ - type: GraphQLNonNull(TestEnum), + type: new GraphQLNonNull(TestEnum), }), fieldWithObjectInput: fieldWithInputArg({ type: TestInputObject }), fieldWithNullableStringInput: fieldWithInputArg({ type: GraphQLString }), fieldWithNonNullableStringInput: fieldWithInputArg({ - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), }), fieldWithDefaultArgumentValue: fieldWithInputArg({ type: GraphQLString, defaultValue: 'Hello World', }), fieldWithNonNullableStringInputAndDefaultArgumentValue: fieldWithInputArg({ - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), defaultValue: 'Hello World', }), fieldWithNestedInputObject: fieldWithInputArg({ type: TestNestedInputObject, defaultValue: 'Hello World', }), - list: fieldWithInputArg({ type: GraphQLList(GraphQLString) }), + list: fieldWithInputArg({ type: new GraphQLList(GraphQLString) }), nnList: fieldWithInputArg({ - type: GraphQLNonNull(GraphQLList(GraphQLString)), + type: new GraphQLNonNull(new GraphQLList(GraphQLString)), }), listNN: fieldWithInputArg({ - type: GraphQLList(GraphQLNonNull(GraphQLString)), + type: new GraphQLList(new GraphQLNonNull(GraphQLString)), }), nnListNN: fieldWithInputArg({ - type: GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))), + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(GraphQLString)), + ), }), }, }); const schema = new GraphQLSchema({ query: TestType }); -function executeQuery(query, variableValues) { +function executeQuery( + query: string, + variableValues?: { [variable: string]: mixed, ... }, +) { const document = parse(query); - return execute({ schema, document, variableValues }); + return executeSync({ schema, document, variableValues }); } describe('Execute: Handles inputs', () => { @@ -1010,7 +1014,7 @@ describe('Execute: Handles inputs', () => { const inputValue = { input: [0, 1, 2] }; - function invalidValueError(value, index) { + function invalidValueError(value: number, index: number) { return { message: `Variable "$input" got invalid value ${value} at "input[${index}]"; String cannot represent a non string value: ${value}`, locations: [{ line: 2, column: 14 }], diff --git a/src/execution/execute.d.ts b/src/execution/execute.d.ts index 46a1bc60e5..a20db8c224 100644 --- a/src/execution/execute.d.ts +++ b/src/execution/execute.d.ts @@ -1,8 +1,10 @@ -import Maybe from '../tsutils/Maybe'; +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, @@ -42,13 +44,29 @@ export interface ExecutionContext { * * - `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 { +export interface ExecutionResult< + TData = { [key: string]: any }, + TExtensions = { [key: string]: any } +> { errors?: ReadonlyArray; - data?: { [key: string]: any } | null; + // 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 type ExecutionArgs = { +export interface ExecutionArgs { schema: GraphQLSchema; document: DocumentNode; rootValue?: any; @@ -57,7 +75,7 @@ export type ExecutionArgs = { operationName?: Maybe; fieldResolver?: Maybe>; typeResolver?: Maybe>; -}; +} /** * Implements the "Evaluating requests" section of the GraphQL specification. @@ -83,6 +101,13 @@ export function execute( 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. @@ -134,21 +159,6 @@ export function buildResolveInfo( path: Path, ): GraphQLResolveInfo; -/** - * Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField` - * function. Returns the result of resolveFn or the abrupt-return Error object. - * - * @internal - */ -export function resolveFieldValueOrError( - exeContext: ExecutionContext, - fieldDef: GraphQLField, - fieldNodes: ReadonlyArray, - resolveFn: GraphQLFieldResolver, - source: any, - info: GraphQLResolveInfo, -): Error | any; - /** * If a resolveType function is not given, then a default resolve behavior is * used which attempts two strategies: diff --git a/src/execution/execute.js b/src/execution/execute.js index a78df7729a..f272b65aef 100644 --- a/src/execution/execute.js +++ b/src/execution/execute.js @@ -1,36 +1,47 @@ -// @flow strict - import arrayFrom from '../polyfills/arrayFrom'; +import type { Path } from '../jsutils/Path'; +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 { type ObjMap } from '../jsutils/ObjMap'; import isObjectLike from '../jsutils/isObjectLike'; import isCollection from '../jsutils/isCollection'; import promiseReduce from '../jsutils/promiseReduce'; import promiseForObject from '../jsutils/promiseForObject'; -import { type PromiseOrValue } from '../jsutils/PromiseOrValue'; -import { type Path, addPath, pathToArray } from '../jsutils/Path'; +import { addPath, pathToArray } from '../jsutils/Path'; +import type { GraphQLFormattedError } from '../error/formatError'; import { GraphQLError } from '../error/GraphQLError'; import { locatedError } from '../error/locatedError'; -import { Kind } from '../language/kinds'; -import { - type DocumentNode, - type OperationDefinitionNode, - type SelectionSetNode, - type FieldNode, - type FragmentSpreadNode, - type InlineFragmentNode, - type FragmentDefinitionNode, +import type { + DocumentNode, + OperationDefinitionNode, + SelectionSetNode, + FieldNode, + FragmentSpreadNode, + InlineFragmentNode, + FragmentDefinitionNode, } from '../language/ast'; +import { Kind } from '../language/kinds'; +import type { GraphQLSchema } from '../type/schema'; +import type { + GraphQLObjectType, + GraphQLOutputType, + GraphQLLeafType, + GraphQLAbstractType, + GraphQLField, + GraphQLFieldResolver, + GraphQLResolveInfo, + GraphQLTypeResolver, + GraphQLList, +} from '../type/definition'; import { assertValidSchema } from '../type/validate'; -import { type GraphQLSchema } from '../type/schema'; import { SchemaMetaFieldDef, TypeMetaFieldDef, @@ -41,15 +52,7 @@ import { GraphQLSkipDirective, } from '../type/directives'; import { - type GraphQLObjectType, - type GraphQLOutputType, - type GraphQLLeafType, - type GraphQLAbstractType, - type GraphQLField, - type GraphQLFieldResolver, - type GraphQLResolveInfo, - type GraphQLTypeResolver, - type GraphQLList, + isNamedType, isObjectType, isAbstractType, isLeafType, @@ -109,10 +112,18 @@ export type ExecutionContext = {| * * - `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 type ExecutionResult = {| errors?: $ReadOnlyArray, data?: ObjMap | null, + extensions?: ObjMap, +|}; + +export type FormattedExecutionResult = {| + errors?: $ReadOnlyArray, + data?: ObjMap | null, + extensions?: ObjMap, |}; export type ExecutionArgs = {| @@ -179,6 +190,22 @@ export function execute( }); } +/** + * 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; +} + function executeImpl(args: ExecutionArgs): PromiseOrValue { const { schema, @@ -311,7 +338,7 @@ export function buildExecutionContext( return [new GraphQLError('Must provide an operation.')]; } - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const variableDefinitions = operation.variableDefinitions ?? []; const coercedVariableValues = getVariableValues( @@ -360,8 +387,6 @@ function executeOperation( // 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. - // - // Similar to completeValueCatchingError. try { const result = operation.operation === 'mutation' @@ -395,7 +420,7 @@ function executeFieldsSerially( Object.keys(fields), (results, responseName) => { const fieldNodes = fields[responseName]; - const fieldPath = addPath(path, responseName); + const fieldPath = addPath(path, responseName, parentType.name); const result = resolveField( exeContext, parentType, @@ -435,7 +460,7 @@ function executeFields( for (const responseName of Object.keys(fields)) { const fieldNodes = fields[responseName]; - const fieldPath = addPath(path, responseName); + const fieldPath = addPath(path, responseName, parentType.name); const result = resolveField( exeContext, parentType, @@ -446,7 +471,7 @@ function executeFields( if (result !== undefined) { results[responseName] = result; - if (!containsPromise && isPromise(result)) { + if (isPromise(result)) { containsPromise = true; } } @@ -617,6 +642,7 @@ function resolveField( return; } + const returnType = fieldDef.type; const resolveFn = fieldDef.resolve ?? exeContext.fieldResolver; const info = buildResolveInfo( @@ -627,67 +653,7 @@ function resolveField( path, ); - // Get the resolve function, regardless of if its result is normal - // or abrupt (error). - const result = resolveFieldValueOrError( - exeContext, - fieldDef, - fieldNodes, - resolveFn, - source, - info, - ); - - return completeValueCatchingError( - exeContext, - fieldDef.type, - fieldNodes, - info, - path, - result, - ); -} - -/** - * @internal - */ -export function buildResolveInfo( - exeContext: ExecutionContext, - fieldDef: GraphQLField, - fieldNodes: $ReadOnlyArray, - parentType: GraphQLObjectType, - path: Path, -): GraphQLResolveInfo { - // The resolve function's optional fourth argument is a collection of - // information about the current execution state. - return { - fieldName: fieldDef.name, - fieldNodes, - returnType: fieldDef.type, - parentType, - path, - schema: exeContext.schema, - fragments: exeContext.fragments, - rootValue: exeContext.rootValue, - operation: exeContext.operation, - variableValues: exeContext.variableValues, - }; -} - -/** - * Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField` - * function. Returns the result of resolveFn or the abrupt-return Error object. - * - * @internal - */ -export function resolveFieldValueOrError( - exeContext: ExecutionContext, - fieldDef: GraphQLField, - fieldNodes: $ReadOnlyArray, - resolveFn: GraphQLFieldResolver, - source: mixed, - info: GraphQLResolveInfo, -): Error | mixed { + // Get the resolve function, regardless of if its result is normal or abrupt (error). try { // Build a JS object of arguments from the field.arguments AST, using the // variables scope to fulfill any variable references. @@ -704,32 +670,7 @@ export function resolveFieldValueOrError( const contextValue = exeContext.contextValue; const result = resolveFn(source, args, contextValue, info); - return isPromise(result) ? result.then(undefined, asErrorInstance) : result; - } catch (error) { - return asErrorInstance(error); - } -} -// Sometimes a non-error is thrown, wrap it as an Error instance to ensure a -// consistent Error interface. -function asErrorInstance(error: mixed): Error { - if (error instanceof Error) { - return error; - } - return new Error('Unexpected error value: ' + inspect(error)); -} - -// This is a small wrapper around completeValue which detects and logs errors -// in the execution context. -function completeValueCatchingError( - exeContext: ExecutionContext, - returnType: GraphQLOutputType, - fieldNodes: $ReadOnlyArray, - info: GraphQLResolveInfo, - path: Path, - result: mixed, -): PromiseOrValue { - try { let completed; if (isPromise(result)) { completed = result.then((resolved) => @@ -749,23 +690,49 @@ function completeValueCatchingError( if (isPromise(completed)) { // Note: we don't rely on a `catch` method, but we do expect "thenable" // to take a second callback for the error case. - return completed.then(undefined, (error) => - handleFieldError(error, fieldNodes, path, returnType, exeContext), - ); + return completed.then(undefined, (rawError) => { + const error = locatedError(rawError, fieldNodes, pathToArray(path)); + return handleFieldError(error, returnType, exeContext); + }); } return completed; - } catch (error) { - return handleFieldError(error, fieldNodes, path, returnType, exeContext); + } catch (rawError) { + const error = locatedError(rawError, fieldNodes, pathToArray(path)); + return handleFieldError(error, returnType, exeContext); } } -function handleFieldError(rawError, fieldNodes, path, returnType, exeContext) { - const error = locatedError( - asErrorInstance(rawError), +/** + * @internal + */ +export function buildResolveInfo( + exeContext: ExecutionContext, + fieldDef: GraphQLField, + fieldNodes: $ReadOnlyArray, + parentType: GraphQLObjectType, + path: Path, +): GraphQLResolveInfo { + // The resolve function's optional fourth argument is a collection of + // information about the current execution state. + return { + fieldName: fieldDef.name, fieldNodes, - pathToArray(path), - ); + returnType: fieldDef.type, + parentType, + path, + schema: exeContext.schema, + fragments: exeContext.fragments, + rootValue: exeContext.rootValue, + operation: exeContext.operation, + variableValues: exeContext.variableValues, + }; +} +function handleFieldError( + error: GraphQLError, + returnType: GraphQLOutputType, + exeContext: ExecutionContext, +): null { // If the field type is non-nullable, then it is resolved without any // protection from errors, however it still properly locates the error. if (isNonNullType(returnType)) { @@ -868,6 +835,7 @@ 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, @@ -879,7 +847,7 @@ function completeValue( ); } - // Not reachable. All possible output types have been considered. + // istanbul ignore next (Not reachable. All possible output types have been considered) invariant( false, 'Cannot complete value of unexpected output type: ' + @@ -912,21 +880,49 @@ function completeListValue( const completedResults = arrayFrom(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 fieldPath = addPath(path, index); - const completedItem = completeValueCatchingError( - exeContext, - itemType, - fieldNodes, - info, - fieldPath, - item, - ); + const itemPath = addPath(path, index, undefined); + try { + let completedItem; + if (isPromise(item)) { + completedItem = item.then((resolved) => + completeValue( + exeContext, + itemType, + fieldNodes, + info, + itemPath, + resolved, + ), + ); + } else { + completedItem = completeValue( + exeContext, + itemType, + fieldNodes, + info, + itemPath, + item, + ); + } - if (!containsPromise && isPromise(completedItem)) { - containsPromise = true; + if (isPromise(completedItem)) { + containsPromise = true; + // Note: we don't rely on a `catch` method, but we do expect "thenable" + // to take a second callback for the error case. + return completedItem.then(undefined, (rawError) => { + const error = locatedError( + rawError, + fieldNodes, + pathToArray(itemPath), + ); + return handleFieldError(error, itemType, exeContext); + }); + } + return completedItem; + } catch (rawError) { + const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); + return handleFieldError(error, itemType, exeContext); } - - return completedItem; }); return containsPromise ? Promise.all(completedResults) : completedResults; @@ -1001,23 +997,43 @@ function completeAbstractValue( } function ensureValidRuntimeType( - runtimeTypeOrName: ?GraphQLObjectType | string, + runtimeTypeOrName: mixed, exeContext: ExecutionContext, returnType: GraphQLAbstractType, fieldNodes: $ReadOnlyArray, info: GraphQLResolveInfo, result: mixed, ): GraphQLObjectType { - const runtimeType = - typeof runtimeTypeOrName === 'string' - ? exeContext.schema.getType(runtimeTypeOrName) - : runtimeTypeOrName; + if (runtimeTypeOrName == 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, + ); + } - if (!isObjectType(runtimeType)) { + // FIXME: temporary workaround until support for passing object types would be removed in v16.0.0 + const runtimeTypeName = isNamedType(runtimeTypeOrName) + ? runtimeTypeOrName.name + : runtimeTypeOrName; + + 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(runtimeType)}". ` + - `Either the "${returnType.name}" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.`, + `value ${inspect(result)}, received "${inspect(runtimeTypeOrName)}".`, + ); + } + + 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, + ); + } + + if (!isObjectType(runtimeType)) { + throw new GraphQLError( + `Abstract type "${returnType.name}" was resolve to a non-object type "${runtimeTypeName}".`, fieldNodes, ); } @@ -1162,7 +1178,7 @@ export const defaultTypeResolver: GraphQLTypeResolver = function ( if (isPromise(isTypeOfResult)) { promisedIsTypeOfResults[i] = isTypeOfResult; } else if (isTypeOfResult) { - return type; + return type.name; } } } @@ -1171,7 +1187,7 @@ export const defaultTypeResolver: GraphQLTypeResolver = function ( return Promise.all(promisedIsTypeOfResults).then((isTypeOfResults) => { for (let i = 0; i < isTypeOfResults.length; i++) { if (isTypeOfResults[i]) { - return possibleTypes[i]; + return possibleTypes[i].name; } } }); @@ -1200,12 +1216,12 @@ 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. + * It has special casing for the three introspection fields, + * __schema, __type 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 and __type + * could get automatically added to the query type, but that would + * require mutating type definitions, which would cause issues. * * @internal */ diff --git a/src/execution/index.d.ts b/src/execution/index.d.ts index ed0f8f1808..d70ba3aaa5 100644 --- a/src/execution/index.d.ts +++ b/src/execution/index.d.ts @@ -2,10 +2,12 @@ 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.js index c7ffa5cdef..5ae0706ec9 100644 --- a/src/execution/index.js +++ b/src/execution/index.js @@ -1,8 +1,16 @@ -// @flow strict - export { pathToArray as responsePathAsArray } from '../jsutils/Path'; -export { execute, defaultFieldResolver, defaultTypeResolver } from './execute'; -export type { ExecutionArgs, ExecutionResult } from './execute'; +export { + execute, + executeSync, + defaultFieldResolver, + defaultTypeResolver, +} from './execute'; + +export type { + ExecutionArgs, + ExecutionResult, + FormattedExecutionResult, +} from './execute'; export { getDirectiveValues } from './values'; diff --git a/src/execution/values.d.ts b/src/execution/values.d.ts index 82e2ce8cbe..8b17b5487a 100644 --- a/src/execution/values.d.ts +++ b/src/execution/values.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { GraphQLError } from '../error/GraphQLError'; import { FieldNode, diff --git a/src/execution/values.js b/src/execution/values.js index aaafd51d95..cfe9a4e0d7 100644 --- a/src/execution/values.js +++ b/src/execution/values.js @@ -1,29 +1,24 @@ -// @flow strict - import find from '../polyfills/find'; +import type { ObjMap } from '../jsutils/ObjMap'; import keyMap from '../jsutils/keyMap'; import inspect from '../jsutils/inspect'; -import { type ObjMap } from '../jsutils/ObjMap'; import printPathArray from '../jsutils/printPathArray'; import { GraphQLError } from '../error/GraphQLError'; +import type { + FieldNode, + DirectiveNode, + VariableDefinitionNode, +} from '../language/ast'; import { Kind } from '../language/kinds'; import { print } from '../language/printer'; -import { - type FieldNode, - type DirectiveNode, - type VariableDefinitionNode, -} from '../language/ast'; -import { type GraphQLSchema } from '../type/schema'; -import { type GraphQLDirective } from '../type/directives'; -import { - type GraphQLField, - isInputType, - isNonNullType, -} from '../type/definition'; +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 { typeFromAST } from '../utilities/typeFromAST'; import { valueFromAST } from '../utilities/valueFromAST'; @@ -170,7 +165,7 @@ export function getArgumentValues( ): { [argument: string]: mixed, ... } { const coercedValues = {}; - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const argumentNodes = node.arguments ?? []; const argNodeMap = keyMap(argumentNodes, (arg) => arg.name.value); diff --git a/src/graphql.d.ts b/src/graphql.d.ts index c4ef398ba9..8ba8ef72c8 100644 --- a/src/graphql.d.ts +++ b/src/graphql.d.ts @@ -1,4 +1,5 @@ -import Maybe from './tsutils/Maybe'; +import { Maybe } from './jsutils/Maybe'; + import { Source } from './language/source'; import { GraphQLSchema } from './type/schema'; import { GraphQLFieldResolver, GraphQLTypeResolver } from './type/definition'; diff --git a/src/graphql.js b/src/graphql.js index 5a82d4e444..da9428086d 100644 --- a/src/graphql.js +++ b/src/graphql.js @@ -1,21 +1,20 @@ -// @flow strict - +import type { PromiseOrValue } from './jsutils/PromiseOrValue'; import isPromise from './jsutils/isPromise'; -import { type PromiseOrValue } from './jsutils/PromiseOrValue'; +import type { Source } from './language/source'; import { parse } from './language/parser'; -import { type Source } from './language/source'; import { validate } from './validation/validate'; -import { validateSchema } from './type/validate'; -import { type GraphQLSchema } from './type/schema'; -import { - type GraphQLFieldResolver, - type GraphQLTypeResolver, +import type { + GraphQLFieldResolver, + GraphQLTypeResolver, } from './type/definition'; +import type { GraphQLSchema } from './type/schema'; +import { validateSchema } from './type/validate'; -import { type ExecutionResult, execute } from './execution/execute'; +import type { ExecutionResult } from './execution/execute'; +import { execute } from './execution/execute'; /** * This is the primary entry point function for fulfilling GraphQL operations diff --git a/src/index.d.ts b/src/index.d.ts index f3181728f3..0776078b8b 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -55,6 +55,7 @@ export { GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, + GraphQLSpecifiedByDirective, // "Enum" of Type Kinds TypeKind, // Constant Deprecation Reason @@ -138,32 +139,44 @@ export { GraphQLNamedType, Thunk, GraphQLSchemaConfig, + GraphQLSchemaExtensions, GraphQLDirectiveConfig, + GraphQLDirectiveExtensions, GraphQLArgument, GraphQLArgumentConfig, + GraphQLArgumentExtensions, GraphQLEnumTypeConfig, + GraphQLEnumTypeExtensions, GraphQLEnumValue, GraphQLEnumValueConfig, + GraphQLEnumValueExtensions, GraphQLEnumValueConfigMap, GraphQLField, GraphQLFieldConfig, + GraphQLFieldExtensions, GraphQLFieldConfigArgumentMap, GraphQLFieldConfigMap, GraphQLFieldMap, GraphQLFieldResolver, GraphQLInputField, GraphQLInputFieldConfig, + GraphQLInputFieldExtensions, GraphQLInputFieldConfigMap, GraphQLInputFieldMap, GraphQLInputObjectTypeConfig, + GraphQLInputObjectTypeExtensions, GraphQLInterfaceTypeConfig, + GraphQLInterfaceTypeExtensions, GraphQLIsTypeOfFn, GraphQLObjectTypeConfig, + GraphQLObjectTypeExtensions, GraphQLResolveInfo, ResponsePath, GraphQLScalarTypeConfig, + GraphQLScalarTypeExtensions, GraphQLTypeResolver, GraphQLUnionTypeConfig, + GraphQLUnionTypeExtensions, GraphQLScalarSerializer, GraphQLScalarValueParser, GraphQLScalarLiteralParser, @@ -171,7 +184,9 @@ export { // Parse and operate on GraphQL language source files. export { + Token, Source, + Location, getLocation, // Print source location printLocation, @@ -207,8 +222,6 @@ export { export { ParseOptions, SourceLocation, - Location, - Token, TokenKindEnum, KindEnum, DirectiveLocationEnum, @@ -279,12 +292,14 @@ export { // Execute GraphQL queries. export { execute, + executeSync, defaultFieldResolver, defaultTypeResolver, responsePathAsArray, getDirectiveValues, ExecutionArgs, ExecutionResult, + FormattedExecutionResult, } from './execution/index'; export { @@ -334,6 +349,9 @@ export { UniqueFieldDefinitionNamesRule, UniqueDirectiveNamesRule, PossibleTypeExtensionsRule, + // Custom validation rules + NoDeprecatedCustomRule, + NoSchemaIntrospectionCustomRule, ValidationRule, } from './validation/index'; @@ -413,7 +431,7 @@ export { DangerousChangeType, findBreakingChanges, findDangerousChanges, - // Report all deprecated usage within a GraphQL document. + // @deprecated: Report all deprecated usage within a GraphQL document. findDeprecatedUsages, } from './utilities/index'; @@ -443,4 +461,5 @@ export { BuildSchemaOptions, BreakingChange, DangerousChange, + TypedQueryDocumentNode, } from './utilities/index'; diff --git a/src/index.js b/src/index.js index e92c936595..104ab88658 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,3 @@ -// @flow strict - /** * GraphQL.js provides a reference implementation for the GraphQL specification * but is also a useful utility for operating on GraphQL files and building @@ -56,6 +54,7 @@ export { GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, + GraphQLSpecifiedByDirective, // "Enum" of Type Kinds TypeKind, // Constant Deprecation Reason @@ -172,7 +171,9 @@ export type { // Parse and operate on GraphQL language source files. export { + Token, Source, + Location, getLocation, // Print source location printLocation, @@ -208,8 +209,6 @@ export { export type { ParseOptions, SourceLocation, - Location, - Token, TokenKindEnum, KindEnum, DirectiveLocationEnum, @@ -280,13 +279,18 @@ export type { // Execute GraphQL queries. export { execute, + executeSync, defaultFieldResolver, defaultTypeResolver, responsePathAsArray, getDirectiveValues, } from './execution/index'; -export type { ExecutionArgs, ExecutionResult } from './execution/index'; +export type { + ExecutionArgs, + ExecutionResult, + FormattedExecutionResult, +} from './execution/index'; export { subscribe, createSourceEventStream } from './subscription/index'; export type { SubscriptionArgs } from './subscription/index'; @@ -332,6 +336,9 @@ export { UniqueFieldDefinitionNamesRule, UniqueDirectiveNamesRule, PossibleTypeExtensionsRule, + // Custom validation rules + NoDeprecatedCustomRule, + NoSchemaIntrospectionCustomRule, } from './validation/index'; export type { ValidationRule } from './validation/index'; @@ -413,7 +420,7 @@ export { DangerousChangeType, findBreakingChanges, findDangerousChanges, - // Report all deprecated usage within a GraphQL document. + // @deprecated: Report all deprecated usage within a GraphQL document. findDeprecatedUsages, } from './utilities/index'; diff --git a/src/jsutils/Maybe.d.ts b/src/jsutils/Maybe.d.ts new file mode 100644 index 0000000000..e8b5e217d0 --- /dev/null +++ b/src/jsutils/Maybe.d.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 index 63a8251084..9b6ef5e16e 100644 --- a/src/jsutils/ObjMap.js +++ b/src/jsutils/ObjMap.js @@ -1,5 +1,3 @@ -// @flow strict - export type ObjMap = { [key: string]: T, __proto__: null, ... }; export type ObjMapLike = ObjMap | { [key: string]: T, ... }; diff --git a/src/jsutils/Path.d.ts b/src/jsutils/Path.d.ts index ef8f10a510..9a2233dd60 100644 --- a/src/jsutils/Path.d.ts +++ b/src/jsutils/Path.d.ts @@ -1,12 +1,17 @@ -export type Path = { +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): Path; +export function addPath( + prev: Path | undefined, + key: string | number, + typename: string | undefined, +): Path; /** * Given a Path, return an Array of the path keys. diff --git a/src/jsutils/Path.js b/src/jsutils/Path.js index f477354e07..47e8c7693c 100644 --- a/src/jsutils/Path.js +++ b/src/jsutils/Path.js @@ -1,8 +1,7 @@ -// @flow strict - export type Path = {| +prev: Path | void, +key: string | number, + +typename: string | void, |}; /** @@ -11,8 +10,9 @@ export type Path = {| export function addPath( prev: $ReadOnly | void, key: string | number, + typename: string | void, ): Path { - return { prev, key }; + return { prev, key, typename }; } /** diff --git a/src/jsutils/PromiseOrValue.js b/src/jsutils/PromiseOrValue.js index 2d37412289..e493c87e06 100644 --- a/src/jsutils/PromiseOrValue.js +++ b/src/jsutils/PromiseOrValue.js @@ -1,3 +1 @@ -// @flow strict - export type PromiseOrValue<+T> = Promise | T; diff --git a/src/jsutils/__tests__/didYouMean-test.js b/src/jsutils/__tests__/didYouMean-test.js index ff79ad757a..70a4ac5237 100644 --- a/src/jsutils/__tests__/didYouMean-test.js +++ b/src/jsutils/__tests__/didYouMean-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/jsutils/__tests__/identityFunc-test.js b/src/jsutils/__tests__/identityFunc-test.js index 438f02b2c9..8c7eff39bc 100644 --- a/src/jsutils/__tests__/identityFunc-test.js +++ b/src/jsutils/__tests__/identityFunc-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/jsutils/__tests__/inspect-test.js b/src/jsutils/__tests__/inspect-test.js index f85cfb47b9..a3fedb9d15 100644 --- a/src/jsutils/__tests__/inspect-test.js +++ b/src/jsutils/__tests__/inspect-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -37,11 +35,12 @@ describe('inspect', () => { it('function', () => { const unnamedFuncStr = inspect( - /* istanbul ignore next */ () => invariant(false), + // istanbul ignore next (Never called and used as a placeholder) + () => invariant(false), ); expect(unnamedFuncStr).to.equal('[function]'); - /* istanbul ignore next */ + // istanbul ignore next (Never called and used as a placeholder) function namedFunc() { invariant(false); } @@ -80,8 +79,8 @@ describe('inspect', () => { expect(inspect({ a: { b: { c: 1 } } })).to.equal('{ a: { b: [Object] } }'); const map = Object.create(null); - map['a'] = true; - map['b'] = null; + map.a = true; + map.b = null; expect(inspect(map)).to.equal('{ a: true, b: null }'); }); @@ -107,7 +106,7 @@ describe('inspect', () => { it('custom symbol inspect is take precedence', () => { const object = { - /* istanbul ignore next */ + // istanbul ignore next (Never called and use just as a placeholder) inspect() { invariant(false); }, @@ -186,6 +185,7 @@ describe('inspect', () => { expect(inspect([[new Foo()]])).to.equal('[[[Bar]]]'); const objectWithoutClassName = new (function () { + // eslint-disable-next-line no-invalid-this this.foo = 1; })(); expect(inspect([[objectWithoutClassName]])).to.equal('[[[Object]]]'); diff --git a/src/jsutils/__tests__/instanceOf-test.js b/src/jsutils/__tests__/instanceOf-test.js index b91f03f9ce..17a8d4e46d 100644 --- a/src/jsutils/__tests__/instanceOf-test.js +++ b/src/jsutils/__tests__/instanceOf-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/jsutils/__tests__/invariant-test.js b/src/jsutils/__tests__/invariant-test.js index 762143076a..97c293596e 100644 --- a/src/jsutils/__tests__/invariant-test.js +++ b/src/jsutils/__tests__/invariant-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/jsutils/__tests__/isAsyncIterable-test.js b/src/jsutils/__tests__/isAsyncIterable-test.js new file mode 100644 index 0000000000..282e6a3474 --- /dev/null +++ b/src/jsutils/__tests__/isAsyncIterable-test.js @@ -0,0 +1,51 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +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); + + // 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 + expect(isAsyncIterable(asyncGeneratorFunc)).to.equal(false); + }); + + it('should return `false` for all other values', () => { + expect(isAsyncIterable(null)).to.equal(false); + expect(isAsyncIterable(undefined)).to.equal(false); + + expect(isAsyncIterable('ABC')).to.equal(false); + expect(isAsyncIterable('0')).to.equal(false); + expect(isAsyncIterable('')).to.equal(false); + + expect(isAsyncIterable([])).to.equal(false); + expect(isAsyncIterable(new Int8Array(1))).to.equal(false); + + expect(isAsyncIterable({})).to.equal(false); + expect(isAsyncIterable({ iterable: true })).to.equal(false); + + const iterator = { [Symbol.iterator]: identityFunc }; + expect(isAsyncIterable(iterator)).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 = { + [Symbol.asyncIterator]: { next: identityFunc }, + }; + expect(isAsyncIterable(invalidAsyncIteratable)).to.equal(false); + }); +}); diff --git a/src/jsutils/__tests__/isCollection-test.js b/src/jsutils/__tests__/isCollection-test.js index caa105f555..0277d2eb53 100644 --- a/src/jsutils/__tests__/isCollection-test.js +++ b/src/jsutils/__tests__/isCollection-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -19,22 +17,25 @@ describe('isCollection', () => { } expect(isCollection(getArguments())).to.equal(true); - const arrayLike = { - length: 3, - '0': 'Alpha', - '1': 'Bravo', - '2': 'Charlie', - }; + 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 + // 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', () => { @@ -62,9 +63,9 @@ describe('isCollection', () => { const iteratorWithoutSymbol = { next: identityFunc }; expect(isCollection(iteratorWithoutSymbol)).to.equal(false); - const iteratorWithInvalidTypedSymbol = { + const invalidIteratable = { [Symbol.iterator]: { next: identityFunc }, }; - expect(isCollection(iteratorWithInvalidTypedSymbol)).to.equal(false); + expect(isCollection(invalidIteratable)).to.equal(false); }); }); diff --git a/src/jsutils/__tests__/isObjectLike-test.js b/src/jsutils/__tests__/isObjectLike-test.js index 5827023f14..724d3ab10c 100644 --- a/src/jsutils/__tests__/isObjectLike-test.js +++ b/src/jsutils/__tests__/isObjectLike-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/jsutils/__tests__/suggestionList-test.js b/src/jsutils/__tests__/suggestionList-test.js index e9316f6393..57a2d55c71 100644 --- a/src/jsutils/__tests__/suggestionList-test.js +++ b/src/jsutils/__tests__/suggestionList-test.js @@ -1,11 +1,9 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; import suggestionList from '../suggestionList'; -function expectSuggestions(input, options) { +function expectSuggestions(input: string, options: Array) { return expect(suggestionList(input, options)); } diff --git a/src/jsutils/__tests__/toObjMap-test.js b/src/jsutils/__tests__/toObjMap-test.js index 51b6f81128..3f5ab924f5 100644 --- a/src/jsutils/__tests__/toObjMap-test.js +++ b/src/jsutils/__tests__/toObjMap-test.js @@ -1,10 +1,8 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import type { ObjMapLike } from '../ObjMap'; import toObjMap from '../toObjMap'; -import { type ObjMapLike } from '../ObjMap'; // Workaround to make both ESLint and Flow happy const __proto__: string = '__proto__'; diff --git a/src/jsutils/defineInspect.js b/src/jsutils/defineInspect.js new file mode 100644 index 0000000000..b0773a9a79 --- /dev/null +++ b/src/jsutils/defineInspect.js @@ -0,0 +1,19 @@ +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/defineToJSON.js b/src/jsutils/defineToJSON.js deleted file mode 100644 index 76d6f75ccc..0000000000 --- a/src/jsutils/defineToJSON.js +++ /dev/null @@ -1,20 +0,0 @@ -// @flow strict - -import nodejsCustomInspectSymbol from './nodejsCustomInspectSymbol'; - -/** - * The `defineToJSON()` function defines toJSON() and inspect() prototype - * methods, if no function provided they become aliases for toString(). - */ -export default function defineToJSON( - classObject: Class | ((...args: Array) => mixed), - fn?: () => mixed = classObject.prototype.toString, -): void { - classObject.prototype.toJSON = fn; - 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 index 4d465c4539..da2adfcd00 100644 --- a/src/jsutils/devAssert.js +++ b/src/jsutils/devAssert.js @@ -1,8 +1,6 @@ -// @flow strict - export default function devAssert(condition: mixed, message: string): void { const booleanCondition = Boolean(condition); - /* istanbul ignore else (see transformation done in './resources/inlineInvariant.js') */ + // istanbul ignore else (See transformation done in './resources/inlineInvariant.js') if (!booleanCondition) { throw new Error(message); } diff --git a/src/jsutils/didYouMean.js b/src/jsutils/didYouMean.js index 3e6bc94503..45e1a93c83 100644 --- a/src/jsutils/didYouMean.js +++ b/src/jsutils/didYouMean.js @@ -1,5 +1,3 @@ -// @flow strict - const MAX_SUGGESTIONS = 5; /** diff --git a/src/jsutils/identityFunc.js b/src/jsutils/identityFunc.js index 5cf7c4c33b..94cb7e1534 100644 --- a/src/jsutils/identityFunc.js +++ b/src/jsutils/identityFunc.js @@ -1,5 +1,3 @@ -// @flow strict - /** * Returns the first argument it receives. */ diff --git a/src/jsutils/inspect.js b/src/jsutils/inspect.js index 9ae109a9f4..b33f70c825 100644 --- a/src/jsutils/inspect.js +++ b/src/jsutils/inspect.js @@ -1,5 +1,4 @@ -// @flow strict - +/* eslint-disable flowtype/no-weak-types */ import nodejsCustomInspectSymbol from './nodejsCustomInspectSymbol'; const MAX_ARRAY_LENGTH = 10; @@ -12,7 +11,7 @@ export default function inspect(value: mixed): string { return formatValue(value, []); } -function formatValue(value, seenValues) { +function formatValue(value: mixed, seenValues: Array): string { switch (typeof value) { case 'string': return JSON.stringify(value); @@ -28,7 +27,10 @@ function formatValue(value, seenValues) { } } -function formatObjectValue(value, previouslySeenValues) { +function formatObjectValue( + value: Object, + previouslySeenValues: Array, +): string { if (previouslySeenValues.indexOf(value) !== -1) { return '[Circular]'; } @@ -37,7 +39,6 @@ function formatObjectValue(value, previouslySeenValues) { const customInspectFn = getCustomFn(value); if (customInspectFn !== undefined) { - // $FlowFixMe(>=0.90.0) const customValue = customInspectFn.call(value); // check for infinite recursion @@ -53,7 +54,7 @@ function formatObjectValue(value, previouslySeenValues) { return formatObject(value, seenValues); } -function formatObject(object, seenValues) { +function formatObject(object: Object, seenValues: Array): string { const keys = Object.keys(object); if (keys.length === 0) { return '{}'; @@ -71,7 +72,7 @@ function formatObject(object, seenValues) { return '{ ' + properties.join(', ') + ' }'; } -function formatArray(array, seenValues) { +function formatArray(array: Array, seenValues: Array): string { if (array.length === 0) { return '[]'; } @@ -97,7 +98,7 @@ function formatArray(array, seenValues) { return '[' + items.join(', ') + ']'; } -function getCustomFn(object) { +function getCustomFn(object: Object) { const customInspectFn = object[String(nodejsCustomInspectSymbol)]; if (typeof customInspectFn === 'function') { @@ -109,7 +110,7 @@ function getCustomFn(object) { } } -function getObjectTag(object) { +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 index e944809396..e55cd13f73 100644 --- a/src/jsutils/instanceOf.js +++ b/src/jsutils/instanceOf.js @@ -1,5 +1,3 @@ -// @flow strict - /** * A replacement for instanceof which includes an error warning when multi-realm * constructors are detected. @@ -12,13 +10,13 @@ declare function instanceOf( // 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) */ + ? // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') // eslint-disable-next-line no-shadow - function instanceOf(value: mixed, constructor: mixed) { + function instanceOf(value: mixed, constructor: mixed): boolean { return value instanceof constructor; } : // eslint-disable-next-line no-shadow - function instanceOf(value: any, constructor: any) { + function instanceOf(value: any, constructor: any): boolean { if (value instanceof constructor) { return true; } diff --git a/src/jsutils/invariant.js b/src/jsutils/invariant.js index f3af549ac3..668f6ea426 100644 --- a/src/jsutils/invariant.js +++ b/src/jsutils/invariant.js @@ -1,8 +1,6 @@ -// @flow strict - export default function invariant(condition: mixed, message?: string): void { const booleanCondition = Boolean(condition); - /* istanbul ignore else (see transformation done in './resources/inlineInvariant.js') */ + // 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 new file mode 100644 index 0000000000..3dbbf9e214 --- /dev/null +++ b/src/jsutils/isAsyncIterable.js @@ -0,0 +1,17 @@ +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) { + if (maybeAsyncIterable == null || typeof maybeAsyncIterable !== 'object') { + return false; + } + + return typeof maybeAsyncIterable[SYMBOL_ASYNC_ITERATOR] === 'function'; +} diff --git a/src/jsutils/isCollection.js b/src/jsutils/isCollection.js index e5ff8e9ef0..731470256d 100644 --- a/src/jsutils/isCollection.js +++ b/src/jsutils/isCollection.js @@ -1,5 +1,3 @@ -// @flow strict - import { SYMBOL_ITERATOR } from '../polyfills/symbols'; /** diff --git a/src/jsutils/isObjectLike.js b/src/jsutils/isObjectLike.js index 45d29f6037..a5f9754dd7 100644 --- a/src/jsutils/isObjectLike.js +++ b/src/jsutils/isObjectLike.js @@ -1,5 +1,3 @@ -// @flow strict - /** * Return true if `value` is object-like. A value is object-like if it's not * `null` and has a `typeof` result of "object". diff --git a/src/jsutils/isPromise.js b/src/jsutils/isPromise.js index d6ef8177a0..4bbb5768e1 100644 --- a/src/jsutils/isPromise.js +++ b/src/jsutils/isPromise.js @@ -1,5 +1,3 @@ -// @flow strict - /** * Returns true if the value acts like a Promise, i.e. has a "then" function, * otherwise returns false. diff --git a/src/jsutils/keyMap.js b/src/jsutils/keyMap.js index 410dad4370..eb847d02c9 100644 --- a/src/jsutils/keyMap.js +++ b/src/jsutils/keyMap.js @@ -1,6 +1,4 @@ -// @flow strict - -import { type ObjMap } from './ObjMap'; +import type { ObjMap } from './ObjMap'; /** * Creates a keyed JS object from an array, given a function to produce the keys diff --git a/src/jsutils/keyValMap.js b/src/jsutils/keyValMap.js index 6f6e703aaa..a91e90b447 100644 --- a/src/jsutils/keyValMap.js +++ b/src/jsutils/keyValMap.js @@ -1,6 +1,4 @@ -// @flow strict - -import { type ObjMap } from './ObjMap'; +import type { ObjMap } from './ObjMap'; /** * Creates a keyed JS object from an array, given a function to produce the keys diff --git a/src/jsutils/mapValue.js b/src/jsutils/mapValue.js index 4390b4f693..a2b91be2dd 100644 --- a/src/jsutils/mapValue.js +++ b/src/jsutils/mapValue.js @@ -1,8 +1,6 @@ -// @flow strict - import objectEntries from '../polyfills/objectEntries'; -import { type ObjMap } from './ObjMap'; +import type { ObjMap } from './ObjMap'; /** * Creates an object map with the same keys as `map` and values generated by diff --git a/src/jsutils/memoize3.js b/src/jsutils/memoize3.js index 2d5707c5e9..be73a96fb2 100644 --- a/src/jsutils/memoize3.js +++ b/src/jsutils/memoize3.js @@ -1,5 +1,3 @@ -// @flow strict - /** * Memoizes the provided three-argument function. */ @@ -11,7 +9,7 @@ export default function memoize3< >(fn: (A1, A2, A3) => R): (A1, A2, A3) => R { let cache0; - function memoized(a1, a2, a3) { + return function memoized(a1, a2, a3) { if (!cache0) { cache0 = new WeakMap(); } @@ -36,7 +34,5 @@ export default function memoize3< const newValue = fn(a1, a2, a3); cache2.set(a3, newValue); return newValue; - } - - return memoized; + }; } diff --git a/src/jsutils/nodejsCustomInspectSymbol.js b/src/jsutils/nodejsCustomInspectSymbol.js index a884a47572..9a646e60cf 100644 --- a/src/jsutils/nodejsCustomInspectSymbol.js +++ b/src/jsutils/nodejsCustomInspectSymbol.js @@ -1,6 +1,4 @@ -// @flow strict - -/* istanbul ignore next (See: https://github.com/graphql/graphql-js/issues/2317) */ +// 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') diff --git a/src/jsutils/printPathArray.js b/src/jsutils/printPathArray.js index 10f6d119f2..34ab13daa0 100644 --- a/src/jsutils/printPathArray.js +++ b/src/jsutils/printPathArray.js @@ -1,5 +1,3 @@ -// @flow strict - /** * Build a string describing the path. */ diff --git a/src/jsutils/promiseForObject.js b/src/jsutils/promiseForObject.js index ab0435dccc..bf07e4a3f0 100644 --- a/src/jsutils/promiseForObject.js +++ b/src/jsutils/promiseForObject.js @@ -1,6 +1,4 @@ -// @flow strict - -import { type ObjMap } from './ObjMap'; +import type { ObjMap } from './ObjMap'; /** * This function transforms a JS object `ObjMap>` into diff --git a/src/jsutils/promiseReduce.js b/src/jsutils/promiseReduce.js index 0a610e77f7..43d905283e 100644 --- a/src/jsutils/promiseReduce.js +++ b/src/jsutils/promiseReduce.js @@ -1,7 +1,6 @@ -// @flow strict +import type { PromiseOrValue } from './PromiseOrValue'; import isPromise from './isPromise'; -import { type PromiseOrValue } from './PromiseOrValue'; /** * Similar to Array.prototype.reduce(), however the reducing callback may return diff --git a/src/jsutils/suggestionList.js b/src/jsutils/suggestionList.js index 04e61c2408..4128e24b07 100644 --- a/src/jsutils/suggestionList.js +++ b/src/jsutils/suggestionList.js @@ -1,5 +1,3 @@ -// @flow strict - /** * 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. @@ -127,7 +125,7 @@ class LexicalDistance { } } -function stringToArray(str) { +function stringToArray(str: string): Array { const strLength = str.length; const array = new Array(strLength); for (let i = 0; i < strLength; ++i) { diff --git a/src/jsutils/toObjMap.js b/src/jsutils/toObjMap.js index cf0da8fbe2..c0dc9e2fdb 100644 --- a/src/jsutils/toObjMap.js +++ b/src/jsutils/toObjMap.js @@ -1,12 +1,10 @@ -// @flow strict - import objectEntries from '../polyfills/objectEntries'; -import { - type ObjMap, - type ObjMapLike, - type ReadOnlyObjMap, - type ReadOnlyObjMapLike, +import type { + ObjMap, + ObjMapLike, + ReadOnlyObjMap, + ReadOnlyObjMapLike, } from './ObjMap'; /* eslint-disable no-redeclare */ diff --git a/src/language/__tests__/blockString-fuzz.js b/src/language/__tests__/blockString-fuzz.js new file mode 100644 index 0000000000..1479aa2aa7 --- /dev/null +++ b/src/language/__tests__/blockString-fuzz.js @@ -0,0 +1,66 @@ +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-test.js b/src/language/__tests__/blockString-test.js index dced428f3a..929404eb73 100644 --- a/src/language/__tests__/blockString-test.js +++ b/src/language/__tests__/blockString-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -9,7 +7,7 @@ import { printBlockString, } from '../blockString'; -function joinLines(...args) { +function joinLines(...args: Array) { return args.join('\n'); } @@ -98,37 +96,41 @@ describe('dedentBlockStringValue', () => { }); describe('getBlockStringIndentation', () => { - it('returns zero for an empty array', () => { - expect(getBlockStringIndentation([])).to.equal(0); + 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', ' b'])).to.equal(2); + expect(getBlockStringIndentation(' a')).to.equal(0); + expect(getBlockStringIndentation(' a\n b')).to.equal(2); }); it('returns minimal indentation length', () => { - expect(getBlockStringIndentation(['', ' a', ' b'])).to.equal(1); - expect(getBlockStringIndentation(['', ' a', ' b'])).to.equal(1); - expect(getBlockStringIndentation(['', ' a', ' b', 'c'])).to.equal(0); + 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(['', '\ta', ' b'])).to.equal(1); - expect(getBlockStringIndentation(['', '\t a', ' b'])).to.equal(2); - expect(getBlockStringIndentation(['', ' \t a', ' b'])).to.equal(3); + 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', '\t'])).to.equal(0); - expect(getBlockStringIndentation(['a', ' '])).to.equal(0); - expect(getBlockStringIndentation(['a', ' ', ' b'])).to.equal(2); - expect(getBlockStringIndentation(['a', ' ', ' b'])).to.equal(2); - expect(getBlockStringIndentation(['a', '', ' b'])).to.equal(1); + 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"""'); @@ -155,6 +157,13 @@ describe('printBlockString', () => { ); }); + 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 ', diff --git a/src/language/__tests__/lexer-test.js b/src/language/__tests__/lexer-test.js index bbfea7e30f..2aba2d8b78 100644 --- a/src/language/__tests__/lexer-test.js +++ b/src/language/__tests__/lexer-test.js @@ -1,11 +1,11 @@ -// @flow strict - +// 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 '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; + import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; @@ -14,18 +14,18 @@ import { Source } from '../source'; import { TokenKind } from '../tokenKind'; import { Lexer, isPunctuatorTokenKind } from '../lexer'; -function lexOne(str) { +function lexOne(str: string) { const lexer = new Lexer(new Source(str)); return lexer.advance(); } -function lexSecond(str) { +function lexSecond(str: string) { const lexer = new Lexer(new Source(str)); lexer.advance(); return lexer.advance(); } -function expectSyntaxError(text) { +function expectSyntaxError(text: string) { return expect(() => lexSecond(text)).to.throw(); } @@ -906,7 +906,7 @@ describe('Lexer', () => { }); describe('isPunctuatorTokenKind', () => { - function isPunctuatorToken(text) { + function isPunctuatorToken(text: string) { return isPunctuatorTokenKind(lexOne(text).kind); } diff --git a/src/language/__tests__/parser-benchmark.js b/src/language/__tests__/parser-benchmark.js deleted file mode 100644 index f443f7237b..0000000000 --- a/src/language/__tests__/parser-benchmark.js +++ /dev/null @@ -1,11 +0,0 @@ -// @flow strict - -import { parse } from '../parser'; - -import { kitchenSinkQuery } from '../../__fixtures__/index'; - -export const name = 'Parse kitchen sink'; -export const count = 1000; -export function measure() { - parse(kitchenSinkQuery); -} diff --git a/src/language/__tests__/parser-test.js b/src/language/__tests__/parser-test.js index c3ff3a57de..9b9c91f387 100644 --- a/src/language/__tests__/parser-test.js +++ b/src/language/__tests__/parser-test.js @@ -1,11 +1,12 @@ -// @flow strict - +// 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 '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; +import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; + import inspect from '../../jsutils/inspect'; import { Kind } from '../kinds'; @@ -13,25 +14,13 @@ import { Source } from '../source'; import { TokenKind } from '../tokenKind'; import { parse, parseValue, parseType } from '../parser'; -import { kitchenSinkQuery } from '../../__fixtures__/index'; - import toJSONDeep from './toJSONDeep'; -function expectSyntaxError(text) { +function expectSyntaxError(text: string) { return expect(() => parse(text)).to.throw(); } describe('Parser', () => { - it('asserts that a source to parse was provided', () => { - // $DisableFlowOnNegativeTest - expect(() => parse()).to.throw('Must provide Source. Received: undefined.'); - }); - - it('asserts that an invalid source to parse was provided', () => { - // $DisableFlowOnNegativeTest - expect(() => parse({})).to.throw('Must provide Source. Received: {}.'); - }); - it('parse provides useful errors', () => { let caughtError; try { diff --git a/src/language/__tests__/predicates-test.js b/src/language/__tests__/predicates-test.js index 0f01049f85..eb620abd61 100644 --- a/src/language/__tests__/predicates-test.js +++ b/src/language/__tests__/predicates-test.js @@ -1,10 +1,8 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import type { ASTNode } from '../ast'; import { Kind } from '../kinds'; -import { type ASTNode } from '../ast'; import { isDefinitionNode, isExecutableDefinitionNode, diff --git a/src/language/__tests__/printLocation-test.js b/src/language/__tests__/printLocation-test.js index 32789a85a1..2fbcdcca4e 100644 --- a/src/language/__tests__/printLocation-test.js +++ b/src/language/__tests__/printLocation-test.js @@ -1,9 +1,7 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; import { Source } from '../source'; import { printSourceLocation } from '../printLocation'; diff --git a/src/language/__tests__/printer-test.js b/src/language/__tests__/printer-test.js index d6cf65adc8..55adc17a78 100644 --- a/src/language/__tests__/printer-test.js +++ b/src/language/__tests__/printer-test.js @@ -1,15 +1,12 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; +import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; import { parse } from '../parser'; import { print } from '../printer'; -import { kitchenSinkQuery } from '../../__fixtures__/index'; - describe('Printer: Query document', () => { it('does not alter ast', () => { const ast = parse(kitchenSinkQuery); @@ -25,7 +22,8 @@ describe('Printer: Query document', () => { it('produces helpful error messages', () => { const badAST = { random: 'Data' }; - // $DisableFlowOnNegativeTest + + // $FlowExpectedError[incompatible-call] expect(() => print(badAST)).to.throw( 'Invalid AST Node: { random: "Data" }.', ); @@ -80,6 +78,45 @@ describe('Printer: Query document', () => { `); }); + it('keeps arguments on one line if line is short (<= 80 chars)', () => { + const printed = print( + parse('{trip(wheelchair:false arriveBy:false){dateTime}}'), + ); + + expect(printed).to.equal( + dedent` + { + trip(wheelchair: false, arriveBy: false) { + dateTime + } + } + `, + ); + }); + + it('puts arguments on multiple lines if line is long (> 80 chars)', () => { + const printed = print( + parse( + '{trip(wheelchair:false arriveBy:false includePlannedCancellations:true transitDistanceReluctance:2000){dateTime}}', + ), + ); + + expect(printed).to.equal( + dedent` + { + trip( + wheelchair: false + arriveBy: false + includePlannedCancellations: true + transitDistanceReluctance: 2000 + ) { + dateTime + } + } + `, + ); + }); + it('Experimental: prints fragment with variable directives', () => { const queryASTWithVariableDirective = parse( 'fragment Foo($foo: TestType @test) on TestType @testDirective { id }', @@ -114,7 +151,7 @@ describe('Printer: Query document', () => { const printed = print(parse(kitchenSinkQuery)); expect(printed).to.equal( - // $FlowFixMe + // $FlowFixMe[incompatible-call] dedent(String.raw` query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { whoever123is: node(id: [123, 456]) { @@ -159,9 +196,13 @@ describe('Printer: Query document', () => { } fragment frag on Friend @onFragmentDefinition { - foo(size: $size, bar: $b, obj: {key: "value", block: """ - block string uses \""" - """}) + foo( + size: $size + bar: $b + obj: {key: "value", block: """ + block string uses \""" + """} + ) } { diff --git a/src/language/__tests__/schema-parser-test.js b/src/language/__tests__/schema-parser-test.js index a9577d12da..02dab56622 100644 --- a/src/language/__tests__/schema-parser-test.js +++ b/src/language/__tests__/schema-parser-test.js @@ -1,21 +1,18 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; - -import { kitchenSinkSDL } from '../../__fixtures__/index'; +import dedent from '../../__testUtils__/dedent'; +import kitchenSinkSDL from '../../__testUtils__/kitchenSinkSDL'; import { parse } from '../parser'; import toJSONDeep from './toJSONDeep'; -function expectSyntaxError(text) { +function expectSyntaxError(text: string) { return expect(() => parse(text)).to.throw(); } -function typeNode(name, loc) { +function typeNode(name: mixed, loc: mixed) { return { kind: 'NamedType', name: nameNode(name, loc), @@ -23,7 +20,7 @@ function typeNode(name, loc) { }; } -function nameNode(name, loc) { +function nameNode(name: mixed, loc: mixed) { return { kind: 'Name', value: name, @@ -31,11 +28,11 @@ function nameNode(name, loc) { }; } -function fieldNode(name, type, loc) { +function fieldNode(name: mixed, type: mixed, loc: mixed) { return fieldNodeWithArgs(name, type, [], loc); } -function fieldNodeWithArgs(name, type, args, loc) { +function fieldNodeWithArgs(name: mixed, type: mixed, args: mixed, loc: mixed) { return { kind: 'FieldDefinition', description: undefined, @@ -47,7 +44,7 @@ function fieldNodeWithArgs(name, type, args, loc) { }; } -function enumValueNode(name, loc) { +function enumValueNode(name: mixed, loc: mixed) { return { kind: 'EnumValueDefinition', name: nameNode(name, loc), @@ -57,7 +54,12 @@ function enumValueNode(name, loc) { }; } -function inputValueNode(name, type, defaultValue, loc) { +function inputValueNode( + name: mixed, + type: mixed, + defaultValue: mixed, + loc: mixed, +) { return { kind: 'InputValueDefinition', name, @@ -108,7 +110,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.nested.deep.property( + expect(toJSONDeep(doc)).to.deep.nested.property( 'definitions[0].description', { kind: 'StringValue', @@ -130,7 +132,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.nested.deep.property( + expect(toJSONDeep(doc)).to.deep.nested.property( 'definitions[0].description', { kind: 'StringValue', @@ -149,7 +151,7 @@ describe('Schema Parser', () => { } `); - expect(toJSONDeep(doc)).to.nested.deep.property( + expect(toJSONDeep(doc)).to.deep.nested.property( 'definitions[0].description', { kind: 'StringValue', diff --git a/src/language/__tests__/schema-printer-test.js b/src/language/__tests__/schema-printer-test.js index c1cbbf9ea5..8a9505939c 100644 --- a/src/language/__tests__/schema-printer-test.js +++ b/src/language/__tests__/schema-printer-test.js @@ -1,15 +1,12 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; +import kitchenSinkSDL from '../../__testUtils__/kitchenSinkSDL'; import { parse } from '../parser'; import { print } from '../printer'; -import { kitchenSinkSDL } from '../../__fixtures__/index'; - describe('Printer: SDL document', () => { it('prints minimal ast', () => { const ast = { @@ -21,7 +18,8 @@ describe('Printer: SDL document', () => { it('produces helpful error messages', () => { const badAST = { random: 'Data' }; - // $DisableFlowOnNegativeTest + + // $FlowExpectedError[incompatible-call] expect(() => print(badAST)).to.throw( 'Invalid AST Node: { random: "Data" }.', ); diff --git a/src/language/__tests__/source-test.js b/src/language/__tests__/source-test.js index 64b1a89d03..31a34aa16d 100644 --- a/src/language/__tests__/source-test.js +++ b/src/language/__tests__/source-test.js @@ -1,11 +1,23 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; import { Source } from '../source'; describe('Source', () => { + it('asserts that a body was provided', () => { + // $FlowExpectedError[incompatible-call] + expect(() => new Source()).to.throw( + 'Body must be a string. Received: undefined.', + ); + }); + + it('asserts that a valid body was provided', () => { + // $FlowExpectedError[incompatible-call] + expect(() => new Source({})).to.throw( + 'Body must be a string. Received: {}.', + ); + }); + it('can be Object.toStringified', () => { const source = new Source(''); @@ -13,7 +25,7 @@ describe('Source', () => { }); it('rejects invalid locationOffset', () => { - function createSource(locationOffset) { + 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 index 5405b99ce1..3c3fae57f3 100644 --- a/src/language/__tests__/toJSONDeep.js +++ b/src/language/__tests__/toJSONDeep.js @@ -1,5 +1,3 @@ -// @flow strict - import isObjectLike from '../../jsutils/isObjectLike'; /** @@ -12,7 +10,7 @@ export default function toJSONDeep(value: mixed): mixed { } if (typeof value.toJSON === 'function') { - // $FlowFixMe(>=0.90.0) + // $FlowFixMe[incompatible-use] return value.toJSON(); } diff --git a/src/language/__tests__/visitor-test.js b/src/language/__tests__/visitor-test.js index c4bcf1d687..1dfce965b8 100644 --- a/src/language/__tests__/visitor-test.js +++ b/src/language/__tests__/visitor-test.js @@ -1,17 +1,16 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; + import invariant from '../../jsutils/invariant'; +import type { ASTNode } from '../ast'; import { Kind } from '../kinds'; import { parse } from '../parser'; import { visit, visitInParallel, BREAK, QueryDocumentKeys } from '../visitor'; -import { kitchenSinkQuery } from '../../__fixtures__/index'; - -function checkVisitorFnArgs(ast, args, isEdited) { +function checkVisitorFnArgs(ast: any, args: any, isEdited: boolean = false) { const [node, key, parent, path, ancestors] = args; expect(node).to.be.an.instanceof(Object); @@ -52,7 +51,7 @@ function checkVisitorFnArgs(ast, args, isEdited) { } } -function getValue(node) { +function getValue(node: ASTNode) { return node.value != null ? node.value : undefined; } @@ -1132,7 +1131,7 @@ describe('Visitor', () => { return BREAK; } }, - /* istanbul ignore next */ + // istanbul ignore next (Never called and used as a placeholder) leave() { invariant(false); }, diff --git a/src/language/ast.d.ts b/src/language/ast.d.ts index 576db47b6c..61cb9f4eb5 100644 --- a/src/language/ast.d.ts +++ b/src/language/ast.d.ts @@ -32,6 +32,8 @@ export class Location { readonly source: Source; constructor(startToken: Token, endToken: Token, source: Source); + + toJSON(): { start: number; end: number }; } /** @@ -86,6 +88,13 @@ export class Token { prev: Token | null, value?: string, ); + + toJSON(): { + kind: TokenKindEnum; + value: string | undefined; + line: number; + column: number; + }; } /** @@ -526,12 +535,12 @@ export interface DirectiveDefinitionNode { export type TypeSystemExtensionNode = SchemaExtensionNode | TypeExtensionNode; -export type SchemaExtensionNode = { +export interface SchemaExtensionNode { readonly kind: 'SchemaExtension'; readonly loc?: Location; readonly directives?: ReadonlyArray; readonly operationTypes?: ReadonlyArray; -}; +} // Type Extensions diff --git a/src/language/ast.js b/src/language/ast.js index 8592996b47..0b69454977 100644 --- a/src/language/ast.js +++ b/src/language/ast.js @@ -1,9 +1,7 @@ -// @flow strict +import defineInspect from '../jsutils/defineInspect'; -import defineToJSON from '../jsutils/defineToJSON'; - -import { type Source } from './source'; -import { type TokenKindEnum } from './tokenKind'; +import type { Source } from './source'; +import type { TokenKindEnum } from './tokenKind'; /** * Contains a range of UTF-8 character offsets and token references that @@ -42,12 +40,14 @@ export class Location { 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 JSON/util.inspect. -defineToJSON(Location, function () { - 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 @@ -110,17 +110,24 @@ export class Token { 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 JSON/util.inspect. -defineToJSON(Token, function () { - 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 diff --git a/src/language/blockString.d.ts b/src/language/blockString.d.ts index fe997b404d..70ffc666c7 100644 --- a/src/language/blockString.d.ts +++ b/src/language/blockString.d.ts @@ -9,7 +9,7 @@ export function dedentBlockStringValue(rawString: string): string; /** * @internal */ -export function getBlockStringIndentation(lines: ReadonlyArray): number; +export function getBlockStringIndentation(body: string): number; /** * Print a block string in the indented block form by adding a leading and diff --git a/src/language/blockString.js b/src/language/blockString.js index dba151a125..65b70ba696 100644 --- a/src/language/blockString.js +++ b/src/language/blockString.js @@ -1,5 +1,3 @@ -// @flow strict - /** * 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. @@ -13,7 +11,7 @@ export function dedentBlockStringValue(rawString: string): string { const lines = rawString.split(/\r\n|[\n\r]/g); // Remove common indentation from all lines but first. - const commonIndent = getBlockStringIndentation(lines); + const commonIndent = getBlockStringIndentation(rawString); if (commonIndent !== 0) { for (let i = 1; i < lines.length; i++) { @@ -22,52 +20,68 @@ export function dedentBlockStringValue(rawString: string): string { } // Remove leading and trailing blank lines. - while (lines.length > 0 && isBlank(lines[0])) { - lines.shift(); + let startLine = 0; + while (startLine < lines.length && isBlank(lines[startLine])) { + ++startLine; } - while (lines.length > 0 && isBlank(lines[lines.length - 1])) { - lines.pop(); + + let endLine = lines.length; + while (endLine > startLine && isBlank(lines[endLine - 1])) { + --endLine; } // Return a string of the lines joined with U+000A. - return lines.join('\n'); + 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( - lines: $ReadOnlyArray, -): number { +export function getBlockStringIndentation(value: string): number { + let isFirstLine = true; + let isEmptyLine = true; + let indent = 0; let commonIndent = null; - for (let i = 1; i < lines.length; i++) { - const line = lines[i]; - const indent = leadingWhitespace(line); - if (indent === line.length) { - continue; // skip empty lines - } - - if (commonIndent === null || indent < commonIndent) { - commonIndent = indent; - if (commonIndent === 0) { + 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 === null ? 0 : commonIndent; -} - -function leadingWhitespace(str) { - let i = 0; - while (i < str.length && (str[i] === ' ' || str[i] === '\t')) { - i++; - } - return i; -} - -function isBlank(str) { - return leadingWhitespace(str) === str.length; + return commonIndent ?? 0; } /** @@ -85,8 +99,12 @@ export function printBlockString( 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 || preferMultipleLines; + !isSingleLine || + hasTrailingQuote || + hasTrailingSlash || + preferMultipleLines; let result = ''; // Format a multi-line block quote to account for leading space. diff --git a/src/language/directiveLocation.d.ts b/src/language/directiveLocation.d.ts index 31365f5901..225e129cd8 100644 --- a/src/language/directiveLocation.d.ts +++ b/src/language/directiveLocation.d.ts @@ -1,12 +1,7 @@ /** * The set of allowed directive location values. */ -export const DirectiveLocation: _DirectiveLocation; - -/** - * @internal - */ -type _DirectiveLocation = { +export const DirectiveLocation: { // Request Definitions QUERY: 'QUERY'; MUTATION: 'MUTATION'; @@ -34,4 +29,4 @@ type _DirectiveLocation = { /** * The enum type representing the directive location values. */ -export type DirectiveLocationEnum = _DirectiveLocation[keyof _DirectiveLocation]; +export type DirectiveLocationEnum = typeof DirectiveLocation[keyof typeof DirectiveLocation]; diff --git a/src/language/directiveLocation.js b/src/language/directiveLocation.js index 6529898869..9fa1348cf8 100644 --- a/src/language/directiveLocation.js +++ b/src/language/directiveLocation.js @@ -1,5 +1,3 @@ -// @flow strict - /** * The set of allowed directive location values. */ diff --git a/src/language/experimentalOnlineParser/README.md b/src/language/experimentalOnlineParser/README.md new file mode 100644 index 0000000000..dfcd9996d7 --- /dev/null +++ b/src/language/experimentalOnlineParser/README.md @@ -0,0 +1,26 @@ +## 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 new file mode 100644 index 0000000000..6e71a66a72 --- /dev/null +++ b/src/language/experimentalOnlineParser/grammar.d.ts @@ -0,0 +1,1006 @@ +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 new file mode 100644 index 0000000000..0ab7788534 --- /dev/null +++ b/src/language/experimentalOnlineParser/grammar.js @@ -0,0 +1,999 @@ +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 new file mode 100644 index 0000000000..039446a16c --- /dev/null +++ b/src/language/experimentalOnlineParser/index.d.ts @@ -0,0 +1,6 @@ +export { + OnlineParser, + RuleKind, + TokenKind, + OnlineParserState, +} from './onlineParser'; diff --git a/src/language/experimentalOnlineParser/index.js b/src/language/experimentalOnlineParser/index.js new file mode 100644 index 0000000000..039446a16c --- /dev/null +++ b/src/language/experimentalOnlineParser/index.js @@ -0,0 +1,6 @@ +export { + OnlineParser, + RuleKind, + TokenKind, + OnlineParserState, +} from './onlineParser'; diff --git a/src/language/experimentalOnlineParser/onlineParser.d.ts b/src/language/experimentalOnlineParser/onlineParser.d.ts new file mode 100644 index 0000000000..9570b9e589 --- /dev/null +++ b/src/language/experimentalOnlineParser/onlineParser.d.ts @@ -0,0 +1,125 @@ +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 new file mode 100644 index 0000000000..f296d1c8e2 --- /dev/null +++ b/src/language/experimentalOnlineParser/onlineParser.js @@ -0,0 +1,722 @@ +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.js b/src/language/index.js index 0ce8ff6097..6055ff4fe3 100644 --- a/src/language/index.js +++ b/src/language/index.js @@ -1,5 +1,3 @@ -// @flow strict - export { Source } from './source'; export { getLocation } from './location'; @@ -23,9 +21,8 @@ export { print } from './printer'; export { visit, visitInParallel, getVisitFn, BREAK } from './visitor'; export type { ASTVisitor, Visitor, VisitFn, VisitorKeyMap } from './visitor'; +export { Location, Token } from './ast'; export type { - Location, - Token, ASTNode, ASTKindToNode, // Each kind of AST node diff --git a/src/language/kinds.d.ts b/src/language/kinds.d.ts index e655af00d8..35a7239923 100644 --- a/src/language/kinds.d.ts +++ b/src/language/kinds.d.ts @@ -1,12 +1,7 @@ /** * The set of allowed kind values for AST nodes. */ -export const Kind: _Kind; - -/** - * @internal - */ -type _Kind = { +export const Kind: { // Name NAME: 'Name'; @@ -76,4 +71,4 @@ type _Kind = { /** * The enum type representing the possible kind values of AST nodes. */ -export type KindEnum = _Kind[keyof _Kind]; +export type KindEnum = typeof Kind[keyof typeof Kind]; diff --git a/src/language/kinds.js b/src/language/kinds.js index d3292b203b..99e3e4a9ea 100644 --- a/src/language/kinds.js +++ b/src/language/kinds.js @@ -1,5 +1,3 @@ -// @flow strict - /** * The set of allowed kind values for AST nodes. */ diff --git a/src/language/lexer.d.ts b/src/language/lexer.d.ts index 92484b6ccd..40dbf9a6b2 100644 --- a/src/language/lexer.d.ts +++ b/src/language/lexer.d.ts @@ -1,5 +1,6 @@ import { Token } from './ast'; import { Source } from './source'; +import { TokenKindEnum } from './tokenKind'; /** * Given a Source object, this returns a Lexer for that source. @@ -50,3 +51,8 @@ export class Lexer { * @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 index b6ab501308..ad42ce9897 100644 --- a/src/language/lexer.js +++ b/src/language/lexer.js @@ -1,11 +1,10 @@ -// @flow strict - import { syntaxError } from '../error/syntaxError'; +import type { Source } from './source'; +import type { TokenKindEnum } from './tokenKind'; import { Token } from './ast'; -import { type Source } from './source'; +import { TokenKind } from './tokenKind'; import { dedentBlockStringValue } from './blockString'; -import { type TokenKindEnum, TokenKind } from './tokenKind'; /** * Given a Source object, creates a Lexer for that source. @@ -95,7 +94,7 @@ export function isPunctuatorTokenKind(kind: TokenKindEnum): boolean %checks { ); } -function printCharCode(code) { +function printCharCode(code: number): string { return ( // NaN/undefined represents access beyond the end of the file. isNaN(code) @@ -120,149 +119,159 @@ function readToken(lexer: Lexer, prev: Token): Token { const body = source.body; const bodyLength = body.length; - const pos = positionAfterWhitespace(body, prev.end, lexer); - const line = lexer.line; - const col = 1 + pos - lexer.lineStart; + let pos = prev.end; + while (pos < bodyLength) { + const code = body.charCodeAt(pos); - if (pos >= bodyLength) { - return new Token(TokenKind.EOF, bodyLength, bodyLength, line, col, prev); - } + const line = lexer.line; + const col = 1 + pos - lexer.lineStart; - const code = body.charCodeAt(pos); - - // SourceCharacter - switch (code) { - // ! - 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); - // A-Z _ a-z - case 65: - case 66: - case 67: - case 68: - case 69: - case 70: - case 71: - case 72: - case 73: - case 74: - case 75: - case 76: - case 77: - case 78: - case 79: - case 80: - case 81: - case 82: - case 83: - case 84: - case 85: - case 86: - case 87: - case 88: - case 89: - case 90: - case 95: - case 97: - case 98: - case 99: - case 100: - case 101: - case 102: - case 103: - case 104: - case 105: - case 106: - case 107: - case 108: - case 109: - case 110: - case 111: - case 112: - case 113: - case 114: - case 115: - case 116: - case 117: - case 118: - case 119: - case 120: - case 121: - case 122: - return readName(source, pos, line, col, prev); - // - 0-9 - case 45: - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: - case 56: - case 57: - return readNumber(source, pos, code, 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); + // 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)); } - 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) { +function unexpectedCharacterMessage(code: number): string { if (code < 0x0020 && code !== 0x0009 && code !== 0x000a && code !== 0x000d) { return `Cannot contain the invalid character ${printCharCode(code)}.`; } @@ -275,49 +284,18 @@ function unexpectedCharacterMessage(code) { return `Cannot parse the unexpected character ${printCharCode(code)}.`; } -/** - * Reads from body starting at startPosition until it finds a non-whitespace - * character, then returns the position of that character for lexing. - */ -function positionAfterWhitespace( - body: string, - startPosition: number, - lexer: Lexer, -): number { - const bodyLength = body.length; - let position = startPosition; - while (position < bodyLength) { - const code = body.charCodeAt(position); - // tab | space | comma | BOM - if (code === 9 || code === 32 || code === 44 || code === 0xfeff) { - ++position; - } else 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 { - break; - } - } - return position; -} - /** * Reads a comment token from the source file. * * #[\u0009\u0020-\uFFFF]* */ -function readComment(source, start, line, col, prev): Token { +function readComment( + source: Source, + start: number, + line: number, + col: number, + prev: Token | null, +): Token { const body = source.body; let code; let position = start; @@ -348,7 +326,14 @@ function readComment(source, start, line, col, prev): Token { * Int: -?(0|[1-9][0-9]*) * Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)? */ -function readNumber(source, start, firstCode, line, col, prev): Token { +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; @@ -419,7 +404,7 @@ function readNumber(source, start, firstCode, line, col, prev): Token { /** * Returns the new position in the source after reading digits. */ -function readDigits(source, start, firstCode) { +function readDigits(source: Source, start: number, firstCode: number): number { const body = source.body; let position = start; let code = firstCode; @@ -442,7 +427,13 @@ function readDigits(source, start, firstCode) { * * "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*" */ -function readString(source, start, line, col, prev): Token { +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; @@ -551,7 +542,14 @@ function readString(source, start, line, col, prev): Token { * * """("?"?(\\"""|\\(?!=""")|[^"\\]))*""" */ -function readBlockString(source, start, line, col, prev, lexer): Token { +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; @@ -633,7 +631,7 @@ function readBlockString(source, start, line, col, prev, lexer): Token { * 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, b, c, d) { +function uniCharCode(a: number, b: number, c: number, d: number): number { return ( (char2hex(a) << 12) | (char2hex(b) << 8) | (char2hex(c) << 4) | char2hex(d) ); @@ -647,7 +645,7 @@ function uniCharCode(a, b, c, d) { * * Returns -1 on error. */ -function char2hex(a) { +function char2hex(a: number): number { return a >= 48 && a <= 57 ? a - 48 // 0-9 : a >= 65 && a <= 70 @@ -662,7 +660,13 @@ function char2hex(a) { * * [_A-Za-z][_0-9A-Za-z]* */ -function readName(source, start, line, col, prev): Token { +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; @@ -671,8 +675,8 @@ function readName(source, start, line, col, prev): Token { position !== bodyLength && !isNaN((code = body.charCodeAt(position))) && (code === 95 || // _ - (code >= 48 && code <= 57) || // 0-9 - (code >= 65 && code <= 90) || // A-Z + (code >= 48 && code <= 57) || // 0-9 + (code >= 65 && code <= 90) || // A-Z (code >= 97 && code <= 122)) // a-z ) { ++position; @@ -689,7 +693,7 @@ function readName(source, start, line, col, prev): Token { } // _ A-Z a-z -function isNameStart(code): boolean { +function isNameStart(code: number): boolean { return ( code === 95 || (code >= 65 && code <= 90) || (code >= 97 && code <= 122) ); diff --git a/src/language/location.js b/src/language/location.js index 3918513007..8da175d4f2 100644 --- a/src/language/location.js +++ b/src/language/location.js @@ -1,6 +1,4 @@ -// @flow strict - -import { type Source } from './source'; +import type { Source } from './source'; /** * Represents a location in a Source. diff --git a/src/language/parser.js b/src/language/parser.js index 2fdcdc6ab6..5d7b16186d 100644 --- a/src/language/parser.js +++ b/src/language/parser.js @@ -1,63 +1,59 @@ -// @flow strict - -import inspect from '../jsutils/inspect'; -import devAssert from '../jsutils/devAssert'; - +import type { GraphQLError } from '../error/GraphQLError'; import { syntaxError } from '../error/syntaxError'; -import { type GraphQLError } from '../error/GraphQLError'; +import type { TokenKindEnum } from './tokenKind'; +import type { + Token, + NameNode, + VariableNode, + DocumentNode, + DefinitionNode, + OperationDefinitionNode, + OperationTypeNode, + VariableDefinitionNode, + SelectionSetNode, + SelectionNode, + FieldNode, + ArgumentNode, + FragmentSpreadNode, + InlineFragmentNode, + FragmentDefinitionNode, + ValueNode, + StringValueNode, + ListValueNode, + ObjectValueNode, + ObjectFieldNode, + DirectiveNode, + TypeNode, + NamedTypeNode, + TypeSystemDefinitionNode, + SchemaDefinitionNode, + OperationTypeDefinitionNode, + ScalarTypeDefinitionNode, + ObjectTypeDefinitionNode, + FieldDefinitionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + UnionTypeDefinitionNode, + EnumTypeDefinitionNode, + EnumValueDefinitionNode, + InputObjectTypeDefinitionNode, + DirectiveDefinitionNode, + TypeSystemExtensionNode, + SchemaExtensionNode, + ScalarTypeExtensionNode, + ObjectTypeExtensionNode, + InterfaceTypeExtensionNode, + UnionTypeExtensionNode, + EnumTypeExtensionNode, + InputObjectTypeExtensionNode, +} from './ast'; import { Kind } from './kinds'; -import { Source } from './source'; +import { Location } from './ast'; +import { TokenKind } from './tokenKind'; +import { Source, isSource } from './source'; import { DirectiveLocation } from './directiveLocation'; -import { type TokenKindEnum, TokenKind } from './tokenKind'; import { Lexer, isPunctuatorTokenKind } from './lexer'; -import { - Location, - type Token, - type NameNode, - type VariableNode, - type DocumentNode, - type DefinitionNode, - type OperationDefinitionNode, - type OperationTypeNode, - type VariableDefinitionNode, - type SelectionSetNode, - type SelectionNode, - type FieldNode, - type ArgumentNode, - type FragmentSpreadNode, - type InlineFragmentNode, - type FragmentDefinitionNode, - type ValueNode, - type StringValueNode, - type ListValueNode, - type ObjectValueNode, - type ObjectFieldNode, - type DirectiveNode, - type TypeNode, - type NamedTypeNode, - type TypeSystemDefinitionNode, - type SchemaDefinitionNode, - type OperationTypeDefinitionNode, - type ScalarTypeDefinitionNode, - type ObjectTypeDefinitionNode, - type FieldDefinitionNode, - type InputValueDefinitionNode, - type InterfaceTypeDefinitionNode, - type UnionTypeDefinitionNode, - type EnumTypeDefinitionNode, - type EnumValueDefinitionNode, - type InputObjectTypeDefinitionNode, - type DirectiveDefinitionNode, - type TypeSystemExtensionNode, - type SchemaExtensionNode, - type ScalarTypeExtensionNode, - type ObjectTypeExtensionNode, - type InterfaceTypeExtensionNode, - type UnionTypeExtensionNode, - type EnumTypeExtensionNode, - type InputObjectTypeExtensionNode, -} from './ast'; /** * Configuration options to control parser behavior @@ -163,16 +159,23 @@ export function parseType( return type; } -class Parser { +/** + * This class is exported only to assist people in implementing their own parsers + * without duplicating too much code and should be used only as last resort for cases + * such as experimental syntax or if certain features could not be contributed upstream. + * + * It is still part of the internal API and is versioned, so any changes to it are never + * considered breaking changes. If you still need to support multiple versions of the + * library, please use the `versionInfo` variable for version detection. + * + * @internal + */ +export class Parser { _options: ?ParseOptions; _lexer: Lexer; constructor(source: string | Source, options?: ParseOptions) { - const sourceObj = typeof source === 'string' ? new Source(source) : source; - devAssert( - sourceObj instanceof Source, - `Must provide Source. Received: ${inspect(sourceObj)}.`, - ); + const sourceObj = isSource(source) ? source : new Source(source); this._lexer = new Lexer(sourceObj); this._options = options; @@ -852,20 +855,24 @@ class Parser { * - ImplementsInterfaces & NamedType */ parseImplementsInterfaces(): Array { - const types = []; - if (this.expectOptionalKeyword('implements')) { + 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) || - // Legacy support for the SDL? - (this._options?.allowLegacySDLImplementsInterfaces === true && - this.peek(TokenKind.NAME)) + this.peek(TokenKind.NAME) ); + return types; } - return types; + + return this.delimitedMany(TokenKind.AMP, this.parseNamedType); } /** @@ -999,15 +1006,9 @@ class Parser { * - UnionMemberTypes | NamedType */ parseUnionMemberTypes(): Array { - const types = []; - if (this.expectOptionalToken(TokenKind.EQUALS)) { - // Optional leading pipe - this.expectOptionalToken(TokenKind.PIPE); - do { - types.push(this.parseNamedType()); - } while (this.expectOptionalToken(TokenKind.PIPE)); - } - return types; + return this.expectOptionalToken(TokenKind.EQUALS) + ? this.delimitedMany(TokenKind.PIPE, this.parseNamedType) + : []; } /** @@ -1343,13 +1344,7 @@ class Parser { * - DirectiveLocations | DirectiveLocation */ parseDirectiveLocations(): Array { - // Optional leading pipe - this.expectOptionalToken(TokenKind.PIPE); - const locations = []; - do { - locations.push(this.parseDirectiveLocation()); - } while (this.expectOptionalToken(TokenKind.PIPE)); - return locations; + return this.delimitedMany(TokenKind.PIPE, this.parseDirectiveLocation); } /* @@ -1391,8 +1386,7 @@ 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 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) { @@ -1412,8 +1406,8 @@ 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. + * 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 { const token = this._lexer.token; @@ -1430,8 +1424,8 @@ 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 that token after advancing the lexer. + * Otherwise, do not change the parser state and return undefined. */ expectOptionalToken(kind: TokenKindEnum): ?Token { const token = this._lexer.token; @@ -1460,8 +1454,8 @@ class Parser { } /** - * If the next token is a given keyword, return "true" after advancing - * the lexer. Otherwise, do not change the parser state and return "false". + * If the next token is a given keyword, return "true" after advancing the lexer. + * Otherwise, do not change the parser state and return "false". */ expectOptionalKeyword(value: string): boolean { const token = this._lexer.token; @@ -1473,8 +1467,7 @@ class Parser { } /** - * Helper function for creating an error when an unexpected lexed token - * is encountered. + * Helper function for creating an error when an unexpected lexed token is encountered. */ unexpected(atToken?: ?Token): GraphQLError { const token = atToken ?? this._lexer.token; @@ -1486,10 +1479,9 @@ class Parser { } /** - * Returns a possibly empty list of parse nodes, determined by - * the parseFn. This list begins with a lex token of openKind - * and ends with a lex token of closeKind. Advances the parser - * to the next lex token after the closing token. + * Returns a possibly empty list of parse nodes, determined by the parseFn. + * This list begins with a lex token of openKind and ends with a lex token of closeKind. + * Advances the parser to the next lex token after the closing token. */ any( openKind: TokenKindEnum, @@ -1506,10 +1498,9 @@ class Parser { /** * Returns a list of parse nodes, determined by the parseFn. - * It can be empty only if open token is missing otherwise it will always - * return non-empty list that begins with a lex token of openKind and ends - * with a lex token of closeKind. Advances the parser to the next lex token - * after the closing token. + * It can be empty only if open token is missing otherwise it will always return non-empty list + * that begins with a lex token of openKind and ends with a lex token of closeKind. + * Advances the parser to the next lex token after the closing token. */ optionalMany( openKind: TokenKindEnum, @@ -1527,10 +1518,9 @@ class Parser { } /** - * Returns a non-empty list of parse nodes, determined by - * the parseFn. This list begins with a lex token of openKind - * and ends with a lex token of closeKind. Advances the parser - * to the next lex token after the closing token. + * Returns a non-empty list of parse nodes, determined by the parseFn. + * This list begins with a lex token of openKind and ends with a lex token of closeKind. + * Advances the parser to the next lex token after the closing token. */ many( openKind: TokenKindEnum, @@ -1544,10 +1534,25 @@ class Parser { } while (!this.expectOptionalToken(closeKind)); return nodes; } + + /** + * Returns a non-empty list of parse nodes, determined by the parseFn. + * 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 { + this.expectOptionalToken(delimiterKind); + + const nodes = []; + do { + nodes.push(parseFn.call(this)); + } while (this.expectOptionalToken(delimiterKind)); + return nodes; + } } /** - * A helper function to describe a token as a string for debugging + * A helper function to describe a token as a string for debugging. */ function getTokenDesc(token: Token): string { const value = token.value; @@ -1555,7 +1560,7 @@ function getTokenDesc(token: Token): string { } /** - * A helper function to describe a token kind as a string for debugging + * A helper function to describe a token kind as a string for debugging. */ function getTokenKindDesc(kind: TokenKindEnum): string { return isPunctuatorTokenKind(kind) ? `"${kind}"` : kind; diff --git a/src/language/predicates.js b/src/language/predicates.js index 9cdef3d541..b9108f87ad 100644 --- a/src/language/predicates.js +++ b/src/language/predicates.js @@ -1,7 +1,5 @@ -// @flow strict - +import type { ASTNode } from './ast'; import { Kind } from './kinds'; -import { type ASTNode } from './ast'; export function isDefinitionNode(node: ASTNode): boolean %checks { return ( diff --git a/src/language/printLocation.js b/src/language/printLocation.js index af5cff0817..fbf3504634 100644 --- a/src/language/printLocation.js +++ b/src/language/printLocation.js @@ -1,8 +1,7 @@ -// @flow strict - -import { type Location } from './ast'; -import { type Source } from './source'; -import { type SourceLocation, getLocation } from './location'; +import type { Source } from './source'; +import type { Location } from './ast'; +import type { SourceLocation } from './location'; +import { getLocation } from './location'; /** * Render a helpful description of the location in the GraphQL Source document. diff --git a/src/language/printer.js b/src/language/printer.js index c035401aba..8ca8fb2dad 100644 --- a/src/language/printer.js +++ b/src/language/printer.js @@ -1,7 +1,6 @@ -// @flow strict +import type { ASTNode } from './ast'; import { visit } from './visitor'; -import { type ASTNode } from './ast'; import { printBlockString } from './blockString'; /** @@ -12,6 +11,8 @@ 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, @@ -42,15 +43,16 @@ const printDocASTReducer: any = { wrap(' ', join(directives, ' ')), SelectionSet: ({ selections }) => block(selections), - Field: ({ alias, name, arguments: args, directives, selectionSet }) => - join( - [ - wrap('', alias, ': ') + name + wrap('(', join(args, ', '), ')'), - join(directives, ' '), - selectionSet, - ], - ' ', - ), + 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, @@ -255,7 +257,7 @@ function addDescription(cb) { * 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 = '') { +function join(maybeArray: ?Array, separator = ''): string { return maybeArray?.filter((x) => x).join(separator) ?? ''; } @@ -263,28 +265,27 @@ function join(maybeArray: ?Array, separator = '') { * Given array, print each item on its own line, wrapped in an * indented "{ }" block. */ -function block(array) { - return array && array.length !== 0 - ? '{\n' + indent(join(array, '\n')) + '\n}' - : ''; +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. + * If maybeString is not null or empty, then wrap with start and end, otherwise print an empty string. */ -function wrap(start, maybeString, end = '') { - return maybeString ? start + maybeString + end : ''; +function wrap(start: string, maybeString: ?string, end: string = ''): string { + return maybeString != null && maybeString !== '' + ? start + maybeString + end + : ''; } -function indent(maybeString) { - return maybeString && ' ' + maybeString.replace(/\n/g, '\n '); +function indent(str: string): string { + return wrap(' ', str.replace(/\n/g, '\n ')); } -function isMultiline(string) { - return string.indexOf('\n') !== -1; +function isMultiline(str: string): boolean { + return str.indexOf('\n') !== -1; } -function hasMultilineItems(maybeArray) { - return maybeArray && maybeArray.some(isMultiline); +function hasMultilineItems(maybeArray: ?Array): boolean { + return maybeArray != null && maybeArray.some(isMultiline); } diff --git a/src/language/source.d.ts b/src/language/source.d.ts index 4517784b22..a7df7cbb6b 100644 --- a/src/language/source.d.ts +++ b/src/language/source.d.ts @@ -4,12 +4,11 @@ interface Location { } /** - * A representation of source input to GraphQL. - * `name` and `locationOffset` are optional. 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: 0 }`. - * line and column in locationOffset are 1-indexed + * 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; @@ -17,3 +16,10 @@ export class Source { 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.js index 961205a2cf..05a0fc9c81 100644 --- a/src/language/source.js +++ b/src/language/source.js @@ -1,8 +1,8 @@ -// @flow strict - import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols'; +import inspect from '../jsutils/inspect'; import devAssert from '../jsutils/devAssert'; +import instanceOf from '../jsutils/instanceOf'; type Location = {| line: number, @@ -10,12 +10,11 @@ type Location = {| |}; /** - * A representation of source input to GraphQL. - * `name` and `locationOffset` are optional. 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: 0 }`. - * line and column in locationOffset are 1-indexed + * 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; @@ -27,6 +26,11 @@ export class Source { name: string = 'GraphQL request', locationOffset: Location = { line: 1, column: 1 }, ): void { + devAssert( + typeof body === 'string', + `Body must be a string. Received: ${inspect(body)}.`, + ); + this.body = body; this.name = name; this.locationOffset = locationOffset; @@ -40,8 +44,20 @@ export class Source { ); } - // $FlowFixMe Flow doesn't support computed properties yet + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'Source'; } } + +/** + * Test if the given value is a Source object. + * + * @internal + */ +declare function isSource(source: mixed): boolean %checks(source instanceof + Source); +// eslint-disable-next-line no-redeclare +export function isSource(source) { + return instanceOf(source, Source); +} diff --git a/src/language/tokenKind.d.ts b/src/language/tokenKind.d.ts index 9919487e90..fa27e23293 100644 --- a/src/language/tokenKind.d.ts +++ b/src/language/tokenKind.d.ts @@ -2,9 +2,7 @@ * An exported enum describing the different kinds of tokens that the * lexer emits. */ -export const TokenKind: _TokenKind; - -type _TokenKind = { +export const TokenKind: { SOF: ''; EOF: ''; BANG: '!'; @@ -32,4 +30,4 @@ type _TokenKind = { /** * The enum type representing the token kinds values. */ -export type TokenKindEnum = _TokenKind[keyof _TokenKind]; +export type TokenKindEnum = typeof TokenKind[keyof typeof TokenKind]; diff --git a/src/language/tokenKind.js b/src/language/tokenKind.js index 0dd0afc8c9..b4f5248c13 100644 --- a/src/language/tokenKind.js +++ b/src/language/tokenKind.js @@ -1,5 +1,3 @@ -// @flow strict - /** * An exported enum describing the different kinds of tokens that the * lexer emits. diff --git a/src/language/visitor.d.ts b/src/language/visitor.d.ts index d5b46182a6..22e634663c 100644 --- a/src/language/visitor.d.ts +++ b/src/language/visitor.d.ts @@ -1,4 +1,4 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; import { ASTNode, ASTKindToNode } from './ast'; @@ -31,7 +31,7 @@ type ShapeMapVisitor = { * during the visitor's traversal. */ export type VisitFn = ( - /** The current node being visiting.*/ + /** The current node being visiting. */ node: TVisitedNode, /** The index or key to this node from the parent node or Array. */ key: string | number | undefined, @@ -39,7 +39,8 @@ export type VisitFn = ( 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. + /** + * 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. */ @@ -150,7 +151,7 @@ export const QueryDocumentKeys: { export const BREAK: any; /** - * 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. * @@ -184,10 +185,10 @@ export const BREAK: any; * * 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 + * enter/leave visitors at a named key, leading to four permutations of the * visitor API: * - * 1) Named visitors triggered when entering a node a specific kind. + * 1) Named visitors triggered when entering a node of a specific kind. * * visit(ast, { * Kind(node) { diff --git a/src/language/visitor.js b/src/language/visitor.js index e310ecdefc..5e367ce4a9 100644 --- a/src/language/visitor.js +++ b/src/language/visitor.js @@ -1,8 +1,7 @@ -// @flow strict - import inspect from '../jsutils/inspect'; -import { type ASTNode, type ASTKindToNode, isNode } from './ast'; +import type { ASTNode, ASTKindToNode } from './ast'; +import { isNode } from './ast'; /** * A visitor is provided to visit, it contains the collection of @@ -138,7 +137,7 @@ export const QueryDocumentKeys: VisitorKeyMap = { export const BREAK: { ... } = Object.freeze({}); /** - * 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. * @@ -172,10 +171,10 @@ export const BREAK: { ... } = Object.freeze({}); * * 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 + * enter/leave visitors at a named key, leading to four permutations of the * visitor API: * - * 1) Named visitors triggered when entering a node a specific kind. + * 1) Named visitors triggered when entering a node of a specific kind. * * visit(ast, { * Kind(node) { diff --git a/src/polyfills/arrayFrom.js b/src/polyfills/arrayFrom.js index f10ae58d08..2d153c56da 100644 --- a/src/polyfills/arrayFrom.js +++ b/src/polyfills/arrayFrom.js @@ -1,5 +1,3 @@ -// @flow strict - import { SYMBOL_ITERATOR } from './symbols'; declare function arrayFrom(arrayLike: Iterable): Array; @@ -11,7 +9,7 @@ declare function arrayFrom( ): Array; /* eslint-disable no-redeclare */ -// $FlowFixMe +// $FlowFixMe[name-already-bound] const arrayFrom = Array.from || function (obj, mapFn, thisArg) { @@ -32,7 +30,7 @@ const arrayFrom = 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 */ + // istanbul ignore if (Too big to actually test) if (i > 9999999) { throw new TypeError('Near-infinite iteration.'); } diff --git a/src/polyfills/find.js b/src/polyfills/find.js index 224a99da4a..403ba0f2b7 100644 --- a/src/polyfills/find.js +++ b/src/polyfills/find.js @@ -1,12 +1,10 @@ -// @flow strict - declare function find( list: $ReadOnlyArray, predicate: (item: T) => boolean, ): T | void; /* eslint-disable no-redeclare */ -// $FlowFixMe +// $FlowFixMe[name-already-bound] const find = Array.prototype.find ? function (list, predicate) { return Array.prototype.find.call(list, predicate); diff --git a/src/polyfills/flatMap.js b/src/polyfills/flatMap.js deleted file mode 100644 index 38f739e97c..0000000000 --- a/src/polyfills/flatMap.js +++ /dev/null @@ -1,28 +0,0 @@ -// @flow strict - -declare function flatMap( - list: $ReadOnlyArray, - fn: (item: T, index: number) => $ReadOnlyArray | U, -): Array; - -const flatMapMethod = Array.prototype.flatMap; - -/* eslint-disable no-redeclare */ -// $FlowFixMe -const flatMap = flatMapMethod - ? function (list, fn) { - return flatMapMethod.call(list, fn); - } - : function (list, fn) { - let result = []; - for (const item of list) { - const value = fn(item); - if (Array.isArray(value)) { - result = result.concat(value); - } else { - result.push(value); - } - } - return result; - }; -export default flatMap; diff --git a/src/polyfills/isFinite.js b/src/polyfills/isFinite.js index 8b26d8d2d9..58f8614b9f 100644 --- a/src/polyfills/isFinite.js +++ b/src/polyfills/isFinite.js @@ -1,11 +1,9 @@ -// @flow strict - declare function isFinitePolyfill( value: mixed, ): boolean %checks(typeof value === 'number'); /* eslint-disable no-redeclare */ -// $FlowFixMe workaround for: https://github.com/facebook/flow/issues/4441 +// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 const isFinitePolyfill = Number.isFinite || function (value) { diff --git a/src/polyfills/isInteger.js b/src/polyfills/isInteger.js index ba79ee4430..fdd50ff247 100644 --- a/src/polyfills/isInteger.js +++ b/src/polyfills/isInteger.js @@ -1,10 +1,8 @@ -// @flow strict - declare function isInteger(value: mixed): boolean %checks(typeof value === 'number'); /* eslint-disable no-redeclare */ -// $FlowFixMe workaround for: https://github.com/facebook/flow/issues/4441 +// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 const isInteger = Number.isInteger || function (value) { diff --git a/src/polyfills/objectEntries.js b/src/polyfills/objectEntries.js index d47e6c51b9..30e5585272 100644 --- a/src/polyfills/objectEntries.js +++ b/src/polyfills/objectEntries.js @@ -1,11 +1,9 @@ -// @flow strict - -import { type ObjMap } from '../jsutils/ObjMap'; +import type { ObjMap } from '../jsutils/ObjMap'; declare function objectEntries(obj: ObjMap): Array<[string, T]>; /* eslint-disable no-redeclare */ -// $FlowFixMe workaround for: https://github.com/facebook/flow/issues/5838 +// $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]])); diff --git a/src/polyfills/objectValues.js b/src/polyfills/objectValues.js index afe1af290e..943362a640 100644 --- a/src/polyfills/objectValues.js +++ b/src/polyfills/objectValues.js @@ -1,11 +1,9 @@ -// @flow strict - -import { type ObjMap } from '../jsutils/ObjMap'; +import type { ObjMap } from '../jsutils/ObjMap'; declare function objectValues(obj: ObjMap): Array; /* eslint-disable no-redeclare */ -// $FlowFixMe workaround for: https://github.com/facebook/flow/issues/2221 +// $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 index af2d2673a6..e13d8b4f3a 100644 --- a/src/polyfills/symbols.js +++ b/src/polyfills/symbols.js @@ -1,17 +1,19 @@ -// @flow strict - // In ES2015 (or a polyfilled) environment, this will be Symbol.iterator -/* istanbul ignore next (See: https://github.com/graphql/graphql-js/issues/2317) */ +// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') export const SYMBOL_ITERATOR: string = - typeof Symbol === 'function' ? Symbol.iterator : '@@iterator'; + 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) */ +// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') export const SYMBOL_ASYNC_ITERATOR: string = - // $FlowFixMe Flow doesn't define `Symbol.asyncIterator` yet - typeof Symbol === 'function' ? Symbol.asyncIterator : '@@asyncIterator'; + typeof Symbol === 'function' && Symbol.asyncIterator != null + ? Symbol.asyncIterator + : '@@asyncIterator'; -/* istanbul ignore next (See: https://github.com/graphql/graphql-js/issues/2317) */ +// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') export const SYMBOL_TO_STRING_TAG: string = - // $FlowFixMe Flow doesn't define `Symbol.toStringTag` yet - typeof Symbol === 'function' ? Symbol.toStringTag : '@@toStringTag'; + typeof Symbol === 'function' && Symbol.toStringTag != null + ? Symbol.toStringTag + : '@@toStringTag'; diff --git a/src/subscription/__tests__/eventEmitterAsyncIterator.js b/src/subscription/__tests__/eventEmitterAsyncIterator.js deleted file mode 100644 index c1c5abbfa7..0000000000 --- a/src/subscription/__tests__/eventEmitterAsyncIterator.js +++ /dev/null @@ -1,67 +0,0 @@ -// @flow strict - -import type EventEmitter from 'events'; - -/** - * Create an AsyncIterator from an EventEmitter. Useful for mocking a - * PubSub system for tests. - */ -export default function eventEmitterAsyncIterator( - eventEmitter: EventEmitter, - eventName: string, -): AsyncIterator { - const pullQueue = []; - const pushQueue = []; - let listening = true; - eventEmitter.addListener(eventName, pushValue); - - function pushValue(event) { - if (pullQueue.length !== 0) { - pullQueue.shift()({ value: event, done: false }); - } else { - pushQueue.push(event); - } - } - - function pullValue() { - return new Promise((resolve) => { - if (pushQueue.length !== 0) { - resolve({ value: pushQueue.shift(), done: false }); - } else { - pullQueue.push(resolve); - } - }); - } - - function emptyQueue() { - if (listening) { - listening = false; - eventEmitter.removeListener(eventName, pushValue); - for (const resolve of pullQueue) { - resolve({ value: undefined, done: true }); - } - pullQueue.length = 0; - pushQueue.length = 0; - } - } - - /* TODO: Flow doesn't support symbols as keys: - https://github.com/facebook/flow/issues/3258 */ - return ({ - next() { - return listening ? pullValue() : this.return(); - }, - return() { - emptyQueue(); - return Promise.resolve({ value: undefined, done: true }); - }, - throw(error) { - emptyQueue(); - return Promise.reject(error); - }, - // $FlowFixMe Blocked by https://github.com/facebook/flow/issues/3258 - [Symbol.asyncIterator]() { - return this; - }, - }: any); -} diff --git a/src/subscription/__tests__/mapAsyncIterator-test.js b/src/subscription/__tests__/mapAsyncIterator-test.js index a4b8b7f2ac..4af866f20a 100644 --- a/src/subscription/__tests__/mapAsyncIterator-test.js +++ b/src/subscription/__tests__/mapAsyncIterator-test.js @@ -1,13 +1,6 @@ -// @flow strict - -// FIXME temporary hack until https://github.com/eslint/eslint/pull/12484 is merged -/* eslint-disable require-await */ - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import invariant from '../../jsutils/invariant'; - import mapAsyncIterator from '../mapAsyncIterator'; describe('mapAsyncIterator', () => { @@ -33,7 +26,6 @@ describe('mapAsyncIterator', () => { const items = [1, 2, 3]; const iterator: any = { - // $FlowFixMe Blocked by https://github.com/facebook/flow/issues/3258 [Symbol.asyncIterator]() { return this; }, @@ -99,7 +91,7 @@ describe('mapAsyncIterator', () => { yield 1; yield 2; - /* istanbul ignore next (shouldn't be reached) */ + // istanbul ignore next (Shouldn't be reached) yield 3; } @@ -129,7 +121,6 @@ describe('mapAsyncIterator', () => { const items = [1, 2, 3]; const iterator: any = { - // $FlowFixMe Blocked by https://github.com/facebook/flow/issues/3258 [Symbol.asyncIterator]() { return this; }, @@ -159,7 +150,7 @@ describe('mapAsyncIterator', () => { yield 1; yield 2; - /* istanbul ignore next (shouldn't be reached) */ + // istanbul ignore next (Shouldn't be reached) yield 3; } finally { yield 'Done'; @@ -193,7 +184,6 @@ describe('mapAsyncIterator', () => { const items = [1, 2, 3]; const iterator: any = { - // $FlowFixMe Blocked by https://github.com/facebook/flow/issues/3258 [Symbol.asyncIterator]() { return this; }, @@ -226,7 +216,7 @@ describe('mapAsyncIterator', () => { yield 1; yield 2; - /* istanbul ignore next (shouldn't be reached) */ + // istanbul ignore next (Shouldn't be reached) yield 3; } catch (e) { yield e; @@ -274,8 +264,9 @@ describe('mapAsyncIterator', () => { caughtError = e; } - invariant(caughtError != null); - expect(caughtError.message).to.equal('Goodbye'); + expect(caughtError) + .to.be.an.instanceOf(Error) + .with.property('message', 'Goodbye'); }); it('maps over thrown errors if second callback provided', async () => { @@ -296,8 +287,9 @@ describe('mapAsyncIterator', () => { }); const result = await doubles.next(); - invariant(result.value instanceof Error); - expect(result.value.message).to.equal('Goodbye'); + 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({ @@ -306,7 +298,7 @@ describe('mapAsyncIterator', () => { }); }); - async function testClosesSourceWithMapper(mapper) { + async function testClosesSourceWithMapper(mapper: (number) => T) { let didVisitFinally = false; async function* source() { @@ -314,7 +306,7 @@ describe('mapAsyncIterator', () => { yield 1; yield 2; - /* istanbul ignore next (shouldn't be reached) */ + // istanbul ignore next (Shouldn't be reached) yield 3; } finally { didVisitFinally = true; @@ -333,8 +325,9 @@ describe('mapAsyncIterator', () => { expectedError = error; } - invariant(expectedError instanceof Error); - expect(expectedError.message).to.equal('Cannot count to 2'); + expect(expectedError) + .to.be.an.instanceOf(Error) + .with.property('message', 'Cannot count to 2'); expect(await throwOver1.next()).to.deep.equal({ value: undefined, @@ -361,7 +354,7 @@ describe('mapAsyncIterator', () => { ); }); - async function testClosesSourceWithRejectMapper(mapper) { + async function testClosesSourceWithRejectMapper(mapper: (Error) => T) { async function* source() { yield 1; throw new Error(2); @@ -378,8 +371,9 @@ describe('mapAsyncIterator', () => { expectedError = error; } - invariant(expectedError instanceof Error); - expect(expectedError.message).to.equal('Cannot count to 2'); + expect(expectedError) + .to.be.an.instanceOf(Error) + .with.property('message', 'Cannot count to 2'); expect(await throwOver1.next()).to.deep.equal({ value: undefined, diff --git a/src/subscription/__tests__/eventEmitterAsyncIterator-test.js b/src/subscription/__tests__/simplePubSub-test.js similarity index 62% rename from src/subscription/__tests__/eventEmitterAsyncIterator-test.js rename to src/subscription/__tests__/simplePubSub-test.js index 4e5ee51f36..d92339687b 100644 --- a/src/subscription/__tests__/eventEmitterAsyncIterator-test.js +++ b/src/subscription/__tests__/simplePubSub-test.js @@ -1,21 +1,16 @@ -// @flow strict - -import EventEmitter from 'events'; - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import eventEmitterAsyncIterator from './eventEmitterAsyncIterator'; +import SimplePubSub from './simplePubSub'; -describe('eventEmitterAsyncIterator', () => { +describe('SimplePubSub', () => { it('subscribe async-iterator mock', async () => { - // Create an AsyncIterator from an EventEmitter - const emitter = new EventEmitter(); - const iterator = eventEmitterAsyncIterator(emitter, 'publish'); + const pubsub = new SimplePubSub(); + const iterator = pubsub.getSubscriber(); // Queue up publishes - expect(emitter.emit('publish', 'Apple')).to.equal(true); - expect(emitter.emit('publish', 'Banana')).to.equal(true); + expect(pubsub.emit('Apple')).to.equal(true); + expect(pubsub.emit('Banana')).to.equal(true); // Read payloads expect(await iterator.next()).to.deep.equal({ @@ -32,8 +27,8 @@ describe('eventEmitterAsyncIterator', () => { const i4 = iterator.next().then((x) => x); // Publish - expect(emitter.emit('publish', 'Coconut')).to.equal(true); - expect(emitter.emit('publish', 'Durian')).to.equal(true); + expect(pubsub.emit('Coconut')).to.equal(true); + expect(pubsub.emit('Durian')).to.equal(true); // Await out of order to get correct results expect(await i4).to.deep.equal({ done: false, value: 'Durian' }); @@ -42,12 +37,11 @@ describe('eventEmitterAsyncIterator', () => { // Read ahead const i5 = iterator.next().then((x) => x); - // Terminate emitter - // $FlowFixMe + // Terminate queue await iterator.return(); // Publish is not caught after terminate - expect(emitter.emit('publish', 'Fig')).to.equal(false); + expect(pubsub.emit('Fig')).to.equal(false); // Find that cancelled read-ahead got a "done" result expect(await i5).to.deep.equal({ done: true, value: undefined }); diff --git a/src/subscription/__tests__/simplePubSub.js b/src/subscription/__tests__/simplePubSub.js new file mode 100644 index 0000000000..e12c93d0b9 --- /dev/null +++ b/src/subscription/__tests__/simplePubSub.js @@ -0,0 +1,70 @@ +/** + * Create an AsyncIterator from an EventEmitter. Useful for mocking a + * PubSub system for tests. + */ +export default class SimplePubSub { + _subscribers: Set<(T) => void>; + + constructor() { + this._subscribers = new Set(); + } + + emit(event: T): boolean { + for (const subscriber of this._subscribers) { + subscriber(event); + } + return this._subscribers.size > 0; + } + + getSubscriber(transform?: (T) => R): AsyncGenerator { + const pullQueue = []; + const pushQueue = []; + let listening = true; + this._subscribers.add(pushValue); + + const emptyQueue = () => { + listening = false; + this._subscribers.delete(pushValue); + for (const resolve of pullQueue) { + resolve({ value: undefined, done: true }); + } + pullQueue.length = 0; + pushQueue.length = 0; + }; + + /* TODO: Flow doesn't support symbols as keys: + https://github.com/facebook/flow/issues/3258 */ + return ({ + next() { + if (!listening) { + return Promise.resolve({ value: undefined, done: true }); + } + + if (pushQueue.length > 0) { + return Promise.resolve({ value: pushQueue.shift(), done: false }); + } + return new Promise((resolve) => pullQueue.push(resolve)); + }, + return() { + emptyQueue(); + return Promise.resolve({ value: undefined, done: true }); + }, + throw(error: mixed) { + emptyQueue(); + return Promise.reject(error); + }, + [Symbol.asyncIterator]() { + return this; + }, + }: any); + + function pushValue(event: T): void { + const value = transform != null ? transform(event) : event; + if (pullQueue.length > 0) { + pullQueue.shift()({ value, done: false }); + } else { + pushQueue.push(value); + } + } + } +} diff --git a/src/subscription/__tests__/subscribe-test.js b/src/subscription/__tests__/subscribe-test.js index 63af656067..919614649e 100644 --- a/src/subscription/__tests__/subscribe-test.js +++ b/src/subscription/__tests__/subscribe-test.js @@ -1,13 +1,12 @@ -// @flow strict - -// FIXME temporary hack until https://github.com/eslint/eslint/pull/12484 is merged -/* eslint-disable require-await */ - -import EventEmitter from 'events'; - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import resolveOnNextTick from '../../__testUtils__/resolveOnNextTick'; + +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'; @@ -18,7 +17,14 @@ import { GraphQLInt, GraphQLString, GraphQLBoolean } from '../../type/scalars'; import { createSourceEventStream, subscribe } from '../subscribe'; -import eventEmitterAsyncIterator from './eventEmitterAsyncIterator'; +import SimplePubSub from './simplePubSub'; + +type Email = {| + from: string, + subject: string, + message: string, + unread: boolean, +|}; const EmailType = new GraphQLObjectType({ name: 'Email', @@ -41,7 +47,7 @@ const InboxType = new GraphQLObjectType({ type: GraphQLInt, resolve: (inbox) => inbox.emails.filter((email) => email.unread).length, }, - emails: { type: GraphQLList(EmailType) }, + emails: { type: new GraphQLList(EmailType) }, }, }); @@ -62,7 +68,10 @@ const EmailEventType = new GraphQLObjectType({ const emailSchema = emailSchemaWithResolvers(); -function emailSchemaWithResolvers(subscribeFn, resolveFn) { +function emailSchemaWithResolvers( + subscribeFn?: (T) => mixed, + resolveFn?: (T) => mixed, +) { return new GraphQLSchema({ query: QueryType, subscription: new GraphQLObjectType({ @@ -96,56 +105,44 @@ const defaultSubscriptionAST = parse(` } `); -async function createSubscription( - pubsub, - schema = emailSchema, - document = defaultSubscriptionAST, - perEventContextResolver = undefined, +function createSubscription( + pubsub: SimplePubSub, + schema: GraphQLSchema = emailSchema, + document: DocumentNode = defaultSubscriptionAST, ) { - const data = { - inbox: { - emails: [ - { - from: 'joe@graphql.org', - subject: 'Hello', - message: 'Hello World', - unread: false, - }, - ], - }, - importantEmail() { - return eventEmitterAsyncIterator(pubsub, 'importantEmail'); + const emails = [ + { + from: 'joe@graphql.org', + subject: 'Hello', + message: 'Hello World', + unread: false, }, - }; + ]; - function sendImportantEmail(newEmail) { - data.inbox.emails.push(newEmail); - // Returns true if the event was consumed by a subscriber. - return pubsub.emit('importantEmail', { - importantEmail: { - email: newEmail, - inbox: data.inbox, - }, - }); - } + const data = { + inbox: { emails }, + importantEmail: pubsub.getSubscriber((newEmail) => { + emails.push(newEmail); - // `subscribe` returns Promise - return { - sendImportantEmail, - // $FlowFixMe - subscription: await subscribe({ - schema, - document, - rootValue: data, - perEventContextResolver, + return { + importantEmail: { + email: newEmail, + inbox: data.inbox, + }, + }; }), }; + + return subscribe({ schema, document, rootValue: data }); } -async function expectPromiseToThrow(promise, message) { +async function expectPromiseToThrow( + promise: () => Promise, + message: string, +) { try { await promise(); - /* istanbul ignore next */ + // istanbul ignore next (Shouldn't be reached) expect.fail('promise should have thrown but did not'); } catch (error) { expect(error).to.be.an.instanceOf(Error); @@ -166,7 +163,7 @@ describe('Subscription Initialization Phase', () => { // Empty } - // $FlowFixMe + // $FlowFixMe[incompatible-call] const ai = await subscribe(emailSchema, document, { importantEmail: emptyAsyncIterator, }); @@ -176,7 +173,7 @@ describe('Subscription Initialization Phase', () => { }); it('accepts multiple subscription fields defined in schema', async () => { - const pubsub = new EventEmitter(); + const pubsub = new SimplePubSub(); const SubscriptionTypeMultiple = new GraphQLObjectType({ name: 'Subscription', fields: { @@ -190,12 +187,10 @@ describe('Subscription Initialization Phase', () => { subscription: SubscriptionTypeMultiple, }); - const { subscription, sendImportantEmail } = await createSubscription( - pubsub, - testSchema, - ); + const subscription = await createSubscription(pubsub, testSchema); + invariant(isAsyncIterable(subscription)); - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright', message: 'Tests are good', @@ -206,7 +201,7 @@ describe('Subscription Initialization Phase', () => { }); it('accepts type definition with sync subscribe function', async () => { - const pubsub = new EventEmitter(); + const pubsub = new SimplePubSub(); const schema = new GraphQLSchema({ query: QueryType, subscription: new GraphQLObjectType({ @@ -214,14 +209,12 @@ describe('Subscription Initialization Phase', () => { fields: { importantEmail: { type: GraphQLString, - subscribe: () => - eventEmitterAsyncIterator(pubsub, 'importantEmail'), + subscribe: () => pubsub.getSubscriber(), }, }, }), }); - // $FlowFixMe const subscription = await subscribe({ schema, document: parse(` @@ -230,16 +223,15 @@ describe('Subscription Initialization Phase', () => { } `), }); + invariant(isAsyncIterable(subscription)); - pubsub.emit('importantEmail', { - importantEmail: {}, - }); + pubsub.emit({ importantEmail: {} }); await subscription.next(); }); it('accepts type definition with async subscribe function', async () => { - const pubsub = new EventEmitter(); + const pubsub = new SimplePubSub(); const schema = new GraphQLSchema({ query: QueryType, subscription: new GraphQLObjectType({ @@ -248,15 +240,14 @@ describe('Subscription Initialization Phase', () => { importantEmail: { type: GraphQLString, subscribe: async () => { - await new Promise(setImmediate); - return eventEmitterAsyncIterator(pubsub, 'importantEmail'); + await resolveOnNextTick(); + return pubsub.getSubscriber(); }, }, }, }), }); - // $FlowFixMe const subscription = await subscribe({ schema, document: parse(` @@ -265,11 +256,11 @@ describe('Subscription Initialization Phase', () => { } `), }); + invariant(isAsyncIterable(subscription)); - pubsub.emit('importantEmail', { - importantEmail: {}, - }); + expect(subscription).to.have.property('next'); + pubsub.emit({ importantEmail: {} }); await subscription.next(); }); @@ -284,15 +275,15 @@ describe('Subscription Initialization Phase', () => { type: EmailEventType, subscribe() { didResolveImportantEmail = true; - return eventEmitterAsyncIterator(new EventEmitter(), 'event'); + return new SimplePubSub().getSubscriber(); }, }, nonImportantEmail: { type: EmailEventType, - /* istanbul ignore next (shouldn't be called) */ + // istanbul ignore next (Shouldn't be called) subscribe() { didResolveNonImportantEmail = true; - return eventEmitterAsyncIterator(new EventEmitter(), 'event'); + return new SimplePubSub().getSubscriber(); }, }, }, @@ -303,7 +294,6 @@ describe('Subscription Initialization Phase', () => { subscription: SubscriptionTypeMultiple, }); - // $FlowFixMe const subscription = await subscribe({ schema, document: parse(` @@ -313,6 +303,7 @@ describe('Subscription Initialization Phase', () => { } `), }); + invariant(isAsyncIterable(subscription)); subscription.next(); // Ask for a result, but ignore it. @@ -331,13 +322,13 @@ describe('Subscription Initialization Phase', () => { `); await expectPromiseToThrow( - // $DisableFlowOnNegativeTest - () => subscribe(null, document), + // $FlowExpectedError[incompatible-call] + () => subscribe({ schema: null, document }), 'Expected null to be a GraphQL schema.', ); await expectPromiseToThrow( - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] () => subscribe({ document }), 'Expected undefined to be a GraphQL schema.', ); @@ -345,13 +336,13 @@ describe('Subscription Initialization Phase', () => { it('throws an error if document is missing', async () => { await expectPromiseToThrow( - // $DisableFlowOnNegativeTest - () => subscribe(emailSchema, null), + // $FlowExpectedError[incompatible-call] + () => subscribe({ schema: emailSchema, document: null }), 'Must provide document.', ); await expectPromiseToThrow( - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] () => subscribe({ schema: emailSchema }), 'Must provide document.', ); @@ -364,9 +355,8 @@ describe('Subscription Initialization Phase', () => { } `); - const pubsub = new EventEmitter(); - - const { subscription } = await createSubscription(pubsub, emailSchema, ast); + const pubsub = new SimplePubSub(); + const subscription = await createSubscription(pubsub, emailSchema, ast); expect(subscription).to.deep.equal({ errors: [ @@ -381,7 +371,7 @@ describe('Subscription Initialization Phase', () => { it('should pass through unexpected errors thrown in subscribe', async () => { let expectedError; try { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] await subscribe({ schema: emailSchema, document: {} }); } catch (error) { expectedError = error; @@ -403,7 +393,7 @@ describe('Subscription Initialization Phase', () => { }), }); - const pubsub = new EventEmitter(); + const pubsub = new SimplePubSub(); await expectPromiseToThrow( () => createSubscription(pubsub, invalidEmailSchema), @@ -436,7 +426,7 @@ describe('Subscription Initialization Phase', () => { ); await testReportsError(subscriptionRejectingErrorSchema); - async function testReportsError(schema) { + async function testReportsError(schema: GraphQLSchema) { // Promise | ExecutionResult> const result = await subscribe({ schema, @@ -484,7 +474,7 @@ describe('Subscription Initialization Phase', () => { ); await testReportsError(subscriptionRejectingErrorSchema); - async function testReportsError(schema) { + async function testReportsError(schema: GraphQLSchema) { // Promise | ExecutionResult> const result = await createSourceEventStream( schema, @@ -544,21 +534,22 @@ describe('Subscription Initialization Phase', () => { }); }); -// Once a subscription returns a valid AsyncIterator, it can still yield -// errors. +// 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 EventEmitter(); - const { sendImportantEmail, subscription } = await createSubscription( - pubsub, - ); - const second = await createSubscription(pubsub); + const pubsub = new SimplePubSub(); + + const subscription = await createSubscription(pubsub); + invariant(isAsyncIterable(subscription)); + + const secondSubscription = await createSubscription(pubsub); + invariant(isAsyncIterable(secondSubscription)); const payload1 = subscription.next(); - const payload2 = second.subscription.next(); + const payload2 = secondSubscription.next(); expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright', message: 'Tests are good', @@ -589,17 +580,16 @@ describe('Subscription Publish Phase', () => { }); it('produces a payload per subscription event', async () => { - const pubsub = new EventEmitter(); - const { sendImportantEmail, subscription } = await createSubscription( - pubsub, - ); + const pubsub = new SimplePubSub(); + const subscription = await createSubscription(pubsub); + invariant(isAsyncIterable(subscription)); // Wait for the next subscription payload. const payload = subscription.next(); // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright', message: 'Tests are good', @@ -628,7 +618,7 @@ describe('Subscription Publish Phase', () => { // Another new email arrives, before subscription.next() is called. expect( - sendImportantEmail({ + pubsub.emit({ from: 'hyo@graphql.org', subject: 'Tools', message: 'I <3 making things', @@ -663,7 +653,7 @@ describe('Subscription Publish Phase', () => { // Which may result in disconnecting upstream services as well. expect( - sendImportantEmail({ + pubsub.emit({ from: 'adam@graphql.org', subject: 'Important', message: 'Read me please', @@ -679,15 +669,15 @@ describe('Subscription Publish Phase', () => { }); it('produces a payload when there are multiple events', async () => { - const pubsub = new EventEmitter(); - const { sendImportantEmail, subscription } = await createSubscription( - pubsub, - ); + const pubsub = new SimplePubSub(); + const subscription = await createSubscription(pubsub); + invariant(isAsyncIterable(subscription)); + let payload = subscription.next(); // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright', message: 'Tests are good', @@ -717,7 +707,7 @@ describe('Subscription Publish Phase', () => { // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright 2', message: 'Tests are good 2', @@ -745,15 +735,15 @@ describe('Subscription Publish Phase', () => { }); it('should not trigger when subscription is already done', async () => { - const pubsub = new EventEmitter(); - const { sendImportantEmail, subscription } = await createSubscription( - pubsub, - ); + const pubsub = new SimplePubSub(); + const subscription = await createSubscription(pubsub); + invariant(isAsyncIterable(subscription)); + let payload = subscription.next(); // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright', message: 'Tests are good', @@ -784,7 +774,7 @@ describe('Subscription Publish Phase', () => { // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright 2', message: 'Tests are good 2', @@ -799,15 +789,15 @@ describe('Subscription Publish Phase', () => { }); it('should not trigger when subscription is thrown', async () => { - const pubsub = new EventEmitter(); - const { sendImportantEmail, subscription } = await createSubscription( - pubsub, - ); + const pubsub = new SimplePubSub(); + const subscription = await createSubscription(pubsub); + invariant(isAsyncIterable(subscription)); + let payload = subscription.next(); // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright', message: 'Tests are good', @@ -846,7 +836,7 @@ describe('Subscription Publish Phase', () => { // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Alright 2', message: 'Tests are good 2', @@ -861,15 +851,15 @@ describe('Subscription Publish Phase', () => { }); it('event order is correct for multiple publishes', async () => { - const pubsub = new EventEmitter(); - const { sendImportantEmail, subscription } = await createSubscription( - pubsub, - ); + const pubsub = new SimplePubSub(); + const subscription = await createSubscription(pubsub); + invariant(isAsyncIterable(subscription)); + let payload = subscription.next(); // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Message', message: 'Tests are good', @@ -879,7 +869,7 @@ describe('Subscription Publish Phase', () => { // A new email arrives! expect( - sendImportantEmail({ + pubsub.emit({ from: 'yuzhi@graphql.org', subject: 'Message 2', message: 'Tests are good 2', @@ -941,7 +931,6 @@ describe('Subscription Publish Phase', () => { }, ); - // $FlowFixMe const subscription = await subscribe({ schema: erroringEmailSchema, document: parse(` @@ -954,6 +943,7 @@ describe('Subscription Publish Phase', () => { } `), }); + invariant(isAsyncIterable(subscription)); const payload1 = await subscription.next(); expect(payload1).to.deep.equal({ @@ -1013,7 +1003,6 @@ describe('Subscription Publish Phase', () => { (email) => email, ); - // $FlowFixMe const subscription = await subscribe({ schema: erroringEmailSchema, document: parse(` @@ -1026,6 +1015,7 @@ describe('Subscription Publish Phase', () => { } `), }); + invariant(isAsyncIterable(subscription)); const payload1 = await subscription.next(); expect(payload1).to.deep.equal({ @@ -1067,7 +1057,6 @@ describe('Subscription Publish Phase', () => { (email) => email, ); - // $FlowFixMe const subscription = await subscribe({ schema: erroringEmailSchema, document: parse(` @@ -1080,6 +1069,7 @@ describe('Subscription Publish Phase', () => { } `), }); + invariant(isAsyncIterable(subscription)); const payload1 = await subscription.next(); expect(payload1).to.deep.equal({ diff --git a/src/subscription/index.js b/src/subscription/index.js index 45645edb8e..899e443b6b 100644 --- a/src/subscription/index.js +++ b/src/subscription/index.js @@ -1,4 +1,2 @@ -// @flow strict - export { subscribe, createSourceEventStream } from './subscribe'; export type { SubscriptionArgs } from './subscribe'; diff --git a/src/subscription/mapAsyncIterator.js b/src/subscription/mapAsyncIterator.js index afe05c8d51..8ab691d391 100644 --- a/src/subscription/mapAsyncIterator.js +++ b/src/subscription/mapAsyncIterator.js @@ -1,32 +1,30 @@ -// @flow strict - import { SYMBOL_ASYNC_ITERATOR } from '../polyfills/symbols'; -import { type PromiseOrValue } from '../jsutils/PromiseOrValue'; +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, + iterable: AsyncIterable | AsyncGenerator, callback: (T) => PromiseOrValue, rejectCallback?: (any) => PromiseOrValue, ): AsyncGenerator { - // $FlowFixMe + // $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) => { + abruptClose = (error: mixed) => { const rethrow = () => Promise.reject(error); return $return.call(iterator).then(rethrow, rethrow); }; } - function mapResult(result) { + function mapResult(result: IteratorResult) { return result.done ? result : asyncMapValue(result.value, callback).then(iteratorResult, abruptClose); @@ -36,14 +34,14 @@ export default function mapAsyncIterator( if (rejectCallback) { // Capture rejectCallback to ensure it cannot be null. const reject = rejectCallback; - mapReject = (error) => + 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() { + next(): Promise> { return iterator.next().then(mapResult, mapReject); }, return() { @@ -51,7 +49,7 @@ export default function mapAsyncIterator( ? $return.call(iterator).then(mapResult, mapReject) : Promise.resolve({ value: undefined, done: true }); }, - throw(error) { + throw(error?: mixed): Promise> { if (typeof iterator.throw === 'function') { return iterator.throw(error).then(mapResult, mapReject); } @@ -60,7 +58,7 @@ export default function mapAsyncIterator( [SYMBOL_ASYNC_ITERATOR]() { return this; }, - }: any); + }: $FlowFixMe); } function asyncMapValue( diff --git a/src/subscription/subscribe.d.ts b/src/subscription/subscribe.d.ts index 3dc0e3219b..aa85d93880 100644 --- a/src/subscription/subscribe.d.ts +++ b/src/subscription/subscribe.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { DocumentNode } from '../language/ast'; import { ExecutionResult } from '../execution/execute'; import { GraphQLSchema } from '../type/schema'; diff --git a/src/subscription/subscribe.js b/src/subscription/subscribe.js index 86a1ef7217..37fff25d18 100644 --- a/src/subscription/subscribe.js +++ b/src/subscription/subscribe.js @@ -1,28 +1,25 @@ -// @flow strict - -import { SYMBOL_ASYNC_ITERATOR } from '../polyfills/symbols'; - 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 { DocumentNode } from '../language/ast'; +import type { ExecutionResult, ExecutionContext } from '../execution/execute'; +import { getArgumentValues } from '../execution/values'; import { - type ExecutionResult, assertValidExecutionArguments, buildExecutionContext, buildResolveInfo, collectFields, execute, getFieldDef, - resolveFieldValueOrError, } from '../execution/execute'; -import { type GraphQLSchema } from '../type/schema'; -import { type GraphQLFieldResolver } from '../type/definition'; +import type { GraphQLSchema } from '../type/schema'; +import type { GraphQLFieldResolver } from '../type/definition'; import { getOperationRootType } from '../utilities/getOperationRootType'; @@ -67,7 +64,7 @@ export type SubscriptionArgs = {| declare function subscribe( SubscriptionArgs, ..._: [] -): Promise | ExecutionResult>; +): Promise | ExecutionResult>; /* eslint-disable no-redeclare */ declare function subscribe( schema: GraphQLSchema, @@ -113,7 +110,7 @@ export function subscribe( * an ExecutionResult, containing only errors and no data. Otherwise treat the * error as a system-class error and re-throw it. */ -function reportGraphQLError(error) { +function reportGraphQLError(error: mixed): ExecutionResult { if (error instanceof GraphQLError) { return { errors: [error] }; } @@ -122,7 +119,7 @@ function reportGraphQLError(error) { function subscribeImpl( args: SubscriptionArgs, -): Promise | ExecutionResult> { +): Promise | ExecutionResult> { const { schema, document, @@ -172,7 +169,7 @@ function subscribeImpl( // Note: Flow can't refine isAsyncIterable, so explicit casts are used. isAsyncIterable(resultOrStream) ? mapAsyncIterator( - ((resultOrStream: any): AsyncIterable), + resultOrStream, mapSourceToResponse, reportGraphQLError, ) @@ -221,7 +218,7 @@ export function createSourceEventStream( // developer mistake which should throw an early error. assertValidExecutionArguments(schema, document, variableValues); - try { + return new Promise((resolve) => { // If a valid context cannot be created due to incorrect arguments, // this will throw an error. const exeContext = buildExecutionContext( @@ -234,91 +231,79 @@ export function createSourceEventStream( fieldResolver, ); - // Return early errors if execution context failed. - if (Array.isArray(exeContext)) { - return Promise.resolve({ errors: exeContext }); - } - - const type = getOperationRootType(schema, exeContext.operation); - const fields = collectFields( - exeContext, - type, - exeContext.operation.selectionSet, - Object.create(null), - Object.create(null), + resolve( + // Return early errors if execution context failed. + Array.isArray(exeContext) + ? { errors: exeContext } + : executeSubscription(exeContext), ); - 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); + }).catch(reportGraphQLError); +} - if (!fieldDef) { - throw new GraphQLError( - `The subscription field "${fieldName}" is not defined.`, - fieldNodes, - ); - } +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); - // Call the `subscribe()` resolver or the default resolver to produce an - // AsyncIterable yielding raw payloads. - const resolveFn = fieldDef.subscribe ?? exeContext.fieldResolver; + if (!fieldDef) { + throw new GraphQLError( + `The subscription field "${fieldName}" is not defined.`, + fieldNodes, + ); + } - const path = addPath(undefined, responseName); + const path = addPath(undefined, responseName, type.name); + const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, type, path); - 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`. - // resolveFieldValueOrError implements the "ResolveFieldEventStream" - // algorithm from GraphQL specification. It differs from - // "ResolveFieldValue" due to providing a different `resolveFn`. - const result = resolveFieldValueOrError( - exeContext, - fieldDef, - fieldNodes, - resolveFn, - rootValue, - info, - ); + // 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); - // Coerce to Promise for easier error handling and consistent return type. - return Promise.resolve(result).then((eventStream) => { - // If eventStream is an Error, rethrow a located error. + // 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) { - return { - errors: [locatedError(eventStream, fieldNodes, pathToArray(path))], - }; + throw locatedError(eventStream, fieldNodes, pathToArray(path)); } // Assert field returned an event stream, otherwise yield an error. - if (isAsyncIterable(eventStream)) { - // Note: isAsyncIterable above ensures this will be correct. - return ((eventStream: any): AsyncIterable); + if (!isAsyncIterable(eventStream)) { + throw new Error( + 'Subscription field must return Async Iterable. ' + + `Received: ${inspect(eventStream)}.`, + ); } - - throw new Error( - 'Subscription field must return Async Iterable. ' + - `Received: ${inspect(eventStream)}.`, - ); - }); - } catch (error) { - // As with reportGraphQLError above, if the error is a GraphQLError, report - // it as an ExecutionResult; otherwise treat it as a system-class error and - // re-throw it. - return error instanceof GraphQLError - ? Promise.resolve({ errors: [error] }) - : Promise.reject(error); - } -} - -/** - * Returns true if the provided object implements the AsyncIterator protocol via - * either implementing a `Symbol.asyncIterator` or `"@@asyncIterator"` method. - */ -function isAsyncIterable(maybeAsyncIterable: mixed): boolean { - if (maybeAsyncIterable == null || typeof maybeAsyncIterable !== 'object') { - return false; - } - - return typeof maybeAsyncIterable[SYMBOL_ASYNC_ITERATOR] === 'function'; + return eventStream; + }, + (error) => { + throw locatedError(error, fieldNodes, pathToArray(path)); + }, + ); } diff --git a/src/tslint.json b/src/tslint.json deleted file mode 100644 index 8c08a13eb3..0000000000 --- a/src/tslint.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "dtslint/dtslint.json", - "rules": { - // All are TODOs - "array-type": false, - "interface-over-type-literal": false, - "jsdoc-format": false, - "no-any-union": false, - "no-consecutive-blank-lines": false, - "no-duplicate-imports": false, - "no-empty-interface": false, - "no-redundant-undefined": false, - "no-unnecessary-generics": false, - "semicolon": false, - "strict-export-declare-modifiers": false, - "unified-signatures": false, - "use-default-type-parameter": false, - "void-return": false - } -} diff --git a/src/tsutils/Maybe.d.ts b/src/tsutils/Maybe.d.ts deleted file mode 100644 index eb9563a382..0000000000 --- a/src/tsutils/Maybe.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ -type Maybe = null | undefined | T; - -// See https://github.com/typescript-eslint/typescript-eslint/issues/131 -// eslint-disable-next-line no-undef -export default Maybe; diff --git a/src/type/__tests__/definition-test.js b/src/type/__tests__/definition-test.js index 25803830a2..d63bc922aa 100644 --- a/src/type/__tests__/definition-test.js +++ b/src/type/__tests__/definition-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -8,17 +6,16 @@ import identityFunc from '../../jsutils/identityFunc'; import { parseValue } from '../../language/parser'; +import type { GraphQLType, GraphQLNullableType } from '../definition'; import { - type GraphQLType, - type GraphQLNullableType, + GraphQLList, + GraphQLNonNull, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, - GraphQLList, - GraphQLNonNull, } from '../definition'; const ScalarType = new GraphQLScalarType({ name: 'Scalar' }); @@ -34,12 +31,12 @@ const InputObjectType = new GraphQLInputObjectType({ fields: {}, }); -const ListOfScalarsType = GraphQLList(ScalarType); -const NonNullScalarType = GraphQLNonNull(ScalarType); -const ListOfNonNullScalarsType = GraphQLList(NonNullScalarType); -const NonNullListOfScalars = GraphQLNonNull(ListOfScalarsType); +const ListOfScalarsType = new GraphQLList(ScalarType); +const NonNullScalarType = new GraphQLNonNull(ScalarType); +const ListOfNonNullScalarsType = new GraphQLList(NonNullScalarType); +const NonNullListOfScalars = new GraphQLNonNull(ListOfScalarsType); -/* istanbul ignore next */ +// istanbul ignore next (Never called and used as a placeholder) const dummyFunc = () => { /* empty */ }; @@ -49,6 +46,16 @@ describe('Type System: Scalars', () => { expect(() => new GraphQLScalarType({ name: 'SomeScalar' })).to.not.throw(); }); + it('accepts a Scalar type defining specifiedByUrl', () => { + expect( + () => + new GraphQLScalarType({ + name: 'SomeScalar', + specifiedByUrl: 'https://example.com/foo_spec', + }), + ).not.to.throw(); + }); + it('accepts a Scalar type defining parseValue and parseLiteral', () => { expect( () => @@ -82,10 +89,13 @@ describe('Type System: Scalars', () => { expect(scalar.parseLiteral(parseValue('{ foo: "bar" }'))).to.equal( 'parseValue: { foo: "bar" }', ); + expect( + scalar.parseLiteral(parseValue('{ foo: { bar: $var } }'), { var: 'baz' }), + ).to.equal('parseValue: { foo: { bar: "baz" } }'); }); it('rejects a Scalar type without name', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => new GraphQLScalarType({})).to.throw('Must provide name.'); }); @@ -94,7 +104,7 @@ describe('Type System: Scalars', () => { () => new GraphQLScalarType({ name: 'SomeScalar', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] serialize: {}, }), ).to.throw( @@ -119,15 +129,28 @@ describe('Type System: Scalars', () => { () => new GraphQLScalarType({ name: 'SomeScalar', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] parseValue: {}, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] parseLiteral: {}, }), ).to.throw( 'SomeScalar must provide both "parseValue" and "parseLiteral" functions.', ); }); + + it('rejects a Scalar type defining specifiedByUrl with an incorrect type', () => { + expect( + () => + new GraphQLScalarType({ + name: 'SomeScalar', + // $FlowExpectedError[incompatible-call] + specifiedByUrl: {}, + }), + ).to.throw( + 'SomeScalar must provide "specifiedByUrl" as a string, but got: {}.', + ); + }); }); describe('Type System: Objects', () => { @@ -259,6 +282,7 @@ describe('Type System: Objects', () => { description: undefined, type: ScalarType, defaultValue: undefined, + deprecationReason: undefined, extensions: undefined, astNode: undefined, }, @@ -305,7 +329,7 @@ describe('Type System: Objects', () => { }); it('rejects an Object type without name', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => new GraphQLObjectType({})).to.throw('Must provide name.'); }); @@ -313,7 +337,7 @@ describe('Type System: Objects', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', fields: { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] f: undefined, }, }); @@ -325,7 +349,7 @@ describe('Type System: Objects', () => { it('rejects an Object type with incorrectly typed fields', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: [{ field: ScalarType }], }); expect(() => objType.getFields()).to.throw( @@ -336,14 +360,12 @@ describe('Type System: Objects', () => { it('rejects an Object type with a field function that returns incorrect type', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', - // $DisableFlowOnNegativeTest fields() { + // $FlowExpectedError[incompatible-call] return [{ field: ScalarType }]; }, }); - expect(() => objType.getFields()).to.throw( - 'SomeObject fields must be an object with field names as keys or a function which returns such an object.', - ); + expect(() => objType.getFields()).to.throw(); }); it('rejects an Object type with incorrectly typed field args', () => { @@ -352,7 +374,7 @@ describe('Type System: Objects', () => { fields: { badField: { type: ScalarType, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] args: [{ badArg: ScalarType }], }, }, @@ -365,7 +387,7 @@ describe('Type System: Objects', () => { it('rejects an Object type with an isDeprecated instead of deprecationReason on field', () => { const OldObject = new GraphQLObjectType({ name: 'OldObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: { field: { type: ScalarType, isDeprecated: true }, }, @@ -380,7 +402,7 @@ describe('Type System: Objects', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', fields: {}, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] interfaces: {}, }); expect(() => objType.getInterfaces()).to.throw( @@ -392,8 +414,8 @@ describe('Type System: Objects', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', fields: {}, - // $DisableFlowOnNegativeTest interfaces() { + // $FlowExpectedError[incompatible-call] return {}; }, }); @@ -405,7 +427,7 @@ describe('Type System: Objects', () => { it('rejects an empty Object field resolver', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: { field: { type: ScalarType, resolve: {} }, }, @@ -419,7 +441,7 @@ describe('Type System: Objects', () => { it('rejects a constant scalar value resolver', () => { const objType = new GraphQLObjectType({ name: 'SomeObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: { field: { type: ScalarType, resolve: 0 }, }, @@ -436,7 +458,7 @@ describe('Type System: Objects', () => { new GraphQLObjectType({ name: 'AnotherObject', fields: {}, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] isTypeOf: {}, }), ).to.throw( @@ -475,7 +497,7 @@ describe('Type System: Interfaces', () => { }); it('rejects an Interface type without name', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => new GraphQLInterfaceType({})).to.throw('Must provide name.'); }); @@ -483,7 +505,7 @@ describe('Type System: Interfaces', () => { const objType = new GraphQLInterfaceType({ name: 'AnotherInterface', fields: {}, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] interfaces: {}, }); expect(() => objType.getInterfaces()).to.throw( @@ -495,8 +517,8 @@ describe('Type System: Interfaces', () => { const objType = new GraphQLInterfaceType({ name: 'AnotherInterface', fields: {}, - // $DisableFlowOnNegativeTest interfaces() { + // $FlowExpectedError[incompatible-call] return {}; }, }); @@ -511,7 +533,7 @@ describe('Type System: Interfaces', () => { new GraphQLInterfaceType({ name: 'AnotherInterface', fields: {}, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] resolveType: {}, }), ).to.throw( @@ -556,7 +578,7 @@ describe('Type System: Unions', () => { }); it('rejects an Union type without name', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => new GraphQLUnionType({})).to.throw('Must provide name.'); }); @@ -566,7 +588,7 @@ describe('Type System: Unions', () => { new GraphQLUnionType({ name: 'SomeUnion', types: [], - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] resolveType: {}, }), ).to.throw( @@ -577,7 +599,7 @@ describe('Type System: Unions', () => { it('rejects a Union type with incorrectly typed types', () => { const unionType = new GraphQLUnionType({ name: 'SomeUnion', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] types: { ObjectType }, }); @@ -676,7 +698,7 @@ describe('Type System: Enums', () => { }); it('rejects an Enum type without name', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => new GraphQLEnumType({ values: {} })).to.throw( 'Must provide name.', ); @@ -687,7 +709,7 @@ describe('Type System: Enums', () => { () => new GraphQLEnumType({ name: 'SomeEnum', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] values: [{ FOO: 10 }], }), ).to.throw('SomeEnum values must be an object with value names as keys.'); @@ -698,7 +720,7 @@ describe('Type System: Enums', () => { () => new GraphQLEnumType({ name: 'SomeEnum', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] values: { FOO: null }, }), ).to.throw( @@ -711,7 +733,7 @@ describe('Type System: Enums', () => { () => new GraphQLEnumType({ name: 'SomeEnum', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] values: { FOO: 10 }, }), ).to.throw( @@ -724,7 +746,7 @@ describe('Type System: Enums', () => { () => new GraphQLEnumType({ name: 'SomeEnum', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] values: { FOO: { isDeprecated: true }, }, @@ -750,6 +772,7 @@ describe('Type System: Input Objects', () => { description: undefined, type: ScalarType, defaultValue: undefined, + deprecationReason: undefined, extensions: undefined, astNode: undefined, }, @@ -770,13 +793,14 @@ describe('Type System: Input Objects', () => { type: ScalarType, defaultValue: undefined, extensions: undefined, + deprecationReason: undefined, astNode: undefined, }, }); }); it('rejects an Input Object type without name', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => new GraphQLInputObjectType({})).to.throw( 'Must provide name.', ); @@ -785,7 +809,7 @@ describe('Type System: Input Objects', () => { it('rejects an Input Object type with incorrect fields', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: [], }); expect(() => inputObjType.getFields()).to.throw( @@ -796,7 +820,7 @@ describe('Type System: Input Objects', () => { it('rejects an Input Object type with fields function that returns incorrect type', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: () => [], }); expect(() => inputObjType.getFields()).to.throw( @@ -809,7 +833,7 @@ describe('Type System: Input Objects', () => { it('rejects an Input Object type with resolvers', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: { f: { type: ScalarType, resolve: dummyFunc }, }, @@ -822,7 +846,7 @@ describe('Type System: Input Objects', () => { it('rejects an Input Object type with resolver constant', () => { const inputObjType = new GraphQLInputObjectType({ name: 'SomeInputObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] fields: { f: { type: ScalarType, resolve: {} }, }, @@ -836,7 +860,7 @@ describe('Type System: Input Objects', () => { describe('Type System: List', () => { function expectList(type: GraphQLType) { - return expect(() => GraphQLList(type)); + return expect(() => new GraphQLList(type)); } it('accepts an type as item type of list', () => { @@ -851,22 +875,22 @@ describe('Type System: List', () => { }); it('rejects a non-type as item type of list', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectList({}).to.throw('Expected {} to be a GraphQL type.'); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectList(String).to.throw( 'Expected [function String] to be a GraphQL type.', ); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectList(null).to.throw('Expected null to be a GraphQL type.'); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectList(undefined).to.throw('Expected undefined to be a GraphQL type.'); }); }); describe('Type System: Non-Null', () => { function expectNonNull(type: GraphQLNullableType) { - return expect(() => GraphQLNonNull(type)); + return expect(() => new GraphQLNonNull(type)); } it('accepts an type as nullable type of non-null', () => { @@ -881,21 +905,21 @@ describe('Type System: Non-Null', () => { }); it('rejects a non-type as nullable type of non-null', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectNonNull(NonNullScalarType).to.throw( 'Expected Scalar! to be a GraphQL nullable type.', ); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectNonNull({}).to.throw('Expected {} to be a GraphQL nullable type.'); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectNonNull(String).to.throw( 'Expected [function String] to be a GraphQL nullable type.', ); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectNonNull(null).to.throw( 'Expected null to be a GraphQL nullable type.', ); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expectNonNull(undefined).to.throw( 'Expected undefined to be a GraphQL nullable type.', ); @@ -915,7 +939,7 @@ describe('Type System: test utility methods', () => { expect(String(ListOfScalarsType)).to.equal('[Scalar]'); expect(String(NonNullListOfScalars)).to.equal('[Scalar]!'); expect(String(ListOfNonNullScalarsType)).to.equal('[Scalar!]'); - expect(String(GraphQLList(ListOfScalarsType))).to.equal('[[Scalar]]'); + expect(String(new GraphQLList(ListOfScalarsType))).to.equal('[[Scalar]]'); }); it('JSON.stringifies types', () => { @@ -930,13 +954,13 @@ describe('Type System: test utility methods', () => { expect(JSON.stringify(ListOfScalarsType)).to.equal('"[Scalar]"'); expect(JSON.stringify(NonNullListOfScalars)).to.equal('"[Scalar]!"'); expect(JSON.stringify(ListOfNonNullScalarsType)).to.equal('"[Scalar!]"'); - expect(JSON.stringify(GraphQLList(ListOfScalarsType))).to.equal( + expect(JSON.stringify(new GraphQLList(ListOfScalarsType))).to.equal( '"[[Scalar]]"', ); }); it('Object.toStringifies types', () => { - function toString(obj) { + function toString(obj: mixed): string { return Object.prototype.toString.call(obj); } diff --git a/src/type/__tests__/directive-test.js b/src/type/__tests__/directive-test.js index 38bbe852a9..0dc7de5132 100644 --- a/src/type/__tests__/directive-test.js +++ b/src/type/__tests__/directive-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -39,6 +37,7 @@ describe('Type System: Directive', () => { description: undefined, type: GraphQLString, defaultValue: undefined, + deprecationReason: undefined, extensions: undefined, astNode: undefined, }, @@ -47,6 +46,7 @@ describe('Type System: Directive', () => { description: undefined, type: GraphQLInt, defaultValue: undefined, + deprecationReason: undefined, extensions: undefined, astNode: undefined, }, @@ -85,8 +85,8 @@ describe('Type System: Directive', () => { }); it('rejects an unnamed directive', () => { - // $DisableFlowOnNegativeTest - expect(() => new GraphQLDirective({ locations: ['Query'] })).to.throw( + // $FlowExpectedError[prop-missing] + expect(() => new GraphQLDirective({ locations: ['QUERY'] })).to.throw( 'Directive must be named.', ); }); @@ -97,21 +97,21 @@ describe('Type System: Directive', () => { new GraphQLDirective({ name: 'Foo', locations: ['QUERY'], - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] args: [], }), ).to.throw('@Foo args must be an object with argument names as keys.'); }); it('rejects a directive with undefined locations', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => new GraphQLDirective({ name: 'Foo' })).to.throw( '@Foo locations must be an Array.', ); }); it('rejects a directive with incorrectly typed locations', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] 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.js index e4b12195cb..e9dbeedec2 100644 --- a/src/type/__tests__/enumType-test.js +++ b/src/type/__tests__/enumType-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -114,7 +112,10 @@ const schema = new GraphQLSchema({ subscription: SubscriptionType, }); -function executeQuery(source, variableValues) { +function executeQuery( + source: string, + variableValues?: { +[variable: string]: mixed, ... }, +) { return graphqlSync({ schema, source, variableValues }); } @@ -365,7 +366,7 @@ describe('Type System: Enum Values', () => { const oneValue = ComplexEnum.getValue('ONE'); expect(oneValue).to.include({ name: 'ONE', value: Complex1 }); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] const badUsage = ComplexEnum.getValue(Complex1); expect(badUsage).to.equal(undefined); }); diff --git a/src/type/__tests__/extensions-test.js b/src/type/__tests__/extensions-test.js index 96027a116b..76dd0ee233 100644 --- a/src/type/__tests__/extensions-test.js +++ b/src/type/__tests__/extensions-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -18,7 +16,7 @@ import { const dummyType = new GraphQLScalarType({ name: 'DummyScalar' }); -function expectObjMap(value) { +function expectObjMap(value: mixed) { invariant(value != null && typeof value === 'object'); expect(Object.getPrototypeOf(value)).to.equal(null); return expect(value); diff --git a/src/type/__tests__/introspection-test.js b/src/type/__tests__/introspection-test.js index 5c60e8a071..478cc9bd18 100644 --- a/src/type/__tests__/introspection-test.js +++ b/src/type/__tests__/introspection-test.js @@ -1,35 +1,28 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; import invariant from '../../jsutils/invariant'; -import { graphqlSync } from '../../graphql'; +import { buildSchema } from '../../utilities/buildASTSchema'; import { getIntrospectionQuery } from '../../utilities/getIntrospectionQuery'; -import { GraphQLSchema } from '../schema'; -import { GraphQLString } from '../scalars'; -import { - GraphQLList, - GraphQLObjectType, - GraphQLInputObjectType, - GraphQLEnumType, -} from '../definition'; +import { graphqlSync } from '../../graphql'; describe('Introspection', () => { it('executes an introspection query', () => { - const schema = new GraphQLSchema({ - description: 'Sample schema', - query: new GraphQLObjectType({ - name: 'QueryRoot', - fields: { - onlyField: { type: GraphQLString }, - }, - }), - }); + const schema = buildSchema(` + type SomeObject { + someField: String + } + + schema { + query: SomeObject + } + `); + const source = getIntrospectionQuery({ descriptions: false, + specifiedByUrl: true, directiveIsRepeatable: true, }); @@ -37,18 +30,17 @@ describe('Introspection', () => { expect(result).to.deep.equal({ data: { __schema: { + queryType: { name: 'SomeObject' }, mutationType: null, subscriptionType: null, - queryType: { - name: 'QueryRoot', - }, types: [ { kind: 'OBJECT', - name: 'QueryRoot', + name: 'SomeObject', + specifiedByUrl: null, fields: [ { - name: 'onlyField', + name: 'someField', args: [], type: { kind: 'SCALAR', @@ -67,6 +59,7 @@ describe('Introspection', () => { { kind: 'SCALAR', name: 'String', + specifiedByUrl: null, fields: null, inputFields: null, interfaces: null, @@ -76,6 +69,7 @@ describe('Introspection', () => { { kind: 'SCALAR', name: 'Boolean', + specifiedByUrl: null, fields: null, inputFields: null, interfaces: null, @@ -85,6 +79,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Schema', + specifiedByUrl: null, fields: [ { name: 'description', @@ -189,6 +184,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Type', + specifiedByUrl: null, fields: [ { name: 'kind', @@ -227,6 +223,17 @@ describe('Introspection', () => { isDeprecated: false, deprecationReason: null, }, + { + name: 'specifiedByUrl', + args: [], + type: { + kind: 'SCALAR', + name: 'String', + ofType: null, + }, + isDeprecated: false, + deprecationReason: null, + }, { name: 'fields', args: [ @@ -325,7 +332,17 @@ describe('Introspection', () => { }, { name: 'inputFields', - args: [], + args: [ + { + name: 'includeDeprecated', + type: { + kind: 'SCALAR', + name: 'Boolean', + ofType: null, + }, + defaultValue: 'false', + }, + ], type: { kind: 'LIST', name: null, @@ -362,6 +379,7 @@ describe('Introspection', () => { { kind: 'ENUM', name: '__TypeKind', + specifiedByUrl: null, fields: null, inputFields: null, interfaces: null, @@ -412,6 +430,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Field', + specifiedByUrl: null, fields: [ { name: 'name', @@ -441,7 +460,17 @@ describe('Introspection', () => { }, { name: 'args', - args: [], + args: [ + { + name: 'includeDeprecated', + type: { + kind: 'SCALAR', + name: 'Boolean', + ofType: null, + }, + defaultValue: 'false', + }, + ], type: { kind: 'NON_NULL', name: null, @@ -512,6 +541,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__InputValue', + specifiedByUrl: null, fields: [ { name: 'name', @@ -565,6 +595,32 @@ describe('Introspection', () => { isDeprecated: false, deprecationReason: null, }, + { + name: 'isDeprecated', + args: [], + type: { + kind: 'NON_NULL', + name: null, + ofType: { + kind: 'SCALAR', + name: 'Boolean', + ofType: null, + }, + }, + isDeprecated: false, + deprecationReason: null, + }, + { + name: 'deprecationReason', + args: [], + type: { + kind: 'SCALAR', + name: 'String', + ofType: null, + }, + isDeprecated: false, + deprecationReason: null, + }, ], inputFields: null, interfaces: [], @@ -574,6 +630,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__EnumValue', + specifiedByUrl: null, fields: [ { name: 'name', @@ -636,6 +693,7 @@ describe('Introspection', () => { { kind: 'OBJECT', name: '__Directive', + specifiedByUrl: null, fields: [ { name: 'name', @@ -733,6 +791,7 @@ describe('Introspection', () => { { kind: 'ENUM', name: '__DirectiveLocation', + specifiedByUrl: null, fields: null, inputFields: null, interfaces: null, @@ -880,7 +939,12 @@ describe('Introspection', () => { { name: 'deprecated', isRepeatable: false, - locations: ['FIELD_DEFINITION', 'ENUM_VALUE'], + locations: [ + 'FIELD_DEFINITION', + 'ARGUMENT_DEFINITION', + 'INPUT_FIELD_DEFINITION', + 'ENUM_VALUE', + ], args: [ { defaultValue: '"No longer supported"', @@ -893,6 +957,26 @@ describe('Introspection', () => { }, ], }, + { + name: 'specifiedBy', + isRepeatable: false, + locations: ['SCALAR'], + args: [ + { + defaultValue: null, + name: 'url', + type: { + kind: 'NON_NULL', + name: null, + ofType: { + kind: 'SCALAR', + name: 'String', + ofType: null, + }, + }, + }, + ], + }, ], }, }, @@ -900,29 +984,21 @@ describe('Introspection', () => { }); it('introspects on input object', () => { - const TestInputObject = new GraphQLInputObjectType({ - name: 'TestInputObject', - fields: { - a: { type: GraphQLString, defaultValue: 'tes\t de\fault' }, - b: { type: GraphQLList(GraphQLString) }, - c: { type: GraphQLString, defaultValue: null }, - }, - }); + const schema = buildSchema(` + input SomeInputObject { + a: String = "tes\\t de\\fault" + b: [String] + c: String = null + } - const TestType = new GraphQLObjectType({ - name: 'TestType', - fields: { - field: { - type: GraphQLString, - args: { complex: { type: TestInputObject } }, - }, - }, - }); + type Query { + someField(someArg: SomeInputObject): String + } + `); - const schema = new GraphQLSchema({ query: TestType }); const source = ` { - __type(name: "TestInputObject") { + __type(name: "SomeInputObject") { kind name inputFields { @@ -955,7 +1031,7 @@ describe('Introspection', () => { data: { __type: { kind: 'INPUT_OBJECT', - name: 'TestInputObject', + name: 'SomeInputObject', inputFields: [ { name: 'a', @@ -995,19 +1071,15 @@ describe('Introspection', () => { }); it('supports the __type root field', () => { - const TestType = new GraphQLObjectType({ - name: 'TestType', - fields: { - testField: { - type: GraphQLString, - }, - }, - }); + const schema = buildSchema(` + type Query { + someField: String + } + `); - const schema = new GraphQLSchema({ query: TestType }); const source = ` { - __type(name: "TestType") { + __type(name: "Query") { name } } @@ -1015,36 +1087,23 @@ describe('Introspection', () => { expect(graphqlSync({ schema, source })).to.deep.equal({ data: { - __type: { - name: 'TestType', - }, + __type: { name: 'Query' }, }, }); }); it('identifies deprecated fields', () => { - const TestType = new GraphQLObjectType({ - name: 'TestType', - fields: { - nonDeprecated: { - type: GraphQLString, - }, - deprecated: { - type: GraphQLString, - deprecationReason: 'Removed in 1.0', - }, - deprecatedWithEmptyReason: { - type: GraphQLString, - deprecationReason: '', - }, - }, - }); + const schema = buildSchema(` + type Query { + nonDeprecated: String + deprecated: String @deprecated(reason: "Removed in 1.0") + deprecatedWithEmptyReason: String @deprecated(reason: "") + } + `); - const schema = new GraphQLSchema({ query: TestType }); const source = ` { - __type(name: "TestType") { - name + __type(name: "Query") { fields(includeDeprecated: true) { name isDeprecated, @@ -1057,7 +1116,6 @@ describe('Introspection', () => { expect(graphqlSync({ schema, source })).to.deep.equal({ data: { __type: { - name: 'TestType', fields: [ { name: 'nonDeprecated', @@ -1081,24 +1139,16 @@ describe('Introspection', () => { }); it('respects the includeDeprecated parameter for fields', () => { - const TestType = new GraphQLObjectType({ - name: 'TestType', - fields: { - nonDeprecated: { - type: GraphQLString, - }, - deprecated: { - type: GraphQLString, - deprecationReason: 'Removed in 1.0', - }, - }, - }); + const schema = buildSchema(` + type Query { + nonDeprecated: String + deprecated: String @deprecated(reason: "Removed in 1.0") + } + `); - const schema = new GraphQLSchema({ query: TestType }); const source = ` { - __type(name: "TestType") { - name + __type(name: "Query") { trueFields: fields(includeDeprecated: true) { name } @@ -1115,23 +1165,104 @@ describe('Introspection', () => { expect(graphqlSync({ schema, source })).to.deep.equal({ data: { __type: { - name: 'TestType', - trueFields: [ - { - name: 'nonDeprecated', - }, - { - name: 'deprecated', - }, - ], - falseFields: [ + trueFields: [{ name: 'nonDeprecated' }, { name: 'deprecated' }], + falseFields: [{ name: 'nonDeprecated' }], + omittedFields: [{ name: 'nonDeprecated' }], + }, + }, + }); + }); + + it('identifies deprecated args', () => { + const schema = buildSchema(` + type Query { + someField( + nonDeprecated: String + deprecated: String @deprecated(reason: "Removed in 1.0") + deprecatedWithEmptyReason: String @deprecated(reason: "") + ): String + } + `); + + const source = ` + { + __type(name: "Query") { + fields { + args(includeDeprecated: true) { + name + isDeprecated, + deprecationReason + } + } + } + } + `; + + expect(graphqlSync({ schema, source })).to.deep.equal({ + data: { + __type: { + fields: [ { - name: 'nonDeprecated', + args: [ + { + name: 'nonDeprecated', + isDeprecated: false, + deprecationReason: null, + }, + { + name: 'deprecated', + isDeprecated: true, + deprecationReason: 'Removed in 1.0', + }, + { + name: 'deprecatedWithEmptyReason', + isDeprecated: true, + deprecationReason: '', + }, + ], }, ], - omittedFields: [ + }, + }, + }); + }); + + it('respects the includeDeprecated parameter for args', () => { + const schema = buildSchema(` + type Query { + someField( + nonDeprecated: String + deprecated: String @deprecated(reason: "Removed in 1.0") + ): String + } + `); + + const source = ` + { + __type(name: "Query") { + fields { + trueArgs: args(includeDeprecated: true) { + name + } + falseArgs: args(includeDeprecated: false) { + name + } + omittedArgs: args { + name + } + } + } + } + `; + + expect(graphqlSync({ schema, source })).to.deep.equal({ + data: { + __type: { + fields: [ { - name: 'nonDeprecated', + trueArgs: [{ name: 'nonDeprecated' }, { name: 'deprecated' }], + falseArgs: [{ name: 'nonDeprecated' }], + omittedArgs: [{ name: 'nonDeprecated' }], }, ], }, @@ -1140,29 +1271,21 @@ describe('Introspection', () => { }); it('identifies deprecated enum values', () => { - const TestEnum = new GraphQLEnumType({ - name: 'TestEnum', - values: { - NON_DEPRECATED: { value: 0 }, - DEPRECATED: { value: 1, deprecationReason: 'Removed in 1.0' }, - ALSO_NON_DEPRECATED: { value: 2 }, - }, - }); + const schema = buildSchema(` + enum SomeEnum { + NON_DEPRECATED + DEPRECATED @deprecated(reason: "Removed in 1.0") + ALSO_NON_DEPRECATED + } - const TestType = new GraphQLObjectType({ - name: 'TestType', - fields: { - testEnum: { - type: TestEnum, - }, - }, - }); + type Query { + someField(someArg: SomeEnum): String + } + `); - const schema = new GraphQLSchema({ query: TestType }); const source = ` { - __type(name: "TestEnum") { - name + __type(name: "SomeEnum") { enumValues(includeDeprecated: true) { name isDeprecated, @@ -1175,7 +1298,6 @@ describe('Introspection', () => { expect(graphqlSync({ schema, source })).to.deep.equal({ data: { __type: { - name: 'TestEnum', enumValues: [ { name: 'NON_DEPRECATED', @@ -1199,29 +1321,22 @@ describe('Introspection', () => { }); it('respects the includeDeprecated parameter for enum values', () => { - const TestEnum = new GraphQLEnumType({ - name: 'TestEnum', - values: { - NON_DEPRECATED: {}, - DEPRECATED: { deprecationReason: 'Removed in 1.0' }, - DEPRECATED_WITH_EMPTY_REASON: { deprecationReason: '' }, - ALSO_NON_DEPRECATED: {}, - }, - }); + const schema = buildSchema(` + enum SomeEnum { + NON_DEPRECATED + DEPRECATED @deprecated(reason: "Removed in 1.0") + DEPRECATED_WITH_EMPTY_REASON @deprecated(reason: "") + ALSO_NON_DEPRECATED + } - const TestType = new GraphQLObjectType({ - name: 'TestType', - fields: { - testEnum: { - type: TestEnum, - }, - }, - }); + type Query { + someField(someArg: SomeEnum): String + } + `); - const schema = new GraphQLSchema({ query: TestType }); const source = ` { - __type(name: "TestEnum") { + __type(name: "SomeEnum") { trueValues: enumValues(includeDeprecated: true) { name } @@ -1257,53 +1372,79 @@ describe('Introspection', () => { }); }); - it('fails as expected on the __type root field without an arg', () => { - const TestType = new GraphQLObjectType({ - name: 'TestType', - fields: { - testField: { - type: GraphQLString, - }, - }, - }); + it('identifies deprecated for input fields', () => { + const schema = buildSchema(` + input SomeInputObject { + nonDeprecated: String + deprecated: String @deprecated(reason: "Removed in 1.0") + deprecatedWithEmptyReason: String @deprecated(reason: "") + } + + type Query { + someField(someArg: SomeInputObject): String + } + `); - const schema = new GraphQLSchema({ query: TestType }); const source = ` { - __type { - name + __type(name: "SomeInputObject") { + inputFields(includeDeprecated: true) { + name + isDeprecated, + deprecationReason + } } } `; expect(graphqlSync({ schema, source })).to.deep.equal({ - errors: [ - { - message: - 'Field "__type" argument "name" of type "String!" is required, but it was not provided.', - locations: [{ line: 3, column: 9 }], + data: { + __type: { + inputFields: [ + { + name: 'nonDeprecated', + isDeprecated: false, + deprecationReason: null, + }, + { + name: 'deprecated', + isDeprecated: true, + deprecationReason: 'Removed in 1.0', + }, + { + name: 'deprecatedWithEmptyReason', + isDeprecated: true, + deprecationReason: '', + }, + ], }, - ], + }, }); }); - it('exposes descriptions on types and fields', () => { - const QueryRoot = new GraphQLObjectType({ - name: 'QueryRoot', - fields: { - onlyField: { type: GraphQLString }, - }, - }); + it('respects the includeDeprecated parameter for input fields', () => { + const schema = buildSchema(` + input SomeInputObject { + nonDeprecated: String + deprecated: String @deprecated(reason: "Removed in 1.0") + } + + type Query { + someField(someArg: SomeInputObject): String + } + `); - const schema = new GraphQLSchema({ query: QueryRoot }); const source = ` { - schemaType: __type(name: "__Schema") { - name, - description, - fields { - name, - description + __type(name: "SomeInputObject") { + trueFields: inputFields(includeDeprecated: true) { + name + } + falseFields: inputFields(includeDeprecated: false) { + name + } + omittedFields: inputFields { + name } } } @@ -1311,59 +1452,75 @@ describe('Introspection', () => { expect(graphqlSync({ schema, source })).to.deep.equal({ data: { - schemaType: { - 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.', - fields: [ - { - name: 'description', - description: null, - }, - { - name: 'types', - description: 'A list of all types supported by this server.', - }, - { - name: 'queryType', - description: 'The type that query operations will be rooted at.', - }, - { - name: 'mutationType', - description: - 'If this server supports mutation, the type that mutation operations will be rooted at.', - }, - { - name: 'subscriptionType', - description: - 'If this server support subscription, the type that subscription operations will be rooted at.', - }, - { - name: 'directives', - description: 'A list of all directives supported by this server.', - }, - ], + __type: { + trueFields: [{ name: 'nonDeprecated' }, { name: 'deprecated' }], + falseFields: [{ name: 'nonDeprecated' }], + omittedFields: [{ name: 'nonDeprecated' }], }, }, }); }); - it('exposes descriptions on enums', () => { - const QueryRoot = new GraphQLObjectType({ - name: 'QueryRoot', - fields: { - onlyField: { type: GraphQLString }, - }, + it('fails as expected on the __type root field without an arg', () => { + const schema = buildSchema(` + type Query { + someField: String + } + `); + + const source = ` + { + __type { + name + } + } + `; + + expect(graphqlSync({ schema, source })).to.deep.equal({ + errors: [ + { + message: + 'Field "__type" argument "name" of type "String!" is required, but it was not provided.', + locations: [{ line: 3, column: 9 }], + }, + ], }); + }); + + it('exposes descriptions', () => { + const schema = buildSchema(` + """Enum description""" + enum SomeEnum { + """Value description""" + VALUE + } + + """Object description""" + type SomeObject { + """Field description""" + someField(arg: SomeEnum): String + } + + """Schema description""" + schema { + query: SomeObject + } + `); - const schema = new GraphQLSchema({ query: QueryRoot }); const source = ` { - typeKindType: __type(name: "__TypeKind") { - name, + Schema: __schema { description } + SomeObject: __type(name: "SomeObject") { description, + fields { + name + description + } + } + SomeEnum: __type(name: "SomeEnum") { + description enumValues { - name, + name description } } @@ -1372,49 +1529,24 @@ describe('Introspection', () => { expect(graphqlSync({ schema, source })).to.deep.equal({ data: { - typeKindType: { - name: '__TypeKind', - description: - 'An enum describing what kind of type a given `__Type` is.', + Schema: { + description: 'Schema description', + }, + SomeEnum: { + description: 'Enum description', enumValues: [ { - description: 'Indicates this type is a scalar.', - name: 'SCALAR', - }, - { - description: - 'Indicates this type is an object. `fields` and `interfaces` are valid fields.', - name: 'OBJECT', - }, - { - description: - 'Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields.', - name: 'INTERFACE', - }, - { - description: - 'Indicates this type is a union. `possibleTypes` is a valid field.', - name: 'UNION', - }, - { - description: - 'Indicates this type is an enum. `enumValues` is a valid field.', - name: 'ENUM', - }, - { - description: - 'Indicates this type is an input object. `inputFields` is a valid field.', - name: 'INPUT_OBJECT', - }, - { - description: - 'Indicates this type is a list. `ofType` is a valid field.', - name: 'LIST', + name: 'VALUE', + description: 'Value description', }, + ], + }, + SomeObject: { + description: 'Object description', + fields: [ { - description: - 'Indicates this type is a non-null. `ofType` is a valid field.', - name: 'NON_NULL', + name: 'someField', + description: 'Field description', }, ], }, @@ -1422,22 +1554,36 @@ describe('Introspection', () => { }); }); - it('executes an introspection query without calling global fieldResolver', () => { - const QueryRoot = new GraphQLObjectType({ - name: 'QueryRoot', - fields: { - onlyField: { type: GraphQLString }, - }, - }); + it('executes an introspection query without calling global resolvers', () => { + const schema = buildSchema(` + type Query { + someField: String + } + `); - const schema = new GraphQLSchema({ query: QueryRoot }); - const source = getIntrospectionQuery({ directiveIsRepeatable: true }); + const source = getIntrospectionQuery({ + specifiedByUrl: true, + directiveIsRepeatable: true, + schemaDescription: true, + }); - /* istanbul ignore next */ + // istanbul ignore next (Called only to fail test) function fieldResolver(_1, _2, _3, info) { invariant(false, `Called on ${info.parentType.name}::${info.fieldName}`); } - expect(() => graphqlSync({ schema, source, fieldResolver })).to.not.throw(); + // istanbul ignore next (Called only to fail test) + function typeResolver(_1, _2, info) { + invariant(false, `Called on ${info.parentType.name}::${info.fieldName}`); + } + + expect(() => + graphqlSync({ + schema, + source, + fieldResolver, + typeResolver, + }), + ).to.not.throw(); }); }); diff --git a/src/type/__tests__/predicate-test.js b/src/type/__tests__/predicate-test.js index 40dcca7ee8..33c2c49f57 100644 --- a/src/type/__tests__/predicate-test.js +++ b/src/type/__tests__/predicate-test.js @@ -1,8 +1,7 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import type { GraphQLArgument, GraphQLInputField } from '../definition'; import { GraphQLDirective, GraphQLSkipDirective, @@ -21,14 +20,14 @@ import { isSpecifiedScalarType, } from '../scalars'; import { + GraphQLList, + GraphQLNonNull, GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType, - GraphQLList, - GraphQLNonNull, isType, isScalarType, isObjectType, @@ -96,8 +95,10 @@ describe('Type predicates', () => { }); it('returns true for wrapped types', () => { - expect(isType(GraphQLNonNull(GraphQLString))).to.equal(true); - expect(() => assertType(GraphQLNonNull(GraphQLString))).to.not.throw(); + expect(isType(new GraphQLNonNull(GraphQLString))).to.equal(true); + expect(() => + assertType(new GraphQLNonNull(GraphQLString)), + ).to.not.throw(); }); it('returns false for type classes (rather than instances)', () => { @@ -128,8 +129,8 @@ describe('Type predicates', () => { }); it('returns false for wrapped scalar', () => { - expect(isScalarType(GraphQLList(ScalarType))).to.equal(false); - expect(() => assertScalarType(GraphQLList(ScalarType))).to.throw(); + expect(isScalarType(new GraphQLList(ScalarType))).to.equal(false); + expect(() => assertScalarType(new GraphQLList(ScalarType))).to.throw(); }); it('returns false for non-scalar', () => { @@ -166,8 +167,8 @@ describe('Type predicates', () => { }); it('returns false for wrapped object type', () => { - expect(isObjectType(GraphQLList(ObjectType))).to.equal(false); - expect(() => assertObjectType(GraphQLList(ObjectType))).to.throw(); + expect(isObjectType(new GraphQLList(ObjectType))).to.equal(false); + expect(() => assertObjectType(new GraphQLList(ObjectType))).to.throw(); }); it('returns false for non-object type', () => { @@ -183,8 +184,10 @@ describe('Type predicates', () => { }); it('returns false for wrapped interface type', () => { - expect(isInterfaceType(GraphQLList(InterfaceType))).to.equal(false); - expect(() => assertInterfaceType(GraphQLList(InterfaceType))).to.throw(); + expect(isInterfaceType(new GraphQLList(InterfaceType))).to.equal(false); + expect(() => + assertInterfaceType(new GraphQLList(InterfaceType)), + ).to.throw(); }); it('returns false for non-interface type', () => { @@ -200,8 +203,8 @@ describe('Type predicates', () => { }); it('returns false for wrapped union type', () => { - expect(isUnionType(GraphQLList(UnionType))).to.equal(false); - expect(() => assertUnionType(GraphQLList(UnionType))).to.throw(); + expect(isUnionType(new GraphQLList(UnionType))).to.equal(false); + expect(() => assertUnionType(new GraphQLList(UnionType))).to.throw(); }); it('returns false for non-union type', () => { @@ -217,8 +220,8 @@ describe('Type predicates', () => { }); it('returns false for wrapped enum type', () => { - expect(isEnumType(GraphQLList(EnumType))).to.equal(false); - expect(() => assertEnumType(GraphQLList(EnumType))).to.throw(); + expect(isEnumType(new GraphQLList(EnumType))).to.equal(false); + expect(() => assertEnumType(new GraphQLList(EnumType))).to.throw(); }); it('returns false for non-enum type', () => { @@ -234,9 +237,11 @@ describe('Type predicates', () => { }); it('returns false for wrapped input object type', () => { - expect(isInputObjectType(GraphQLList(InputObjectType))).to.equal(false); + expect(isInputObjectType(new GraphQLList(InputObjectType))).to.equal( + false, + ); expect(() => - assertInputObjectType(GraphQLList(InputObjectType)), + assertInputObjectType(new GraphQLList(InputObjectType)), ).to.throw(); }); @@ -248,8 +253,8 @@ describe('Type predicates', () => { describe('isListType', () => { it('returns true for a list wrapped type', () => { - expect(isListType(GraphQLList(ObjectType))).to.equal(true); - expect(() => assertListType(GraphQLList(ObjectType))).to.not.throw(); + expect(isListType(new GraphQLList(ObjectType))).to.equal(true); + expect(() => assertListType(new GraphQLList(ObjectType))).to.not.throw(); }); it('returns false for an unwrapped type', () => { @@ -258,20 +263,20 @@ describe('Type predicates', () => { }); it('returns false for a non-list wrapped type', () => { - expect(isListType(GraphQLNonNull(GraphQLList(ObjectType)))).to.equal( - false, - ); + expect( + isListType(new GraphQLNonNull(new GraphQLList(ObjectType))), + ).to.equal(false); expect(() => - assertListType(GraphQLNonNull(GraphQLList(ObjectType))), + assertListType(new GraphQLNonNull(new GraphQLList(ObjectType))), ).to.throw(); }); }); describe('isNonNullType', () => { it('returns true for a non-null wrapped type', () => { - expect(isNonNullType(GraphQLNonNull(ObjectType))).to.equal(true); + expect(isNonNullType(new GraphQLNonNull(ObjectType))).to.equal(true); expect(() => - assertNonNullType(GraphQLNonNull(ObjectType)), + assertNonNullType(new GraphQLNonNull(ObjectType)), ).to.not.throw(); }); @@ -281,17 +286,17 @@ describe('Type predicates', () => { }); it('returns false for a not non-null wrapped type', () => { - expect(isNonNullType(GraphQLList(GraphQLNonNull(ObjectType)))).to.equal( - false, - ); + expect( + isNonNullType(new GraphQLList(new GraphQLNonNull(ObjectType))), + ).to.equal(false); expect(() => - assertNonNullType(GraphQLList(GraphQLNonNull(ObjectType))), + assertNonNullType(new GraphQLList(new GraphQLNonNull(ObjectType))), ).to.throw(); }); }); describe('isInputType', () => { - function expectInputType(type) { + function expectInputType(type: mixed) { expect(isInputType(type)).to.equal(true); expect(() => assertInputType(type)).to.not.throw(); } @@ -303,16 +308,16 @@ describe('Type predicates', () => { }); it('returns true for a wrapped input type', () => { - expectInputType(GraphQLList(GraphQLString)); - expectInputType(GraphQLList(EnumType)); - expectInputType(GraphQLList(InputObjectType)); + expectInputType(new GraphQLList(GraphQLString)); + expectInputType(new GraphQLList(EnumType)); + expectInputType(new GraphQLList(InputObjectType)); - expectInputType(GraphQLNonNull(GraphQLString)); - expectInputType(GraphQLNonNull(EnumType)); - expectInputType(GraphQLNonNull(InputObjectType)); + expectInputType(new GraphQLNonNull(GraphQLString)); + expectInputType(new GraphQLNonNull(EnumType)); + expectInputType(new GraphQLNonNull(InputObjectType)); }); - function expectNonInputType(type) { + function expectNonInputType(type: mixed) { expect(isInputType(type)).to.equal(false); expect(() => assertInputType(type)).to.throw(); } @@ -324,18 +329,18 @@ describe('Type predicates', () => { }); it('returns false for a wrapped output type', () => { - expectNonInputType(GraphQLList(ObjectType)); - expectNonInputType(GraphQLList(InterfaceType)); - expectNonInputType(GraphQLList(UnionType)); + expectNonInputType(new GraphQLList(ObjectType)); + expectNonInputType(new GraphQLList(InterfaceType)); + expectNonInputType(new GraphQLList(UnionType)); - expectNonInputType(GraphQLNonNull(ObjectType)); - expectNonInputType(GraphQLNonNull(InterfaceType)); - expectNonInputType(GraphQLNonNull(UnionType)); + expectNonInputType(new GraphQLNonNull(ObjectType)); + expectNonInputType(new GraphQLNonNull(InterfaceType)); + expectNonInputType(new GraphQLNonNull(UnionType)); }); }); describe('isOutputType', () => { - function expectOutputType(type) { + function expectOutputType(type: mixed) { expect(isOutputType(type)).to.equal(true); expect(() => assertOutputType(type)).to.not.throw(); } @@ -349,20 +354,20 @@ describe('Type predicates', () => { }); it('returns true for a wrapped output type', () => { - expectOutputType(GraphQLList(GraphQLString)); - expectOutputType(GraphQLList(ObjectType)); - expectOutputType(GraphQLList(InterfaceType)); - expectOutputType(GraphQLList(UnionType)); - expectOutputType(GraphQLList(EnumType)); + expectOutputType(new GraphQLList(GraphQLString)); + expectOutputType(new GraphQLList(ObjectType)); + expectOutputType(new GraphQLList(InterfaceType)); + expectOutputType(new GraphQLList(UnionType)); + expectOutputType(new GraphQLList(EnumType)); - expectOutputType(GraphQLNonNull(GraphQLString)); - expectOutputType(GraphQLNonNull(ObjectType)); - expectOutputType(GraphQLNonNull(InterfaceType)); - expectOutputType(GraphQLNonNull(UnionType)); - expectOutputType(GraphQLNonNull(EnumType)); + expectOutputType(new GraphQLNonNull(GraphQLString)); + expectOutputType(new GraphQLNonNull(ObjectType)); + expectOutputType(new GraphQLNonNull(InterfaceType)); + expectOutputType(new GraphQLNonNull(UnionType)); + expectOutputType(new GraphQLNonNull(EnumType)); }); - function expectNonOutputType(type) { + function expectNonOutputType(type: mixed) { expect(isOutputType(type)).to.equal(false); expect(() => assertOutputType(type)).to.throw(); } @@ -372,8 +377,8 @@ describe('Type predicates', () => { }); it('returns false for a wrapped input type', () => { - expectNonOutputType(GraphQLList(InputObjectType)); - expectNonOutputType(GraphQLNonNull(InputObjectType)); + expectNonOutputType(new GraphQLList(InputObjectType)); + expectNonOutputType(new GraphQLNonNull(InputObjectType)); }); }); @@ -386,8 +391,8 @@ describe('Type predicates', () => { }); it('returns false for wrapped leaf type', () => { - expect(isLeafType(GraphQLList(ScalarType))).to.equal(false); - expect(() => assertLeafType(GraphQLList(ScalarType))).to.throw(); + expect(isLeafType(new GraphQLList(ScalarType))).to.equal(false); + expect(() => assertLeafType(new GraphQLList(ScalarType))).to.throw(); }); it('returns false for non-leaf type', () => { @@ -396,8 +401,8 @@ describe('Type predicates', () => { }); it('returns false for wrapped non-leaf type', () => { - expect(isLeafType(GraphQLList(ObjectType))).to.equal(false); - expect(() => assertLeafType(GraphQLList(ObjectType))).to.throw(); + expect(isLeafType(new GraphQLList(ObjectType))).to.equal(false); + expect(() => assertLeafType(new GraphQLList(ObjectType))).to.throw(); }); }); @@ -412,8 +417,8 @@ describe('Type predicates', () => { }); it('returns false for wrapped composite type', () => { - expect(isCompositeType(GraphQLList(ObjectType))).to.equal(false); - expect(() => assertCompositeType(GraphQLList(ObjectType))).to.throw(); + expect(isCompositeType(new GraphQLList(ObjectType))).to.equal(false); + expect(() => assertCompositeType(new GraphQLList(ObjectType))).to.throw(); }); it('returns false for non-composite type', () => { @@ -422,9 +427,9 @@ describe('Type predicates', () => { }); it('returns false for wrapped non-composite type', () => { - expect(isCompositeType(GraphQLList(InputObjectType))).to.equal(false); + expect(isCompositeType(new GraphQLList(InputObjectType))).to.equal(false); expect(() => - assertCompositeType(GraphQLList(InputObjectType)), + assertCompositeType(new GraphQLList(InputObjectType)), ).to.throw(); }); }); @@ -438,8 +443,10 @@ describe('Type predicates', () => { }); it('returns false for wrapped abstract type', () => { - expect(isAbstractType(GraphQLList(InterfaceType))).to.equal(false); - expect(() => assertAbstractType(GraphQLList(InterfaceType))).to.throw(); + expect(isAbstractType(new GraphQLList(InterfaceType))).to.equal(false); + expect(() => + assertAbstractType(new GraphQLList(InterfaceType)), + ).to.throw(); }); it('returns false for non-abstract type', () => { @@ -448,18 +455,20 @@ describe('Type predicates', () => { }); it('returns false for wrapped non-abstract type', () => { - expect(isAbstractType(GraphQLList(ObjectType))).to.equal(false); - expect(() => assertAbstractType(GraphQLList(ObjectType))).to.throw(); + expect(isAbstractType(new GraphQLList(ObjectType))).to.equal(false); + expect(() => assertAbstractType(new GraphQLList(ObjectType))).to.throw(); }); }); describe('isWrappingType', () => { it('returns true for list and non-null types', () => { - expect(isWrappingType(GraphQLList(ObjectType))).to.equal(true); - expect(() => assertWrappingType(GraphQLList(ObjectType))).to.not.throw(); - expect(isWrappingType(GraphQLNonNull(ObjectType))).to.equal(true); + expect(isWrappingType(new GraphQLList(ObjectType))).to.equal(true); expect(() => - assertWrappingType(GraphQLNonNull(ObjectType)), + assertWrappingType(new GraphQLList(ObjectType)), + ).to.not.throw(); + expect(isWrappingType(new GraphQLNonNull(ObjectType))).to.equal(true); + expect(() => + assertWrappingType(new GraphQLNonNull(ObjectType)), ).to.not.throw(); }); @@ -476,17 +485,19 @@ describe('Type predicates', () => { }); it('returns true for list of non-null types', () => { - expect(isNullableType(GraphQLList(GraphQLNonNull(ObjectType)))).to.equal( - true, - ); + expect( + isNullableType(new GraphQLList(new GraphQLNonNull(ObjectType))), + ).to.equal(true); expect(() => - assertNullableType(GraphQLList(GraphQLNonNull(ObjectType))), + assertNullableType(new GraphQLList(new GraphQLNonNull(ObjectType))), ).to.not.throw(); }); it('returns false for non-null types', () => { - expect(isNullableType(GraphQLNonNull(ObjectType))).to.equal(false); - expect(() => assertNullableType(GraphQLNonNull(ObjectType))).to.throw(); + expect(isNullableType(new GraphQLNonNull(ObjectType))).to.equal(false); + expect(() => + assertNullableType(new GraphQLNonNull(ObjectType)), + ).to.throw(); }); }); @@ -498,12 +509,14 @@ describe('Type predicates', () => { it('returns self for a nullable type', () => { expect(getNullableType(ObjectType)).to.equal(ObjectType); - const listOfObj = GraphQLList(ObjectType); + const listOfObj = new GraphQLList(ObjectType); expect(getNullableType(listOfObj)).to.equal(listOfObj); }); it('unwraps non-null type', () => { - expect(getNullableType(GraphQLNonNull(ObjectType))).to.equal(ObjectType); + expect(getNullableType(new GraphQLNonNull(ObjectType))).to.equal( + ObjectType, + ); }); }); @@ -514,10 +527,10 @@ describe('Type predicates', () => { }); it('returns false for list and non-null types', () => { - expect(isNamedType(GraphQLList(ObjectType))).to.equal(false); - expect(() => assertNamedType(GraphQLList(ObjectType))).to.throw(); - expect(isNamedType(GraphQLNonNull(ObjectType))).to.equal(false); - expect(() => assertNamedType(GraphQLNonNull(ObjectType))).to.throw(); + expect(isNamedType(new GraphQLList(ObjectType))).to.equal(false); + expect(() => assertNamedType(new GraphQLList(ObjectType))).to.throw(); + expect(isNamedType(new GraphQLNonNull(ObjectType))).to.equal(false); + expect(() => assertNamedType(new GraphQLNonNull(ObjectType))).to.throw(); }); }); @@ -532,23 +545,26 @@ describe('Type predicates', () => { }); it('unwraps wrapper types', () => { - expect(getNamedType(GraphQLNonNull(ObjectType))).to.equal(ObjectType); - expect(getNamedType(GraphQLList(ObjectType))).to.equal(ObjectType); + expect(getNamedType(new GraphQLNonNull(ObjectType))).to.equal(ObjectType); + expect(getNamedType(new GraphQLList(ObjectType))).to.equal(ObjectType); }); it('unwraps deeply wrapper types', () => { expect( - getNamedType(GraphQLNonNull(GraphQLList(GraphQLNonNull(ObjectType)))), + getNamedType( + new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(ObjectType))), + ), ).to.equal(ObjectType); }); }); describe('isRequiredArgument', () => { - function buildArg(config) { + function buildArg(config: $Shape) { return { name: 'someArg', description: undefined, defaultValue: undefined, + deprecationReason: null, extensions: undefined, astNode: undefined, ...config, @@ -557,7 +573,7 @@ describe('Type predicates', () => { it('returns true for required arguments', () => { const requiredArg = buildArg({ - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), }); expect(isRequiredArgument(requiredArg)).to.equal(true); }); @@ -575,12 +591,12 @@ describe('Type predicates', () => { expect(isRequiredArgument(optArg2)).to.equal(false); const optArg3 = buildArg({ - type: GraphQLList(GraphQLNonNull(GraphQLString)), + type: new GraphQLList(new GraphQLNonNull(GraphQLString)), }); expect(isRequiredArgument(optArg3)).to.equal(false); const optArg4 = buildArg({ - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), defaultValue: 'default', }); expect(isRequiredArgument(optArg4)).to.equal(false); @@ -588,11 +604,12 @@ describe('Type predicates', () => { }); describe('isRequiredInputField', () => { - function buildInputField(config) { + function buildInputField(config: $Shape) { return { name: 'someInputField', description: undefined, defaultValue: undefined, + deprecationReason: null, extensions: undefined, astNode: undefined, ...config, @@ -601,7 +618,7 @@ describe('Type predicates', () => { it('returns true for required input field', () => { const requiredField = buildInputField({ - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), }); expect(isRequiredInputField(requiredField)).to.equal(true); }); @@ -619,12 +636,12 @@ describe('Type predicates', () => { expect(isRequiredInputField(optField2)).to.equal(false); const optField3 = buildInputField({ - type: GraphQLList(GraphQLNonNull(GraphQLString)), + type: new GraphQLList(new GraphQLNonNull(GraphQLString)), }); expect(isRequiredInputField(optField3)).to.equal(false); const optField4 = buildInputField({ - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), defaultValue: 'default', }); expect(isRequiredInputField(optField4)).to.equal(false); diff --git a/src/type/__tests__/scalars-test.js b/src/type/__tests__/scalars-test.js index 3ad38fa15c..6e901c3fb0 100644 --- a/src/type/__tests__/scalars-test.js +++ b/src/type/__tests__/scalars-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -16,7 +14,7 @@ import { describe('Type System: Specified scalar types', () => { describe('GraphQLInt', () => { it('parseValue', () => { - function parseValue(value) { + function parseValue(value: mixed) { return GraphQLInt.parseValue(value); } @@ -67,7 +65,7 @@ describe('Type System: Specified scalar types', () => { }); it('parseLiteral', () => { - function parseLiteral(str) { + function parseLiteral(str: string) { return GraphQLInt.parseLiteral(parseValueToAST(str)); } @@ -110,11 +108,82 @@ describe('Type System: Specified scalar types', () => { 'Int cannot represent non-integer value: $var', ); }); + + it('serialize', () => { + function serialize(value: mixed) { + return GraphQLInt.serialize(value); + } + + expect(serialize(1)).to.equal(1); + expect(serialize('123')).to.equal(123); + expect(serialize(0)).to.equal(0); + expect(serialize(-1)).to.equal(-1); + expect(serialize(1e5)).to.equal(100000); + expect(serialize(false)).to.equal(0); + expect(serialize(true)).to.equal(1); + + const customValueOfObj = { + value: 5, + valueOf() { + return this.value; + }, + }; + expect(serialize(customValueOfObj)).to.equal(5); + + // The GraphQL specification does not allow serializing non-integer values + // as Int to avoid accidental data loss. + expect(() => serialize(0.1)).to.throw( + 'Int cannot represent non-integer value: 0.1', + ); + expect(() => serialize(1.1)).to.throw( + 'Int cannot represent non-integer value: 1.1', + ); + expect(() => serialize(-1.1)).to.throw( + 'Int cannot represent non-integer value: -1.1', + ); + expect(() => serialize('-1.1')).to.throw( + 'Int cannot represent non-integer value: "-1.1"', + ); + + // Maybe a safe JavaScript int, but bigger than 2^32, so not + // representable as a GraphQL Int + expect(() => serialize(9876504321)).to.throw( + 'Int cannot represent non 32-bit signed integer value: 9876504321', + ); + expect(() => serialize(-9876504321)).to.throw( + 'Int cannot represent non 32-bit signed integer value: -9876504321', + ); + + // Too big to represent as an Int in JavaScript or GraphQL + expect(() => serialize(1e100)).to.throw( + 'Int cannot represent non 32-bit signed integer value: 1e+100', + ); + expect(() => serialize(-1e100)).to.throw( + 'Int cannot represent non 32-bit signed integer value: -1e+100', + ); + expect(() => serialize('one')).to.throw( + 'Int cannot represent non-integer value: "one"', + ); + + // Doesn't represent number + expect(() => serialize('')).to.throw( + 'Int cannot represent non-integer value: ""', + ); + expect(() => serialize(NaN)).to.throw( + 'Int cannot represent non-integer value: NaN', + ); + expect(() => serialize(Infinity)).to.throw( + 'Int cannot represent non-integer value: Infinity', + ); + expect(() => serialize([5])).to.throw( + 'Int cannot represent non-integer value: [5]', + ); + }); }); describe('GraphQLFloat', () => { it('parseValue', () => { - function parseValue(value) { + function parseValue(value: mixed) { return GraphQLFloat.parseValue(value); } @@ -161,7 +230,7 @@ describe('Type System: Specified scalar types', () => { }); it('parseLiteral', () => { - function parseLiteral(str) { + function parseLiteral(str: string) { return GraphQLFloat.parseLiteral(parseValueToAST(str)); } @@ -199,11 +268,52 @@ describe('Type System: Specified scalar types', () => { 'Float cannot represent non numeric value: $var', ); }); + + it('serialize', () => { + function serialize(value: mixed) { + return GraphQLFloat.serialize(value); + } + + expect(serialize(1)).to.equal(1.0); + expect(serialize(0)).to.equal(0.0); + expect(serialize('123.5')).to.equal(123.5); + expect(serialize(-1)).to.equal(-1.0); + expect(serialize(0.1)).to.equal(0.1); + expect(serialize(1.1)).to.equal(1.1); + expect(serialize(-1.1)).to.equal(-1.1); + expect(serialize('-1.1')).to.equal(-1.1); + expect(serialize(false)).to.equal(0.0); + expect(serialize(true)).to.equal(1.0); + + const customValueOfObj = { + value: 5.5, + valueOf() { + return this.value; + }, + }; + expect(serialize(customValueOfObj)).to.equal(5.5); + + expect(() => serialize(NaN)).to.throw( + 'Float cannot represent non numeric value: NaN', + ); + expect(() => serialize(Infinity)).to.throw( + 'Float cannot represent non numeric value: Infinity', + ); + expect(() => serialize('one')).to.throw( + 'Float cannot represent non numeric value: "one"', + ); + expect(() => serialize('')).to.throw( + 'Float cannot represent non numeric value: ""', + ); + expect(() => serialize([5])).to.throw( + 'Float cannot represent non numeric value: [5]', + ); + }); }); describe('GraphQLString', () => { it('parseValue', () => { - function parseValue(value) { + function parseValue(value: mixed) { return GraphQLString.parseValue(value); } @@ -233,7 +343,7 @@ describe('Type System: Specified scalar types', () => { }); it('parseLiteral', () => { - function parseLiteral(str) { + function parseLiteral(str: string) { return GraphQLString.parseLiteral(parseValueToAST(str)); } @@ -265,11 +375,50 @@ describe('Type System: Specified scalar types', () => { 'String cannot represent a non string value: $var', ); }); + + it('serialize', () => { + function serialize(value: mixed) { + return GraphQLString.serialize(value); + } + + expect(serialize('string')).to.equal('string'); + expect(serialize(1)).to.equal('1'); + expect(serialize(-1.1)).to.equal('-1.1'); + expect(serialize(true)).to.equal('true'); + expect(serialize(false)).to.equal('false'); + + const valueOf = () => 'valueOf string'; + const toJSON = () => 'toJSON string'; + + const valueOfAndToJSONValue = { valueOf, toJSON }; + expect(serialize(valueOfAndToJSONValue)).to.equal('valueOf string'); + + const onlyToJSONValue = { toJSON }; + expect(serialize(onlyToJSONValue)).to.equal('toJSON string'); + + expect(() => serialize(NaN)).to.throw( + 'String cannot represent value: NaN', + ); + + expect(() => serialize([1])).to.throw( + 'String cannot represent value: [1]', + ); + + const badObjValue = {}; + expect(() => serialize(badObjValue)).to.throw( + 'String cannot represent value: {}', + ); + + const badValueOfObjValue = { valueOf: 'valueOf string' }; + expect(() => serialize(badValueOfObjValue)).to.throw( + 'String cannot represent value: { valueOf: "valueOf string" }', + ); + }); }); describe('GraphQLBoolean', () => { it('parseValue', () => { - function parseValue(value) { + function parseValue(value: mixed) { return GraphQLBoolean.parseValue(value); } @@ -306,7 +455,7 @@ describe('Type System: Specified scalar types', () => { }); it('parseLiteral', () => { - function parseLiteral(str) { + function parseLiteral(str: string) { return GraphQLBoolean.parseLiteral(parseValueToAST(str)); } @@ -344,11 +493,46 @@ describe('Type System: Specified scalar types', () => { 'Boolean cannot represent a non boolean value: $var', ); }); + + it('serialize', () => { + function serialize(value: mixed) { + return GraphQLBoolean.serialize(value); + } + + expect(serialize(1)).to.equal(true); + expect(serialize(0)).to.equal(false); + expect(serialize(true)).to.equal(true); + expect(serialize(false)).to.equal(false); + expect( + serialize({ + value: true, + valueOf() { + return this.value; + }, + }), + ).to.equal(true); + + expect(() => serialize(NaN)).to.throw( + 'Boolean cannot represent a non boolean value: NaN', + ); + expect(() => serialize('')).to.throw( + 'Boolean cannot represent a non boolean value: ""', + ); + expect(() => serialize('true')).to.throw( + 'Boolean cannot represent a non boolean value: "true"', + ); + expect(() => serialize([false])).to.throw( + 'Boolean cannot represent a non boolean value: [false]', + ); + expect(() => serialize({})).to.throw( + 'Boolean cannot represent a non boolean value: {}', + ); + }); }); describe('GraphQLID', () => { it('parseValue', () => { - function parseValue(value) { + function parseValue(value: mixed) { return GraphQLID.parseValue(value); } @@ -386,7 +570,7 @@ describe('Type System: Specified scalar types', () => { }); it('parseLiteral', () => { - function parseLiteral(str) { + function parseLiteral(str: string) { return GraphQLID.parseLiteral(parseValueToAST(str)); } @@ -424,5 +608,47 @@ describe('Type System: Specified scalar types', () => { 'ID cannot represent a non-string and non-integer value: $var', ); }); + + it('serialize', () => { + function serialize(value: mixed) { + return GraphQLID.serialize(value); + } + + expect(serialize('string')).to.equal('string'); + expect(serialize('false')).to.equal('false'); + expect(serialize('')).to.equal(''); + expect(serialize(123)).to.equal('123'); + expect(serialize(0)).to.equal('0'); + expect(serialize(-1)).to.equal('-1'); + + const valueOf = () => 'valueOf ID'; + const toJSON = () => 'toJSON ID'; + + const valueOfAndToJSONValue = { valueOf, toJSON }; + expect(serialize(valueOfAndToJSONValue)).to.equal('valueOf ID'); + + const onlyToJSONValue = { toJSON }; + expect(serialize(onlyToJSONValue)).to.equal('toJSON ID'); + + const badObjValue = { + _id: false, + valueOf() { + return this._id; + }, + }; + expect(() => serialize(badObjValue)).to.throw( + 'ID cannot represent value: { _id: false, valueOf: [function valueOf] }', + ); + + expect(() => serialize(true)).to.throw('ID cannot represent value: true'); + + expect(() => serialize(3.14)).to.throw('ID cannot represent value: 3.14'); + + expect(() => serialize({})).to.throw('ID cannot represent value: {}'); + + expect(() => serialize(['abc'])).to.throw( + 'ID cannot represent value: ["abc"]', + ); + }); }); }); diff --git a/src/type/__tests__/schema-test.js b/src/type/__tests__/schema-test.js index f5f558799b..1d8817e3c6 100644 --- a/src/type/__tests__/schema-test.js +++ b/src/type/__tests__/schema-test.js @@ -1,9 +1,7 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; import { printSchema } from '../../utilities/printSchema'; @@ -61,7 +59,7 @@ describe('Type System: Schema', () => { type: BlogArticle, }, feed: { - type: GraphQLList(BlogArticle), + type: new GraphQLList(BlogArticle), }, }, }); @@ -331,11 +329,11 @@ describe('Type System: Schema', () => { }); it('checks the configuration for mistakes', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-exact] expect(() => new GraphQLSchema(JSON.parse)).to.throw(); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => new GraphQLSchema({ types: {} })).to.throw(); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => new GraphQLSchema({ directives: {} })).to.throw(); }); }); @@ -364,7 +362,7 @@ describe('Type System: Schema', () => { }); const types = [{}, query, {}]; - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] 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__/serialization-test.js b/src/type/__tests__/serialization-test.js deleted file mode 100644 index c851f02657..0000000000 --- a/src/type/__tests__/serialization-test.js +++ /dev/null @@ -1,227 +0,0 @@ -// @flow strict - -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { - GraphQLInt, - GraphQLID, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, -} from '../scalars'; - -describe('Type System: Scalar coercion', () => { - it('serializes output as Int', () => { - expect(GraphQLInt.serialize(1)).to.equal(1); - expect(GraphQLInt.serialize('123')).to.equal(123); - expect(GraphQLInt.serialize(0)).to.equal(0); - expect(GraphQLInt.serialize(-1)).to.equal(-1); - expect(GraphQLInt.serialize(1e5)).to.equal(100000); - expect(GraphQLInt.serialize(false)).to.equal(0); - expect(GraphQLInt.serialize(true)).to.equal(1); - expect( - GraphQLInt.serialize({ - value: 5, - valueOf() { - return this.value; - }, - }), - ).to.equal(5); - - // The GraphQL specification does not allow serializing non-integer values - // as Int to avoid accidental data loss. - expect(() => GraphQLInt.serialize(0.1)).to.throw( - 'Int cannot represent non-integer value: 0.1', - ); - expect(() => GraphQLInt.serialize(1.1)).to.throw( - 'Int cannot represent non-integer value: 1.1', - ); - expect(() => GraphQLInt.serialize(-1.1)).to.throw( - 'Int cannot represent non-integer value: -1.1', - ); - expect(() => GraphQLInt.serialize('-1.1')).to.throw( - 'Int cannot represent non-integer value: "-1.1"', - ); - // Maybe a safe JavaScript int, but bigger than 2^32, so not - // representable as a GraphQL Int - expect(() => GraphQLInt.serialize(9876504321)).to.throw( - 'Int cannot represent non 32-bit signed integer value: 9876504321', - ); - expect(() => GraphQLInt.serialize(-9876504321)).to.throw( - 'Int cannot represent non 32-bit signed integer value: -9876504321', - ); - // Too big to represent as an Int in JavaScript or GraphQL - expect(() => GraphQLInt.serialize(1e100)).to.throw( - 'Int cannot represent non 32-bit signed integer value: 1e+100', - ); - expect(() => GraphQLInt.serialize(-1e100)).to.throw( - 'Int cannot represent non 32-bit signed integer value: -1e+100', - ); - expect(() => GraphQLInt.serialize('one')).to.throw( - 'Int cannot represent non-integer value: "one"', - ); - // Doesn't represent number - expect(() => GraphQLInt.serialize('')).to.throw( - 'Int cannot represent non-integer value: ""', - ); - expect(() => GraphQLInt.serialize(NaN)).to.throw( - 'Int cannot represent non-integer value: NaN', - ); - expect(() => GraphQLInt.serialize(Infinity)).to.throw( - 'Int cannot represent non-integer value: Infinity', - ); - expect(() => GraphQLInt.serialize([5])).to.throw( - 'Int cannot represent non-integer value: [5]', - ); - }); - - it('serializes output as Float', () => { - expect(GraphQLFloat.serialize(1)).to.equal(1.0); - expect(GraphQLFloat.serialize(0)).to.equal(0.0); - expect(GraphQLFloat.serialize('123.5')).to.equal(123.5); - expect(GraphQLFloat.serialize(-1)).to.equal(-1.0); - expect(GraphQLFloat.serialize(0.1)).to.equal(0.1); - expect(GraphQLFloat.serialize(1.1)).to.equal(1.1); - expect(GraphQLFloat.serialize(-1.1)).to.equal(-1.1); - expect(GraphQLFloat.serialize('-1.1')).to.equal(-1.1); - expect(GraphQLFloat.serialize(false)).to.equal(0.0); - expect(GraphQLFloat.serialize(true)).to.equal(1.0); - expect( - GraphQLFloat.serialize({ - value: 5.5, - valueOf() { - return this.value; - }, - }), - ).to.equal(5.5); - - expect(() => GraphQLFloat.serialize(NaN)).to.throw( - 'Float cannot represent non numeric value: NaN', - ); - expect(() => GraphQLFloat.serialize(Infinity)).to.throw( - 'Float cannot represent non numeric value: Infinity', - ); - expect(() => GraphQLFloat.serialize('one')).to.throw( - 'Float cannot represent non numeric value: "one"', - ); - expect(() => GraphQLFloat.serialize('')).to.throw( - 'Float cannot represent non numeric value: ""', - ); - expect(() => GraphQLFloat.serialize([5])).to.throw( - 'Float cannot represent non numeric value: [5]', - ); - }); - - it('serializes output as String', () => { - expect(GraphQLString.serialize('string')).to.equal('string'); - expect(GraphQLString.serialize(1)).to.equal('1'); - expect(GraphQLString.serialize(-1.1)).to.equal('-1.1'); - expect(GraphQLString.serialize(true)).to.equal('true'); - expect(GraphQLString.serialize(false)).to.equal('false'); - - const valueOf = () => 'valueOf string'; - const toJSON = () => 'toJSON string'; - - const valueOfAndToJSONValue = { valueOf, toJSON }; - expect(GraphQLString.serialize(valueOfAndToJSONValue)).to.equal( - 'valueOf string', - ); - - const onlyToJSONValue = { toJSON }; - expect(GraphQLString.serialize(onlyToJSONValue)).to.equal('toJSON string'); - - expect(() => GraphQLString.serialize(NaN)).to.throw( - 'String cannot represent value: NaN', - ); - - expect(() => GraphQLString.serialize([1])).to.throw( - 'String cannot represent value: [1]', - ); - - const badObjValue = {}; - expect(() => GraphQLString.serialize(badObjValue)).to.throw( - 'String cannot represent value: {}', - ); - - const badValueOfObjValue = { valueOf: 'valueOf string' }; - expect(() => GraphQLString.serialize(badValueOfObjValue)).to.throw( - 'String cannot represent value: { valueOf: "valueOf string" }', - ); - }); - - it('serializes output as Boolean', () => { - expect(GraphQLBoolean.serialize(1)).to.equal(true); - expect(GraphQLBoolean.serialize(0)).to.equal(false); - expect(GraphQLBoolean.serialize(true)).to.equal(true); - expect(GraphQLBoolean.serialize(false)).to.equal(false); - expect( - GraphQLBoolean.serialize({ - value: true, - valueOf() { - return this.value; - }, - }), - ).to.equal(true); - - expect(() => GraphQLBoolean.serialize(NaN)).to.throw( - 'Boolean cannot represent a non boolean value: NaN', - ); - expect(() => GraphQLBoolean.serialize('')).to.throw( - 'Boolean cannot represent a non boolean value: ""', - ); - expect(() => GraphQLBoolean.serialize('true')).to.throw( - 'Boolean cannot represent a non boolean value: "true"', - ); - expect(() => GraphQLBoolean.serialize([false])).to.throw( - 'Boolean cannot represent a non boolean value: [false]', - ); - expect(() => GraphQLBoolean.serialize({})).to.throw( - 'Boolean cannot represent a non boolean value: {}', - ); - }); - - it('serializes output as ID', () => { - expect(GraphQLID.serialize('string')).to.equal('string'); - expect(GraphQLID.serialize('false')).to.equal('false'); - expect(GraphQLID.serialize('')).to.equal(''); - expect(GraphQLID.serialize(123)).to.equal('123'); - expect(GraphQLID.serialize(0)).to.equal('0'); - expect(GraphQLID.serialize(-1)).to.equal('-1'); - - const valueOf = () => 'valueOf ID'; - const toJSON = () => 'toJSON ID'; - - const valueOfAndToJSONValue = { valueOf, toJSON }; - expect(GraphQLID.serialize(valueOfAndToJSONValue)).to.equal('valueOf ID'); - - const onlyToJSONValue = { toJSON }; - expect(GraphQLID.serialize(onlyToJSONValue)).to.equal('toJSON ID'); - - const badObjValue = { - _id: false, - valueOf() { - return this._id; - }, - }; - expect(() => GraphQLID.serialize(badObjValue)).to.throw( - 'ID cannot represent value: { _id: false, valueOf: [function valueOf] }', - ); - - expect(() => GraphQLID.serialize(true)).to.throw( - 'ID cannot represent value: true', - ); - - expect(() => GraphQLID.serialize(3.14)).to.throw( - 'ID cannot represent value: 3.14', - ); - - expect(() => GraphQLID.serialize({})).to.throw( - 'ID cannot represent value: {}', - ); - - expect(() => GraphQLID.serialize(['abc'])).to.throw( - 'ID cannot represent value: ["abc"]', - ); - }); -}); diff --git a/src/type/__tests__/validation-test.js b/src/type/__tests__/validation-test.js index b17245812f..a3e35443da 100644 --- a/src/type/__tests__/validation-test.js +++ b/src/type/__tests__/validation-test.js @@ -1,9 +1,8 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; + import inspect from '../../jsutils/inspect'; import { parse } from '../../language/parser'; @@ -11,14 +10,20 @@ import { parse } from '../../language/parser'; import { extendSchema } from '../../utilities/extendSchema'; import { buildSchema } from '../../utilities/buildASTSchema'; +import type { + GraphQLNamedType, + GraphQLInputType, + GraphQLOutputType, + GraphQLFieldConfig, + GraphQLArgumentConfig, + GraphQLInputFieldConfig, + GraphQLEnumValueConfigMap, +} from '../definition'; import { GraphQLSchema } from '../schema'; import { GraphQLString } from '../scalars'; import { validateSchema, assertValidSchema } from '../validate'; import { GraphQLDirective, assertDirective } from '../directives'; import { - type GraphQLNamedType, - type GraphQLInputType, - type GraphQLOutputType, GraphQLList, GraphQLNonNull, GraphQLObjectType, @@ -68,9 +73,9 @@ function withModifiers( ): Array | GraphQLNonNull>> { return [ type, - GraphQLList(type), - GraphQLNonNull(type), - GraphQLNonNull(GraphQLList(type)), + new GraphQLList(type), + new GraphQLNonNull(type), + new GraphQLNonNull(new GraphQLList(type)), ]; } @@ -100,13 +105,12 @@ const notInputTypes: Array = [ ...withModifiers(SomeInterfaceType), ]; -function schemaWithFieldType(type) { +function schemaWithFieldType(type: GraphQLOutputType): GraphQLSchema { return new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { f: { type } }, }), - types: [type], }); } @@ -387,7 +391,7 @@ 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, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] types: [{ name: 'SomeType' }, SomeDirective], }); expect(validateSchema(schema)).to.deep.equal([ @@ -404,7 +408,7 @@ 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, - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] directives: [null, 'SomeDirective', SomeScalarType], }); expect(validateSchema(schema)).to.deep.equal([ @@ -513,18 +517,20 @@ describe('Type System: Fields args must be properly named', () => { }); it('rejects field arg with invalid names', () => { - const QueryType = new GraphQLObjectType({ - name: 'SomeObject', - fields: { - badField: { - type: GraphQLString, - args: { - 'bad-name-with-dashes': { type: GraphQLString }, + const schema = schemaWithFieldType( + new GraphQLObjectType({ + name: 'SomeObject', + fields: { + badField: { + type: GraphQLString, + args: { + 'bad-name-with-dashes': { type: GraphQLString }, + }, }, }, - }, - }); - const schema = new GraphQLSchema({ query: QueryType }); + }), + ); + expect(validateSchema(schema)).to.deep.equal([ { message: @@ -682,7 +688,7 @@ describe('Type System: Union types must be valid', () => { for (const memberType of badUnionMemberTypes) { const badUnion = new GraphQLUnionType({ name: 'BadUnion', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] types: [memberType], }); const badSchema = schemaWithFieldType(badUnion); @@ -892,6 +898,30 @@ describe('Type System: Input Objects must have fields', () => { }, ]); }); + + it('rejects an Input Object type with required argument that is deprecated', () => { + const schema = buildSchema(` + type Query { + field(arg: SomeInputObject): String + } + + input SomeInputObject { + badField: String! @deprecated + optionalField: String @deprecated + anotherOptionalField: String! = "" @deprecated + } + `); + expect(validateSchema(schema)).to.deep.equal([ + { + message: + 'Required input field SomeInputObject.badField cannot be deprecated.', + locations: [ + { line: 7, column: 27 }, + { line: 7, column: 19 }, + ], + }, + ]); + }); }); describe('Type System: Enum types must be well defined', () => { @@ -925,7 +955,7 @@ describe('Type System: Enum types must be well defined', () => { }); it('rejects an Enum type with incorrectly named values', () => { - function schemaWithEnum(values) { + function schemaWithEnum(values: GraphQLEnumValueConfigMap): GraphQLSchema { return schemaWithFieldType( new GraphQLEnumType({ name: 'SomeEnum', @@ -976,11 +1006,13 @@ describe('Type System: Enum types must be well defined', () => { }); describe('Type System: Object fields must have output types', () => { - function schemaWithObjectFieldOfType(fieldType: GraphQLOutputType) { + function schemaWithObjectField( + fieldConfig: GraphQLFieldConfig, + ): GraphQLSchema { const BadObjectType = new GraphQLObjectType({ name: 'BadObject', fields: { - badField: { type: fieldType }, + badField: fieldConfig, }, }); @@ -998,14 +1030,14 @@ describe('Type System: Object fields must have output types', () => { for (const type of outputTypes) { const typeName = inspect(type); it(`accepts an output type as an Object field type: ${typeName}`, () => { - const schema = schemaWithObjectFieldOfType(type); + const schema = schemaWithObjectField({ type }); expect(validateSchema(schema)).to.deep.equal([]); }); } it('rejects an empty Object field type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithObjectFieldOfType(undefined); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithObjectField({ type: undefined }); expect(validateSchema(schema)).to.deep.equal([ { message: @@ -1017,8 +1049,8 @@ 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}`, () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithObjectFieldOfType(type); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithObjectField({ type }); expect(validateSchema(schema)).to.deep.equal([ { message: `The type of BadObject.badField must be Output Type but got: ${typeStr}.`, @@ -1028,8 +1060,8 @@ describe('Type System: Object fields must have output types', () => { } it('rejects a non-type value as an Object field type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithObjectFieldOfType(Number); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithObjectField({ type: Number }); expect(validateSchema(schema)).to.deep.equal([ { message: @@ -1066,7 +1098,7 @@ describe('Type System: Objects can only implement unique interfaces', () => { const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'BadObject', - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] interfaces: [undefined], fields: { f: { type: GraphQLString } }, }), @@ -1289,20 +1321,20 @@ describe('Type System: Interface extensions should be valid', () => { }); describe('Type System: Interface fields must have output types', () => { - function schemaWithInterfaceFieldOfType(fieldType: GraphQLOutputType) { + function schemaWithInterfaceField( + fieldConfig: GraphQLFieldConfig, + ): GraphQLSchema { + const fields = { badField: fieldConfig }; + const BadInterfaceType = new GraphQLInterfaceType({ name: 'BadInterface', - fields: { - badField: { type: fieldType }, - }, + fields, }); const BadImplementingType = new GraphQLObjectType({ name: 'BadImplementing', interfaces: [BadInterfaceType], - fields: { - badField: { type: fieldType }, - }, + fields, }); return new GraphQLSchema({ @@ -1319,14 +1351,14 @@ describe('Type System: Interface fields must have output types', () => { for (const type of outputTypes) { const typeName = inspect(type); it(`accepts an output type as an Interface field type: ${typeName}`, () => { - const schema = schemaWithInterfaceFieldOfType(type); + const schema = schemaWithInterfaceField({ type }); expect(validateSchema(schema)).to.deep.equal([]); }); } it('rejects an empty Interface field type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithInterfaceFieldOfType(undefined); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithInterfaceField({ type: undefined }); expect(validateSchema(schema)).to.deep.equal([ { message: @@ -1342,8 +1374,8 @@ 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}`, () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithInterfaceFieldOfType(type); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithInterfaceField({ type }); expect(validateSchema(schema)).to.deep.equal([ { message: `The type of BadImplementing.badField must be Output Type but got: ${typeStr}.`, @@ -1356,8 +1388,8 @@ describe('Type System: Interface fields must have output types', () => { } it('rejects a non-type value as an Interface field type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithInterfaceFieldOfType(Number); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithInterfaceField({ type: Number }); expect(validateSchema(schema)).to.deep.equal([ { message: @@ -1420,14 +1452,14 @@ describe('Type System: Interface fields must have output types', () => { }); describe('Type System: Arguments must have input types', () => { - function schemaWithArgOfType(argType: GraphQLInputType) { + function schemaWithArg(argConfig: GraphQLArgumentConfig): GraphQLSchema { const BadObjectType = new GraphQLObjectType({ name: 'BadObject', fields: { badField: { type: GraphQLString, args: { - badArg: { type: argType }, + badArg: argConfig, }, }, }, @@ -1444,7 +1476,7 @@ describe('Type System: Arguments must have input types', () => { new GraphQLDirective({ name: 'BadDirective', args: { - badArg: { type: argType }, + badArg: argConfig, }, locations: ['QUERY'], }), @@ -1455,14 +1487,14 @@ describe('Type System: Arguments must have input types', () => { for (const type of inputTypes) { const typeName = inspect(type); it(`accepts an input type as a field arg type: ${typeName}`, () => { - const schema = schemaWithArgOfType(type); + const schema = schemaWithArg({ type }); expect(validateSchema(schema)).to.deep.equal([]); }); } it('rejects an empty field arg type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithArgOfType(undefined); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithArg({ type: undefined }); expect(validateSchema(schema)).to.deep.equal([ { message: @@ -1478,8 +1510,8 @@ 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}`, () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithArgOfType(type); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithArg({ type }); expect(validateSchema(schema)).to.deep.equal([ { message: `The type of @BadDirective(badArg:) must be Input Type but got: ${typeStr}.`, @@ -1492,8 +1524,8 @@ describe('Type System: Arguments must have input types', () => { } it('rejects a non-type value as a field arg type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithArgOfType(Number); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithArg({ type: Number }); expect(validateSchema(schema)).to.deep.equal([ { message: @@ -1509,6 +1541,41 @@ describe('Type System: Arguments must have input types', () => { ]); }); + it('rejects an required argument that is deprecated', () => { + const schema = buildSchema(` + directive @BadDirective( + badArg: String! @deprecated + optionalArg: String @deprecated + anotherOptionalArg: String! = "" @deprecated + ) on FIELD + + type Query { + test( + badArg: String! @deprecated + optionalArg: String @deprecated + anotherOptionalArg: String! = "" @deprecated + ): String + } + `); + expect(validateSchema(schema)).to.deep.equal([ + { + message: + 'Required argument @BadDirective(badArg:) cannot be deprecated.', + locations: [ + { line: 3, column: 25 }, + { line: 3, column: 17 }, + ], + }, + { + message: 'Required argument Query.test(badArg:) cannot be deprecated.', + locations: [ + { line: 10, column: 27 }, + { line: 10, column: 19 }, + ], + }, + ]); + }); + it('rejects a non-input type as a field arg with locations', () => { const schema = buildSchema(` type Query { @@ -1530,11 +1597,13 @@ describe('Type System: Arguments must have input types', () => { }); describe('Type System: Input Object fields must have input types', () => { - function schemaWithInputFieldOfType(inputFieldType: GraphQLInputType) { + function schemaWithInputField( + inputFieldConfig: GraphQLInputFieldConfig, + ): GraphQLSchema { const BadInputObjectType = new GraphQLInputObjectType({ name: 'BadInputObject', fields: { - badField: { type: inputFieldType }, + badField: inputFieldConfig, }, }); @@ -1556,14 +1625,14 @@ describe('Type System: Input Object fields must have input types', () => { for (const type of inputTypes) { const typeName = inspect(type); it(`accepts an input type as an input field type: ${typeName}`, () => { - const schema = schemaWithInputFieldOfType(type); + const schema = schemaWithInputField({ type }); expect(validateSchema(schema)).to.deep.equal([]); }); } it('rejects an empty input field type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithInputFieldOfType(undefined); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithInputField({ type: undefined }); expect(validateSchema(schema)).to.deep.equal([ { message: @@ -1575,8 +1644,8 @@ 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}`, () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithInputFieldOfType(type); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithInputField({ type }); expect(validateSchema(schema)).to.deep.equal([ { message: `The type of BadInputObject.badField must be Input Type but got: ${typeStr}.`, @@ -1586,8 +1655,8 @@ describe('Type System: Input Object fields must have input types', () => { } it('rejects a non-type value as an input field type', () => { - // $DisableFlowOnNegativeTest - const schema = schemaWithInputFieldOfType(Number); + // $FlowExpectedError[incompatible-call] + const schema = schemaWithInputField({ type: Number }); expect(validateSchema(schema)).to.deep.equal([ { message: diff --git a/src/type/definition.d.ts b/src/type/definition.d.ts index 530a01a7e7..06799981f9 100644 --- a/src/type/definition.d.ts +++ b/src/type/definition.d.ts @@ -1,7 +1,8 @@ // FIXME /* eslint-disable import/no-cycle */ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { PromiseOrValue } from '../jsutils/PromiseOrValue'; import { Path } from '../jsutils/Path'; @@ -172,9 +173,9 @@ export function assertAbstractType(type: any): GraphQLAbstractType; */ interface GraphQLList { readonly ofType: T; - toString(): string; - toJSON(): string; - inspect(): string; + toString: () => string; + toJSON: () => string; + inspect: () => string; } interface _GraphQLList { @@ -182,6 +183,7 @@ interface _GraphQLList { new (type: T): GraphQLList; } +// eslint-disable-next-line @typescript-eslint/no-redeclare export const GraphQLList: _GraphQLList; /** @@ -206,9 +208,9 @@ export const GraphQLList: _GraphQLList; */ interface GraphQLNonNull { readonly ofType: T; - toString(): string; - toJSON(): string; - inspect(): string; + toString: () => string; + toJSON: () => string; + inspect: () => string; } interface _GraphQLNonNull { @@ -216,6 +218,7 @@ interface _GraphQLNonNull { new (type: T): GraphQLNonNull; } +// eslint-disable-next-line @typescript-eslint/no-redeclare export const GraphQLNonNull: _GraphQLNonNull; export type GraphQLWrappingType = GraphQLList | GraphQLNonNull; @@ -240,9 +243,10 @@ export function isNullableType(type: any): type is GraphQLNullableType; export function assertNullableType(type: any): GraphQLNullableType; -export function getNullableType(type: void): undefined; +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; @@ -262,7 +266,7 @@ export function isNamedType(type: any): type is GraphQLNamedType; export function assertNamedType(type: any): GraphQLNamedType; -export function getNamedType(type: void): undefined; +export function getNamedType(type: undefined): undefined; export function getNamedType(type: GraphQLType): GraphQLNamedType; /** @@ -271,6 +275,19 @@ export function getNamedType(type: GraphQLType): GraphQLNamedType; */ 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 * @@ -291,20 +308,22 @@ export type Thunk = (() => T) | T; export class GraphQLScalarType { name: string; description: Maybe; + specifiedByUrl: Maybe; serialize: GraphQLScalarSerializer; parseValue: GraphQLScalarValueParser; parseLiteral: GraphQLScalarLiteralParser; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; constructor(config: Readonly>); toConfig(): GraphQLScalarTypeConfig & { + specifiedByUrl: Maybe; serialize: GraphQLScalarSerializer; parseValue: GraphQLScalarValueParser; parseLiteral: GraphQLScalarLiteralParser; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -327,17 +346,34 @@ export type GraphQLScalarLiteralParser = ( export interface GraphQLScalarTypeConfig { name: string; description?: Maybe; + specifiedByUrl?: Maybe; // Serializes an internal value to include in a response. - serialize: GraphQLScalarSerializer; + 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>>; + 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 * @@ -379,7 +415,7 @@ export class GraphQLObjectType { name: string; description: Maybe; isTypeOf: Maybe>; - extensions: Maybe>>; + extensions: Maybe>>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -391,7 +427,7 @@ export class GraphQLObjectType { toConfig(): GraphQLObjectTypeConfig & { interfaces: Array; fields: GraphQLFieldConfigMap; - extensions: Maybe>>; + extensions: Maybe>>; extensionASTNodes: ReadonlyArray; }; @@ -410,7 +446,7 @@ export interface GraphQLObjectTypeConfig { interfaces?: Thunk>>; fields: Thunk>; isTypeOf?: Maybe>; - extensions?: Maybe>>; + extensions?: Maybe>>; astNode?: Maybe; extensionASTNodes?: Maybe>; } @@ -452,6 +488,26 @@ export interface GraphQLResolveInfo { 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, @@ -463,25 +519,41 @@ export interface GraphQLFieldConfig< resolve?: GraphQLFieldResolver; subscribe?: GraphQLFieldResolver; deprecationReason?: Maybe; - extensions?: Maybe>>; + extensions?: Maybe< + Readonly> + >; astNode?: Maybe; } -export type GraphQLFieldConfigArgumentMap = { +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; - extensions?: Maybe>>; + deprecationReason?: Maybe; + extensions?: Maybe>; astNode?: Maybe; } -export type GraphQLFieldConfigMap = { +export interface GraphQLFieldConfigMap { [key: string]: GraphQLFieldConfig; -}; +} export interface GraphQLField< TSource, @@ -494,10 +566,12 @@ export interface GraphQLField< args: Array; resolve?: GraphQLFieldResolver; subscribe?: GraphQLFieldResolver; - isDeprecated: boolean; deprecationReason: Maybe; - extensions: Maybe>>; + extensions: Maybe>>; astNode?: Maybe; + + // @deprecated and will be removed in v16 + isDeprecated: boolean; } export interface GraphQLArgument { @@ -505,15 +579,29 @@ export interface GraphQLArgument { description: Maybe; type: GraphQLInputType; defaultValue: any; - extensions: Maybe>>; + deprecationReason: Maybe; + extensions: Maybe>; astNode: Maybe; } export function isRequiredArgument(arg: GraphQLArgument): boolean; -export type GraphQLFieldMap = { +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 @@ -537,7 +625,7 @@ export class GraphQLInterfaceType { name: string; description: Maybe; resolveType: Maybe>; - extensions: Maybe>>; + extensions: Maybe>; astNode?: Maybe; extensionASTNodes: Maybe>; @@ -548,7 +636,7 @@ export class GraphQLInterfaceType { toConfig(): GraphQLInterfaceTypeConfig & { interfaces: Array; fields: GraphQLFieldConfigMap; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -568,11 +656,24 @@ export interface GraphQLInterfaceTypeConfig { * Object type. */ resolveType?: Maybe>; - extensions?: 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 * @@ -600,7 +701,7 @@ export class GraphQLUnionType { name: string; description: Maybe; resolveType: Maybe>; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -609,7 +710,7 @@ export class GraphQLUnionType { toConfig(): GraphQLUnionTypeConfig & { types: Array; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -628,11 +729,24 @@ export interface GraphQLUnionTypeConfig { * Object type. */ resolveType?: Maybe>; - extensions?: 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 * @@ -657,7 +771,7 @@ export interface GraphQLUnionTypeConfig { export class GraphQLEnumType { name: string; description: Maybe; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -672,7 +786,7 @@ export class GraphQLEnumType { ): Maybe; toConfig(): GraphQLEnumTypeConfig & { - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -685,20 +799,33 @@ export interface GraphQLEnumTypeConfig { name: string; description?: Maybe; values: GraphQLEnumValueConfigMap; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } -export type GraphQLEnumValueConfigMap = { +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>>; + extensions?: Maybe>; astNode?: Maybe; } @@ -706,10 +833,25 @@ export interface GraphQLEnumValue { name: string; description: Maybe; value: any; - isDeprecated: boolean; deprecationReason: Maybe; - extensions: 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; } /** @@ -735,7 +877,7 @@ export interface GraphQLEnumValue { export class GraphQLInputObjectType { name: string; description: Maybe; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -744,7 +886,7 @@ export class GraphQLInputObjectType { toConfig(): GraphQLInputObjectTypeConfig & { fields: GraphQLInputFieldConfigMap; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; }; @@ -757,32 +899,49 @@ export interface GraphQLInputObjectTypeConfig { name: string; description?: Maybe; fields: Thunk; - extensions?: 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 GraphQLInputFieldExtensions { + [attributeName: string]: any; +} + export interface GraphQLInputFieldConfig { description?: Maybe; type: GraphQLInputType; defaultValue?: any; - extensions?: Maybe>>; + deprecationReason?: Maybe; + extensions?: Maybe>; astNode?: Maybe; } -export type GraphQLInputFieldConfigMap = { +export interface GraphQLInputFieldConfigMap { [key: string]: GraphQLInputFieldConfig; -}; +} export interface GraphQLInputField { name: string; description?: Maybe; type: GraphQLInputType; defaultValue?: any; - extensions: Maybe>>; + deprecationReason: Maybe; + extensions: Maybe>; astNode?: Maybe; } export function isRequiredInputField(field: GraphQLInputField): boolean; -export type GraphQLInputFieldMap = { [key: string]: GraphQLInputField }; +export interface GraphQLInputFieldMap { + [key: string]: GraphQLInputField; +} diff --git a/src/type/definition.js b/src/type/definition.js index 16cd2de08e..ca0e1f5a38 100644 --- a/src/type/definition.js +++ b/src/type/definition.js @@ -1,60 +1,55 @@ -// @flow strict - -// FIXME -/* eslint-disable import/no-cycle */ - 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 { type Path } from '../jsutils/Path'; 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 defineToJSON from '../jsutils/defineToJSON'; +import defineInspect from '../jsutils/defineInspect'; import suggestionList from '../jsutils/suggestionList'; -import { type PromiseOrValue } from '../jsutils/PromiseOrValue'; -import { - type ObjMap, - type ReadOnlyObjMap, - type ReadOnlyObjMapLike, -} from '../jsutils/ObjMap'; + +import { GraphQLError } from '../error/GraphQLError'; import { Kind } from '../language/kinds'; import { print } from '../language/printer'; -import { - type ScalarTypeDefinitionNode, - type ObjectTypeDefinitionNode, - type FieldDefinitionNode, - type InputValueDefinitionNode, - type InterfaceTypeDefinitionNode, - type UnionTypeDefinitionNode, - type EnumTypeDefinitionNode, - type EnumValueDefinitionNode, - type InputObjectTypeDefinitionNode, - type ScalarTypeExtensionNode, - type ObjectTypeExtensionNode, - type InterfaceTypeExtensionNode, - type UnionTypeExtensionNode, - type EnumTypeExtensionNode, - type InputObjectTypeExtensionNode, - type OperationDefinitionNode, - type FieldNode, - type FragmentDefinitionNode, - type ValueNode, +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 { GraphQLError } from '../error/GraphQLError'; - import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped'; -import { type GraphQLSchema } from './schema'; +import type { GraphQLSchema } from './schema'; // Predicates & Assertions @@ -344,8 +339,8 @@ export function assertAbstractType(type: mixed): GraphQLAbstractType { * const PersonType = new GraphQLObjectType({ * name: 'Person', * fields: () => ({ - * parents: { type: GraphQLList(PersonType) }, - * children: { type: GraphQLList(PersonType) }, + * parents: { type: new GraphQLList(PersonType) }, + * children: { type: new GraphQLList(PersonType) }, * }) * }) * @@ -361,6 +356,7 @@ declare class GraphQLList<+T: GraphQLType> { */ export function GraphQLList(ofType) { + // istanbul ignore else (to be removed in v16.0.0) if (this instanceof GraphQLList) { this.ofType = assertType(ofType); } else { @@ -373,13 +369,18 @@ export function GraphQLList(ofType) { return '[' + String(this.ofType) + ']'; }; +(GraphQLList.prototype: any).toJSON = function toJSON() { + return this.toString(); +}; + Object.defineProperty(GraphQLList.prototype, SYMBOL_TO_STRING_TAG, { get() { return 'GraphQLList'; }, }); -defineToJSON(GraphQLList); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLList); /** * Non-Null Type Wrapper @@ -395,7 +396,7 @@ defineToJSON(GraphQLList); * const RowType = new GraphQLObjectType({ * name: 'Row', * fields: () => ({ - * id: { type: GraphQLNonNull(GraphQLString) }, + * id: { type: new GraphQLNonNull(GraphQLString) }, * }) * }) * @@ -412,6 +413,7 @@ declare class GraphQLNonNull<+T: GraphQLNullableType> { */ export function GraphQLNonNull(ofType) { + // istanbul ignore else (to be removed in v16.0.0) if (this instanceof GraphQLNonNull) { this.ofType = assertNullableType(ofType); } else { @@ -424,13 +426,18 @@ export function GraphQLNonNull(ofType) { return String(this.ofType) + '!'; }; +(GraphQLNonNull.prototype: any).toJSON = function toJSON() { + return this.toString(); +}; + Object.defineProperty(GraphQLNonNull.prototype, SYMBOL_TO_STRING_TAG, { get() { return 'GraphQLNonNull'; }, }); -defineToJSON(GraphQLNonNull); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLNonNull); /** * These types wrap and modify other types @@ -533,7 +540,7 @@ export function getNamedType(type) { export type Thunk<+T> = (() => T) | T; function resolveThunk<+T>(thunk: Thunk): T { - // $FlowFixMe(>=0.90.0) + // $FlowFixMe[incompatible-use] return typeof thunk === 'function' ? thunk() : thunk; } @@ -568,6 +575,7 @@ function undefineIfEmpty(arr: ?$ReadOnlyArray): ?$ReadOnlyArray { export class GraphQLScalarType { name: string; description: ?string; + specifiedByUrl: ?string; serialize: GraphQLScalarSerializer; parseValue: GraphQLScalarValueParser; parseLiteral: GraphQLScalarLiteralParser; @@ -579,15 +587,25 @@ export class GraphQLScalarType { 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) => parseValue(valueFromASTUntyped(node))); + 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.`, @@ -613,6 +631,7 @@ export class GraphQLScalarType { return { name: this.name, description: this.description, + specifiedByUrl: this.specifiedByUrl, serialize: this.serialize, parseValue: this.parseValue, parseLiteral: this.parseLiteral, @@ -626,13 +645,18 @@ export class GraphQLScalarType { return this.name; } - // $FlowFixMe Flow doesn't support computed properties yet + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLScalarType'; } } -defineToJSON(GraphQLScalarType); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLScalarType); export type GraphQLScalarSerializer = ( outputValue: mixed, @@ -650,6 +674,7 @@ export type GraphQLScalarLiteralParser = ( 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. @@ -764,13 +789,18 @@ export class GraphQLObjectType { return this.name; } - // $FlowFixMe Flow doesn't support computed properties yet + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLObjectType'; } } -defineToJSON(GraphQLObjectType); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLObjectType); function defineInterfaces( config: $ReadOnly< @@ -824,6 +854,7 @@ function defineFieldMap( description: argConfig.description, type: argConfig.type, defaultValue: argConfig.defaultValue, + deprecationReason: argConfig.deprecationReason, extensions: argConfig.extensions && toObjMap(argConfig.extensions), astNode: argConfig.astNode, })); @@ -843,11 +874,13 @@ function defineFieldMap( }); } -function isPlainObj(obj) { +function isPlainObj(obj: mixed): boolean { return isObjectLike(obj) && !Array.isArray(obj); } -function fieldsToFieldsConfig(fields) { +function fieldsToFieldsConfig( + fields: GraphQLFieldMap, +): GraphQLFieldConfigMap { return mapValue(fields, (field) => ({ description: field.description, type: field.type, @@ -873,6 +906,7 @@ export function argsToArgsConfig( description: arg.description, type: arg.type, defaultValue: arg.defaultValue, + deprecationReason: arg.deprecationReason, extensions: arg.extensions, astNode: arg.astNode, }), @@ -890,6 +924,9 @@ export type GraphQLObjectTypeConfig = {| extensionASTNodes?: ?$ReadOnlyArray, |}; +/** + * Note: returning GraphQLObjectType is deprecated and will be removed in v16.0.0 + */ export type GraphQLTypeResolver = ( value: TSource, context: TContext, @@ -949,6 +986,7 @@ export type GraphQLArgumentConfig = {| type: GraphQLInputType, defaultValue?: mixed, extensions?: ?ReadOnlyObjMapLike, + deprecationReason?: ?string, astNode?: ?InputValueDefinitionNode, |}; @@ -967,10 +1005,12 @@ export type GraphQLField< args: Array, resolve?: GraphQLFieldResolver, subscribe?: GraphQLFieldResolver, - isDeprecated: boolean, deprecationReason: ?string, extensions: ?ReadOnlyObjMap, astNode: ?FieldDefinitionNode, + + // @deprecated and will be removed in v16 + isDeprecated: boolean, |}; export type GraphQLArgument = {| @@ -978,6 +1018,7 @@ export type GraphQLArgument = {| description: ?string, type: GraphQLInputType, defaultValue: mixed, + deprecationReason: ?string, extensions: ?ReadOnlyObjMap, astNode: ?InputValueDefinitionNode, |}; @@ -1074,13 +1115,18 @@ export class GraphQLInterfaceType { return this.name; } - // $FlowFixMe Flow doesn't support computed properties yet + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLInterfaceType'; } } -defineToJSON(GraphQLInterfaceType); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLInterfaceType); export type GraphQLInterfaceTypeConfig = {| name: string, @@ -1176,13 +1222,18 @@ export class GraphQLUnionType { return this.name; } - // $FlowFixMe Flow doesn't support computed properties yet + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLUnionType'; } } -defineToJSON(GraphQLUnionType); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLUnionType); function defineTypes( config: $ReadOnly>, @@ -1349,13 +1400,18 @@ export class GraphQLEnumType /* */ { return this.name; } - // $FlowFixMe Flow doesn't support computed properties yet + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLEnumType'; } } -defineToJSON(GraphQLEnumType); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLEnumType); function didYouMeanEnumValue( enumType: GraphQLEnumType, @@ -1420,10 +1476,12 @@ export type GraphQLEnumValue /* */ = {| name: string, description: ?string, value: any /* T */, - isDeprecated: boolean, deprecationReason: ?string, extensions: ?ReadOnlyObjMap, astNode: ?EnumValueDefinitionNode, + + // @deprecated and will be removed in v16 + isDeprecated: boolean, |}; /** @@ -1439,8 +1497,8 @@ export type GraphQLEnumValue /* */ = {| * const GeoPoint = new GraphQLInputObjectType({ * name: 'GeoPoint', * fields: { - * lat: { type: GraphQLNonNull(GraphQLFloat) }, - * lon: { type: GraphQLNonNull(GraphQLFloat) }, + * lat: { type: new GraphQLNonNull(GraphQLFloat) }, + * lon: { type: new GraphQLNonNull(GraphQLFloat) }, * alt: { type: GraphQLFloat, defaultValue: 0 }, * } * }); @@ -1501,13 +1559,18 @@ export class GraphQLInputObjectType { return this.name; } - // $FlowFixMe Flow doesn't support computed properties yet + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLInputObjectType'; } } -defineToJSON(GraphQLInputObjectType); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLInputObjectType); function defineInputFieldMap( config: $ReadOnly, @@ -1528,6 +1591,7 @@ function defineInputFieldMap( description: fieldConfig.description, type: fieldConfig.type, defaultValue: fieldConfig.defaultValue, + deprecationReason: fieldConfig.deprecationReason, extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), astNode: fieldConfig.astNode, }; @@ -1547,6 +1611,7 @@ export type GraphQLInputFieldConfig = {| description?: ?string, type: GraphQLInputType, defaultValue?: mixed, + deprecationReason?: ?string, extensions?: ?ReadOnlyObjMapLike, astNode?: ?InputValueDefinitionNode, |}; @@ -1558,6 +1623,7 @@ export type GraphQLInputField = {| description: ?string, type: GraphQLInputType, defaultValue: mixed, + deprecationReason: ?string, extensions: ?ReadOnlyObjMap, astNode: ?InputValueDefinitionNode, |}; diff --git a/src/type/directives.d.ts b/src/type/directives.d.ts index 8865cdcc6b..2c6de77b1d 100644 --- a/src/type/directives.d.ts +++ b/src/type/directives.d.ts @@ -1,7 +1,7 @@ // FIXME /* eslint-disable import/no-cycle */ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; import { DirectiveDefinitionNode } from '../language/ast'; import { DirectiveLocationEnum } from '../language/directiveLocation'; @@ -13,6 +13,20 @@ import { GraphQLFieldConfigArgumentMap, GraphQLArgument } from './definition'; */ 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. @@ -23,7 +37,7 @@ export class GraphQLDirective { locations: Array; isRepeatable: boolean; args: Array; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; constructor(config: Readonly); @@ -31,7 +45,7 @@ export class GraphQLDirective { toConfig(): GraphQLDirectiveConfig & { args: GraphQLFieldConfigArgumentMap; isRepeatable: boolean; - extensions: Maybe>>; + extensions: Maybe>; }; toString(): string; @@ -45,7 +59,7 @@ export interface GraphQLDirectiveConfig { locations: Array; args?: Maybe; isRepeatable?: Maybe; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; } @@ -59,6 +73,11 @@ export const GraphQLIncludeDirective: GraphQLDirective; */ 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. */ diff --git a/src/type/directives.js b/src/type/directives.js index d3ed6fdae9..ff4cce6dd2 100644 --- a/src/type/directives.js +++ b/src/type/directives.js @@ -1,32 +1,24 @@ -// @flow strict - 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 defineToJSON from '../jsutils/defineToJSON'; import isObjectLike from '../jsutils/isObjectLike'; -import { - type ReadOnlyObjMap, - type ReadOnlyObjMapLike, -} from '../jsutils/ObjMap'; +import defineInspect from '../jsutils/defineInspect'; -import { type DirectiveDefinitionNode } from '../language/ast'; -import { - DirectiveLocation, - type DirectiveLocationEnum, -} from '../language/directiveLocation'; +import type { DirectiveDefinitionNode } from '../language/ast'; +import type { DirectiveLocationEnum } from '../language/directiveLocation'; +import { DirectiveLocation } from '../language/directiveLocation'; -import { GraphQLString, GraphQLBoolean } from './scalars'; -import { - type GraphQLFieldConfigArgumentMap, - type GraphQLArgument, - argsToArgsConfig, - GraphQLNonNull, +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. @@ -86,6 +78,7 @@ export class GraphQLDirective { description: argConfig.description, type: argConfig.type, defaultValue: argConfig.defaultValue, + deprecationReason: argConfig.deprecationReason, extensions: argConfig.extensions && toObjMap(argConfig.extensions), astNode: argConfig.astNode, })); @@ -112,13 +105,18 @@ export class GraphQLDirective { return '@' + this.name; } - // $FlowFixMe Flow doesn't support computed properties yet + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLDirective'; } } -defineToJSON(GraphQLDirective); +// Print a simplified form when appearing in `inspect` and `util.inspect`. +defineInspect(GraphQLDirective); export type GraphQLDirectiveConfig = {| name: string, @@ -144,7 +142,7 @@ export const GraphQLIncludeDirective = new GraphQLDirective({ ], args: { if: { - type: GraphQLNonNull(GraphQLBoolean), + type: new GraphQLNonNull(GraphQLBoolean), description: 'Included when true.', }, }, @@ -164,7 +162,7 @@ export const GraphQLSkipDirective = new GraphQLDirective({ ], args: { if: { - type: GraphQLNonNull(GraphQLBoolean), + type: new GraphQLNonNull(GraphQLBoolean), description: 'Skipped when true.', }, }, @@ -181,7 +179,12 @@ export const DEFAULT_DEPRECATION_REASON = 'No longer supported'; export const GraphQLDeprecatedDirective = new GraphQLDirective({ name: 'deprecated', description: 'Marks an element of a GraphQL schema as no longer supported.', - locations: [DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE], + locations: [ + DirectiveLocation.FIELD_DEFINITION, + DirectiveLocation.ARGUMENT_DEFINITION, + DirectiveLocation.INPUT_FIELD_DEFINITION, + DirectiveLocation.ENUM_VALUE, + ], args: { reason: { type: GraphQLString, @@ -192,6 +195,21 @@ export const GraphQLDeprecatedDirective = new GraphQLDirective({ }, }); +/** + * 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. */ @@ -199,6 +217,7 @@ export const specifiedDirectives = Object.freeze([ GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, + GraphQLSpecifiedByDirective, ]); export function isSpecifiedDirective( diff --git a/src/type/index.d.ts b/src/type/index.d.ts index b6780d8171..9686f413b7 100644 --- a/src/type/index.d.ts +++ b/src/type/index.d.ts @@ -8,6 +8,7 @@ export { // GraphQL Schema definition GraphQLSchema, GraphQLSchemaConfig, + GraphQLSchemaExtensions, } from './schema'; export { @@ -75,28 +76,38 @@ export { Thunk, GraphQLArgument, GraphQLArgumentConfig, + GraphQLArgumentExtensions, GraphQLEnumTypeConfig, + GraphQLEnumTypeExtensions, GraphQLEnumValue, GraphQLEnumValueConfig, GraphQLEnumValueConfigMap, + GraphQLEnumValueExtensions, GraphQLField, GraphQLFieldConfig, GraphQLFieldConfigArgumentMap, GraphQLFieldConfigMap, + GraphQLFieldExtensions, GraphQLFieldMap, GraphQLFieldResolver, GraphQLInputField, GraphQLInputFieldConfig, GraphQLInputFieldConfigMap, + GraphQLInputFieldExtensions, GraphQLInputFieldMap, GraphQLInputObjectTypeConfig, + GraphQLInputObjectTypeExtensions, GraphQLInterfaceTypeConfig, + GraphQLInterfaceTypeExtensions, GraphQLIsTypeOfFn, GraphQLObjectTypeConfig, + GraphQLObjectTypeExtensions, GraphQLResolveInfo, GraphQLScalarTypeConfig, + GraphQLScalarTypeExtensions, GraphQLTypeResolver, GraphQLUnionTypeConfig, + GraphQLUnionTypeExtensions, GraphQLScalarSerializer, GraphQLScalarValueParser, GraphQLScalarLiteralParser, @@ -115,10 +126,12 @@ export { GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, + GraphQLSpecifiedByDirective, // Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, // type GraphQLDirectiveConfig, + GraphQLDirectiveExtensions, } from './directives'; // Common built-in scalar instances. diff --git a/src/type/index.js b/src/type/index.js index ec87a1c7b0..811d50247a 100644 --- a/src/type/index.js +++ b/src/type/index.js @@ -1,5 +1,3 @@ -// @flow strict - export type { Path as ResponsePath } from '../jsutils/Path'; export { @@ -79,6 +77,7 @@ export { GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, + GraphQLSpecifiedByDirective, // Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, } from './directives'; diff --git a/src/type/introspection.js b/src/type/introspection.js index 62f53325c5..77362ed02d 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.js @@ -1,8 +1,3 @@ -// @flow strict - -// FIXME -/* eslint-disable import/no-cycle */ - import objectValues from '../polyfills/objectValues'; import inspect from '../jsutils/inspect'; @@ -12,20 +7,22 @@ import { print } from '../language/printer'; import { DirectiveLocation } from '../language/directiveLocation'; import { astFromValue } from '../utilities/astFromValue'; -import { type GraphQLSchema } from './schema'; -import { type GraphQLDirective } from './directives'; +import type { GraphQLSchema } from './schema'; +import type { GraphQLDirective } from './directives'; +import type { + GraphQLType, + GraphQLNamedType, + GraphQLInputField, + GraphQLEnumValue, + GraphQLField, + GraphQLFieldConfigMap, +} from './definition'; import { GraphQLString, GraphQLBoolean } from './scalars'; import { - type GraphQLType, - type GraphQLNamedType, - type GraphQLInputField, - type GraphQLEnumValue, - type GraphQLField, - type GraphQLFieldConfigMap, - GraphQLObjectType, - GraphQLEnumType, GraphQLList, GraphQLNonNull, + GraphQLObjectType, + GraphQLEnumType, isScalarType, isObjectType, isInterfaceType, @@ -49,14 +46,14 @@ export const __Schema = new GraphQLObjectType({ }, types: { description: 'A list of all types supported by this server.', - type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__Type))), + type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__Type))), resolve(schema) { return objectValues(schema.getTypeMap()); }, }, queryType: { description: 'The type that query operations will be rooted at.', - type: GraphQLNonNull(__Type), + type: new GraphQLNonNull(__Type), resolve: (schema) => schema.getQueryType(), }, mutationType: { @@ -73,7 +70,9 @@ export const __Schema = new GraphQLObjectType({ }, directives: { description: 'A list of all directives supported by this server.', - type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__Directive))), + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(__Directive)), + ), resolve: (schema) => schema.getDirectives(), }, }: GraphQLFieldConfigMap), @@ -86,7 +85,7 @@ export const __Directive = new GraphQLObjectType({ fields: () => ({ name: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), resolve: (directive) => directive.name, }, description: { @@ -94,15 +93,19 @@ export const __Directive = new GraphQLObjectType({ resolve: (directive) => directive.description, }, isRepeatable: { - type: GraphQLNonNull(GraphQLBoolean), + type: new GraphQLNonNull(GraphQLBoolean), resolve: (directive) => directive.isRepeatable, }, locations: { - type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__DirectiveLocation))), + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(__DirectiveLocation)), + ), resolve: (directive) => directive.locations, }, args: { - type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(__InputValue)), + ), resolve: (directive) => directive.args, }, }: GraphQLFieldConfigMap), @@ -195,11 +198,11 @@ export const __DirectiveLocation = new GraphQLEnumType({ export const __Type = 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 and description, 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: { - type: GraphQLNonNull(__TypeKind), + type: new GraphQLNonNull(__TypeKind), resolve(type) { if (isScalarType(type)) { return TypeKind.SCALAR; @@ -222,11 +225,12 @@ 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; } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false, `Unexpected type: "${inspect((type: empty))}".`); }, }, @@ -239,24 +243,27 @@ export const __Type = new GraphQLObjectType({ resolve: (type) => type.description !== undefined ? type.description : undefined, }, + specifiedByUrl: { + type: GraphQLString, + resolve: (obj) => + obj.specifiedByUrl !== undefined ? obj.specifiedByUrl : undefined, + }, fields: { - type: GraphQLList(GraphQLNonNull(__Field)), + type: new GraphQLList(new GraphQLNonNull(__Field)), args: { includeDeprecated: { type: GraphQLBoolean, defaultValue: false }, }, resolve(type, { includeDeprecated }) { if (isObjectType(type) || isInterfaceType(type)) { - let fields = objectValues(type.getFields()); - if (!includeDeprecated) { - fields = fields.filter((field) => !field.isDeprecated); - } - return fields; + const fields = objectValues(type.getFields()); + return includeDeprecated + ? fields + : fields.filter((field) => field.deprecationReason == null); } - return null; }, }, interfaces: { - type: GraphQLList(GraphQLNonNull(__Type)), + type: new GraphQLList(new GraphQLNonNull(__Type)), resolve(type) { if (isObjectType(type) || isInterfaceType(type)) { return type.getInterfaces(); @@ -264,7 +271,7 @@ export const __Type = new GraphQLObjectType({ }, }, possibleTypes: { - type: GraphQLList(GraphQLNonNull(__Type)), + type: new GraphQLList(new GraphQLNonNull(__Type)), resolve(type, _args, _context, { schema }) { if (isAbstractType(type)) { return schema.getPossibleTypes(type); @@ -272,25 +279,33 @@ export const __Type = new GraphQLObjectType({ }, }, enumValues: { - type: GraphQLList(GraphQLNonNull(__EnumValue)), + type: new GraphQLList(new GraphQLNonNull(__EnumValue)), args: { includeDeprecated: { type: GraphQLBoolean, defaultValue: false }, }, resolve(type, { includeDeprecated }) { if (isEnumType(type)) { - let values = type.getValues(); - if (!includeDeprecated) { - values = values.filter((value) => !value.isDeprecated); - } - return values; + const values = type.getValues(); + return includeDeprecated + ? values + : values.filter((field) => field.deprecationReason == null); } }, }, inputFields: { - type: GraphQLList(GraphQLNonNull(__InputValue)), - resolve(type) { + type: new GraphQLList(new GraphQLNonNull(__InputValue)), + args: { + includeDeprecated: { + type: GraphQLBoolean, + defaultValue: false, + }, + }, + resolve(type, { includeDeprecated }) { if (isInputObjectType(type)) { - return objectValues(type.getFields()); + const values = objectValues(type.getFields()); + return includeDeprecated + ? values + : values.filter((field) => field.deprecationReason == null); } }, }, @@ -309,7 +324,7 @@ export const __Field = new GraphQLObjectType({ fields: () => ({ name: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), resolve: (field) => field.name, }, description: { @@ -317,16 +332,28 @@ export const __Field = new GraphQLObjectType({ resolve: (field) => field.description, }, args: { - type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), - resolve: (field) => field.args, + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(__InputValue)), + ), + args: { + includeDeprecated: { + type: GraphQLBoolean, + defaultValue: false, + }, + }, + resolve(field, { includeDeprecated }) { + return includeDeprecated + ? field.args + : field.args.filter((arg) => arg.deprecationReason == null); + }, }, type: { - type: GraphQLNonNull(__Type), + type: new GraphQLNonNull(__Type), resolve: (field) => field.type, }, isDeprecated: { - type: GraphQLNonNull(GraphQLBoolean), - resolve: (field) => field.isDeprecated, + type: new GraphQLNonNull(GraphQLBoolean), + resolve: (field) => field.deprecationReason != null, }, deprecationReason: { type: GraphQLString, @@ -342,7 +369,7 @@ export const __InputValue = new GraphQLObjectType({ fields: () => ({ name: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), resolve: (inputValue) => inputValue.name, }, description: { @@ -350,7 +377,7 @@ export const __InputValue = new GraphQLObjectType({ resolve: (inputValue) => inputValue.description, }, type: { - type: GraphQLNonNull(__Type), + type: new GraphQLNonNull(__Type), resolve: (inputValue) => inputValue.type, }, defaultValue: { @@ -363,6 +390,14 @@ export const __InputValue = new GraphQLObjectType({ return valueAST ? print(valueAST) : null; }, }, + isDeprecated: { + type: new GraphQLNonNull(GraphQLBoolean), + resolve: (field) => field.deprecationReason != null, + }, + deprecationReason: { + type: GraphQLString, + resolve: (obj) => obj.deprecationReason, + }, }: GraphQLFieldConfigMap), }); @@ -373,7 +408,7 @@ export const __EnumValue = new GraphQLObjectType({ fields: () => ({ name: { - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), resolve: (enumValue) => enumValue.name, }, description: { @@ -381,8 +416,8 @@ export const __EnumValue = new GraphQLObjectType({ resolve: (enumValue) => enumValue.description, }, isDeprecated: { - type: GraphQLNonNull(GraphQLBoolean), - resolve: (enumValue) => enumValue.isDeprecated, + type: new GraphQLNonNull(GraphQLBoolean), + resolve: (enumValue) => enumValue.deprecationReason != null, }, deprecationReason: { type: GraphQLString, @@ -454,7 +489,7 @@ export const __TypeKind = new GraphQLEnumType({ export const SchemaMetaFieldDef: GraphQLField = { name: '__schema', - type: GraphQLNonNull(__Schema), + type: new GraphQLNonNull(__Schema), description: 'Access the current type schema of this server.', args: [], resolve: (_source, _args, _context, { schema }) => schema, @@ -472,8 +507,9 @@ export const TypeMetaFieldDef: GraphQLField = { { name: 'name', description: undefined, - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), defaultValue: undefined, + deprecationReason: undefined, extensions: undefined, astNode: undefined, }, @@ -487,7 +523,7 @@ export const TypeMetaFieldDef: GraphQLField = { export const TypeNameMetaFieldDef: GraphQLField = { name: '__typename', - type: GraphQLNonNull(GraphQLString), + type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', args: [], resolve: (_source, _args, _context, { parentType }) => parentType.name, diff --git a/src/type/scalars.js b/src/type/scalars.js index e425a17067..ceca14b5c3 100644 --- a/src/type/scalars.js +++ b/src/type/scalars.js @@ -1,5 +1,3 @@ -// @flow strict - import isFinite from '../polyfills/isFinite'; import isInteger from '../polyfills/isInteger'; @@ -11,7 +9,8 @@ import { print } from '../language/printer'; import { GraphQLError } from '../error/GraphQLError'; -import { type GraphQLNamedType, GraphQLScalarType } from './definition'; +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. @@ -143,7 +142,7 @@ function serializeObject(outputValue: mixed): mixed { } } if (typeof outputValue.toJSON === 'function') { - // $FlowFixMe(>=0.90.0) + // $FlowFixMe[incompatible-use] return outputValue.toJSON(); } } diff --git a/src/type/schema.d.ts b/src/type/schema.d.ts index 7f36dab382..4f759f9f27 100644 --- a/src/type/schema.d.ts +++ b/src/type/schema.d.ts @@ -1,7 +1,7 @@ // FIXME /* eslint-disable import/no-cycle */ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; import { SchemaDefinitionNode, SchemaExtensionNode } from '../language/ast'; @@ -19,6 +19,19 @@ import { 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 * @@ -47,7 +60,7 @@ export function assertSchema(schema: any): GraphQLSchema; */ export class GraphQLSchema { description: Maybe; - extensions: Maybe>>; + extensions: Maybe>; astNode: Maybe; extensionASTNodes: Maybe>; @@ -83,18 +96,20 @@ export class GraphQLSchema { toConfig(): GraphQLSchemaConfig & { types: Array; directives: Array; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: ReadonlyArray; assumeValid: boolean; }; } -type TypeMap = { [key: string]: GraphQLNamedType }; +interface TypeMap { + [key: string]: GraphQLNamedType; +} -type InterfaceImplementations = { +interface InterfaceImplementations { objects: ReadonlyArray; interfaces: ReadonlyArray; -}; +} export interface GraphQLSchemaValidationOptions { /** @@ -109,12 +124,12 @@ export interface GraphQLSchemaValidationOptions { export interface GraphQLSchemaConfig extends GraphQLSchemaValidationOptions { description?: Maybe; - query: Maybe; + query?: Maybe; mutation?: Maybe; subscription?: Maybe; types?: Maybe>; directives?: Maybe>; - extensions?: Maybe>>; + extensions?: Maybe>; astNode?: Maybe; extensionASTNodes?: Maybe>; } @@ -126,7 +141,7 @@ export interface GraphQLSchemaNormalizedConfig extends GraphQLSchemaConfig { description: Maybe; types: Array; directives: Array; - extensions: Maybe>>; + extensions: Maybe>; extensionASTNodes: Maybe>; assumeValid: boolean; } diff --git a/src/type/schema.js b/src/type/schema.js index 85e9f02ac3..230b1dcc62 100644 --- a/src/type/schema.js +++ b/src/type/schema.js @@ -1,27 +1,33 @@ -// @flow strict - 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 { - type ObjMap, - type ReadOnlyObjMap, - type ReadOnlyObjMapLike, -} from '../jsutils/ObjMap'; -import { type GraphQLError } from '../error/GraphQLError'; -import { - type SchemaDefinitionNode, - type SchemaExtensionNode, +import type { GraphQLError } from '../error/GraphQLError'; + +import type { + SchemaDefinitionNode, + SchemaExtensionNode, } from '../language/ast'; +import type { + GraphQLType, + GraphQLNamedType, + GraphQLAbstractType, + GraphQLObjectType, + GraphQLInterfaceType, +} from './definition'; import { __Schema } from './introspection'; import { GraphQLDirective, @@ -29,11 +35,6 @@ import { specifiedDirectives, } from './directives'; import { - type GraphQLType, - type GraphQLNamedType, - type GraphQLAbstractType, - type GraphQLObjectType, - type GraphQLInterfaceType, isObjectType, isInterfaceType, isUnionType, @@ -354,7 +355,7 @@ export class GraphQLSchema { }; } - // $FlowFixMe Flow doesn't support computed properties yet + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG]() { return 'GraphQLSchema'; } diff --git a/src/type/validate.js b/src/type/validate.js index d297005b49..a2ddfe4a43 100644 --- a/src/type/validate.js +++ b/src/type/validate.js @@ -1,7 +1,4 @@ -// @flow strict - import find from '../polyfills/find'; -import flatMap from '../polyfills/flatMap'; import objectValues from '../polyfills/objectValues'; import inspect from '../jsutils/inspect'; @@ -9,20 +6,28 @@ import inspect from '../jsutils/inspect'; import { GraphQLError } from '../error/GraphQLError'; import { locatedError } from '../error/locatedError'; -import { type ASTNode, type NamedTypeNode } from '../language/ast'; +import type { + ASTNode, + NamedTypeNode, + DirectiveNode, + OperationTypeNode, +} from '../language/ast'; import { isValidNameError } from '../utilities/assertValidName'; import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators'; -import { isDirective } from './directives'; +import type { GraphQLSchema } from './schema'; +import type { + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLInputObjectType, +} from './definition'; +import { assertSchema } from './schema'; import { isIntrospectionType } from './introspection'; -import { type GraphQLSchema, assertSchema } from './schema'; +import { isDirective, GraphQLDeprecatedDirective } from './directives'; import { - type GraphQLObjectType, - type GraphQLInterfaceType, - type GraphQLUnionType, - type GraphQLEnumType, - type GraphQLInputObjectType, isObjectType, isInterfaceType, isUnionType, @@ -33,6 +38,7 @@ import { isInputType, isOutputType, isRequiredArgument, + isRequiredInputField, } from './definition'; /** @@ -103,7 +109,7 @@ class SchemaValidationContext { } } -function validateRootTypes(context) { +function validateRootTypes(context: SchemaValidationContext): void { const schema = context.schema; const queryType = schema.getQueryType(); if (!queryType) { @@ -113,7 +119,7 @@ function validateRootTypes(context) { `Query root type must be Object type, it cannot be ${inspect( queryType, )}.`, - getOperationTypeNode(schema, queryType, 'query'), + getOperationTypeNode(schema, 'query') ?? queryType.astNode, ); } @@ -122,7 +128,7 @@ function validateRootTypes(context) { context.reportError( 'Mutation root type must be Object type if provided, it cannot be ' + `${inspect(mutationType)}.`, - getOperationTypeNode(schema, mutationType, 'mutation'), + getOperationTypeNode(schema, 'mutation') ?? mutationType.astNode, ); } @@ -131,15 +137,14 @@ function validateRootTypes(context) { context.reportError( 'Subscription root type must be Object type if provided, it cannot be ' + `${inspect(subscriptionType)}.`, - getOperationTypeNode(schema, subscriptionType, 'subscription'), + getOperationTypeNode(schema, 'subscription') ?? subscriptionType.astNode, ); } } function getOperationTypeNode( schema: GraphQLSchema, - type: GraphQLObjectType, - operation: string, + operation: OperationTypeNode, ): ?ASTNode { const operationNodes = getAllSubNodes(schema, (node) => node.operationTypes); for (const node of operationNodes) { @@ -147,8 +152,7 @@ function getOperationTypeNode( return node.type; } } - - return type.astNode; + return undefined; } function validateDirectives(context: SchemaValidationContext): void { @@ -180,6 +184,17 @@ function validateDirectives(context: SchemaValidationContext): void { arg.astNode, ); } + + 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, + ], + ); + } } } } @@ -285,6 +300,17 @@ function validateFields( arg.astNode?.type, ); } + + 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, + ], + ); + } } } } @@ -355,7 +381,12 @@ function validateTypeImplementsInterface( `Interface field ${iface.name}.${fieldName} expects type ` + `${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` + `is type ${inspect(typeField.type)}.`, - [ifaceField.astNode.type, typeField.astNode.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, + ], ); } @@ -382,7 +413,12 @@ function validateTypeImplementsInterface( `expects type ${inspect(ifaceArg.type)} but ` + `${type.name}.${fieldName}(${argName}:) is type ` + `${inspect(typeArg.type)}.`, - [ifaceArg.astNode.type, typeArg.astNode.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, + ], ); } @@ -510,12 +546,23 @@ function validateInputFields( field.astNode?.type, ); } + + 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, + ], + ); + } } } function createInputObjectCircularRefsValidator( context: SchemaValidationContext, -) { +): (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. @@ -532,7 +579,7 @@ function createInputObjectCircularRefsValidator( // This does a straight-forward DFS to find cycles. // It does not terminate when a cycle was found but continues to explore // the graph to find all possible cycles. - function detectCycleRecursive(inputObj: GraphQLInputObjectType) { + function detectCycleRecursive(inputObj: GraphQLInputObjectType): void { if (visitedTypes[inputObj.name]) { return; } @@ -586,8 +633,12 @@ function getAllSubNodes( object: SDLDefinedObject, getter: (T | K) => ?(L | $ReadOnlyArray), ): $ReadOnlyArray { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ - return flatMap(getAllNodes(object), (item) => getter(item) ?? []); + 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( @@ -607,3 +658,12 @@ function getUnionMemberTypeNodes( (typeNode) => typeNode.name.value === typeName, ); } + +function getDeprecatedDirectiveNode( + definitionNode: ?{ +directives?: $ReadOnlyArray, ... }, +): ?DirectiveNode { + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + return definitionNode?.directives?.find( + (node) => node.name.value === GraphQLDeprecatedDirective.name, + ); +} diff --git a/src/utilities/TypeInfo.d.ts b/src/utilities/TypeInfo.d.ts index 4f9b4265d6..499fb02978 100644 --- a/src/utilities/TypeInfo.d.ts +++ b/src/utilities/TypeInfo.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { Visitor } from '../language/visitor'; import { ASTNode, ASTKindToNode, FieldNode } from '../language/ast'; import { GraphQLSchema } from '../type/schema'; diff --git a/src/utilities/TypeInfo.js b/src/utilities/TypeInfo.js index 04f533f8df..40c27e26df 100644 --- a/src/utilities/TypeInfo.js +++ b/src/utilities/TypeInfo.js @@ -1,27 +1,24 @@ -// @flow strict - import find from '../polyfills/find'; +import type { Visitor } from '../language/visitor'; +import type { ASTNode, ASTKindToNode, FieldNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import { type Visitor, getVisitFn } from '../language/visitor'; -import { - type ASTNode, - type ASTKindToNode, - type FieldNode, - isNode, -} from '../language/ast'; +import { isNode } from '../language/ast'; +import { getVisitFn } from '../language/visitor'; -import { type GraphQLSchema } from '../type/schema'; -import { type GraphQLDirective } from '../type/directives'; +import type { GraphQLSchema } from '../type/schema'; +import type { GraphQLDirective } from '../type/directives'; +import type { + GraphQLType, + GraphQLInputType, + GraphQLOutputType, + GraphQLCompositeType, + GraphQLField, + GraphQLArgument, + GraphQLInputField, + GraphQLEnumValue, +} from '../type/definition'; import { - type GraphQLType, - type GraphQLInputType, - type GraphQLOutputType, - type GraphQLCompositeType, - type GraphQLField, - type GraphQLArgument, - type GraphQLInputField, - type GraphQLEnumValue, isObjectType, isInterfaceType, isEnumType, diff --git a/src/utilities/__tests__/TypeInfo-test.js b/src/utilities/__tests__/TypeInfo-test.js index 53da7e747b..73ca3d5090 100644 --- a/src/utilities/__tests__/TypeInfo-test.js +++ b/src/utilities/__tests__/TypeInfo-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/utilities/__tests__/assertValidName-test.js b/src/utilities/__tests__/assertValidName-test.js index a05c694bd3..40f9d2e398 100644 --- a/src/utilities/__tests__/assertValidName-test.js +++ b/src/utilities/__tests__/assertValidName-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -17,7 +15,7 @@ describe('assertValidName()', () => { }); it('throws for non-strings', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => assertValidName({})).to.throw('Expected name to be a string.'); }); diff --git a/src/utilities/__tests__/astFromValue-test.js b/src/utilities/__tests__/astFromValue-test.js index 123f4ea27f..81c551441e 100644 --- a/src/utilities/__tests__/astFromValue-test.js +++ b/src/utilities/__tests__/astFromValue-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -48,7 +46,7 @@ describe('astFromValue', () => { value: true, }); - const NonNullBoolean = GraphQLNonNull(GraphQLBoolean); + const NonNullBoolean = new GraphQLNonNull(GraphQLBoolean); expect(astFromValue(0, NonNullBoolean)).to.deep.equal({ kind: 'BooleanValue', value: false, @@ -238,7 +236,7 @@ describe('astFromValue', () => { }); it('does not converts NonNull values to NullValue', () => { - const NonNullBoolean = GraphQLNonNull(GraphQLBoolean); + const NonNullBoolean = new GraphQLNonNull(GraphQLBoolean); expect(astFromValue(null, NonNullBoolean)).to.deep.equal(null); }); @@ -277,7 +275,7 @@ describe('astFromValue', () => { it('converts array values to List ASTs', () => { expect( - astFromValue(['FOO', 'BAR'], GraphQLList(GraphQLString)), + astFromValue(['FOO', 'BAR'], new GraphQLList(GraphQLString)), ).to.deep.equal({ kind: 'ListValue', values: [ @@ -287,7 +285,7 @@ describe('astFromValue', () => { }); expect( - astFromValue(['HELLO', 'GOODBYE'], GraphQLList(myEnum)), + astFromValue(['HELLO', 'GOODBYE'], new GraphQLList(myEnum)), ).to.deep.equal({ kind: 'ListValue', values: [ @@ -298,7 +296,7 @@ describe('astFromValue', () => { }); it('converts list singletons', () => { - expect(astFromValue('FOO', GraphQLList(GraphQLString))).to.deep.equal({ + expect(astFromValue('FOO', new GraphQLList(GraphQLString))).to.deep.equal({ kind: 'StringValue', value: 'FOO', }); @@ -307,7 +305,7 @@ describe('astFromValue', () => { it('skip invalid list items', () => { const ast = astFromValue( ['FOO', null, 'BAR'], - GraphQLList(GraphQLNonNull(GraphQLString)), + new GraphQLList(new GraphQLNonNull(GraphQLString)), ); expect(ast).to.deep.equal({ diff --git a/src/utilities/__tests__/buildASTSchema-benchmark.js b/src/utilities/__tests__/buildASTSchema-benchmark.js deleted file mode 100644 index 9a4a276959..0000000000 --- a/src/utilities/__tests__/buildASTSchema-benchmark.js +++ /dev/null @@ -1,15 +0,0 @@ -// @flow strict - -import { parse } from '../../language/parser'; - -import { buildASTSchema } from '../buildASTSchema'; - -import { bigSchemaSDL } from '../../__fixtures__/index'; - -const schemaAST = parse(bigSchemaSDL); - -export const name = 'Build Schema from AST'; -export const count = 10; -export function measure() { - buildASTSchema(schemaAST, { assumeValid: true }); -} diff --git a/src/utilities/__tests__/buildASTSchema-test.js b/src/utilities/__tests__/buildASTSchema-test.js index 2238294e14..f364e311dd 100644 --- a/src/utilities/__tests__/buildASTSchema-test.js +++ b/src/utilities/__tests__/buildASTSchema-test.js @@ -1,22 +1,25 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; + import invariant from '../../jsutils/invariant'; +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 } from '../../type/introspection'; +import { __Schema, __EnumValue } from '../../type/introspection'; import { assertDirective, GraphQLSkipDirective, GraphQLIncludeDirective, GraphQLDeprecatedDirective, + GraphQLSpecifiedByDirective, } from '../../type/directives'; import { GraphQLID, @@ -44,7 +47,7 @@ import { buildASTSchema, buildSchema } from '../buildASTSchema'; * 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, options) { +function cycleSDL(sdl: string, options): string { const ast = parse(sdl); const schema = buildASTSchema(ast, options); @@ -52,12 +55,12 @@ function cycleSDL(sdl, options) { return printSchema(schema, { commentDescriptions }); } -function printASTNode(obj) { +function printASTNode(obj: ?{ +astNode: ?ASTNode, ... }): string { invariant(obj?.astNode != null); return print(obj.astNode); } -function printAllASTNodes(obj) { +function printAllASTNodes(obj: GraphQLNamedType): string { invariant(obj.astNode != null && obj.extensionASTNodes != null); return print({ kind: Kind.DOCUMENT, @@ -112,6 +115,21 @@ describe('Schema Builder', () => { expect(() => buildSchema(sdl)).to.not.throw(); }); + it('Match order of default types and directives', () => { + const schema = new GraphQLSchema({}); + const sdlSchema = buildASTSchema({ + kind: Kind.DOCUMENT, + definitions: [], + }); + + expect(sdlSchema.getDirectives()).to.deep.equal(schema.getDirectives()); + + expect(sdlSchema.getTypeMap()).to.deep.equal(schema.getTypeMap()); + expect(Object.keys(sdlSchema.getTypeMap())).to.deep.equal( + Object.keys(schema.getTypeMap()), + ); + }); + it('Empty type', () => { const sdl = dedent` type EmptyType @@ -171,6 +189,24 @@ describe('Schema Builder', () => { arg: Int ) on FIELD + """Who knows what inside this scalar?""" + scalar MysteryScalar + + """This is a input object type""" + input FooInput { + """It has a field""" + field: Int + } + + """This is a interface type""" + interface Energy { + """It also has a field""" + str: String + } + + """There is nothing inside!""" + union BlackHole + """With an enum""" enum Color { RED @@ -215,15 +251,18 @@ describe('Schema Builder', () => { expect(cycleSDL(sdl, { commentDescriptions: true })).to.equal(sdl); }); - it('Maintains @skip & @include', () => { + it('Maintains @include, @skip & @specifiedBy', () => { const schema = buildSchema('type Query'); - expect(schema.getDirectives()).to.have.lengthOf(3); + expect(schema.getDirectives()).to.have.lengthOf(4); expect(schema.getDirective('skip')).to.equal(GraphQLSkipDirective); expect(schema.getDirective('include')).to.equal(GraphQLIncludeDirective); expect(schema.getDirective('deprecated')).to.equal( GraphQLDeprecatedDirective, ); + expect(schema.getDirective('specifiedBy')).to.equal( + GraphQLSpecifiedByDirective, + ); }); it('Overriding directives excludes specified', () => { @@ -231,9 +270,10 @@ describe('Schema Builder', () => { directive @skip on FIELD directive @include on FIELD directive @deprecated on FIELD_DEFINITION + directive @specifiedBy on FIELD_DEFINITION `); - expect(schema.getDirectives()).to.have.lengthOf(3); + expect(schema.getDirectives()).to.have.lengthOf(4); expect(schema.getDirective('skip')).to.not.equal(GraphQLSkipDirective); expect(schema.getDirective('include')).to.not.equal( GraphQLIncludeDirective, @@ -241,17 +281,21 @@ describe('Schema Builder', () => { expect(schema.getDirective('deprecated')).to.not.equal( GraphQLDeprecatedDirective, ); + expect(schema.getDirective('specifiedBy')).to.not.equal( + GraphQLSpecifiedByDirective, + ); }); - it('Adding directives maintains @skip & @include', () => { + it('Adding directives maintains @include, @skip & @specifiedBy', () => { const schema = buildSchema(` directive @foo(arg: Int) on FIELD `); - expect(schema.getDirectives()).to.have.lengthOf(4); + expect(schema.getDirectives()).to.have.lengthOf(5); 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); }); it('Type modifiers', () => { @@ -461,129 +505,6 @@ describe('Schema Builder', () => { expect(errors).to.have.lengthOf.above(0); }); - it('Specifying Union type using __typename', () => { - const schema = buildSchema(` - type Query { - fruits: [Fruit] - } - - union Fruit = Apple | Banana - - type Apple { - color: String - } - - type Banana { - length: Int - } - `); - - const source = ` - { - fruits { - ... on Apple { - color - } - ... on Banana { - length - } - } - } - `; - - const rootValue = { - fruits: [ - { - color: 'green', - __typename: 'Apple', - }, - { - length: 5, - __typename: 'Banana', - }, - ], - }; - - expect(graphqlSync({ schema, source, rootValue })).to.deep.equal({ - data: { - fruits: [ - { - color: 'green', - }, - { - length: 5, - }, - ], - }, - }); - }); - - it('Specifying Interface type using __typename', () => { - const schema = buildSchema(` - type Query { - characters: [Character] - } - - interface Character { - name: String! - } - - type Human implements Character { - name: String! - totalCredits: Int - } - - type Droid implements Character { - name: String! - primaryFunction: String - } - `); - - const source = ` - { - characters { - name - ... on Human { - totalCredits - } - ... on Droid { - primaryFunction - } - } - } - `; - - const rootValue = { - characters: [ - { - name: 'Han Solo', - totalCredits: 10, - __typename: 'Human', - }, - { - name: 'R2-D2', - primaryFunction: 'Astromech', - __typename: 'Droid', - }, - ], - }; - - expect(graphqlSync({ schema, source, rootValue })).to.deep.equal({ - data: { - characters: [ - { - name: 'Han Solo', - totalCredits: 10, - }, - { - name: 'R2-D2', - primaryFunction: 'Astromech', - }, - ], - }, - }); - }); - it('Custom Scalar', () => { const sdl = dedent` scalar CustomScalar @@ -732,10 +653,19 @@ describe('Schema Builder', () => { OTHER_VALUE @deprecated(reason: "Terrible reasons") } + input MyInput { + oldInput: String @deprecated + otherInput: String @deprecated(reason: "Use newInput") + newInput: String + } + type Query { field1: String @deprecated field2: Int @deprecated(reason: "Because I said so") enum: MyEnum + field3(oldArg: String @deprecated, arg: String): String + field4(oldArg: String @deprecated(reason: "Why not?"), arg: String): String + field5(arg: MyInput): String } `; expect(cycleSDL(sdl)).to.equal(sdl); @@ -768,6 +698,52 @@ describe('Schema Builder', () => { isDeprecated: true, deprecationReason: 'Because I said so', }); + + const inputFields = assertInputObjectType( + schema.getType('MyInput'), + ).getFields(); + + const newInput = inputFields.newInput; + expect(newInput).to.include({ + deprecationReason: undefined, + }); + + const oldInput = inputFields.oldInput; + expect(oldInput).to.include({ + deprecationReason: 'No longer supported', + }); + + const otherInput = inputFields.otherInput; + expect(otherInput).to.include({ + deprecationReason: 'Use newInput', + }); + + const field3OldArg = rootFields.field3.args[0]; + expect(field3OldArg).to.include({ + deprecationReason: 'No longer supported', + }); + + const field4OldArg = rootFields.field4.args[0]; + expect(field4OldArg).to.include({ + deprecationReason: 'Why not?', + }); + }); + + it('Supports @specifiedBy', () => { + const sdl = dedent` + scalar Foo @specifiedBy(url: "https://example.com/foo_spec") + + type Query { + foo: Foo @deprecated + } + `; + expect(cycleSDL(sdl)).to.equal(sdl); + + const schema = buildSchema(sdl); + + expect(schema.getType('Foo')).to.include({ + specifiedByUrl: 'https://example.com/foo_spec', + }); }); it('Correctly extend scalar type', () => { @@ -1062,6 +1038,21 @@ describe('Schema Builder', () => { expect(schema.getType('__Schema')).to.equal(__Schema); }); + it('Allows to reference introspection types', () => { + const schema = buildSchema(` + type Query { + introspectionField: __EnumValue + } + `); + + const queryType = assertObjectType(schema.getType('Query')); + expect(queryType.getFields()).to.have.nested.property( + 'introspectionField.type', + __EnumValue, + ); + expect(schema.getType('__EnumValue')).to.equal(__EnumValue); + }); + it('Rejects invalid SDL', () => { const sdl = ` type Query { @@ -1093,12 +1084,12 @@ describe('Schema Builder', () => { }); it('Rejects invalid AST', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => buildASTSchema(null)).to.throw( 'Must provide valid Document AST', ); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => buildASTSchema({})).to.throw( 'Must provide valid Document AST', ); diff --git a/src/utilities/__tests__/buildClientSchema-benchmark.js b/src/utilities/__tests__/buildClientSchema-benchmark.js deleted file mode 100644 index c9678782b4..0000000000 --- a/src/utilities/__tests__/buildClientSchema-benchmark.js +++ /dev/null @@ -1,11 +0,0 @@ -// @flow strict - -import { buildClientSchema } from '../buildClientSchema'; - -import { bigSchemaIntrospectionResult } from '../../__fixtures__/index'; - -export const name = 'Build Schema from Introspection'; -export const count = 10; -export function measure() { - buildClientSchema(bigSchemaIntrospectionResult.data, { assumeValid: true }); -} diff --git a/src/utilities/__tests__/buildClientSchema-test.js b/src/utilities/__tests__/buildClientSchema-test.js index 3cc63ebfe9..9a0e83de26 100644 --- a/src/utilities/__tests__/buildClientSchema-test.js +++ b/src/utilities/__tests__/buildClientSchema-test.js @@ -1,9 +1,7 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; import { graphqlSync } from '../../graphql'; @@ -33,7 +31,10 @@ import { introspectionFromSchema } from '../introspectionFromSchema'; * returns that schema printed as SDL. */ function cycleIntrospection(sdlString: string): string { - const options = { directiveIsRepeatable: true }; + const options = { + specifiedByUrl: true, + directiveIsRepeatable: true, + }; const serverSchema = buildSchema(sdlString); const initialIntrospection = introspectionFromSchema(serverSchema, options); @@ -76,8 +77,7 @@ describe('Type System: build schema from introspection', () => { const schema = buildSchema(sdl); const introspection = introspectionFromSchema(schema); - // $DisableFlowOnNegativeTest - delete introspection.__schema.queryType; + delete (introspection: any).__schema.queryType; const clientSchema = buildClientSchema(introspection); expect(clientSchema.getQueryType()).to.equal(null); @@ -480,8 +480,7 @@ describe('Type System: build schema from introspection', () => { const schema = buildSchema(sdl); const introspection = introspectionFromSchema(schema); - // $DisableFlowOnNegativeTest - delete introspection.__schema.directives; + delete (introspection: any).__schema.directives; const clientSchema = buildClientSchema(introspection); @@ -533,6 +532,18 @@ describe('Type System: build schema from introspection', () => { expect(cycleIntrospection(sdl)).to.equal(sdl); }); + it('builds a schema with specifiedBy url', () => { + const sdl = dedent` + scalar Foo @specifiedBy(url: "https://example.com/foo_spec") + + type Query { + foo: Foo + } + `; + + expect(cycleIntrospection(sdl)).to.equal(sdl); + }); + it('can use client schema for limited execution', () => { const schema = buildSchema(` scalar CustomScalar @@ -589,12 +600,12 @@ describe('Type System: build schema from introspection', () => { `); it('throws when introspection is missing __schema property', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] 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.', ); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] 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: {}.', ); @@ -603,8 +614,7 @@ describe('Type System: build schema from introspection', () => { it('throws when referenced unknown type', () => { const introspection = introspectionFromSchema(dummySchema); - // $DisableFlowOnNegativeTest - introspection.__schema.types = introspection.__schema.types.filter( + (introspection: any).__schema.types = introspection.__schema.types.filter( ({ name }) => name !== 'Query', ); @@ -621,8 +631,7 @@ describe('Type System: build schema from introspection', () => { `); const introspection = introspectionFromSchema(schema); - // $DisableFlowOnNegativeTest - introspection.__schema.types = introspection.__schema.types.filter( + (introspection: any).__schema.types = introspection.__schema.types.filter( ({ name }) => name !== 'Float', ); @@ -636,8 +645,7 @@ describe('Type System: build schema from introspection', () => { expect(introspection).to.have.nested.property('__schema.queryType.name'); - // $DisableFlowOnNegativeTest - delete introspection.__schema.queryType.name; + delete (introspection: any).__schema.queryType.name; expect(() => buildClientSchema(introspection)).to.throw( 'Unknown type reference: {}.', @@ -652,8 +660,7 @@ describe('Type System: build schema from introspection', () => { expect(queryTypeIntrospection).to.have.property('kind'); - // $DisableFlowOnNegativeTest - delete queryTypeIntrospection.kind; + delete (queryTypeIntrospection: any).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", .* }\./, @@ -668,8 +675,7 @@ describe('Type System: build schema from introspection', () => { expect(queryTypeIntrospection).to.have.property('interfaces'); - // $DisableFlowOnNegativeTest - delete queryTypeIntrospection.interfaces; + delete (queryTypeIntrospection: any).interfaces; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing interfaces: { kind: "OBJECT", name: "Query", .* }\./, @@ -683,8 +689,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someInterfaceIntrospection).to.have.property('interfaces'); - // $DisableFlowOnNegativeTest - someInterfaceIntrospection.interfaces = null; + (someInterfaceIntrospection: any).interfaces = null; const clientSchema = buildClientSchema(introspection); expect(printSchema(clientSchema)).to.equal(printSchema(dummySchema)); @@ -697,9 +702,7 @@ describe('Type System: build schema from introspection', () => { ); expect(queryTypeIntrospection).to.have.property('fields'); - - // $DisableFlowOnNegativeTest - delete queryTypeIntrospection.fields; + delete (queryTypeIntrospection: any).fields; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing fields: { kind: "OBJECT", name: "Query", .* }\./, @@ -713,9 +716,7 @@ describe('Type System: build schema from introspection', () => { ); expect(queryTypeIntrospection).to.have.nested.property('fields[0].args'); - - // $DisableFlowOnNegativeTest - delete queryTypeIntrospection.fields[0].args; + delete (queryTypeIntrospection: any).fields[0].args; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing field args: { name: "foo", .* }\./, @@ -732,8 +733,7 @@ describe('Type System: build schema from introspection', () => { 'fields[0].args[0].type.name', 'String', ); - // $DisableFlowOnNegativeTest - queryTypeIntrospection.fields[0].args[0].type.name = 'SomeUnion'; + (queryTypeIntrospection: any).fields[0].args[0].type.name = 'SomeUnion'; expect(() => buildClientSchema(introspection)).to.throw( 'Introspection must provide input type for arguments, but received: SomeUnion.', @@ -750,8 +750,7 @@ describe('Type System: build schema from introspection', () => { 'fields[0].type.name', 'String', ); - // $DisableFlowOnNegativeTest - queryTypeIntrospection.fields[0].type.name = 'SomeInputObject'; + (queryTypeIntrospection: any).fields[0].type.name = 'SomeInputObject'; expect(() => buildClientSchema(introspection)).to.throw( 'Introspection must provide output type for fields, but received: SomeInputObject.', @@ -765,9 +764,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someUnionIntrospection).to.have.property('possibleTypes'); - - // $DisableFlowOnNegativeTest - delete someUnionIntrospection.possibleTypes; + delete (someUnionIntrospection: any).possibleTypes; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing possibleTypes: { kind: "UNION", name: "SomeUnion",.* }\./, @@ -781,9 +778,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someEnumIntrospection).to.have.property('enumValues'); - - // $DisableFlowOnNegativeTest - delete someEnumIntrospection.enumValues; + delete (someEnumIntrospection: any).enumValues; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing enumValues: { kind: "ENUM", name: "SomeEnum", .* }\./, @@ -797,9 +792,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someInputObjectIntrospection).to.have.property('inputFields'); - - // $DisableFlowOnNegativeTest - delete someInputObjectIntrospection.inputFields; + delete (someInputObjectIntrospection: any).inputFields; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing inputFields: { kind: "INPUT_OBJECT", name: "SomeInputObject", .* }\./, @@ -814,9 +807,7 @@ describe('Type System: build schema from introspection', () => { name: 'SomeDirective', locations: ['QUERY'], }); - - // $DisableFlowOnNegativeTest - delete someDirectiveIntrospection.locations; + delete (someDirectiveIntrospection: any).locations; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing directive locations: { name: "SomeDirective", .* }\./, @@ -831,9 +822,7 @@ describe('Type System: build schema from introspection', () => { name: 'SomeDirective', args: [], }); - - // $DisableFlowOnNegativeTest - delete someDirectiveIntrospection.args; + delete (someDirectiveIntrospection: any).args; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing directive args: { name: "SomeDirective", .* }\./, diff --git a/src/utilities/__tests__/coerceInputValue-test.js b/src/utilities/__tests__/coerceInputValue-test.js index 7675ff44e3..4da5636769 100644 --- a/src/utilities/__tests__/coerceInputValue-test.js +++ b/src/utilities/__tests__/coerceInputValue-test.js @@ -1,10 +1,9 @@ -// @flow strict - 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 { GraphQLList, @@ -16,25 +15,27 @@ import { import { coerceInputValue } from '../coerceInputValue'; -function expectValue(result) { +function expectValue(result: any) { expect(result.errors).to.deep.equal([]); return expect(result.value); } -function expectErrors(result) { +function expectErrors(result: any) { return expect(result.errors); } describe('coerceInputValue', () => { - function coerceValue(inputValue, type) { + function coerceValue(inputValue: mixed, type: GraphQLInputType) { const errors = []; + const value = coerceInputValue( + inputValue, + type, + (path, invalidValue, error) => { + errors.push({ path, value: invalidValue, error: error.message }); + }, + ); - const value = coerceInputValue(inputValue, type, onError); return { errors, value }; - - function onError(path, invalidValue, error) { - errors.push({ path, value: invalidValue, error: error.message }); - } } describe('for GraphQLNonNull', () => { @@ -174,7 +175,7 @@ describe('coerceInputValue', () => { const TestInputObject = new GraphQLInputObjectType({ name: 'TestInputObject', fields: { - foo: { type: GraphQLNonNull(GraphQLInt) }, + foo: { type: new GraphQLNonNull(GraphQLInt) }, bar: { type: GraphQLInt }, }, }); @@ -262,7 +263,7 @@ describe('coerceInputValue', () => { }); describe('for GraphQLInputObject with default value', () => { - const TestInputObject = (defaultValue) => + const makeTestInputObject = (defaultValue) => new GraphQLInputObjectType({ name: 'TestInputObject', fields: { @@ -274,28 +275,28 @@ describe('coerceInputValue', () => { }); it('returns no errors for valid input value', () => { - const result = coerceValue({ foo: 5 }, TestInputObject(7)); + const result = coerceValue({ foo: 5 }, makeTestInputObject(7)); expectValue(result).to.deep.equal({ foo: 5 }); }); it('returns object with default value', () => { - const result = coerceValue({}, TestInputObject(7)); + const result = coerceValue({}, makeTestInputObject(7)); expectValue(result).to.deep.equal({ foo: 7 }); }); it('returns null as value', () => { - const result = coerceValue({}, TestInputObject(null)); + const result = coerceValue({}, makeTestInputObject(null)); expectValue(result).to.deep.equal({ foo: null }); }); it('returns NaN as value', () => { - const result = coerceValue({}, TestInputObject(NaN)); + const result = coerceValue({}, makeTestInputObject(NaN)); expectValue(result).to.have.property('foo').that.satisfy(Number.isNaN); }); }); describe('for GraphQLList', () => { - const TestList = GraphQLList(GraphQLInt); + const TestList = new GraphQLList(GraphQLInt); it('returns no error for a valid input', () => { const result = coerceValue([1, 2, 3], TestList); @@ -341,7 +342,7 @@ describe('coerceInputValue', () => { }); describe('for nested GraphQLList', () => { - const TestNestedList = GraphQLList(GraphQLList(GraphQLInt)); + const TestNestedList = new GraphQLList(new GraphQLList(GraphQLInt)); it('returns no error for a valid input', () => { const result = coerceValue([[1], [2, 3]], TestNestedList); @@ -371,14 +372,19 @@ describe('coerceInputValue', () => { describe('with default onError', () => { it('throw error without path', () => { - expect(() => coerceInputValue(null, GraphQLNonNull(GraphQLInt))).to.throw( + expect(() => + coerceInputValue(null, new GraphQLNonNull(GraphQLInt)), + ).to.throw( 'Invalid value null: Expected non-nullable type "Int!" not to be null.', ); }); it('throw error with path', () => { expect(() => - coerceInputValue([null], GraphQLList(GraphQLNonNull(GraphQLInt))), + coerceInputValue( + [null], + new GraphQLList(new GraphQLNonNull(GraphQLInt)), + ), ).to.throw( 'Invalid value null at "value[0]": Expected non-nullable type "Int!" not to be null.', ); diff --git a/src/utilities/__tests__/concatAST-test.js b/src/utilities/__tests__/concatAST-test.js index c568c49119..089b36e9dd 100644 --- a/src/utilities/__tests__/concatAST-test.js +++ b/src/utilities/__tests__/concatAST-test.js @@ -1,9 +1,7 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/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.js index 5f52ec5bda..e898363a7c 100644 --- a/src/utilities/__tests__/extendSchema-test.js +++ b/src/utilities/__tests__/extendSchema-test.js @@ -1,17 +1,18 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; + import invariant from '../../jsutils/invariant'; +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 { assertDirective } from '../../type/directives'; @@ -36,7 +37,7 @@ import { printSchema } from '../printSchema'; import { extendSchema } from '../extendSchema'; import { buildSchema } from '../buildASTSchema'; -function printExtensionNodes(obj) { +function printExtensionNodes(obj: ?GraphQLNamedType | GraphQLSchema): string { invariant(obj?.extensionASTNodes != null); return print({ kind: Kind.DOCUMENT, @@ -44,7 +45,10 @@ function printExtensionNodes(obj) { }); } -function printSchemaChanges(schema, extendedSchema) { +function printSchemaChanges( + schema: GraphQLSchema, + extendedSchema: GraphQLSchema, +): string { const schemaDefinitions = parse(printSchema(schema)).definitions.map(print); const ast = parse(printSchema(extendedSchema)); return print({ @@ -55,7 +59,7 @@ function printSchemaChanges(schema, extendedSchema) { }); } -function printASTNode(obj) { +function printASTNode(obj: ?{ +astNode: ?ASTNode, ... }): string { invariant(obj?.astNode != null); return print(obj.astNode); } @@ -359,6 +363,31 @@ describe('extendSchema', () => { expect(printExtensionNodes(someScalar)).to.deep.equal(extensionSDL); }); + it('extends scalars by adding specifiedBy directive', () => { + const schema = buildSchema(` + type Query { + foo: Foo + } + + scalar Foo + + directive @foo on SCALAR + `); + const extensionSDL = dedent` + extend scalar Foo @foo + + extend scalar Foo @specifiedBy(url: "https://example.com/foo_spec") + `; + + const extendedSchema = extendSchema(schema, parse(extensionSDL)); + const foo = assertScalarType(extendedSchema.getType('Foo')); + + expect(foo.specifiedByUrl).to.equal('https://example.com/foo_spec'); + + expect(validateSchema(extendedSchema)).to.deep.equal([]); + expect(printExtensionNodes(foo)).to.deep.equal(extensionSDL); + }); + it('correctly assign AST nodes to new and extended types', () => { const schema = buildSchema(` type Query @@ -825,12 +854,15 @@ describe('extendSchema', () => { it('extends different types multiple times', () => { const schema = buildSchema(` type Query { + someScalar: SomeScalar someObject(someInput: SomeInput): SomeObject someInterface: SomeInterface someEnum: SomeEnum someUnion: SomeUnion } + scalar SomeScalar + type SomeObject implements SomeInterface { oldField: String } @@ -850,8 +882,12 @@ describe('extendSchema', () => { } `); const newTypesSDL = dedent` - interface AnotherNewInterface { - anotherNewField: String + scalar NewScalar + + scalar AnotherNewScalar + + type NewObject { + foo: String } type AnotherNewObject { @@ -862,11 +898,17 @@ describe('extendSchema', () => { newField: String } - type NewObject { - foo: String + interface AnotherNewInterface { + anotherNewField: String }`; + const schemaWithNewTypes = extendSchema(schema, parse(newTypesSDL)); + expect(printSchemaChanges(schema, schemaWithNewTypes)).to.equal( + newTypesSDL + '\n', + ); + const extendAST = parse(` - ${newTypesSDL} + extend scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") + extend type SomeObject implements NewInterface { newField: String } @@ -895,10 +937,12 @@ describe('extendSchema', () => { anotherNewField: String } `); - const extendedSchema = extendSchema(schema, extendAST); + const extendedSchema = extendSchema(schemaWithNewTypes, extendAST); expect(validateSchema(extendedSchema)).to.deep.equal([]); expect(printSchemaChanges(schema, extendedSchema)).to.equal(dedent` + scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") + type SomeObject implements SomeInterface & NewInterface & AnotherNewInterface { oldField: String newField: String @@ -1203,12 +1247,12 @@ describe('extendSchema', () => { it('Rejects invalid AST', () => { const schema = new GraphQLSchema({}); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => extendSchema(schema, null)).to.throw( 'Must provide valid Document AST', ); - // $DisableFlowOnNegativeTest + // $FlowExpectedError[prop-missing] expect(() => extendSchema(schema, {})).to.throw( 'Must provide valid Document AST', ); diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 7246f8b413..a4ab722084 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -7,6 +5,7 @@ import { GraphQLSchema } from '../../type/schema'; import { GraphQLSkipDirective, GraphQLIncludeDirective, + GraphQLSpecifiedByDirective, GraphQLDeprecatedDirective, } from '../../type/directives'; @@ -799,7 +798,11 @@ describe('findBreakingChanges', () => { const oldSchema = new GraphQLSchema({}); const newSchema = new GraphQLSchema({ - directives: [GraphQLSkipDirective, GraphQLIncludeDirective], + directives: [ + GraphQLSkipDirective, + GraphQLIncludeDirective, + GraphQLSpecifiedByDirective, + ], }); expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ diff --git a/src/utilities/__tests__/findDeprecatedUsages-test.js b/src/utilities/__tests__/findDeprecatedUsages-test.js deleted file mode 100644 index f49c67589f..0000000000 --- a/src/utilities/__tests__/findDeprecatedUsages-test.js +++ /dev/null @@ -1,76 +0,0 @@ -// @flow strict - -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { parse } from '../../language/parser'; - -import { buildSchema } from '../buildASTSchema'; -import { findDeprecatedUsages } from '../findDeprecatedUsages'; - -describe('findDeprecatedUsages', () => { - const schema = buildSchema(` - enum EnumType { - NORMAL_VALUE - DEPRECATED_VALUE @deprecated(reason: "Some enum reason.") - } - - type Query { - normalField(enumArg: [EnumType]): String - deprecatedField: String @deprecated(reason: "Some field reason.") - } - `); - - it('should report empty set for no deprecated usages', () => { - const errors = findDeprecatedUsages( - schema, - parse('{ normalField(enumArg: [NORMAL_VALUE]) }'), - ); - - expect(errors.length).to.equal(0); - }); - - it('should ignore unknown stuff', () => { - const errors = findDeprecatedUsages( - schema, - parse(` - { - unknownField(unknownArg: UNKNOWN_VALUE) - normalField(enumArg: UNKNOWN_VALUE) - } - `), - ); - - expect(errors.length).to.equal(0); - }); - - it('should report usage of deprecated fields', () => { - const errors = findDeprecatedUsages( - schema, - parse('{ normalField, deprecatedField }'), - ); - - const errorMessages = errors.map((err) => err.message); - - expect(errorMessages).to.deep.equal([ - 'The field "Query.deprecatedField" is deprecated. Some field reason.', - ]); - }); - - it('should report usage of deprecated enums', () => { - const errors = findDeprecatedUsages( - schema, - parse(` - { - normalField(enumArg: [NORMAL_VALUE, DEPRECATED_VALUE]) - } - `), - ); - - const errorMessages = errors.map((err) => err.message); - - expect(errorMessages).to.deep.equal([ - 'The enum value "EnumType.DEPRECATED_VALUE" is deprecated. Some enum reason.', - ]); - }); -}); diff --git a/src/utilities/__tests__/getIntrospectionQuery-test.js b/src/utilities/__tests__/getIntrospectionQuery-test.js index e25a906e19..3a6fad2c4b 100644 --- a/src/utilities/__tests__/getIntrospectionQuery-test.js +++ b/src/utilities/__tests__/getIntrospectionQuery-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -51,4 +49,16 @@ describe('getIntrospectionQuery', () => { getIntrospectionQuery({ descriptions: false, schemaDescription: true }), ).to.not.match(/\bdescription\b/); }); + + it('include "specifiedByUrl" field', () => { + expect(getIntrospectionQuery()).to.not.match(/\bspecifiedByUrl\b/); + + expect(getIntrospectionQuery({ specifiedByUrl: true })).to.match( + /\bspecifiedByUrl\b/, + ); + + expect(getIntrospectionQuery({ specifiedByUrl: false })).to.not.match( + /\bspecifiedByUrl\b/, + ); + }); }); diff --git a/src/utilities/__tests__/getOperationAST-test.js b/src/utilities/__tests__/getOperationAST-test.js index 8bc4c1646a..029dd7706e 100644 --- a/src/utilities/__tests__/getOperationAST-test.js +++ b/src/utilities/__tests__/getOperationAST-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; diff --git a/src/utilities/__tests__/getOperationRootType-test.js b/src/utilities/__tests__/getOperationRootType-test.js index 5f811e9102..8ebdcdfd8b 100644 --- a/src/utilities/__tests__/getOperationRootType-test.js +++ b/src/utilities/__tests__/getOperationRootType-test.js @@ -1,10 +1,9 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; import invariant from '../../jsutils/invariant'; +import type { DocumentNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; @@ -35,7 +34,7 @@ const subscriptionType = new GraphQLObjectType({ }), }); -function getOperationNode(doc) { +function getOperationNode(doc: DocumentNode) { const operationNode = doc.definitions[0]; invariant(operationNode && operationNode.kind === Kind.OPERATION_DEFINITION); return operationNode; @@ -155,7 +154,7 @@ describe('getOperationRootType', () => { operation: 'non_existent_operation', }; - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => getOperationRootType(testSchema, operationNode)).to.throw( 'Can only have query, mutation and subscription operations.', ); diff --git a/src/utilities/__tests__/introspectionFromSchema-benchmark.js b/src/utilities/__tests__/introspectionFromSchema-benchmark.js deleted file mode 100644 index 87a48f52f8..0000000000 --- a/src/utilities/__tests__/introspectionFromSchema-benchmark.js +++ /dev/null @@ -1,18 +0,0 @@ -// @flow strict - -import { parse } from '../../language/parser'; -import { execute } from '../../execution/execute'; - -import { buildSchema } from '../buildASTSchema'; -import { getIntrospectionQuery } from '../getIntrospectionQuery'; - -import { bigSchemaSDL } from '../../__fixtures__/index'; - -const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); -const document = parse(getIntrospectionQuery()); - -export const name = 'Execute Introspection Query'; -export const count = 10; -export function measure() { - execute({ schema, document }); -} diff --git a/src/utilities/__tests__/introspectionFromSchema-test.js b/src/utilities/__tests__/introspectionFromSchema-test.js index 11d885e590..2aacbfce2b 100644 --- a/src/utilities/__tests__/introspectionFromSchema-test.js +++ b/src/utilities/__tests__/introspectionFromSchema-test.js @@ -1,19 +1,18 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; import { GraphQLSchema } from '../../type/schema'; import { GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; +import type { IntrospectionQuery } from '../getIntrospectionQuery'; import { printSchema } from '../printSchema'; import { buildClientSchema } from '../buildClientSchema'; import { introspectionFromSchema } from '../introspectionFromSchema'; -function introspectionToSDL(introspection) { +function introspectionToSDL(introspection: IntrospectionQuery): string { return printSchema(buildClientSchema(introspection)); } diff --git a/src/utilities/__tests__/lexicographicSortSchema-test.js b/src/utilities/__tests__/lexicographicSortSchema-test.js index 0cd2e348ff..b885733c23 100644 --- a/src/utilities/__tests__/lexicographicSortSchema-test.js +++ b/src/utilities/__tests__/lexicographicSortSchema-test.js @@ -1,15 +1,13 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; import { printSchema } from '../printSchema'; import { buildSchema } from '../buildASTSchema'; import { lexicographicSortSchema } from '../lexicographicSortSchema'; -function sortSDL(sdl) { +function sortSDL(sdl: string): string { const schema = buildSchema(sdl); return printSchema(lexicographicSortSchema(schema)); } diff --git a/src/utilities/__tests__/schemaPrinter-test.js b/src/utilities/__tests__/printSchema-test.js similarity index 79% rename from src/utilities/__tests__/schemaPrinter-test.js rename to src/utilities/__tests__/printSchema-test.js index ebfe7f7ff9..df064c3724 100644 --- a/src/utilities/__tests__/schemaPrinter-test.js +++ b/src/utilities/__tests__/printSchema-test.js @@ -1,17 +1,15 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent 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 { - assertObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, @@ -25,35 +23,25 @@ import { import { buildSchema } from '../buildASTSchema'; import { printSchema, printIntrospectionSchema } from '../printSchema'; -function printForTest(schema) { +function expectPrintedSchema(schema: GraphQLSchema) { const schemaText = printSchema(schema); // keep printSchema and buildSchema in sync expect(printSchema(buildSchema(schemaText))).to.equal(schemaText); - return schemaText; + return expect(schemaText); } -function printSingleFieldSchema(fieldConfig) { +function buildSingleFieldSchema(fieldConfig: GraphQLFieldConfig) { const Query = new GraphQLObjectType({ name: 'Query', fields: { singleField: fieldConfig }, }); - return printForTest(new GraphQLSchema({ query: Query })); -} - -function listOf(type) { - return GraphQLList(type); -} - -function nonNull(type) { - return GraphQLNonNull(type); + return new GraphQLSchema({ query: Query }); } describe('Type System Printer', () => { it('Prints String Field', () => { - const output = printSingleFieldSchema({ - type: GraphQLString, - }); - expect(output).to.equal(dedent` + const schema = buildSingleFieldSchema({ type: GraphQLString }); + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField: String } @@ -61,10 +49,11 @@ describe('Type System Printer', () => { }); it('Prints [String] Field', () => { - const output = printSingleFieldSchema({ - type: listOf(GraphQLString), + const schema = buildSingleFieldSchema({ + type: new GraphQLList(GraphQLString), }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField: [String] } @@ -72,10 +61,11 @@ describe('Type System Printer', () => { }); it('Prints String! Field', () => { - const output = printSingleFieldSchema({ - type: nonNull(GraphQLString), + const schema = buildSingleFieldSchema({ + type: new GraphQLNonNull(GraphQLString), }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField: String! } @@ -83,10 +73,11 @@ describe('Type System Printer', () => { }); it('Prints [String]! Field', () => { - const output = printSingleFieldSchema({ - type: nonNull(listOf(GraphQLString)), + const schema = buildSingleFieldSchema({ + type: new GraphQLNonNull(new GraphQLList(GraphQLString)), }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField: [String]! } @@ -94,10 +85,11 @@ describe('Type System Printer', () => { }); it('Prints [String!] Field', () => { - const output = printSingleFieldSchema({ - type: listOf(nonNull(GraphQLString)), + const schema = buildSingleFieldSchema({ + type: new GraphQLList(new GraphQLNonNull(GraphQLString)), }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField: [String!] } @@ -105,10 +97,13 @@ describe('Type System Printer', () => { }); it('Prints [String!]! Field', () => { - const output = printSingleFieldSchema({ - type: nonNull(listOf(nonNull(GraphQLString))), + const schema = buildSingleFieldSchema({ + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(GraphQLString)), + ), }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField: [String!]! } @@ -120,10 +115,9 @@ describe('Type System Printer', () => { name: 'Foo', fields: { str: { type: GraphQLString } }, }); + const schema = new GraphQLSchema({ types: [FooType] }); - const Schema = new GraphQLSchema({ types: [FooType] }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` type Foo { str: String } @@ -131,11 +125,12 @@ describe('Type System Printer', () => { }); it('Prints String Field With Int Arg', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLInt } }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int): String } @@ -143,11 +138,12 @@ describe('Type System Printer', () => { }); it('Prints String Field With Int Arg With Default', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLInt, defaultValue: 2 } }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int = 2): String } @@ -155,12 +151,13 @@ describe('Type System Printer', () => { }); it('Prints String Field With String Arg With Default', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLString, defaultValue: 'tes\t de\fault' } }, }); - expect(output).to.equal( - // $FlowFixMe + + expectPrintedSchema(schema).to.equal( + // $FlowFixMe[incompatible-call] dedent(String.raw` type Query { singleField(argOne: String = "tes\t de\fault"): String @@ -170,11 +167,12 @@ describe('Type System Printer', () => { }); it('Prints String Field With Int Arg With Default Null', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLInt, defaultValue: null } }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int = null): String } @@ -182,11 +180,12 @@ describe('Type System Printer', () => { }); it('Prints String Field With Int! Arg', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, - args: { argOne: { type: nonNull(GraphQLInt) } }, + args: { argOne: { type: new GraphQLNonNull(GraphQLInt) } }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int!): String } @@ -194,14 +193,15 @@ describe('Type System Printer', () => { }); it('Prints String Field With Multiple Args', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLInt }, argTwo: { type: GraphQLString }, }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int, argTwo: String): String } @@ -209,7 +209,7 @@ describe('Type System Printer', () => { }); it('Prints String Field With Multiple Args, First is Default', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLInt, defaultValue: 1 }, @@ -217,7 +217,8 @@ describe('Type System Printer', () => { argThree: { type: GraphQLBoolean }, }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String } @@ -225,7 +226,7 @@ describe('Type System Printer', () => { }); it('Prints String Field With Multiple Args, Second is Default', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLInt }, @@ -233,7 +234,8 @@ describe('Type System Printer', () => { argThree: { type: GraphQLBoolean }, }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String } @@ -241,7 +243,7 @@ describe('Type System Printer', () => { }); it('Prints String Field With Multiple Args, Last is Default', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, args: { argOne: { type: GraphQLInt }, @@ -249,7 +251,8 @@ describe('Type System Printer', () => { argThree: { type: GraphQLBoolean, defaultValue: false }, }, }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String } @@ -257,13 +260,12 @@ describe('Type System Printer', () => { }); it('Prints schema with description', () => { - const Schema = new GraphQLSchema({ + const schema = new GraphQLSchema({ description: 'Schema description.', query: new GraphQLObjectType({ name: 'Query', fields: {} }), }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` """Schema description.""" schema { query: Query @@ -274,12 +276,11 @@ describe('Type System Printer', () => { }); it('Prints custom query root types', () => { - const Schema = new GraphQLSchema({ + const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'CustomType', fields: {} }), }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` schema { query: CustomType } @@ -289,12 +290,11 @@ describe('Type System Printer', () => { }); it('Prints custom mutation root types', () => { - const Schema = new GraphQLSchema({ + const schema = new GraphQLSchema({ mutation: new GraphQLObjectType({ name: 'CustomType', fields: {} }), }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` schema { mutation: CustomType } @@ -304,12 +304,11 @@ describe('Type System Printer', () => { }); it('Prints custom subscription root types', () => { - const Schema = new GraphQLSchema({ + const schema = new GraphQLSchema({ subscription: new GraphQLObjectType({ name: 'CustomType', fields: {} }), }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` schema { subscription: CustomType } @@ -330,9 +329,8 @@ describe('Type System Printer', () => { interfaces: [FooType], }); - const Schema = new GraphQLSchema({ types: [BarType] }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + const schema = new GraphQLSchema({ types: [BarType] }); + expectPrintedSchema(schema).to.equal(dedent` type Bar implements Foo { str: String } @@ -363,9 +361,8 @@ describe('Type System Printer', () => { interfaces: [FooType, BazType], }); - const Schema = new GraphQLSchema({ types: [BarType] }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + const schema = new GraphQLSchema({ types: [BarType] }); + expectPrintedSchema(schema).to.equal(dedent` type Bar implements Foo & Baz { str: String int: Int @@ -410,12 +407,8 @@ describe('Type System Printer', () => { fields: { bar: { type: BarType } }, }); - const Schema = new GraphQLSchema({ - query: Query, - types: [BarType], - }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + const schema = new GraphQLSchema({ query: Query, types: [BarType] }); + expectPrintedSchema(schema).to.equal(dedent` type Bar implements Foo & Baz { str: String int: Int @@ -461,9 +454,8 @@ describe('Type System Printer', () => { types: [FooType, BarType], }); - const Schema = new GraphQLSchema({ types: [SingleUnion, MultipleUnion] }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + const schema = new GraphQLSchema({ types: [SingleUnion, MultipleUnion] }); + expectPrintedSchema(schema).to.equal(dedent` union SingleUnion = Foo type Foo { @@ -486,9 +478,8 @@ describe('Type System Printer', () => { }, }); - const Schema = new GraphQLSchema({ types: [InputType] }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + const schema = new GraphQLSchema({ types: [InputType] }); + expectPrintedSchema(schema).to.equal(dedent` input InputType { int: Int } @@ -498,13 +489,24 @@ describe('Type System Printer', () => { it('Custom Scalar', () => { const OddType = new GraphQLScalarType({ name: 'Odd' }); - const Schema = new GraphQLSchema({ types: [OddType] }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + const schema = new GraphQLSchema({ types: [OddType] }); + expectPrintedSchema(schema).to.equal(dedent` scalar Odd `); }); + it('Custom Scalar with specifiedByUrl', () => { + const FooType = new GraphQLScalarType({ + name: 'Foo', + specifiedByUrl: 'https://example.com/foo_spec', + }); + + const schema = new GraphQLSchema({ types: [FooType] }); + expectPrintedSchema(schema).to.equal(dedent` + scalar Foo @specifiedBy(url: "https://example.com/foo_spec") + `); + }); + it('Enum', () => { const RGBType = new GraphQLEnumType({ name: 'RGB', @@ -515,9 +517,8 @@ describe('Type System Printer', () => { }, }); - const Schema = new GraphQLSchema({ types: [RGBType] }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + const schema = new GraphQLSchema({ types: [RGBType] }); + expectPrintedSchema(schema).to.equal(dedent` enum RGB { RED GREEN @@ -527,7 +528,7 @@ describe('Type System Printer', () => { }); it('Prints empty types', () => { - const Schema = new GraphQLSchema({ + const schema = new GraphQLSchema({ types: [ new GraphQLEnumType({ name: 'SomeEnum', values: {} }), new GraphQLInputObjectType({ name: 'SomeInputObject', fields: {} }), @@ -537,8 +538,7 @@ describe('Type System Printer', () => { ], }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` enum SomeEnum input SomeInputObject @@ -567,11 +567,10 @@ describe('Type System Printer', () => { locations: [DirectiveLocation.FIELD, DirectiveLocation.QUERY], }); - const Schema = new GraphQLSchema({ + const schema = new GraphQLSchema({ directives: [SimpleDirective, ComplexDirective], }); - const output = printForTest(Schema); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` directive @simpleDirective on FIELD """Complex Directive""" @@ -580,12 +579,12 @@ describe('Type System Printer', () => { }); it('Prints an empty description', () => { - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, description: '', }); - expect(output).to.equal(dedent` + expectPrintedSchema(schema).to.equal(dedent` type Query { """""" singleField: String @@ -594,27 +593,24 @@ describe('Type System Printer', () => { }); it('One-line prints a short description', () => { - const description = 'This field is awesome'; - const output = printSingleFieldSchema({ + const schema = buildSingleFieldSchema({ type: GraphQLString, - description, + description: 'This field is awesome', }); - expect(output).to.equal(dedent` + + expectPrintedSchema(schema).to.equal(dedent` type Query { """This field is awesome""" singleField: String } `); - const schema = buildSchema(output); - const recreatedRoot = assertObjectType(schema.getTypeMap().Query); - const recreatedField = recreatedRoot.getFields().singleField; - expect(recreatedField).to.include({ description }); }); it('Print Introspection Schema', () => { - const Schema = new GraphQLSchema({}); - const output = printIntrospectionSchema(Schema); - const introspectionSchema = dedent` + const schema = new GraphQLSchema({}); + const output = printIntrospectionSchema(schema); + + expect(output).to.equal(dedent` """ Directs the executor to include this field or fragment only when the \`if\` argument is true. """ @@ -637,7 +633,13 @@ describe('Type System Printer', () => { 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 | ENUM_VALUE + ) 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. @@ -668,17 +670,18 @@ 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 and description, 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 fields(includeDeprecated: Boolean = false): [__Field!] interfaces: [__Type!] possibleTypes: [__Type!] enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] + inputFields(includeDeprecated: Boolean = false): [__InputValue!] ofType: __Type } @@ -721,7 +724,7 @@ describe('Type System Printer', () => { type __Field { name: String! description: String - args: [__InputValue!]! + args(includeDeprecated: Boolean = false): [__InputValue!]! type: __Type! isDeprecated: Boolean! deprecationReason: String @@ -739,6 +742,8 @@ describe('Type System Printer', () => { A GraphQL-formatted string representing the default value for this input value. """ defaultValue: String + isDeprecated: Boolean! + deprecationReason: String } """ @@ -825,16 +830,16 @@ describe('Type System Printer', () => { """Location adjacent to an input object field definition.""" INPUT_FIELD_DEFINITION } - `; - expect(output).to.equal(introspectionSchema); + `); }); it('Print Introspection Schema with comment descriptions', () => { - const Schema = new GraphQLSchema({}); - const output = printIntrospectionSchema(Schema, { + const schema = new GraphQLSchema({}); + const output = printIntrospectionSchema(schema, { commentDescriptions: true, }); - const introspectionSchema = dedent` + + 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. @@ -851,7 +856,13 @@ describe('Type System Printer', () => { 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 | ENUM_VALUE + ) 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 { @@ -875,16 +886,17 @@ 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 and description, 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 fields(includeDeprecated: Boolean = false): [__Field!] interfaces: [__Type!] possibleTypes: [__Type!] enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] + inputFields(includeDeprecated: Boolean = false): [__InputValue!] ofType: __Type } @@ -919,7 +931,7 @@ describe('Type System Printer', () => { type __Field { name: String! description: String - args: [__InputValue!]! + args(includeDeprecated: Boolean = false): [__InputValue!]! type: __Type! isDeprecated: Boolean! deprecationReason: String @@ -933,6 +945,8 @@ describe('Type System Printer', () => { # 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. @@ -1013,7 +1027,6 @@ describe('Type System Printer', () => { # Location adjacent to an input object field definition. INPUT_FIELD_DEFINITION } - `; - expect(output).to.equal(introspectionSchema); + `); }); }); diff --git a/src/utilities/__tests__/separateOperations-test.js b/src/utilities/__tests__/separateOperations-test.js index cbdfd02fa7..4240705396 100644 --- a/src/utilities/__tests__/separateOperations-test.js +++ b/src/utilities/__tests__/separateOperations-test.js @@ -1,9 +1,7 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; import { parse } from '../../language/parser'; import { print } from '../../language/printer'; diff --git a/src/utilities/__tests__/stripIgnoredCharacters-fuzz.js b/src/utilities/__tests__/stripIgnoredCharacters-fuzz.js new file mode 100644 index 0000000000..34a2c9a7a5 --- /dev/null +++ b/src/utilities/__tests__/stripIgnoredCharacters-fuzz.js @@ -0,0 +1,51 @@ +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 '../../language/lexer'; +import { Source } from '../../language/source'; + +import { stripIgnoredCharacters } from '../stripIgnoredCharacters'; + +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('stripIgnoredCharacters', () => { + it('strips ignored characters inside random block 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 + } + + const strippedValue = lexValue(stripIgnoredCharacters(testStr)); + + invariant( + testValue === strippedValue, + dedent` + Expected lexValue(stripIgnoredCharacters(${inspectStr(testStr)})) + to equal ${inspectStr(testValue)} + but got ${inspectStr(strippedValue)} + `, + ); + } + }).timeout(20000); +}); diff --git a/src/utilities/__tests__/stripIgnoredCharacters-test.js b/src/utilities/__tests__/stripIgnoredCharacters-test.js index 6e162ba1fe..fdc7d907d6 100644 --- a/src/utilities/__tests__/stripIgnoredCharacters-test.js +++ b/src/utilities/__tests__/stripIgnoredCharacters-test.js @@ -1,19 +1,19 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; -import dedent from '../../jsutils/dedent'; +import dedent from '../../__testUtils__/dedent'; +import inspectStr from '../../__testUtils__/inspectStr'; +import kitchenSinkSDL from '../../__testUtils__/kitchenSinkSDL'; +import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; + import invariant from '../../jsutils/invariant'; +import { Lexer } from '../../language/lexer'; import { parse } from '../../language/parser'; import { Source } from '../../language/source'; -import { Lexer } from '../../language/lexer'; import { stripIgnoredCharacters } from '../stripIgnoredCharacters'; -import { kitchenSinkQuery, kitchenSinkSDL } from '../../__fixtures__/index'; - const ignoredTokens = [ // UnicodeBOM :: '\uFEFF', // Byte Order Mark (U+FEFF) @@ -58,7 +58,7 @@ const nonPunctuatorTokens = [ '"""block\nstring\nvalue"""', // StringValue(BlockString) ]; -function lexValue(str) { +function lexValue(str: string): ?string { const lexer = new Lexer(new Source(str)); const value = lexer.advance().value; @@ -66,17 +66,9 @@ function lexValue(str) { return value; } -// Called only to make error messages for failing tests -/* istanbul ignore next */ -function inspectStr(str) { - return (JSON.stringify(str) ?? '') - .replace(/^"|"$/g, '`') - .replace(/\\"/g, '"'); -} - -function expectStripped(docString) { +function expectStripped(docString: string) { return { - toEqual(expected) { + toEqual(expected: string): void { const stripped = stripIgnoredCharacters(docString); invariant( @@ -99,27 +91,13 @@ function expectStripped(docString) { `, ); }, - toStayTheSame() { + toStayTheSame(): void { this.toEqual(docString); }, }; } describe('stripIgnoredCharacters', () => { - it('asserts that a source was provided', () => { - // $DisableFlowOnNegativeTest - expect(() => stripIgnoredCharacters()).to.throw( - 'Must provide string or Source. Received: undefined.', - ); - }); - - it('asserts that a valid source was provided', () => { - // $DisableFlowOnNegativeTest - expect(() => stripIgnoredCharacters({})).to.throw( - 'Must provide string or Source. Received: {}.', - ); - }); - it('strips ignored characters from GraphQL query document', () => { const query = dedent` query SomeQuery($foo: String!, $bar: String) { @@ -138,6 +116,10 @@ describe('stripIgnoredCharacters', () => { ); }); + it('accepts Source object', () => { + expect(stripIgnoredCharacters(new Source('{ a }'))).to.equal('{a}'); + }); + it('strips ignored characters from GraphQL SDL document', () => { const sdl = dedent` """ @@ -406,7 +388,7 @@ describe('stripIgnoredCharacters', () => { }); it('strips ignored characters inside block strings', () => { - function expectStrippedString(blockStr) { + function expectStrippedString(blockStr: string) { const originalValue = lexValue(blockStr); const strippedValue = lexValue(stripIgnoredCharacters(blockStr)); @@ -441,46 +423,6 @@ describe('stripIgnoredCharacters', () => { expectStrippedString('"""\na\n b"""').toStayTheSame(); expectStrippedString('"""\n a\n b"""').toEqual('"""a\nb"""'); expectStrippedString('"""\na\n b\nc"""').toEqual('"""a\n b\nc"""'); - - // Testing with length >5 is taking exponentially more time. However it is - // highly recommended to test with increased limit if you make any change. - const maxCombinationLength = 5; - const possibleChars = ['\n', ' ', '"', 'a', '\\']; - const numPossibleChars = possibleChars.length; - let numCombinations = 1; - for (let length = 1; length < maxCombinationLength; ++length) { - numCombinations *= numPossibleChars; - for (let combination = 0; combination < numCombinations; ++combination) { - let testStr = '"""'; - - let leftOver = combination; - for (let i = 0; i < length; ++i) { - const reminder = leftOver % numPossibleChars; - testStr += possibleChars[reminder]; - leftOver = (leftOver - reminder) / numPossibleChars; - } - - testStr += '"""'; - - let testValue; - try { - testValue = lexValue(testStr); - } catch (e) { - continue; // skip invalid values - } - - const strippedValue = lexValue(stripIgnoredCharacters(testStr)); - - invariant( - testValue === strippedValue, - dedent` - Expected lexValue(stripIgnoredCharacters(${inspectStr(testStr)})) - to equal ${inspectStr(testValue)} - but got ${inspectStr(strippedValue)} - `, - ); - } - } }); it('strips kitchen sink query but maintains the exact same AST', () => { diff --git a/src/utilities/__tests__/typeComparators-test.js b/src/utilities/__tests__/typeComparators-test.js index f2123c576b..3f2a87ae78 100644 --- a/src/utilities/__tests__/typeComparators-test.js +++ b/src/utilities/__tests__/typeComparators-test.js @@ -1,8 +1,7 @@ -// @flow strict - 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 { @@ -27,29 +26,34 @@ describe('typeComparators', () => { it('lists of same type are equal', () => { expect( - isEqualType(GraphQLList(GraphQLInt), GraphQLList(GraphQLInt)), + isEqualType(new GraphQLList(GraphQLInt), new GraphQLList(GraphQLInt)), ).to.equal(true); }); it('lists is not equal to item', () => { - expect(isEqualType(GraphQLList(GraphQLInt), GraphQLInt)).to.equal(false); + expect(isEqualType(new GraphQLList(GraphQLInt), GraphQLInt)).to.equal( + false, + ); }); it('non-null of same type are equal', () => { expect( - isEqualType(GraphQLNonNull(GraphQLInt), GraphQLNonNull(GraphQLInt)), + isEqualType( + new GraphQLNonNull(GraphQLInt), + new GraphQLNonNull(GraphQLInt), + ), ).to.equal(true); }); it('non-null is not equal to nullable', () => { - expect(isEqualType(GraphQLNonNull(GraphQLInt), GraphQLInt)).to.equal( + expect(isEqualType(new GraphQLNonNull(GraphQLInt), GraphQLInt)).to.equal( false, ); }); }); describe('isTypeSubTypeOf', () => { - function testSchema(fields) { + function testSchema(fields: GraphQLFieldConfigMap) { return new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', @@ -73,28 +77,28 @@ describe('typeComparators', () => { it('non-null is subtype of nullable', () => { const schema = testSchema({ field: { type: GraphQLString } }); expect( - isTypeSubTypeOf(schema, GraphQLNonNull(GraphQLInt), GraphQLInt), + isTypeSubTypeOf(schema, new GraphQLNonNull(GraphQLInt), GraphQLInt), ).to.equal(true); }); it('nullable is not subtype of non-null', () => { const schema = testSchema({ field: { type: GraphQLString } }); expect( - isTypeSubTypeOf(schema, GraphQLInt, GraphQLNonNull(GraphQLInt)), + isTypeSubTypeOf(schema, GraphQLInt, new GraphQLNonNull(GraphQLInt)), ).to.equal(false); }); it('item is not subtype of list', () => { const schema = testSchema({ field: { type: GraphQLString } }); expect( - isTypeSubTypeOf(schema, GraphQLInt, GraphQLList(GraphQLInt)), + isTypeSubTypeOf(schema, GraphQLInt, new GraphQLList(GraphQLInt)), ).to.equal(false); }); it('list is not subtype of item', () => { const schema = testSchema({ field: { type: GraphQLString } }); expect( - isTypeSubTypeOf(schema, GraphQLList(GraphQLInt), GraphQLInt), + isTypeSubTypeOf(schema, new GraphQLList(GraphQLInt), GraphQLInt), ).to.equal(false); }); diff --git a/src/utilities/__tests__/valueFromAST-test.js b/src/utilities/__tests__/valueFromAST-test.js index 91c82a2fed..f4dc325206 100644 --- a/src/utilities/__tests__/valueFromAST-test.js +++ b/src/utilities/__tests__/valueFromAST-test.js @@ -1,12 +1,13 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +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, @@ -15,17 +16,21 @@ import { GraphQLID, } from '../../type/scalars'; import { + GraphQLList, + GraphQLNonNull, GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType, - GraphQLList, - GraphQLNonNull, } from '../../type/definition'; import { valueFromAST } from '../valueFromAST'; describe('valueFromAST', () => { - function expectValueFrom(valueText, type, variables) { + function expectValueFrom( + valueText: string, + type: GraphQLInputType, + variables: ?ObjMap, + ) { const ast = parseValue(valueText); const value = valueFromAST(ast, type, variables); return expect(value); @@ -115,15 +120,15 @@ describe('valueFromAST', () => { }); // Boolean! - const nonNullBool = GraphQLNonNull(GraphQLBoolean); + const nonNullBool = new GraphQLNonNull(GraphQLBoolean); // [Boolean] - const listOfBool = GraphQLList(GraphQLBoolean); + const listOfBool = new GraphQLList(GraphQLBoolean); // [Boolean!] - const listOfNonNullBool = GraphQLList(nonNullBool); + const listOfNonNullBool = new GraphQLList(nonNullBool); // [Boolean]! - const nonNullListOfBool = GraphQLNonNull(listOfBool); + const nonNullListOfBool = new GraphQLNonNull(listOfBool); // [Boolean!]! - const nonNullListOfNonNullBool = GraphQLNonNull(listOfNonNullBool); + const nonNullListOfNonNullBool = new GraphQLNonNull(listOfNonNullBool); it('coerces to null unless non-null', () => { expectValueFrom('null', GraphQLBoolean).to.equal(null); diff --git a/src/utilities/__tests__/valueFromASTUntyped-test.js b/src/utilities/__tests__/valueFromASTUntyped-test.js index de32875d8f..5e971a43f6 100644 --- a/src/utilities/__tests__/valueFromASTUntyped-test.js +++ b/src/utilities/__tests__/valueFromASTUntyped-test.js @@ -1,60 +1,63 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; +import type { ObjMap } from '../../jsutils/ObjMap'; + import { parseValue } from '../../language/parser'; import { valueFromASTUntyped } from '../valueFromASTUntyped'; describe('valueFromASTUntyped', () => { - function testCase(valueText, expected) { - expect(valueFromASTUntyped(parseValue(valueText))).to.deep.equal(expected); - } - - function testCaseWithVars(valueText, variables, expected) { - expect(valueFromASTUntyped(parseValue(valueText), variables)).to.deep.equal( - expected, - ); + function expectValueFrom(valueText: string, variables?: ?ObjMap) { + const ast = parseValue(valueText); + const value = valueFromASTUntyped(ast, variables); + return expect(value); } it('parses simple values', () => { - testCase('null', null); - testCase('true', true); - testCase('false', false); - testCase('123', 123); - testCase('123.456', 123.456); - testCase('"abc123"', 'abc123'); + expectValueFrom('null').to.equal(null); + expectValueFrom('true').to.equal(true); + expectValueFrom('false').to.equal(false); + expectValueFrom('123').to.equal(123); + expectValueFrom('123.456').to.equal(123.456); + expectValueFrom('"abc123"').to.equal('abc123'); }); it('parses lists of values', () => { - testCase('[true, false]', [true, false]); - testCase('[true, 123.45]', [true, 123.45]); - testCase('[true, null]', [true, null]); - testCase('[true, ["foo", 1.2]]', [true, ['foo', 1.2]]); + expectValueFrom('[true, false]').to.deep.equal([true, false]); + expectValueFrom('[true, 123.45]').to.deep.equal([true, 123.45]); + expectValueFrom('[true, null]').to.deep.equal([true, null]); + expectValueFrom('[true, ["foo", 1.2]]').to.deep.equal([true, ['foo', 1.2]]); }); it('parses input objects', () => { - testCase('{ int: 123, bool: false }', { int: 123, bool: false }); - testCase('{ foo: [ { bar: "baz"} ] }', { foo: [{ bar: 'baz' }] }); + expectValueFrom('{ int: 123, bool: false }').to.deep.equal({ + int: 123, + bool: false, + }); + expectValueFrom('{ foo: [ { bar: "baz"} ] }').to.deep.equal({ + foo: [{ bar: 'baz' }], + }); }); it('parses enum values as plain strings', () => { - testCase('TEST_ENUM_VALUE', 'TEST_ENUM_VALUE'); - testCase('[TEST_ENUM_VALUE]', ['TEST_ENUM_VALUE']); + expectValueFrom('TEST_ENUM_VALUE').to.equal('TEST_ENUM_VALUE'); + expectValueFrom('[TEST_ENUM_VALUE]').to.deep.equal(['TEST_ENUM_VALUE']); }); it('parses variables', () => { - testCaseWithVars('$testVariable', { testVariable: 'foo' }, 'foo'); - testCaseWithVars('[$testVariable]', { testVariable: 'foo' }, ['foo']); - testCaseWithVars( - '{a:[$testVariable]}', - { testVariable: 'foo' }, - { a: ['foo'] }, + expectValueFrom('$testVariable', { testVariable: 'foo' }).to.equal('foo'); + expectValueFrom('[$testVariable]', { testVariable: 'foo' }).to.deep.equal([ + 'foo', + ]); + expectValueFrom('{a:[$testVariable]}', { + testVariable: 'foo', + }).to.deep.equal({ a: ['foo'] }); + expectValueFrom('$testVariable', { testVariable: null }).to.equal(null); + expectValueFrom('$testVariable', { testVariable: NaN }).to.satisfy( + Number.isNaN, ); - testCaseWithVars('$testVariable', { testVariable: null }, null); - testCaseWithVars('$testVariable', { testVariable: NaN }, NaN); - testCaseWithVars('$testVariable', {}, undefined); - testCaseWithVars('$testVariable', null, undefined); + expectValueFrom('$testVariable', {}).to.equal(undefined); + expectValueFrom('$testVariable', null).to.equal(undefined); }); }); diff --git a/src/utilities/assertValidName.js b/src/utilities/assertValidName.js index 0d8bab764f..b919b61be7 100644 --- a/src/utilities/assertValidName.js +++ b/src/utilities/assertValidName.js @@ -1,5 +1,3 @@ -// @flow strict - import devAssert from '../jsutils/devAssert'; import { GraphQLError } from '../error/GraphQLError'; diff --git a/src/utilities/astFromValue.d.ts b/src/utilities/astFromValue.d.ts index ed84eb458f..19f0a8feed 100644 --- a/src/utilities/astFromValue.d.ts +++ b/src/utilities/astFromValue.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { ValueNode } from '../language/ast'; import { GraphQLInputType } from '../type/definition'; diff --git a/src/utilities/astFromValue.js b/src/utilities/astFromValue.js index d4ea450624..39ab089d27 100644 --- a/src/utilities/astFromValue.js +++ b/src/utilities/astFromValue.js @@ -1,5 +1,3 @@ -// @flow strict - import isFinite from '../polyfills/isFinite'; import arrayFrom from '../polyfills/arrayFrom'; import objectValues from '../polyfills/objectValues'; @@ -9,12 +7,12 @@ import invariant from '../jsutils/invariant'; import isObjectLike from '../jsutils/isObjectLike'; import isCollection from '../jsutils/isCollection'; +import type { ValueNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import { type ValueNode } from '../language/ast'; +import type { GraphQLInputType } from '../type/definition'; import { GraphQLID } from '../type/scalars'; import { - type GraphQLInputType, isLeafType, isEnumType, isInputObjectType, @@ -101,6 +99,7 @@ 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. @@ -142,7 +141,7 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { throw new TypeError(`Cannot convert value to AST: ${inspect(serialized)}.`); } - // Not reachable. All possible input types have been considered. + // istanbul ignore next (Not reachable. All possible input types have been considered) invariant(false, 'Unexpected input type: ' + inspect((type: empty))); } diff --git a/src/utilities/buildASTSchema.js b/src/utilities/buildASTSchema.js index 7893071779..067338611e 100644 --- a/src/utilities/buildASTSchema.js +++ b/src/utilities/buildASTSchema.js @@ -1,23 +1,16 @@ -// @flow strict - 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 Source } from '../language/source'; -import { type DocumentNode } from '../language/ast'; -import { type ParseOptions, parse } from '../language/parser'; +import { parse } from '../language/parser'; import { assertValidSDL } from '../validation/validate'; -import { - type GraphQLSchemaValidationOptions, - GraphQLSchema, -} from '../type/schema'; -import { - GraphQLSkipDirective, - GraphQLIncludeDirective, - GraphQLDeprecatedDirective, -} from '../type/directives'; +import type { GraphQLSchemaValidationOptions } from '../type/schema'; +import { GraphQLSchema } from '../type/schema'; +import { specifiedDirectives } from '../type/directives'; import { extendSchemaImpl } from './extendSchema'; @@ -71,6 +64,14 @@ export function buildASTSchema( assertValidSDL(documentAST); } + const emptySchemaConfig = { + description: undefined, + types: [], + directives: [], + extensions: undefined, + extensionASTNodes: [], + assumeValid: false, + }; const config = extendSchemaImpl(emptySchemaConfig, documentAST, options); if (config.astNode == null) { @@ -94,23 +95,15 @@ export function buildASTSchema( const { directives } = config; // If specified directives were not explicitly declared, add them. - if (!directives.some((directive) => directive.name === 'skip')) { - directives.push(GraphQLSkipDirective); - } - - if (!directives.some((directive) => directive.name === 'include')) { - directives.push(GraphQLIncludeDirective); - } - - if (!directives.some((directive) => directive.name === 'deprecated')) { - directives.push(GraphQLDeprecatedDirective); + for (const stdDirective of specifiedDirectives) { + if (directives.every((directive) => directive.name !== stdDirective.name)) { + directives.push(stdDirective); + } } return new GraphQLSchema(config); } -const emptySchemaConfig = new GraphQLSchema({ directives: [] }).toConfig(); - /** * A helper function to build a GraphQLSchema directly from a source * document. diff --git a/src/utilities/buildClientSchema.js b/src/utilities/buildClientSchema.js index f1b52c80f0..59498e849b 100644 --- a/src/utilities/buildClientSchema.js +++ b/src/utilities/buildClientSchema.js @@ -1,5 +1,3 @@ -// @flow strict - import objectValues from '../polyfills/objectValues'; import inspect from '../jsutils/inspect'; @@ -9,44 +7,49 @@ import isObjectLike from '../jsutils/isObjectLike'; import { parseValue } from '../language/parser'; +import type { GraphQLSchemaValidationOptions } from '../type/schema'; +import type { + GraphQLType, + GraphQLNamedType, + GraphQLFieldConfig, + GraphQLFieldConfigMap, +} 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 { - type GraphQLSchemaValidationOptions, - GraphQLSchema, -} from '../type/schema'; -import { - type GraphQLType, - type GraphQLNamedType, isInputType, isOutputType, + GraphQLList, + GraphQLNonNull, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, - GraphQLList, - GraphQLNonNull, assertNullableType, assertObjectType, assertInterfaceType, } from '../type/definition'; -import { valueFromAST } from './valueFromAST'; -import { - type IntrospectionQuery, - type IntrospectionType, - type IntrospectionScalarType, - type IntrospectionObjectType, - type IntrospectionInterfaceType, - type IntrospectionUnionType, - type IntrospectionEnumType, - type IntrospectionInputObjectType, - type IntrospectionTypeRef, - type IntrospectionNamedTypeRef, +import type { + IntrospectionQuery, + IntrospectionDirective, + IntrospectionField, + IntrospectionInputValue, + IntrospectionType, + IntrospectionScalarType, + IntrospectionObjectType, + IntrospectionInterfaceType, + IntrospectionUnionType, + IntrospectionEnumType, + IntrospectionInputObjectType, + IntrospectionTypeRef, + IntrospectionNamedTypeRef, } from './getIntrospectionQuery'; +import { valueFromAST } from './valueFromAST'; /** * Build a GraphQLSchema for use by client tools. @@ -126,7 +129,7 @@ export function buildClientSchema( if (!itemRef) { throw new Error('Decorated type deeper than introspection query.'); } - return GraphQLList(getType(itemRef)); + return new GraphQLList(getType(itemRef)); } if (typeRef.kind === TypeKind.NON_NULL) { const nullableRef = typeRef.ofType; @@ -134,7 +137,7 @@ export function buildClientSchema( throw new Error('Decorated type deeper than introspection query.'); } const nullableType = getType(nullableRef); - return GraphQLNonNull(assertNullableType(nullableType)); + return new GraphQLNonNull(assertNullableType(nullableType)); } return getNamedType(typeRef); } @@ -200,6 +203,7 @@ export function buildClientSchema( return new GraphQLScalarType({ name: scalarIntrospection.name, description: scalarIntrospection.description, + specifiedByUrl: scalarIntrospection.specifiedByUrl, }); } @@ -207,7 +211,7 @@ export function buildClientSchema( implementingIntrospection: | IntrospectionObjectType | IntrospectionInterfaceType, - ) { + ): Array { // TODO: Temporary workaround until GraphQL ecosystem will fully support // 'interfaces' on interface types. if ( @@ -304,7 +308,9 @@ export function buildClientSchema( }); } - function buildFieldDefMap(typeIntrospection) { + function buildFieldDefMap( + typeIntrospection: IntrospectionObjectType | IntrospectionInterfaceType, + ): GraphQLFieldConfigMap { if (!typeIntrospection.fields) { throw new Error( `Introspection result missing fields: ${inspect(typeIntrospection)}.`, @@ -318,7 +324,9 @@ export function buildClientSchema( ); } - function buildField(fieldIntrospection) { + function buildField( + fieldIntrospection: IntrospectionField, + ): GraphQLFieldConfig { const type = getType(fieldIntrospection.type); if (!isOutputType(type)) { const typeStr = inspect(type); @@ -342,7 +350,9 @@ export function buildClientSchema( }; } - function buildInputValueDefMap(inputValueIntrospections) { + function buildInputValueDefMap( + inputValueIntrospections: $ReadOnlyArray, + ) { return keyValMap( inputValueIntrospections, (inputValue) => inputValue.name, @@ -350,7 +360,7 @@ export function buildClientSchema( ); } - function buildInputValue(inputValueIntrospection) { + function buildInputValue(inputValueIntrospection: IntrospectionInputValue) { const type = getType(inputValueIntrospection.type); if (!isInputType(type)) { const typeStr = inspect(type); @@ -370,7 +380,9 @@ export function buildClientSchema( }; } - function buildDirective(directiveIntrospection) { + function buildDirective( + directiveIntrospection: IntrospectionDirective, + ): GraphQLDirective { if (!directiveIntrospection.args) { const directiveIntrospectionStr = inspect(directiveIntrospection); throw new Error( diff --git a/src/utilities/coerceInputValue.js b/src/utilities/coerceInputValue.js index b116d514c2..d06f755f59 100644 --- a/src/utilities/coerceInputValue.js +++ b/src/utilities/coerceInputValue.js @@ -1,8 +1,7 @@ -// @flow strict - import arrayFrom from '../polyfills/arrayFrom'; import objectValues from '../polyfills/objectValues'; +import type { Path } from '../jsutils/Path'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; import didYouMean from '../jsutils/didYouMean'; @@ -10,11 +9,12 @@ import isObjectLike from '../jsutils/isObjectLike'; import isCollection from '../jsutils/isCollection'; import suggestionList from '../jsutils/suggestionList'; import printPathArray from '../jsutils/printPathArray'; -import { type Path, addPath, pathToArray } from '../jsutils/Path'; +import { addPath, pathToArray } from '../jsutils/Path'; import { GraphQLError } from '../error/GraphQLError'; + +import type { GraphQLInputType } from '../type/definition'; import { - type GraphQLInputType, isLeafType, isInputObjectType, isListType, @@ -42,7 +42,7 @@ function defaultOnError( path: $ReadOnlyArray, invalidValue: mixed, error: GraphQLError, -) { +): void { let errorPrefix = 'Invalid value ' + inspect(invalidValue); if (path.length > 0) { errorPrefix += ` at "value${printPathArray(path)}"`; @@ -80,7 +80,7 @@ function coerceInputValueImpl( const itemType = type.ofType; if (isCollection(inputValue)) { return arrayFrom(inputValue, (itemValue, index) => { - const itemPath = addPath(path, index); + const itemPath = addPath(path, index, undefined); return coerceInputValueImpl(itemValue, itemType, onError, itemPath); }); } @@ -124,7 +124,7 @@ function coerceInputValueImpl( fieldValue, field.type, onError, - addPath(path, field.name), + addPath(path, field.name, type.name), ); } @@ -148,6 +148,7 @@ function coerceInputValueImpl( return coercedValue; } + // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isLeafType(type)) { let parseResult; @@ -185,6 +186,6 @@ function coerceInputValueImpl( return parseResult; } - // Not reachable. All possible input types have been considered. + // istanbul ignore next (Not reachable. All possible input types have been considered) invariant(false, 'Unexpected input type: ' + inspect((type: empty))); } diff --git a/src/utilities/concatAST.js b/src/utilities/concatAST.js index 895229dd40..b7a0ea4726 100644 --- a/src/utilities/concatAST.js +++ b/src/utilities/concatAST.js @@ -1,17 +1,16 @@ -// @flow strict - -import flatMap from '../polyfills/flatMap'; - -import { type DocumentNode } from '../language/ast'; +import type { 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 { - return { - kind: 'Document', - definitions: flatMap(asts, (ast) => ast.definitions), - }; +export function concatAST( + documents: $ReadOnlyArray, +): DocumentNode { + let definitions = []; + for (const doc of documents) { + definitions = definitions.concat(doc.definitions); + } + return { kind: 'Document', definitions }; } diff --git a/src/utilities/extendSchema.d.ts b/src/utilities/extendSchema.d.ts index a7fa97c84f..6795e01437 100644 --- a/src/utilities/extendSchema.d.ts +++ b/src/utilities/extendSchema.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { Location, DocumentNode, StringValueNode } from '../language/ast'; import { GraphQLSchemaValidationOptions, diff --git a/src/utilities/extendSchema.js b/src/utilities/extendSchema.js index f10195854b..b7d3bfcfd0 100644 --- a/src/utilities/extendSchema.js +++ b/src/utilities/extendSchema.js @@ -1,5 +1,3 @@ -// @flow strict - import objectValues from '../polyfills/objectValues'; import keyMap from '../jsutils/keyMap'; @@ -8,62 +6,68 @@ import mapValue from '../jsutils/mapValue'; import invariant from '../jsutils/invariant'; import devAssert from '../jsutils/devAssert'; +import type { DirectiveLocationEnum } from '../language/directiveLocation'; +import type { + Location, + DocumentNode, + StringValueNode, + TypeNode, + NamedTypeNode, + SchemaDefinitionNode, + SchemaExtensionNode, + TypeDefinitionNode, + InterfaceTypeDefinitionNode, + InterfaceTypeExtensionNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, + UnionTypeDefinitionNode, + UnionTypeExtensionNode, + FieldDefinitionNode, + InputObjectTypeDefinitionNode, + InputObjectTypeExtensionNode, + InputValueDefinitionNode, + EnumTypeDefinitionNode, + EnumTypeExtensionNode, + EnumValueDefinitionNode, + DirectiveDefinitionNode, + ScalarTypeDefinitionNode, + ScalarTypeExtensionNode, +} from '../language/ast'; import { Kind } from '../language/kinds'; import { TokenKind } from '../language/tokenKind'; import { dedentBlockStringValue } from '../language/blockString'; -import { type DirectiveLocationEnum } from '../language/directiveLocation'; import { isTypeDefinitionNode, isTypeExtensionNode, } from '../language/predicates'; -import { - type Location, - type DocumentNode, - type StringValueNode, - type TypeNode, - type NamedTypeNode, - type SchemaDefinitionNode, - type SchemaExtensionNode, - type TypeDefinitionNode, - type InterfaceTypeDefinitionNode, - type InterfaceTypeExtensionNode, - type ObjectTypeDefinitionNode, - type ObjectTypeExtensionNode, - type UnionTypeDefinitionNode, - type UnionTypeExtensionNode, - type FieldDefinitionNode, - type InputObjectTypeDefinitionNode, - type InputObjectTypeExtensionNode, - type InputValueDefinitionNode, - type EnumTypeDefinitionNode, - type EnumTypeExtensionNode, - type EnumValueDefinitionNode, - type DirectiveDefinitionNode, -} from '../language/ast'; 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, + GraphQLInputFieldConfigMap, +} 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 { - type GraphQLSchemaValidationOptions, - assertSchema, - GraphQLSchema, - type GraphQLSchemaNormalizedConfig, -} from '../type/schema'; -import { - type GraphQLType, - type GraphQLNamedType, - type GraphQLFieldConfigMap, - type GraphQLEnumValueConfigMap, - type GraphQLInputFieldConfigMap, - type GraphQLFieldConfigArgumentMap, isScalarType, isObjectType, isInterfaceType, @@ -235,10 +239,13 @@ 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) { + function replaceType(type: T): T { if (isListType(type)) { + // $FlowFixMe[incompatible-return] return new GraphQLList(replaceType(type.ofType)); - } else if (isNonNullType(type)) { + } + if (isNonNullType(type)) { + // $FlowFixMe[incompatible-return] return new GraphQLNonNull(replaceType(type.ofType)); } return replaceNamedType(type); @@ -279,11 +286,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); } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false, 'Unexpected type: ' + inspect((type: empty))); } @@ -324,8 +332,14 @@ export function extendSchemaImpl( const config = type.toConfig(); const extensions = typeExtensionsMap[config.name] ?? []; + let specifiedByUrl = config.specifiedByUrl; + for (const extensionNode of extensions) { + specifiedByUrl = getSpecifiedByUrl(extensionNode) ?? specifiedByUrl; + } + return new GraphQLScalarType({ ...config, + specifiedByUrl, extensionASTNodes: config.extensionASTNodes.concat(extensions), }); } @@ -382,15 +396,18 @@ export function extendSchemaImpl( }); } - function extendField(field) { + function extendField( + field: GraphQLFieldConfig, + ): GraphQLFieldConfig { return { ...field, type: replaceType(field.type), + // $FlowFixMe[incompatible-call] args: mapValue(field.args, extendArg), }; } - function extendArg(arg) { + function extendArg(arg: GraphQLArgumentConfig) { return { ...arg, type: replaceType(arg.type), @@ -406,7 +423,7 @@ export function extendSchemaImpl( |} { const opTypes = {}; for (const node of nodes) { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const operationTypesNodes = node.operationTypes ?? []; for (const operationType of operationTypesNodes) { @@ -465,7 +482,7 @@ export function extendSchemaImpl( ): GraphQLFieldConfigMap { const fieldConfigMap = Object.create(null); for (const node of nodes) { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const nodeFields = node.fields ?? []; for (const field of nodeFields) { @@ -487,7 +504,7 @@ export function extendSchemaImpl( function buildArgumentMap( args: ?$ReadOnlyArray, ): GraphQLFieldConfigArgumentMap { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const argsNodes = args ?? []; const argConfigMap = Object.create(null); @@ -501,6 +518,7 @@ export function extendSchemaImpl( type, description: getDescription(arg, options), defaultValue: valueFromAST(arg.defaultValue, type), + deprecationReason: getDeprecationReason(arg), astNode: arg, }; } @@ -514,7 +532,7 @@ export function extendSchemaImpl( ): GraphQLInputFieldConfigMap { const inputFieldMap = Object.create(null); for (const node of nodes) { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const fieldsNodes = node.fields ?? []; for (const field of fieldsNodes) { @@ -527,6 +545,7 @@ export function extendSchemaImpl( type, description: getDescription(field, options), defaultValue: valueFromAST(field.defaultValue, type), + deprecationReason: getDeprecationReason(field), astNode: field, }; } @@ -539,7 +558,7 @@ export function extendSchemaImpl( ): GraphQLEnumValueConfigMap { const enumValueMap = Object.create(null); for (const node of nodes) { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const valuesNodes = node.values ?? []; for (const value of valuesNodes) { @@ -563,7 +582,7 @@ export function extendSchemaImpl( ): Array { const interfaces = []; for (const node of nodes) { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const interfacesNodes = node.interfaces ?? []; for (const type of interfacesNodes) { @@ -582,7 +601,7 @@ export function extendSchemaImpl( ): Array { const types = []; for (const node of nodes) { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const typeNodes = node.types ?? []; for (const type of typeNodes) { @@ -658,6 +677,7 @@ export function extendSchemaImpl( return new GraphQLScalarType({ name, description, + specifiedByUrl: getSpecifiedByUrl(astNode), astNode, extensionASTNodes, }); @@ -676,7 +696,7 @@ export function extendSchemaImpl( } } - // Not reachable. All possible type definition nodes have been considered. + // istanbul ignore next (Not reachable. All possible type definition nodes have been considered) invariant( false, 'Unexpected type definition node: ' + inspect((astNode: empty)), @@ -694,12 +714,25 @@ const stdTypeMap = keyMap( * deprecation reason. */ function getDeprecationReason( - node: EnumValueDefinitionNode | FieldDefinitionNode, + node: + | EnumValueDefinitionNode + | FieldDefinitionNode + | InputValueDefinitionNode, ): ?string { const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node); return (deprecated?.reason: any); } +/** + * Given a scalar node, returns the string value for the specifiedByUrl. + */ +function getSpecifiedByUrl( + node: ScalarTypeDefinitionNode | ScalarTypeExtensionNode, +): ?string { + const specifiedBy = getDirectiveValues(GraphQLSpecifiedByDirective, node); + return (specifiedBy?.url: any); +} + /** * Given an ast node, returns its string description. * @deprecated: provided to ease adoption and will be removed in v16. diff --git a/src/utilities/findBreakingChanges.d.ts b/src/utilities/findBreakingChanges.d.ts index 37297e2f51..df35805f17 100644 --- a/src/utilities/findBreakingChanges.d.ts +++ b/src/utilities/findBreakingChanges.d.ts @@ -1,17 +1,12 @@ import { GraphQLSchema } from '../type/schema'; -export const BreakingChangeType: _BreakingChangeType; - -/** - * @internal - */ -type _BreakingChangeType = { +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'; - INTERFACE_REMOVED_FROM_OBJECT: 'INTERFACE_REMOVED_FROM_OBJECT'; + IMPLEMENTED_INTERFACE_REMOVED: 'IMPLEMENTED_INTERFACE_REMOVED'; FIELD_REMOVED: 'FIELD_REMOVED'; FIELD_CHANGED_KIND: 'FIELD_CHANGED_KIND'; REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED'; @@ -24,27 +19,22 @@ type _BreakingChangeType = { DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED'; }; -export const DangerousChangeType: _DangerousChangeType; - -/** - * @internal - */ -type _DangerousChangeType = { +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'; - INTERFACE_ADDED_TO_OBJECT: 'INTERFACE_ADDED_TO_OBJECT'; + IMPLEMENTED_INTERFACE_ADDED: 'IMPLEMENTED_INTERFACE_ADDED'; ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE'; }; export interface BreakingChange { - type: keyof _BreakingChangeType; + type: keyof typeof BreakingChangeType; description: string; } export interface DangerousChange { - type: keyof _DangerousChangeType; + type: keyof typeof DangerousChangeType; description: string; } diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index b3dc7f5eb0..999f93feb9 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -1,5 +1,3 @@ -// @flow strict - import objectValues from '../polyfills/objectValues'; import keyMap from '../jsutils/keyMap'; @@ -9,18 +7,20 @@ import invariant from '../jsutils/invariant'; import { print } from '../language/printer'; import { visit } from '../language/visitor'; -import { type GraphQLSchema } from '../type/schema'; +import type { GraphQLSchema } from '../type/schema'; +import type { + GraphQLField, + GraphQLType, + GraphQLInputType, + GraphQLNamedType, + GraphQLEnumType, + GraphQLUnionType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLInputObjectType, +} from '../type/definition'; import { isSpecifiedScalarType } from '../type/scalars'; import { - type GraphQLField, - type GraphQLType, - type GraphQLInputType, - type GraphQLNamedType, - type GraphQLEnumType, - type GraphQLUnionType, - type GraphQLObjectType, - type GraphQLInterfaceType, - type GraphQLInputObjectType, isScalarType, isObjectType, isInterfaceType, @@ -526,11 +526,12 @@ 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'; } - // Not reachable. All possible named types have been considered. + // istanbul ignore next (Not reachable. All possible named types have been considered) invariant(false, 'Unexpected type: ' + inspect((type: empty))); } diff --git a/src/utilities/findDeprecatedUsages.d.ts b/src/utilities/findDeprecatedUsages.d.ts index 6beb244617..bbdf94391e 100644 --- a/src/utilities/findDeprecatedUsages.d.ts +++ b/src/utilities/findDeprecatedUsages.d.ts @@ -6,8 +6,16 @@ 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, -): Array; +): ReadonlyArray; diff --git a/src/utilities/findDeprecatedUsages.js b/src/utilities/findDeprecatedUsages.js index e63003b7e5..f193494bab 100644 --- a/src/utilities/findDeprecatedUsages.js +++ b/src/utilities/findDeprecatedUsages.js @@ -1,58 +1,28 @@ -// @flow strict +import type { GraphQLError } from '../error/GraphQLError'; -import { GraphQLError } from '../error/GraphQLError'; +import type { DocumentNode } from '../language/ast'; -import { visit } from '../language/visitor'; -import { type DocumentNode } from '../language/ast'; +import type { GraphQLSchema } from '../type/schema'; -import { getNamedType } from '../type/definition'; -import { type GraphQLSchema } from '../type/schema'; - -import { TypeInfo, visitWithTypeInfo } from './TypeInfo'; +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, -): Array { - const errors = []; - const typeInfo = new TypeInfo(schema); - - visit( - ast, - visitWithTypeInfo(typeInfo, { - Field(node) { - const parentType = typeInfo.getParentType(); - const fieldDef = typeInfo.getFieldDef(); - if (parentType && fieldDef?.deprecationReason != null) { - errors.push( - new GraphQLError( - `The field "${parentType.name}.${fieldDef.name}" is deprecated. ` + - fieldDef.deprecationReason, - node, - ), - ); - } - }, - EnumValue(node) { - const type = getNamedType(typeInfo.getInputType()); - const enumVal = typeInfo.getEnumValue(); - if (type && enumVal?.deprecationReason != null) { - errors.push( - new GraphQLError( - `The enum value "${type.name}.${enumVal.name}" is deprecated. ` + - enumVal.deprecationReason, - node, - ), - ); - } - }, - }), - ); - - return errors; +): $ReadOnlyArray { + return validate(schema, ast, [NoDeprecatedCustomRule]); } diff --git a/src/utilities/getIntrospectionQuery.d.ts b/src/utilities/getIntrospectionQuery.d.ts index ece6b71db4..b1822168ec 100644 --- a/src/utilities/getIntrospectionQuery.d.ts +++ b/src/utilities/getIntrospectionQuery.d.ts @@ -1,14 +1,23 @@ -import Maybe from '../tsutils/Maybe'; +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; + 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; } export function getIntrospectionQuery(options?: IntrospectionOptions): string; @@ -53,6 +62,7 @@ export interface IntrospectionScalarType { readonly kind: 'SCALAR'; readonly name: string; readonly description?: Maybe; + readonly specifiedByUrl?: Maybe; } export interface IntrospectionObjectType { diff --git a/src/utilities/getIntrospectionQuery.js b/src/utilities/getIntrospectionQuery.js index 8f79aace3b..d54e77e510 100644 --- a/src/utilities/getIntrospectionQuery.js +++ b/src/utilities/getIntrospectionQuery.js @@ -1,12 +1,14 @@ -// @flow strict - -import { type DirectiveLocationEnum } from '../language/directiveLocation'; +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, @@ -19,12 +21,16 @@ export type IntrospectionOptions = {| export function getIntrospectionQuery(options?: IntrospectionOptions): string { const optionsWithDefault = { descriptions: true, + specifiedByUrl: false, directiveIsRepeatable: false, schemaDescription: false, ...options, }; const descriptions = optionsWithDefault.descriptions ? 'description' : ''; + const specifiedByUrl = optionsWithDefault.specifiedByUrl + ? 'specifiedByUrl' + : ''; const directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable ? 'isRepeatable' : ''; @@ -58,6 +64,7 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { kind name ${descriptions} + ${specifiedByUrl} fields(includeDeprecated: true) { name ${descriptions} @@ -166,6 +173,7 @@ export type IntrospectionScalarType = {| +kind: 'SCALAR', +name: string, +description?: ?string, + +specifiedByUrl?: ?string, |}; export type IntrospectionObjectType = {| diff --git a/src/utilities/getOperationAST.d.ts b/src/utilities/getOperationAST.d.ts index 9f72b7eeca..d17a9b495c 100644 --- a/src/utilities/getOperationAST.d.ts +++ b/src/utilities/getOperationAST.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { DocumentNode, OperationDefinitionNode } from '../language/ast'; /** @@ -8,5 +9,5 @@ import { DocumentNode, OperationDefinitionNode } from '../language/ast'; */ export function getOperationAST( documentAST: DocumentNode, - operationName: Maybe, + operationName?: Maybe, ): Maybe; diff --git a/src/utilities/getOperationAST.js b/src/utilities/getOperationAST.js index 7e3dbcbe16..259d2f05c5 100644 --- a/src/utilities/getOperationAST.js +++ b/src/utilities/getOperationAST.js @@ -1,10 +1,5 @@ -// @flow strict - +import type { DocumentNode, OperationDefinitionNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import { - type DocumentNode, - type OperationDefinitionNode, -} from '../language/ast'; /** * Returns an operation AST given a document AST and optionally an operation @@ -13,7 +8,7 @@ import { */ export function getOperationAST( documentAST: DocumentNode, - operationName: ?string, + operationName?: ?string, ): ?OperationDefinitionNode { let operation = null; for (const definition of documentAST.definitions) { diff --git a/src/utilities/getOperationRootType.js b/src/utilities/getOperationRootType.js index 107c6de8b8..039cefaa40 100644 --- a/src/utilities/getOperationRootType.js +++ b/src/utilities/getOperationRootType.js @@ -1,14 +1,12 @@ -// @flow strict - import { GraphQLError } from '../error/GraphQLError'; -import { - type OperationDefinitionNode, - type OperationTypeDefinitionNode, +import type { + OperationDefinitionNode, + OperationTypeDefinitionNode, } from '../language/ast'; -import { type GraphQLSchema } from '../type/schema'; -import { type GraphQLObjectType } from '../type/definition'; +import type { GraphQLSchema } from '../type/schema'; +import type { GraphQLObjectType } from '../type/definition'; /** * Extracts the root type of the operation from the schema. diff --git a/src/utilities/index.d.ts b/src/utilities/index.d.ts index fadc54c67c..a8019f99d8 100644 --- a/src/utilities/index.d.ts +++ b/src/utilities/index.d.ts @@ -112,5 +112,8 @@ export { DangerousChange, } from './findBreakingChanges'; -// Report all deprecated usage within a GraphQL document. +// 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.js index 994948393a..27f849014e 100644 --- a/src/utilities/index.js +++ b/src/utilities/index.js @@ -1,5 +1,3 @@ -// @flow strict - // Produce the GraphQL query recommended for a full schema introspection. // Accepts optional IntrospectionOptions. export { getIntrospectionQuery } from './getIntrospectionQuery'; @@ -111,5 +109,5 @@ export { } from './findBreakingChanges'; export type { BreakingChange, DangerousChange } from './findBreakingChanges'; -// Report all deprecated usage within a GraphQL document. +// @deprecated: Report all deprecated usage within a GraphQL document. export { findDeprecatedUsages } from './findDeprecatedUsages'; diff --git a/src/utilities/introspectionFromSchema.js b/src/utilities/introspectionFromSchema.js index 7fe8dd60e1..e880b82995 100644 --- a/src/utilities/introspectionFromSchema.js +++ b/src/utilities/introspectionFromSchema.js @@ -1,17 +1,16 @@ -// @flow strict - import invariant from '../jsutils/invariant'; -import isPromise from '../jsutils/isPromise'; import { parse } from '../language/parser'; -import { execute } from '../execution/execute'; -import { type GraphQLSchema } from '../type/schema'; -import { - type IntrospectionQuery, - type IntrospectionOptions, - getIntrospectionQuery, +import type { GraphQLSchema } from '../type/schema'; + +import { executeSync } from '../execution/execute'; + +import type { + IntrospectionQuery, + IntrospectionOptions, } from './getIntrospectionQuery'; +import { getIntrospectionQuery } from './getIntrospectionQuery'; /** * Build an IntrospectionQuery from a GraphQLSchema @@ -33,7 +32,7 @@ export function introspectionFromSchema( }; const document = parse(getIntrospectionQuery(optionsWithDefaults)); - const result = execute({ schema, document }); - invariant(!isPromise(result) && !result.errors && result.data); + const result = executeSync({ schema, document }); + invariant(!result.errors && result.data); return (result.data: any); } diff --git a/src/utilities/lexicographicSortSchema.js b/src/utilities/lexicographicSortSchema.js index 494fc5adfc..57cbff0c48 100644 --- a/src/utilities/lexicographicSortSchema.js +++ b/src/utilities/lexicographicSortSchema.js @@ -1,24 +1,28 @@ -// @flow strict - import objectValues from '../polyfills/objectValues'; +import type { ObjMap } from '../jsutils/ObjMap'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; import keyValMap from '../jsutils/keyValMap'; -import { type ObjMap } from '../jsutils/ObjMap'; +import type { + GraphQLType, + GraphQLNamedType, + GraphQLFieldConfigMap, + GraphQLFieldConfigArgumentMap, + GraphQLInputFieldConfigMap, +} from '../type/definition'; import { GraphQLSchema } from '../type/schema'; import { GraphQLDirective } from '../type/directives'; import { isIntrospectionType } from '../type/introspection'; import { - type GraphQLNamedType, + GraphQLList, + GraphQLNonNull, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, - GraphQLList, - GraphQLNonNull, isListType, isNonNullType, isScalarType, @@ -51,10 +55,12 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { subscription: replaceMaybeType(schemaConfig.subscription), }); - function replaceType(type) { + function replaceType(type: T): T { if (isListType(type)) { + // $FlowFixMe[incompatible-return] return new GraphQLList(replaceType(type.ofType)); } else if (isNonNullType(type)) { + // $FlowFixMe[incompatible-return] return new GraphQLNonNull(replaceType(type.ofType)); } return replaceNamedType(type); @@ -64,11 +70,11 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { return ((typeMap[type.name]: any): T); } - function replaceMaybeType(maybeType) { + function replaceMaybeType(maybeType: T): T { return maybeType && replaceNamedType(maybeType); } - function sortDirective(directive) { + function sortDirective(directive: GraphQLDirective) { const config = directive.toConfig(); return new GraphQLDirective({ ...config, @@ -77,14 +83,14 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { }); } - function sortArgs(args) { + function sortArgs(args: GraphQLFieldConfigArgumentMap) { return sortObjMap(args, (arg) => ({ ...arg, type: replaceType(arg.type), })); } - function sortFields(fieldsMap) { + function sortFields(fieldsMap: GraphQLFieldConfigMap) { return sortObjMap(fieldsMap, (field) => ({ ...field, type: replaceType(field.type), @@ -92,7 +98,7 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { })); } - function sortInputFields(fieldsMap) { + function sortInputFields(fieldsMap: GraphQLInputFieldConfigMap) { return sortObjMap(fieldsMap, (field) => ({ ...field, type: replaceType(field.type), @@ -103,7 +109,7 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { return sortByName(arr).map(replaceNamedType); } - function sortNamedType(type) { + function sortNamedType(type: T) { if (isScalarType(type) || isIntrospectionType(type)) { return type; } @@ -137,6 +143,7 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { values: sortObjMap(config.values), }); } + // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isInputObjectType(type)) { const config = type.toConfig(); return new GraphQLInputObjectType({ @@ -145,7 +152,7 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { }); } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false, 'Unexpected type: ' + inspect((type: empty))); } } diff --git a/src/utilities/printSchema.js b/src/utilities/printSchema.js index fba396fb8d..c76f01bef8 100644 --- a/src/utilities/printSchema.js +++ b/src/utilities/printSchema.js @@ -1,5 +1,3 @@ -// @flow strict - import objectValues from '../polyfills/objectValues'; import inspect from '../jsutils/inspect'; @@ -8,22 +6,26 @@ import invariant from '../jsutils/invariant'; import { print } from '../language/printer'; import { printBlockString } from '../language/blockString'; -import { type GraphQLSchema } from '../type/schema'; +import type { GraphQLSchema } from '../type/schema'; +import type { GraphQLDirective } from '../type/directives'; +import type { + GraphQLNamedType, + GraphQLArgument, + GraphQLInputField, + GraphQLScalarType, + GraphQLEnumType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLInputObjectType, +} from '../type/definition'; import { isIntrospectionType } from '../type/introspection'; import { GraphQLString, isSpecifiedScalarType } from '../type/scalars'; import { - GraphQLDirective, DEFAULT_DEPRECATION_REASON, isSpecifiedDirective, } from '../type/directives'; import { - type GraphQLNamedType, - type GraphQLScalarType, - type GraphQLEnumType, - type GraphQLObjectType, - type GraphQLInterfaceType, - type GraphQLUnionType, - type GraphQLInputObjectType, isScalarType, isObjectType, isInterfaceType, @@ -172,16 +174,21 @@ export function printType(type: GraphQLNamedType, options?: Options): string { if (isEnumType(type)) { return printEnum(type, options); } + // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') if (isInputObjectType(type)) { return printInputObject(type, options); } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false, 'Unexpected type: ' + inspect((type: empty))); } function printScalar(type: GraphQLScalarType, options): string { - return printDescription(options, type) + `scalar ${type.name}`; + return ( + printDescription(options, type) + + `scalar ${type.name}` + + printSpecifiedByUrl(type) + ); } function printImplementedInterfaces( @@ -225,7 +232,7 @@ function printEnum(type: GraphQLEnumType, options): string { printDescription(options, value, ' ', !i) + ' ' + value.name + - printDeprecated(value), + printDeprecated(value.deprecationReason), ); return ( @@ -243,7 +250,10 @@ function printInputObject(type: GraphQLInputObjectType, options): string { ); } -function printFields(options, type) { +function printFields( + options, + type: GraphQLObjectType | GraphQLInterfaceType, +): string { const fields = objectValues(type.getFields()).map( (f, i) => printDescription(options, f, ' ', !i) + @@ -252,16 +262,20 @@ function printFields(options, type) { printArgs(options, f.args, ' ') + ': ' + String(f.type) + - printDeprecated(f), + printDeprecated(f.deprecationReason), ); return printBlock(fields); } -function printBlock(items) { +function printBlock(items: $ReadOnlyArray): string { return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : ''; } -function printArgs(options, args, indentation = '') { +function printArgs( + options, + args: Array, + indentation: string = '', +): string { if (args.length === 0) { return ''; } @@ -288,16 +302,16 @@ function printArgs(options, args, indentation = '') { ); } -function printInputValue(arg) { +function printInputValue(arg: GraphQLInputField): string { const defaultAST = astFromValue(arg.defaultValue, arg.type); let argDecl = arg.name + ': ' + String(arg.type); if (defaultAST) { argDecl += ` = ${print(defaultAST)}`; } - return argDecl; + return argDecl + printDeprecated(arg.deprecationReason); } -function printDirective(directive, options) { +function printDirective(directive: GraphQLDirective, options): string { return ( printDescription(options, directive) + 'directive @' + @@ -309,11 +323,10 @@ function printDirective(directive, options) { ); } -function printDeprecated(fieldOrEnumVal) { - if (!fieldOrEnumVal.isDeprecated) { +function printDeprecated(reason: ?string): string { + if (reason == null) { return ''; } - const reason = fieldOrEnumVal.deprecationReason; const reasonAST = astFromValue(reason, GraphQLString); if (reasonAST && reason !== DEFAULT_DEPRECATION_REASON) { return ' @deprecated(reason: ' + print(reasonAST) + ')'; @@ -321,11 +334,24 @@ function printDeprecated(fieldOrEnumVal) { return ' @deprecated'; } +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) + ')'; +} + function printDescription( options, - def, - indentation = '', - firstInBlock = true, + def: { +description: ?string, ... }, + indentation: string = '', + firstInBlock: boolean = true, ): string { const { description } = def; if (description == null) { diff --git a/src/utilities/separateOperations.js b/src/utilities/separateOperations.js index 0c8f9de300..f7be8f5cb9 100644 --- a/src/utilities/separateOperations.js +++ b/src/utilities/separateOperations.js @@ -1,13 +1,8 @@ -// @flow strict - -import { type ObjMap } from '../jsutils/ObjMap'; +import type { ObjMap } from '../jsutils/ObjMap'; +import type { DocumentNode, OperationDefinitionNode } from '../language/ast'; import { Kind } from '../language/kinds'; import { visit } from '../language/visitor'; -import { - type DocumentNode, - type OperationDefinitionNode, -} from '../language/ast'; /** * separateOperations accepts a single AST document which may contain many diff --git a/src/utilities/stripIgnoredCharacters.js b/src/utilities/stripIgnoredCharacters.js index 2b2036b109..f4f53aa042 100644 --- a/src/utilities/stripIgnoredCharacters.js +++ b/src/utilities/stripIgnoredCharacters.js @@ -1,8 +1,4 @@ -// @flow strict - -import inspect from '../jsutils/inspect'; - -import { Source } from '../language/source'; +import { Source, isSource } from '../language/source'; import { TokenKind } from '../language/tokenKind'; import { Lexer, isPunctuatorTokenKind } from '../language/lexer'; import { @@ -63,12 +59,7 @@ import { * """Type description""" type Foo{"""Field description""" bar:String} */ export function stripIgnoredCharacters(source: string | Source): string { - const sourceObj = typeof source === 'string' ? new Source(source) : source; - if (!(sourceObj instanceof Source)) { - throw new TypeError( - `Must provide string or Source. Received: ${inspect(sourceObj)}.`, - ); - } + const sourceObj = isSource(source) ? source : new Source(source); const body = sourceObj.body; const lexer = new Lexer(sourceObj); @@ -104,13 +95,12 @@ export function stripIgnoredCharacters(source: string | Source): string { return strippedBody; } -function dedentBlockString(blockStr) { +function dedentBlockString(blockStr: string): string { // skip leading and trailing triple quotations const rawStr = blockStr.slice(3, -3); let body = dedentBlockStringValue(rawStr); - const lines = body.split(/\r\n|[\n\r]/g); - if (getBlockStringIndentation(lines) > 0) { + if (getBlockStringIndentation(body) > 0) { body = '\n' + body; } diff --git a/src/utilities/typeComparators.js b/src/utilities/typeComparators.js index b878ba8bb3..99f84d2e7a 100644 --- a/src/utilities/typeComparators.js +++ b/src/utilities/typeComparators.js @@ -1,9 +1,6 @@ -// @flow strict - -import { type GraphQLSchema } from '../type/schema'; +import type { GraphQLSchema } from '../type/schema'; +import type { GraphQLType, GraphQLCompositeType } from '../type/definition'; import { - type GraphQLType, - type GraphQLCompositeType, isInterfaceType, isObjectType, isListType, diff --git a/src/utilities/typeFromAST.js b/src/utilities/typeFromAST.js index c418511dae..6903c5287a 100644 --- a/src/utilities/typeFromAST.js +++ b/src/utilities/typeFromAST.js @@ -1,21 +1,17 @@ -// @flow strict - import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; -import { Kind } from '../language/kinds'; -import { - type NamedTypeNode, - type ListTypeNode, - type NonNullTypeNode, +import type { + NamedTypeNode, + ListTypeNode, + NonNullTypeNode, } from '../language/ast'; -import { type GraphQLSchema } from '../type/schema'; -import { - type GraphQLNamedType, - GraphQLList, - GraphQLNonNull, -} from '../type/definition'; +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 @@ -42,16 +38,17 @@ export function typeFromAST(schema, typeNode) { let innerType; if (typeNode.kind === Kind.LIST_TYPE) { innerType = typeFromAST(schema, typeNode.type); - return innerType && GraphQLList(innerType); + return innerType && new GraphQLList(innerType); } if (typeNode.kind === Kind.NON_NULL_TYPE) { innerType = typeFromAST(schema, typeNode.type); - return innerType && GraphQLNonNull(innerType); + 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); } - // Not reachable. All possible type nodes have been considered. + // 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/typedQueryDocumentNode.d.ts b/src/utilities/typedQueryDocumentNode.d.ts new file mode 100644 index 0000000000..0d7b8de17d --- /dev/null +++ b/src/utilities/typedQueryDocumentNode.d.ts @@ -0,0 +1,20 @@ +import { 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 +> extends DocumentNode { + readonly definitions: ReadonlyArray; + // FIXME: remove once TS implements proper way to enforce nominal typing + /** + * This type is used to ensure that the variables you pass in to the query are assignable to Variables + * and that the Result is assignable to whatever you pass your result to. The method is never actually + * implemented, but the type is valid because we list it as optional + */ + __ensureTypesOfVariablesAndResultMatching?: ( + variables: TRequestVariables, + ) => TResponseData; +} diff --git a/src/utilities/valueFromAST.d.ts b/src/utilities/valueFromAST.d.ts index bef11b75d3..acde6ba9df 100644 --- a/src/utilities/valueFromAST.d.ts +++ b/src/utilities/valueFromAST.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { ValueNode } from '../language/ast'; import { GraphQLInputType } from '../type/definition'; diff --git a/src/utilities/valueFromAST.js b/src/utilities/valueFromAST.js index 4820b57c46..7afed42282 100644 --- a/src/utilities/valueFromAST.js +++ b/src/utilities/valueFromAST.js @@ -1,17 +1,15 @@ -// @flow strict - import objectValues from '../polyfills/objectValues'; +import type { ObjMap } from '../jsutils/ObjMap'; import keyMap from '../jsutils/keyMap'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; -import { type ObjMap } from '../jsutils/ObjMap'; +import type { ValueNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import { type ValueNode } from '../language/ast'; +import type { GraphQLInputType } from '../type/definition'; import { - type GraphQLInputType, isLeafType, isInputObjectType, isListType, @@ -131,6 +129,7 @@ export function valueFromAST( 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 @@ -147,13 +146,16 @@ export function valueFromAST( return result; } - // Not reachable. All possible input types have been considered. + // istanbul ignore next (Not reachable. All possible input types have been considered) invariant(false, 'Unexpected input type: ' + inspect((type: empty))); } // Returns true if the provided valueNode is a variable which is not defined // in the set of variables. -function isMissingVariable(valueNode, variables) { +function isMissingVariable( + valueNode: ValueNode, + variables: ?ObjMap, +): boolean { return ( valueNode.kind === Kind.VARIABLE && (variables == null || variables[valueNode.name.value] === undefined) diff --git a/src/utilities/valueFromASTUntyped.d.ts b/src/utilities/valueFromASTUntyped.d.ts index ab7512e465..a44959da6a 100644 --- a/src/utilities/valueFromASTUntyped.d.ts +++ b/src/utilities/valueFromASTUntyped.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { ValueNode } from '../language/ast'; /** diff --git a/src/utilities/valueFromASTUntyped.js b/src/utilities/valueFromASTUntyped.js index 5ccfef9e7d..3b70329bda 100644 --- a/src/utilities/valueFromASTUntyped.js +++ b/src/utilities/valueFromASTUntyped.js @@ -1,12 +1,10 @@ -// @flow strict - +import type { ObjMap } from '../jsutils/ObjMap'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; import keyValMap from '../jsutils/keyValMap'; -import { type ObjMap } from '../jsutils/ObjMap'; import { Kind } from '../language/kinds'; -import { type ValueNode } from '../language/ast'; +import type { ValueNode } from '../language/ast'; /** * Produces a JavaScript value given a GraphQL Value AST. @@ -53,6 +51,6 @@ export function valueFromASTUntyped( return variables?.[valueNode.name.value]; } - // Not reachable. All possible value nodes have been considered. + // 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 index 1591a468b2..e0ca546b0e 100644 --- a/src/validation/ValidationContext.d.ts +++ b/src/validation/ValidationContext.d.ts @@ -1,4 +1,5 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; + import { GraphQLError } from '../error/GraphQLError'; import { ASTVisitor } from '../language/visitor'; import { @@ -17,15 +18,16 @@ import { GraphQLCompositeType, GraphQLField, GraphQLArgument, + GraphQLEnumValue, } from '../type/definition'; import { TypeInfo } from '../utilities/TypeInfo'; type NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode; -type VariableUsage = { +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, @@ -89,6 +91,8 @@ export class ValidationContext extends ASTValidationContext { getDirective(): Maybe; getArgument(): Maybe; + + getEnumValue(): Maybe; } export type ValidationRule = (context: ValidationContext) => ASTVisitor; diff --git a/src/validation/ValidationContext.js b/src/validation/ValidationContext.js index ecb9854f4a..9bb3dbab6b 100644 --- a/src/validation/ValidationContext.js +++ b/src/validation/ValidationContext.js @@ -1,28 +1,29 @@ -// @flow strict - -import { type ObjMap } from '../jsutils/ObjMap'; - -import { type GraphQLError } from '../error/GraphQLError'; - -import { Kind } from '../language/kinds'; -import { type ASTVisitor, visit } from '../language/visitor'; -import { - type DocumentNode, - type OperationDefinitionNode, - type VariableNode, - type SelectionSetNode, - type FragmentSpreadNode, - type FragmentDefinitionNode, +import type { ObjMap } from '../jsutils/ObjMap'; + +import type { GraphQLError } from '../error/GraphQLError'; + +import type { ASTVisitor } from '../language/visitor'; +import type { + DocumentNode, + OperationDefinitionNode, + VariableNode, + SelectionSetNode, + FragmentSpreadNode, + FragmentDefinitionNode, } from '../language/ast'; -import { type GraphQLSchema } from '../type/schema'; -import { type GraphQLDirective } from '../type/directives'; -import { - type GraphQLInputType, - type GraphQLOutputType, - type GraphQLCompositeType, - type GraphQLField, - type GraphQLArgument, +import { Kind } from '../language/kinds'; +import { visit } from '../language/visitor'; + +import type { GraphQLSchema } from '../type/schema'; +import type { GraphQLDirective } from '../type/directives'; +import type { + GraphQLInputType, + GraphQLOutputType, + GraphQLCompositeType, + GraphQLField, + GraphQLArgument, + GraphQLEnumValue, } from '../type/definition'; import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo'; @@ -243,6 +244,10 @@ export class ValidationContext extends ASTValidationContext { getArgument(): ?GraphQLArgument { return this._typeInfo.getArgument(); } + + getEnumValue(): ?GraphQLEnumValue { + return this._typeInfo.getEnumValue(); + } } export type ValidationRule = (ValidationContext) => ASTVisitor; diff --git a/src/validation/__tests__/ExecutableDefinitionsRule-test.js b/src/validation/__tests__/ExecutableDefinitionsRule-test.js index 1779d23209..4409767b5b 100644 --- a/src/validation/__tests__/ExecutableDefinitionsRule-test.js +++ b/src/validation/__tests__/ExecutableDefinitionsRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { ExecutableDefinitionsRule } from '../rules/ExecutableDefinitionsRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(ExecutableDefinitionsRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js index e06233c75c..6ec857a683 100644 --- a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js +++ b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js @@ -1,10 +1,10 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { validate } from '../validate'; @@ -12,11 +12,11 @@ import { FieldsOnCorrectTypeRule } from '../rules/FieldsOnCorrectTypeRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(FieldsOnCorrectTypeRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } @@ -257,7 +257,7 @@ describe('Validate: Fields on correct type', () => { }); describe('Fields on correct type error message', () => { - function expectErrorMessage(schema, queryStr) { + function expectErrorMessage(schema: GraphQLSchema, queryStr: string) { const errors = validate(schema, parse(queryStr), [ FieldsOnCorrectTypeRule, ]); @@ -331,6 +331,32 @@ describe('Validate: Fields on correct type', () => { ); }); + it('Sort type suggestions based on inheritance order', () => { + const schema = buildSchema(` + interface T { bar: String } + type Query { t: T } + + interface Z implements T { + foo: String + bar: String + } + + interface Y implements Z & T { + foo: String + bar: String + } + + type X implements Y & Z & T { + foo: String + bar: String + } + `); + + expectErrorMessage(schema, '{ t { foo } }').to.equal( + 'Cannot query field "foo" on type "T". Did you mean to use an inline fragment on "Z", "Y", or "X"?', + ); + }); + it('Limits lots of type suggestions', () => { const schema = buildSchema(` union T = A | B | C | D | E | F diff --git a/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js b/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js index 4bb7286efc..a9b7ec17d7 100644 --- a/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js +++ b/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { FragmentsOnCompositeTypesRule } from '../rules/FragmentsOnCompositeTypesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(FragmentsOnCompositeTypesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/KnownArgumentNamesRule-test.js b/src/validation/__tests__/KnownArgumentNamesRule-test.js index 1746236216..8bf7567c50 100644 --- a/src/validation/__tests__/KnownArgumentNamesRule-test.js +++ b/src/validation/__tests__/KnownArgumentNamesRule-test.js @@ -1,7 +1,7 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { @@ -11,15 +11,15 @@ import { import { expectValidationErrors, expectSDLValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(KnownArgumentNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors( schema, KnownArgumentNamesOnDirectivesRule, @@ -27,7 +27,7 @@ function expectSDLErrors(sdlStr, schema) { ); } -function expectValidSDL(sdlStr) { +function expectValidSDL(sdlStr: string) { expectSDLErrors(sdlStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/KnownDirectivesRule-test.js b/src/validation/__tests__/KnownDirectivesRule-test.js index acc0b61a9a..13491bc6c5 100644 --- a/src/validation/__tests__/KnownDirectivesRule-test.js +++ b/src/validation/__tests__/KnownDirectivesRule-test.js @@ -1,26 +1,26 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { KnownDirectivesRule } from '../rules/KnownDirectivesRule'; import { expectValidationErrors, expectSDLValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(KnownDirectivesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, KnownDirectivesRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/KnownFragmentNamesRule-test.js b/src/validation/__tests__/KnownFragmentNamesRule-test.js index 551f967a35..68477de864 100644 --- a/src/validation/__tests__/KnownFragmentNamesRule-test.js +++ b/src/validation/__tests__/KnownFragmentNamesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { KnownFragmentNamesRule } from '../rules/KnownFragmentNamesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(KnownFragmentNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/KnownTypeNamesRule-test.js b/src/validation/__tests__/KnownTypeNamesRule-test.js index adfe354a28..f56ef4ceab 100644 --- a/src/validation/__tests__/KnownTypeNamesRule-test.js +++ b/src/validation/__tests__/KnownTypeNamesRule-test.js @@ -1,7 +1,7 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { KnownTypeNamesRule } from '../rules/KnownTypeNamesRule'; @@ -12,34 +12,39 @@ import { expectSDLValidationErrors, } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(KnownTypeNamesRule, queryStr); } -function expectErrorsWithSchema(schema, queryStr) { +function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { return expectValidationErrorsWithSchema(schema, KnownTypeNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, KnownTypeNamesRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } describe('Validate: Known type names', () => { it('known type names are valid', () => { expectValid(` - query Foo($var: String, $required: [String!]!) { + query Foo( + $var: String + $required: [Int!]! + $introspectionType: __EnumValue + ) { user(id: 4) { pets { ... on Pet { name }, ...PetFields, ... { name } } } } + fragment PetFields on Pet { name } @@ -97,7 +102,7 @@ describe('Validate: Known type names', () => { }); describe('within SDL', () => { - it('use standard scalars', () => { + it('use standard types', () => { expectValidSDL(` type Query { string: String @@ -105,6 +110,7 @@ describe('Validate: Known type names', () => { float: Float boolean: Boolean id: ID + introspectionType: __EnumValue } `); }); @@ -239,7 +245,7 @@ describe('Validate: Known type names', () => { ]); }); - it('reference standard scalars inside extension document', () => { + it('reference standard types inside extension document', () => { const schema = buildSchema('type Foo'); const sdl = ` type SomeType { @@ -248,6 +254,7 @@ describe('Validate: Known type names', () => { float: Float boolean: Boolean id: ID + introspectionType: __EnumValue } `; diff --git a/src/validation/__tests__/LoneAnonymousOperationRule-test.js b/src/validation/__tests__/LoneAnonymousOperationRule-test.js index 9ca95088ce..191870dd03 100644 --- a/src/validation/__tests__/LoneAnonymousOperationRule-test.js +++ b/src/validation/__tests__/LoneAnonymousOperationRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { LoneAnonymousOperationRule } from '../rules/LoneAnonymousOperationRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(LoneAnonymousOperationRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/LoneSchemaDefinitionRule-test.js b/src/validation/__tests__/LoneSchemaDefinitionRule-test.js index 34190eab9b..6e040576b2 100644 --- a/src/validation/__tests__/LoneSchemaDefinitionRule-test.js +++ b/src/validation/__tests__/LoneSchemaDefinitionRule-test.js @@ -1,18 +1,18 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { LoneSchemaDefinitionRule } from '../rules/LoneSchemaDefinitionRule'; import { expectSDLValidationErrors } from './harness'; -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, LoneSchemaDefinitionRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/NoDeprecatedCustomRule-test.js b/src/validation/__tests__/NoDeprecatedCustomRule-test.js new file mode 100644 index 0000000000..12d66eafc2 --- /dev/null +++ b/src/validation/__tests__/NoDeprecatedCustomRule-test.js @@ -0,0 +1,272 @@ +import { describe, it } from 'mocha'; + +import { buildSchema } from '../../utilities/buildASTSchema'; + +import { NoDeprecatedCustomRule } from '../rules/custom/NoDeprecatedCustomRule'; + +import { expectValidationErrorsWithSchema } from './harness'; + +function buildAssertion(sdlStr: string) { + const schema = buildSchema(sdlStr); + return { expectErrors, expectValid }; + + function expectErrors(queryStr: string) { + return expectValidationErrorsWithSchema( + schema, + NoDeprecatedCustomRule, + queryStr, + ); + } + + function expectValid(queryStr: string) { + expectErrors(queryStr).to.deep.equal([]); + } +} + +describe('Validate: no deprecated', () => { + describe('no deprecated fields', () => { + const { expectValid, expectErrors } = buildAssertion(` + type Query { + normalField: String + deprecatedField: String @deprecated(reason: "Some field reason.") + } + `); + + it('ignores fields that are not deprecated', () => { + expectValid(` + { + normalField + } + `); + }); + + it('ignores unknown fields', () => { + expectValid(` + { + unknownField + } + + fragment UnknownFragment on UnknownType { + deprecatedField + } + `); + }); + + it('reports error when a deprecated field is selected', () => { + const message = + 'The field Query.deprecatedField is deprecated. Some field reason.'; + + expectErrors(` + { + deprecatedField + } + + fragment QueryFragment on Query { + deprecatedField + } + `).to.deep.equal([ + { message, locations: [{ line: 3, column: 11 }] }, + { message, locations: [{ line: 7, column: 11 }] }, + ]); + }); + }); + + describe('no deprecated arguments on fields', () => { + const { expectValid, expectErrors } = buildAssertion(` + type Query { + someField( + normalArg: String, + deprecatedArg: String @deprecated(reason: "Some arg reason."), + ): String + } + `); + + it('ignores arguments that are not deprecated', () => { + expectValid(` + { + normalField(normalArg: "") + } + `); + }); + + it('ignores unknown arguments', () => { + expectValid(` + { + someField(unknownArg: "") + unknownField(deprecatedArg: "") + } + `); + }); + + it('reports error when a deprecated argument is used', () => { + expectErrors(` + { + someField(deprecatedArg: "") + } + `).to.deep.equal([ + { + message: + 'Field "Query.someField" argument "deprecatedArg" is deprecated. Some arg reason.', + locations: [{ line: 3, column: 21 }], + }, + ]); + }); + }); + + describe('no deprecated arguments on directives', () => { + const { expectValid, expectErrors } = buildAssertion(` + type Query { + someField: String + } + + directive @someDirective( + normalArg: String, + deprecatedArg: String @deprecated(reason: "Some arg reason."), + ) on FIELD + `); + + it('ignores arguments that are not deprecated', () => { + expectValid(` + { + someField @someDirective(normalArg: "") + } + `); + }); + + it('ignores unknown arguments', () => { + expectValid(` + { + someField @someDirective(unknownArg: "") + someField @unknownDirective(deprecatedArg: "") + } + `); + }); + + it('reports error when a deprecated argument is used', () => { + expectErrors(` + { + someField @someDirective(deprecatedArg: "") + } + `).to.deep.equal([ + { + message: + 'Directive "@someDirective" argument "deprecatedArg" is deprecated. Some arg reason.', + locations: [{ line: 3, column: 36 }], + }, + ]); + }); + }); + + describe('no deprecated input fields', () => { + const { expectValid, expectErrors } = buildAssertion(` + input InputType { + normalField: String + deprecatedField: String @deprecated(reason: "Some input field reason.") + } + + type Query { + someField(someArg: InputType): String + } + + directive @someDirective(someArg: InputType) on FIELD + `); + + it('ignores input fields that are not deprecated', () => { + expectValid(` + { + someField( + someArg: { normalField: "" } + ) @someDirective(someArg: { normalField: "" }) + } + `); + }); + + it('ignores unknown input fields', () => { + expectValid(` + { + someField( + someArg: { unknownField: "" } + ) + + someField( + unknownArg: { unknownField: "" } + ) + + unknownField( + unknownArg: { unknownField: "" } + ) + } + `); + }); + + it('reports error when a deprecated input field is used', () => { + const message = + 'The input field InputType.deprecatedField is deprecated. Some input field reason.'; + + expectErrors(` + { + someField( + someArg: { deprecatedField: "" } + ) @someDirective(someArg: { deprecatedField: "" }) + } + `).to.deep.equal([ + { message, locations: [{ line: 4, column: 24 }] }, + { message, locations: [{ line: 5, column: 39 }] }, + ]); + }); + }); + + describe('no deprecated enum values', () => { + const { expectValid, expectErrors } = buildAssertion(` + enum EnumType { + NORMAL_VALUE + DEPRECATED_VALUE @deprecated(reason: "Some enum reason.") + } + + type Query { + someField(enumArg: EnumType): String + } + `); + + it('ignores enum values that are not deprecated', () => { + expectValid(` + { + normalField(enumArg: NORMAL_VALUE) + } + `); + }); + + it('ignores unknown enum values', () => { + expectValid(` + query ( + $unknownValue: EnumType = UNKNOWN_VALUE + $unknownType: UnknownType = UNKNOWN_VALUE + ) { + someField(enumArg: UNKNOWN_VALUE) + someField(unknownArg: UNKNOWN_VALUE) + unknownField(unknownArg: UNKNOWN_VALUE) + } + + fragment SomeFragment on Query { + someField(enumArg: UNKNOWN_VALUE) + } + `); + }); + + it('reports error when a deprecated enum value is used', () => { + const message = + 'The enum value "EnumType.DEPRECATED_VALUE" is deprecated. Some enum reason.'; + + expectErrors(` + query ( + $variable: EnumType = DEPRECATED_VALUE + ) { + someField(enumArg: DEPRECATED_VALUE) + } + `).to.deep.equal([ + { 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.js index 07f42cd766..94c3d1879b 100644 --- a/src/validation/__tests__/NoFragmentCyclesRule-test.js +++ b/src/validation/__tests__/NoFragmentCyclesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { NoFragmentCyclesRule } from '../rules/NoFragmentCyclesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(NoFragmentCyclesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js b/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js new file mode 100644 index 0000000000..85a6dd0e35 --- /dev/null +++ b/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js @@ -0,0 +1,140 @@ +import { describe, it } from 'mocha'; + +import { buildSchema } from '../../utilities/buildASTSchema'; + +import { NoSchemaIntrospectionCustomRule } from '../rules/custom/NoSchemaIntrospectionCustomRule'; + +import { expectValidationErrorsWithSchema } from './harness'; + +function expectErrors(queryStr: string) { + return expectValidationErrorsWithSchema( + schema, + NoSchemaIntrospectionCustomRule, + queryStr, + ); +} + +function expectValid(queryStr: string) { + expectErrors(queryStr).to.deep.equal([]); +} + +const schema = buildSchema(` + type Query { + someQuery: SomeType + } + + type SomeType { + someField: String + introspectionField: __EnumValue + } +`); + +describe('Validate: Prohibit introspection queries', () => { + it('ignores valid fields including __typename', () => { + expectValid(` + { + someQuery { + __typename + someField + } + } + `); + }); + + it('ignores fields not in the schema', () => { + expectValid(` + { + __introspect + } + `); + }); + + it('reports error when a field with an introspection type is requested', () => { + expectErrors(` + { + __schema { + queryType { + name + } + } + } + `).to.deep.equal([ + { + message: + 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', + locations: [{ line: 3, column: 9 }], + }, + { + message: + 'GraphQL introspection has been disabled, but the requested query contained the field "queryType".', + locations: [{ line: 4, column: 11 }], + }, + ]); + }); + + it('reports error when a field with an introspection type is requested and aliased', () => { + expectErrors(` + { + s: __schema { + queryType { + name + } + } + } + `).to.deep.equal([ + { + message: + 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', + locations: [{ line: 3, column: 9 }], + }, + { + message: + 'GraphQL introspection has been disabled, but the requested query contained the field "queryType".', + locations: [{ line: 4, column: 11 }], + }, + ]); + }); + + it('reports error when using a fragment with a field with an introspection type', () => { + expectErrors(` + { + ...QueryFragment + } + + fragment QueryFragment on Query { + __schema { + queryType { + name + } + } + } + `).to.deep.equal([ + { + message: + 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', + locations: [{ line: 7, column: 9 }], + }, + { + message: + 'GraphQL introspection has been disabled, but the requested query contained the field "queryType".', + locations: [{ line: 8, column: 11 }], + }, + ]); + }); + + it('reports error for non-standard introspection fields', () => { + expectErrors(` + { + someQuery { + introspectionField + } + } + `).to.deep.equal([ + { + message: + 'GraphQL introspection has been disabled, but the requested query contained the field "introspectionField".', + locations: [{ line: 4, column: 11 }], + }, + ]); + }); +}); diff --git a/src/validation/__tests__/NoUndefinedVariablesRule-test.js b/src/validation/__tests__/NoUndefinedVariablesRule-test.js index 5c90a00b89..6969c89d8d 100644 --- a/src/validation/__tests__/NoUndefinedVariablesRule-test.js +++ b/src/validation/__tests__/NoUndefinedVariablesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { NoUndefinedVariablesRule } from '../rules/NoUndefinedVariablesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(NoUndefinedVariablesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/NoUnusedFragmentsRule-test.js b/src/validation/__tests__/NoUnusedFragmentsRule-test.js index 8d0e3b9498..d90b1b271a 100644 --- a/src/validation/__tests__/NoUnusedFragmentsRule-test.js +++ b/src/validation/__tests__/NoUnusedFragmentsRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { NoUnusedFragmentsRule } from '../rules/NoUnusedFragmentsRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(NoUnusedFragmentsRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/NoUnusedVariablesRule-test.js b/src/validation/__tests__/NoUnusedVariablesRule-test.js index 4eea095e0c..aa111b11f5 100644 --- a/src/validation/__tests__/NoUnusedVariablesRule-test.js +++ b/src/validation/__tests__/NoUnusedVariablesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { NoUnusedVariablesRule } from '../rules/NoUnusedVariablesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(NoUnusedVariablesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js index 8d46357e89..080f859b89 100644 --- a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js +++ b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js @@ -1,7 +1,7 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { OverlappingFieldsCanBeMergedRule } from '../rules/OverlappingFieldsCanBeMergedRule'; @@ -11,15 +11,15 @@ import { expectValidationErrorsWithSchema, } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(OverlappingFieldsCanBeMergedRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } -function expectErrorsWithSchema(schema, queryStr) { +function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { return expectValidationErrorsWithSchema( schema, OverlappingFieldsCanBeMergedRule, @@ -27,7 +27,7 @@ function expectErrorsWithSchema(schema, queryStr) { ); } -function expectValidWithSchema(schema, queryStr) { +function expectValidWithSchema(schema: GraphQLSchema, queryStr: string) { expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/PossibleFragmentSpreadsRule-test.js b/src/validation/__tests__/PossibleFragmentSpreadsRule-test.js index 6f70058125..267dbd3b38 100644 --- a/src/validation/__tests__/PossibleFragmentSpreadsRule-test.js +++ b/src/validation/__tests__/PossibleFragmentSpreadsRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { PossibleFragmentSpreadsRule } from '../rules/PossibleFragmentSpreadsRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(PossibleFragmentSpreadsRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/PossibleTypeExtensionsRule-test.js b/src/validation/__tests__/PossibleTypeExtensionsRule-test.js index 4f1bcde0c3..932f7ccef6 100644 --- a/src/validation/__tests__/PossibleTypeExtensionsRule-test.js +++ b/src/validation/__tests__/PossibleTypeExtensionsRule-test.js @@ -1,18 +1,18 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { PossibleTypeExtensionsRule } from '../rules/PossibleTypeExtensionsRule'; import { expectSDLValidationErrors } from './harness'; -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, PossibleTypeExtensionsRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js b/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js index d7198b481e..7976f46bd2 100644 --- a/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js +++ b/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js @@ -1,7 +1,7 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { @@ -11,15 +11,15 @@ import { import { expectValidationErrors, expectSDLValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(ProvidedRequiredArgumentsRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors( schema, ProvidedRequiredArgumentsOnDirectivesRule, @@ -27,7 +27,7 @@ function expectSDLErrors(sdlStr, schema) { ); } -function expectValidSDL(sdlStr) { +function expectValidSDL(sdlStr: string) { expectSDLErrors(sdlStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/ScalarLeafsRule-test.js b/src/validation/__tests__/ScalarLeafsRule-test.js index 5f6cc30ab1..a441d4fcc7 100644 --- a/src/validation/__tests__/ScalarLeafsRule-test.js +++ b/src/validation/__tests__/ScalarLeafsRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { ScalarLeafsRule } from '../rules/ScalarLeafsRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(ScalarLeafsRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js b/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js index bbd55b0d8c..c8ddc5add3 100644 --- a/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js +++ b/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { SingleFieldSubscriptionsRule } from '../rules/SingleFieldSubscriptionsRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(SingleFieldSubscriptionsRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueArgumentNamesRule-test.js b/src/validation/__tests__/UniqueArgumentNamesRule-test.js index a72cec64c8..a18c56bd8f 100644 --- a/src/validation/__tests__/UniqueArgumentNamesRule-test.js +++ b/src/validation/__tests__/UniqueArgumentNamesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { UniqueArgumentNamesRule } from '../rules/UniqueArgumentNamesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(UniqueArgumentNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueDirectiveNamesRule-test.js b/src/validation/__tests__/UniqueDirectiveNamesRule-test.js index 65261e985c..5e898998ed 100644 --- a/src/validation/__tests__/UniqueDirectiveNamesRule-test.js +++ b/src/validation/__tests__/UniqueDirectiveNamesRule-test.js @@ -1,18 +1,18 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { UniqueDirectiveNamesRule } from '../rules/UniqueDirectiveNamesRule'; import { expectSDLValidationErrors } from './harness'; -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, UniqueDirectiveNamesRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js b/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js index 411b6cd9d8..79a7522419 100644 --- a/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js +++ b/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js @@ -1,8 +1,9 @@ -// @flow strict - import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; + +import type { GraphQLSchema } from '../../type/schema'; + import { extendSchema } from '../../utilities/extendSchema'; import { UniqueDirectivesPerLocationRule } from '../rules/UniqueDirectivesPerLocationRule'; @@ -21,7 +22,7 @@ const extensionSDL = ` `; const schemaWithDirectives = extendSchema(testSchema, parse(extensionSDL)); -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrorsWithSchema( schemaWithDirectives, UniqueDirectivesPerLocationRule, @@ -29,11 +30,11 @@ function expectErrors(queryStr) { ); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors( schema, UniqueDirectivesPerLocationRule, diff --git a/src/validation/__tests__/UniqueEnumValueNamesRule-test.js b/src/validation/__tests__/UniqueEnumValueNamesRule-test.js index f5c2db52b3..a97ac3b687 100644 --- a/src/validation/__tests__/UniqueEnumValueNamesRule-test.js +++ b/src/validation/__tests__/UniqueEnumValueNamesRule-test.js @@ -1,18 +1,18 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { UniqueEnumValueNamesRule } from '../rules/UniqueEnumValueNamesRule'; import { expectSDLValidationErrors } from './harness'; -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, UniqueEnumValueNamesRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js b/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js index 759ad4b1a2..c27182d1ac 100644 --- a/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js +++ b/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js @@ -1,14 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { UniqueFieldDefinitionNamesRule } from '../rules/UniqueFieldDefinitionNamesRule'; import { expectSDLValidationErrors } from './harness'; -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors( schema, UniqueFieldDefinitionNamesRule, @@ -16,7 +16,7 @@ function expectSDLErrors(sdlStr, schema) { ); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueFragmentNamesRule-test.js b/src/validation/__tests__/UniqueFragmentNamesRule-test.js index cf6a67da06..f67b462e80 100644 --- a/src/validation/__tests__/UniqueFragmentNamesRule-test.js +++ b/src/validation/__tests__/UniqueFragmentNamesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { UniqueFragmentNamesRule } from '../rules/UniqueFragmentNamesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(UniqueFragmentNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueInputFieldNamesRule-test.js b/src/validation/__tests__/UniqueInputFieldNamesRule-test.js index 14b70ff8a4..8f2426db4e 100644 --- a/src/validation/__tests__/UniqueInputFieldNamesRule-test.js +++ b/src/validation/__tests__/UniqueInputFieldNamesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { UniqueInputFieldNamesRule } from '../rules/UniqueInputFieldNamesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(UniqueInputFieldNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueOperationNamesRule-test.js b/src/validation/__tests__/UniqueOperationNamesRule-test.js index 6f1de34b4c..720a285d26 100644 --- a/src/validation/__tests__/UniqueOperationNamesRule-test.js +++ b/src/validation/__tests__/UniqueOperationNamesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { UniqueOperationNamesRule } from '../rules/UniqueOperationNamesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(UniqueOperationNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueOperationTypesRule-test.js b/src/validation/__tests__/UniqueOperationTypesRule-test.js index cf26459103..fd73040c44 100644 --- a/src/validation/__tests__/UniqueOperationTypesRule-test.js +++ b/src/validation/__tests__/UniqueOperationTypesRule-test.js @@ -1,18 +1,18 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { UniqueOperationTypesRule } from '../rules/UniqueOperationTypesRule'; import { expectSDLValidationErrors } from './harness'; -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, UniqueOperationTypesRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueTypeNamesRule-test.js b/src/validation/__tests__/UniqueTypeNamesRule-test.js index 961116fd81..6525275e92 100644 --- a/src/validation/__tests__/UniqueTypeNamesRule-test.js +++ b/src/validation/__tests__/UniqueTypeNamesRule-test.js @@ -1,18 +1,18 @@ -// @flow strict - import { describe, it } from 'mocha'; +import type { GraphQLSchema } from '../../type/schema'; + import { buildSchema } from '../../utilities/buildASTSchema'; import { UniqueTypeNamesRule } from '../rules/UniqueTypeNamesRule'; import { expectSDLValidationErrors } from './harness'; -function expectSDLErrors(sdlStr, schema) { +function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { return expectSDLValidationErrors(schema, UniqueTypeNamesRule, sdlStr); } -function expectValidSDL(sdlStr, schema) { +function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { expectSDLErrors(sdlStr, schema).to.deep.equal([]); } diff --git a/src/validation/__tests__/UniqueVariableNamesRule-test.js b/src/validation/__tests__/UniqueVariableNamesRule-test.js index 779d581704..4b950fb4cf 100644 --- a/src/validation/__tests__/UniqueVariableNamesRule-test.js +++ b/src/validation/__tests__/UniqueVariableNamesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { UniqueVariableNamesRule } from '../rules/UniqueVariableNamesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(UniqueVariableNamesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/ValuesOfCorrectTypeRule-test.js b/src/validation/__tests__/ValuesOfCorrectTypeRule-test.js index 14f095f63f..1831b4670d 100644 --- a/src/validation/__tests__/ValuesOfCorrectTypeRule-test.js +++ b/src/validation/__tests__/ValuesOfCorrectTypeRule-test.js @@ -1,7 +1,7 @@ -// @flow strict - import { describe, it } from 'mocha'; +import inspect from '../../jsutils/inspect'; + import { GraphQLSchema } from '../../type/schema'; import { GraphQLString } from '../../type/scalars'; import { GraphQLScalarType, GraphQLObjectType } from '../../type/definition'; @@ -13,11 +13,11 @@ import { expectValidationErrorsWithSchema, } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(ValuesOfCorrectTypeRule, queryStr); } -function expectErrorsWithSchema(schema, queryStr) { +function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { return expectValidationErrorsWithSchema( schema, ValuesOfCorrectTypeRule, @@ -25,10 +25,14 @@ function expectErrorsWithSchema(schema, queryStr) { ); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } +function expectValidWithSchema(schema: GraphQLSchema, queryStr: string) { + expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); +} + describe('Validate: Values of correct type', () => { describe('Valid values', () => { it('Good int value', () => { @@ -937,17 +941,37 @@ describe('Validate: Values of correct type', () => { }); it('reports original error for custom scalar which throws', () => { - const expectedErrors = expectErrors(` - { - invalidArg(arg: 123) - } - `); + const customScalar = new GraphQLScalarType({ + name: 'Invalid', + parseValue(value) { + throw new Error( + `Invalid scalar is always invalid: ${inspect(value)}`, + ); + }, + }); + + const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + invalidArg: { + type: GraphQLString, + args: { arg: { type: customScalar } }, + }, + }, + }), + }); + + const expectedErrors = expectErrorsWithSchema( + schema, + '{ invalidArg(arg: 123) }', + ); expectedErrors.to.deep.equal([ { message: 'Expected value of type "Invalid", found 123; Invalid scalar is always invalid: 123', - locations: [{ line: 3, column: 27 }], + locations: [{ line: 1, column: 19 }], }, ]); @@ -971,40 +995,45 @@ describe('Validate: Values of correct type', () => { fields: { invalidArg: { type: GraphQLString, - args: { - arg: { type: customScalar }, - }, + args: { arg: { type: customScalar } }, }, }, }), }); - const expectedErrors = expectErrorsWithSchema( - schema, - ` - { - invalidArg(arg: 123) - } - `, - ); - - expectedErrors.to.deep.equal([ + expectErrorsWithSchema(schema, '{ invalidArg(arg: 123) }').to.deep.equal([ { message: 'Expected value of type "CustomScalar", found 123.', - locations: [{ line: 3, column: 27 }], + locations: [{ line: 1, column: 19 }], }, ]); }); it('allows custom scalar to accept complex literals', () => { - expectValid(` - { - test1: anyArg(arg: 123) - test2: anyArg(arg: "abc") - test3: anyArg(arg: [123, "abc"]) - test4: anyArg(arg: {deep: [123, "abc"]}) - } - `); + const customScalar = new GraphQLScalarType({ name: 'Any' }); + const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + anyArg: { + type: GraphQLString, + args: { arg: { type: customScalar } }, + }, + }, + }), + }); + + expectValidWithSchema( + schema, + ` + { + test1: anyArg(arg: 123) + test2: anyArg(arg: "abc") + test3: anyArg(arg: [123, "abc"]) + test4: anyArg(arg: {deep: [123, "abc"]}) + } + `, + ); }); }); diff --git a/src/validation/__tests__/VariablesAreInputTypesRule-test.js b/src/validation/__tests__/VariablesAreInputTypesRule-test.js index 6c489745d6..5a19fca650 100644 --- a/src/validation/__tests__/VariablesAreInputTypesRule-test.js +++ b/src/validation/__tests__/VariablesAreInputTypesRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { VariablesAreInputTypesRule } from '../rules/VariablesAreInputTypesRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(VariablesAreInputTypesRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/VariablesInAllowedPositionRule-test.js b/src/validation/__tests__/VariablesInAllowedPositionRule-test.js index 5654f7e955..2b9ebc5c2d 100644 --- a/src/validation/__tests__/VariablesInAllowedPositionRule-test.js +++ b/src/validation/__tests__/VariablesInAllowedPositionRule-test.js @@ -1,16 +1,14 @@ -// @flow strict - import { describe, it } from 'mocha'; import { VariablesInAllowedPositionRule } from '../rules/VariablesInAllowedPositionRule'; import { expectValidationErrors } from './harness'; -function expectErrors(queryStr) { +function expectErrors(queryStr: string) { return expectValidationErrors(VariablesInAllowedPositionRule, queryStr); } -function expectValid(queryStr) { +function expectValid(queryStr: string) { expectErrors(queryStr).to.deep.equal([]); } diff --git a/src/validation/__tests__/harness.js b/src/validation/__tests__/harness.js index d84d7520e5..99683412d8 100644 --- a/src/validation/__tests__/harness.js +++ b/src/validation/__tests__/harness.js @@ -1,413 +1,161 @@ -// @flow strict - import { expect } from 'chai'; -import inspect from '../../jsutils/inspect'; - import { parse } from '../../language/parser'; import { GraphQLSchema } from '../../type/schema'; -import { - GraphQLDirective, - GraphQLIncludeDirective, - GraphQLSkipDirective, -} from '../../type/directives'; -import { - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, - GraphQLID, -} from '../../type/scalars'; -import { - GraphQLScalarType, - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, - GraphQLList, - GraphQLNonNull, -} from '../../type/definition'; - -import { validate, validateSDL } from '../validate'; -import { - type ValidationRule, - type SDLValidationRule, -} from '../ValidationContext'; - -const Being = new GraphQLInterfaceType({ - name: 'Being', - fields: () => ({ - name: { - type: GraphQLString, - args: { surname: { type: GraphQLBoolean } }, - }, - }), -}); - -const Mammal = new GraphQLInterfaceType({ - name: 'Mammal', - interfaces: [], - fields: () => ({ - mother: { - type: Mammal, - }, - father: { - type: Mammal, - }, - }), -}); - -const Pet = new GraphQLInterfaceType({ - name: 'Pet', - interfaces: [Being], - fields: () => ({ - name: { - type: GraphQLString, - args: { surname: { type: GraphQLBoolean } }, - }, - }), -}); - -const Canine = new GraphQLInterfaceType({ - name: 'Canine', - interfaces: [Mammal, Being], - fields: () => ({ - name: { - type: GraphQLString, - args: { surname: { type: GraphQLBoolean } }, - }, - mother: { - type: Canine, - }, - father: { - type: Canine, - }, - }), -}); - -const DogCommand = new GraphQLEnumType({ - name: 'DogCommand', - values: { - SIT: { value: 0 }, - HEEL: { value: 1 }, - DOWN: { value: 2 }, - }, -}); - -const Dog = new GraphQLObjectType({ - name: 'Dog', - interfaces: [Being, Pet, Mammal, Canine], - fields: () => ({ - name: { - type: GraphQLString, - args: { surname: { type: GraphQLBoolean } }, - }, - nickname: { type: GraphQLString }, - barkVolume: { type: GraphQLInt }, - barks: { type: GraphQLBoolean }, - doesKnowCommand: { - type: GraphQLBoolean, - args: { - dogCommand: { type: DogCommand }, - }, - }, - isHouseTrained: { - type: GraphQLBoolean, - args: { - atOtherHomes: { - type: GraphQLBoolean, - defaultValue: true, - }, - }, - }, - isAtLocation: { - type: GraphQLBoolean, - args: { x: { type: GraphQLInt }, y: { type: GraphQLInt } }, - }, - mother: { - type: Dog, - }, - father: { - type: Dog, - }, - }), -}); - -const Cat = new GraphQLObjectType({ - name: 'Cat', - fields: () => ({ - name: { - type: GraphQLString, - args: { surname: { type: GraphQLBoolean } }, - }, - nickname: { type: GraphQLString }, - meows: { type: GraphQLBoolean }, - meowVolume: { type: GraphQLInt }, - furColor: { type: FurColor }, - }), - interfaces: [Being, Pet], -}); - -const CatOrDog = new GraphQLUnionType({ - name: 'CatOrDog', - types: [Dog, Cat], -}); - -const Intelligent = new GraphQLInterfaceType({ - name: 'Intelligent', - fields: { - iq: { type: GraphQLInt }, - }, -}); -const Human = new GraphQLObjectType({ - name: 'Human', - interfaces: [Being, Intelligent], - fields: () => ({ - name: { - type: GraphQLString, - args: { surname: { type: GraphQLBoolean } }, - }, - pets: { type: GraphQLList(Pet) }, - relatives: { type: GraphQLList(Human) }, - iq: { type: GraphQLInt }, - }), -}); +import { buildSchema } from '../../utilities/buildASTSchema'; -const Alien = new GraphQLObjectType({ - name: 'Alien', - interfaces: [Being, Intelligent], - fields: { - iq: { type: GraphQLInt }, - name: { - type: GraphQLString, - args: { surname: { type: GraphQLBoolean } }, - }, - numEyes: { type: GraphQLInt }, - }, -}); - -const DogOrHuman = new GraphQLUnionType({ - name: 'DogOrHuman', - types: [Dog, Human], -}); - -const HumanOrAlien = new GraphQLUnionType({ - name: 'HumanOrAlien', - types: [Human, Alien], -}); - -const FurColor = new GraphQLEnumType({ - name: 'FurColor', - values: { - BROWN: { value: 0 }, - BLACK: { value: 1 }, - TAN: { value: 2 }, - SPOTTED: { value: 3 }, - NO_FUR: { value: null }, - UNKNOWN: { value: undefined }, - }, -}); - -const ComplexInput = new GraphQLInputObjectType({ - name: 'ComplexInput', - fields: { - requiredField: { type: GraphQLNonNull(GraphQLBoolean) }, - nonNullField: { type: GraphQLNonNull(GraphQLBoolean), defaultValue: false }, - intField: { type: GraphQLInt }, - stringField: { type: GraphQLString }, - booleanField: { type: GraphQLBoolean }, - stringListField: { type: GraphQLList(GraphQLString) }, - }, -}); - -const ComplicatedArgs = new GraphQLObjectType({ - name: 'ComplicatedArgs', - // TODO List - // TODO Coercion - // TODO NotNulls - fields: () => ({ - intArgField: { - type: GraphQLString, - args: { intArg: { type: GraphQLInt } }, - }, - nonNullIntArgField: { - type: GraphQLString, - args: { nonNullIntArg: { type: GraphQLNonNull(GraphQLInt) } }, - }, - stringArgField: { - type: GraphQLString, - args: { stringArg: { type: GraphQLString } }, - }, - booleanArgField: { - type: GraphQLString, - args: { booleanArg: { type: GraphQLBoolean } }, - }, - enumArgField: { - type: GraphQLString, - args: { enumArg: { type: FurColor } }, - }, - floatArgField: { - type: GraphQLString, - args: { floatArg: { type: GraphQLFloat } }, - }, - idArgField: { - type: GraphQLString, - args: { idArg: { type: GraphQLID } }, - }, - stringListArgField: { - type: GraphQLString, - args: { stringListArg: { type: GraphQLList(GraphQLString) } }, - }, - stringListNonNullArgField: { - type: GraphQLString, - args: { - stringListNonNullArg: { - type: GraphQLList(GraphQLNonNull(GraphQLString)), - }, - }, - }, - complexArgField: { - type: GraphQLString, - args: { complexArg: { type: ComplexInput } }, - }, - multipleReqs: { - type: GraphQLString, - args: { - req1: { type: GraphQLNonNull(GraphQLInt) }, - req2: { type: GraphQLNonNull(GraphQLInt) }, - }, - }, - nonNullFieldWithDefault: { - type: GraphQLString, - args: { - arg: { type: GraphQLNonNull(GraphQLInt), defaultValue: 0 }, - }, - }, - multipleOpts: { - type: GraphQLString, - args: { - opt1: { - type: GraphQLInt, - defaultValue: 0, - }, - opt2: { - type: GraphQLInt, - defaultValue: 0, - }, - }, - }, - multipleOptAndReq: { - type: GraphQLString, - args: { - req1: { type: GraphQLNonNull(GraphQLInt) }, - req2: { type: GraphQLNonNull(GraphQLInt) }, - opt1: { - type: GraphQLInt, - defaultValue: 0, - }, - opt2: { - type: GraphQLInt, - defaultValue: 0, - }, - }, - }, - }), -}); - -const InvalidScalar = new GraphQLScalarType({ - name: 'Invalid', - parseValue(value) { - throw new Error(`Invalid scalar is always invalid: ${inspect(value)}`); - }, -}); - -const AnyScalar = new GraphQLScalarType({ name: 'Any' }); - -const QueryRoot = new GraphQLObjectType({ - name: 'QueryRoot', - fields: () => ({ - human: { - args: { id: { type: GraphQLID } }, - type: Human, - }, - alien: { type: Alien }, - dog: { type: Dog }, - cat: { type: Cat }, - pet: { type: Pet }, - catOrDog: { type: CatOrDog }, - dogOrHuman: { type: DogOrHuman }, - humanOrAlien: { type: HumanOrAlien }, - complicatedArgs: { type: ComplicatedArgs }, - invalidArg: { - args: { - arg: { type: InvalidScalar }, - }, - type: GraphQLString, - }, - anyArg: { - args: { - arg: { type: AnyScalar }, - }, - type: GraphQLString, - }, - }), -}); - -export const testSchema = new GraphQLSchema({ - query: QueryRoot, - types: [Cat, Dog, Human, Alien], - directives: [ - GraphQLIncludeDirective, - GraphQLSkipDirective, - new GraphQLDirective({ - name: 'onQuery', - locations: ['QUERY'], - }), - new GraphQLDirective({ - name: 'onMutation', - locations: ['MUTATION'], - }), - new GraphQLDirective({ - name: 'onSubscription', - locations: ['SUBSCRIPTION'], - }), - new GraphQLDirective({ - name: 'onField', - locations: ['FIELD'], - }), - new GraphQLDirective({ - name: 'onFragmentDefinition', - locations: ['FRAGMENT_DEFINITION'], - }), - new GraphQLDirective({ - name: 'onFragmentSpread', - locations: ['FRAGMENT_SPREAD'], - }), - new GraphQLDirective({ - name: 'onInlineFragment', - locations: ['INLINE_FRAGMENT'], - }), - new GraphQLDirective({ - name: 'onVariableDefinition', - locations: ['VARIABLE_DEFINITION'], - }), - ], -}); +import { validate, validateSDL } from '../validate'; +import type { ValidationRule, SDLValidationRule } from '../ValidationContext'; + +export const testSchema = buildSchema(` + interface Being { + name(surname: Boolean): String + } + + interface Mammal { + mother: Mammal + father: Mammal + } + + interface Pet implements Being { + name(surname: Boolean): String + } + + interface Canine implements Mammal & Being { + name(surname: Boolean): String + mother: Canine + father: Canine + } + + enum DogCommand { + SIT + HEEL + DOWN + } + + type Dog implements Being & Pet & Mammal & Canine { + name(surname: Boolean): String + nickname: String + barkVolume: Int + barks: Boolean + doesKnowCommand(dogCommand: DogCommand): Boolean + isHouseTrained(atOtherHomes: Boolean = true): Boolean + isAtLocation(x: Int, y: Int): Boolean + mother: Dog + father: Dog + } + + type Cat implements Being & Pet { + name(surname: Boolean): String + nickname: String + meows: Boolean + meowsVolume: Int + furColor: FurColor + } + + union CatOrDog = Cat | Dog + + interface Intelligent { + iq: Int + } + + type Human implements Being & Intelligent { + 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 + TAN + SPOTTED + NO_FUR + UNKNOWN + } + + input ComplexInput { + requiredField: Boolean! + nonNullField: Boolean! = false + intField: Int + stringField: String + booleanField: Boolean + stringListField: [String] + } + + type ComplicatedArgs { + # TODO List + # TODO Coercion + # TODO NotNulls + intArgField(intArg: Int): String + nonNullIntArgField(nonNullIntArg: Int!): String + stringArgField(stringArg: String): String + booleanArgField(booleanArg: Boolean): String + enumArgField(enumArg: FurColor): String + floatArgField(floatArg: Float): String + idArgField(idArg: ID): String + stringListArgField(stringListArg: [String]): String + stringListNonNullArgField(stringListNonNullArg: [String!]): String + complexArgField(complexArg: ComplexInput): String + multipleReqs(req1: Int!, req2: Int!): String + nonNullFieldWithDefault(arg: Int! = 0): String + multipleOpts(opt1: Int = 0, opt2: Int = 0): String + multipleOptAndReq(req1: Int!, req2: Int!, opt1: Int = 0, opt2: Int = 0): String + } + + type QueryRoot { + human(id: ID): Human + alien: Alien + dog: Dog + cat: Cat + pet: Pet + catOrDog: CatOrDog + dogOrHuman: DogOrHuman + humanOrAlien: HumanOrAlien + complicatedArgs: ComplicatedArgs + } + + schema { + 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( schema: GraphQLSchema, rule: ValidationRule, queryStr: string, -) { +): any { const doc = parse(queryStr); const errors = validate(schema, doc, [rule]); return expect(errors); } -export function expectValidationErrors(rule: ValidationRule, queryStr: string) { +export function expectValidationErrors( + rule: ValidationRule, + queryStr: string, +): any { return expectValidationErrorsWithSchema(testSchema, rule, queryStr); } @@ -415,7 +163,7 @@ export function expectSDLValidationErrors( schema: ?GraphQLSchema, rule: SDLValidationRule, sdlStr: string, -) { +): any { const doc = parse(sdlStr); const errors = validateSDL(doc, schema, [rule]); return expect(errors); diff --git a/src/validation/__tests__/validateGQL-benchmark.js b/src/validation/__tests__/validateGQL-benchmark.js deleted file mode 100644 index 203ed29358..0000000000 --- a/src/validation/__tests__/validateGQL-benchmark.js +++ /dev/null @@ -1,18 +0,0 @@ -// @flow strict - -import { parse } from '../../language/parser'; -import { buildSchema } from '../../utilities/buildASTSchema'; -import { getIntrospectionQuery } from '../../utilities/getIntrospectionQuery'; - -import { validate } from '../validate'; - -import { bigSchemaSDL } from '../../__fixtures__/index'; - -const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); -const queryAST = parse(getIntrospectionQuery()); - -export const name = 'Validate Introspection Query'; -export const count = 50; -export function measure() { - validate(schema, queryAST); -} diff --git a/src/validation/__tests__/validateInvalidGQL-benchmark.js b/src/validation/__tests__/validateInvalidGQL-benchmark.js deleted file mode 100644 index 8e9bb12a22..0000000000 --- a/src/validation/__tests__/validateInvalidGQL-benchmark.js +++ /dev/null @@ -1,29 +0,0 @@ -// @flow strict - -import { parse } from '../../language/parser'; -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { validate } from '../validate'; - -import { bigSchemaSDL } from '../../__fixtures__/index'; - -const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); -const queryAST = parse(` - { - unknownField - ... on unknownType { - anotherUnknownField - ...unknownFragment - } - } - - fragment TestFragment on anotherUnknownType { - yetAnotherUnknownField - } -`); - -export const name = 'Validate Invalid Query'; -export const count = 50; -export function measure() { - validate(schema, queryAST); -} diff --git a/src/validation/__tests__/validateSDL-benchmark.js b/src/validation/__tests__/validateSDL-benchmark.js deleted file mode 100644 index e56eb06236..0000000000 --- a/src/validation/__tests__/validateSDL-benchmark.js +++ /dev/null @@ -1,15 +0,0 @@ -// @flow strict - -import { parse } from '../../language/parser'; - -import { validateSDL } from '../validate'; - -import { bigSchemaSDL } from '../../__fixtures__/index'; - -const sdlAST = parse(bigSchemaSDL); - -export const name = 'Validate SDL Document'; -export const count = 10; -export function measure() { - validateSDL(sdlAST); -} diff --git a/src/validation/__tests__/validation-test.js b/src/validation/__tests__/validation-test.js index 4c4e6cbb25..b1113d2d01 100644 --- a/src/validation/__tests__/validation-test.js +++ b/src/validation/__tests__/validation-test.js @@ -1,5 +1,3 @@ -// @flow strict - import { expect } from 'chai'; import { describe, it } from 'mocha'; @@ -10,13 +8,14 @@ import { parse } from '../../language/parser'; import { TypeInfo } from '../../utilities/TypeInfo'; import { buildSchema } from '../../utilities/buildASTSchema'; +import type { ValidationContext } from '../ValidationContext'; import { validate } from '../validate'; import { testSchema } from './harness'; describe('Validate: Supports full validation', () => { it('rejects invalid documents', () => { - // $DisableFlowOnNegativeTest + // $FlowExpectedError[incompatible-call] expect(() => validate(testSchema, null)).to.throw('Must provide document.'); }); @@ -38,19 +37,18 @@ describe('Validate: Supports full validation', () => { expect(errors).to.deep.equal([]); }); - it('detects bad scalar parse', () => { + it('detects unknown fields', () => { const doc = parse(` - query { - invalidArg(arg: "bad value") + { + unknown } `); const errors = validate(testSchema, doc); expect(errors).to.deep.equal([ { - locations: [{ line: 3, column: 25 }], - message: - 'Expected value of type "Invalid", found "bad value"; Invalid scalar is always invalid: "bad value"', + locations: [{ line: 3, column: 9 }], + message: 'Cannot query field "unknown" on type "QueryRoot".', }, ]); }); @@ -98,7 +96,7 @@ describe('Validate: Supports full validation', () => { } `); - function customRule(context) { + function customRule(context: ValidationContext) { return { Directive(node) { const directiveDef = context.getDirective(); @@ -131,11 +129,11 @@ describe('Validate: Limit maximum number of validation errors', () => { `; const doc = parse(query, { noLocation: true }); - function validateDocument(options) { + function validateDocument(options: {| maxErrors?: number |}) { return validate(testSchema, doc, undefined, undefined, options); } - function invalidFieldError(fieldName) { + function invalidFieldError(fieldName: string) { return { message: `Cannot query field "${fieldName}" on type "QueryRoot".`, locations: [], diff --git a/src/validation/index.d.ts b/src/validation/index.d.ts index 79317bff03..f049bf397e 100644 --- a/src/validation/index.d.ts +++ b/src/validation/index.d.ts @@ -90,3 +90,7 @@ 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.js index 906b31e43c..c0f24a0316 100644 --- a/src/validation/index.js +++ b/src/validation/index.js @@ -1,5 +1,3 @@ -// @flow strict - export { validate } from './validate'; export { ValidationContext } from './ValidationContext'; @@ -94,3 +92,7 @@ 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/rules/ExecutableDefinitions.js b/src/validation/rules/ExecutableDefinitions.js index b9ee751066..94557ad8de 100644 --- a/src/validation/rules/ExecutableDefinitions.js +++ b/src/validation/rules/ExecutableDefinitions.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/ExecutableDefinitionsRule.js b/src/validation/rules/ExecutableDefinitionsRule.js index 4ae128f866..c446e000e1 100644 --- a/src/validation/rules/ExecutableDefinitionsRule.js +++ b/src/validation/rules/ExecutableDefinitionsRule.js @@ -1,12 +1,10 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; +import type { ASTVisitor } from '../../language/visitor'; import { Kind } from '../../language/kinds'; -import { type ASTVisitor } from '../../language/visitor'; import { isExecutableDefinitionNode } from '../../language/predicates'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTValidationContext } from '../ValidationContext'; /** * Executable definitions diff --git a/src/validation/rules/FieldsOnCorrectTypeRule.js b/src/validation/rules/FieldsOnCorrectTypeRule.js index 038d9a8a3f..5b60d53646 100644 --- a/src/validation/rules/FieldsOnCorrectTypeRule.js +++ b/src/validation/rules/FieldsOnCorrectTypeRule.js @@ -1,5 +1,3 @@ -// @flow strict - import arrayFrom from '../../polyfills/arrayFrom'; import didYouMean from '../../jsutils/didYouMean'; @@ -7,20 +5,22 @@ import suggestionList from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import { type FieldNode } from '../../language/ast'; -import { type ASTVisitor } from '../../language/visitor'; +import type { FieldNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; -import { type GraphQLSchema } from '../../type/schema'; +import type { GraphQLSchema } from '../../type/schema'; +import type { + GraphQLOutputType, + GraphQLObjectType, + GraphQLInterfaceType, +} from '../../type/definition'; import { - type GraphQLOutputType, - type GraphQLObjectType, - type GraphQLInterfaceType, isObjectType, isInterfaceType, isAbstractType, } from '../../type/definition'; -import { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; /** * Fields on correct type diff --git a/src/validation/rules/FragmentsOnCompositeTypesRule.js b/src/validation/rules/FragmentsOnCompositeTypesRule.js index 4eee719d3a..75f49158c7 100644 --- a/src/validation/rules/FragmentsOnCompositeTypesRule.js +++ b/src/validation/rules/FragmentsOnCompositeTypesRule.js @@ -1,15 +1,13 @@ -// @flow strict - 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'; import { typeFromAST } from '../../utilities/typeFromAST'; -import { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; /** * Fragments on composite type diff --git a/src/validation/rules/KnownArgumentNamesRule.js b/src/validation/rules/KnownArgumentNamesRule.js index d397bf2429..b1fd082463 100644 --- a/src/validation/rules/KnownArgumentNamesRule.js +++ b/src/validation/rules/KnownArgumentNamesRule.js @@ -1,18 +1,16 @@ -// @flow strict - 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, - type SDLValidationContext, +import type { + ValidationContext, + SDLValidationContext, } from '../ValidationContext'; /** @@ -23,6 +21,7 @@ import { */ export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor { return { + // eslint-disable-next-line new-cap ...KnownArgumentNamesOnDirectivesRule(context), Argument(argNode) { const argDef = context.getArgument(); @@ -64,7 +63,7 @@ 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) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const argsNodes = def.arguments ?? []; directiveArgs[def.name.value] = argsNodes.map((arg) => arg.name.value); diff --git a/src/validation/rules/KnownDirectivesRule.js b/src/validation/rules/KnownDirectivesRule.js index 9bece5bfce..8c2e60de88 100644 --- a/src/validation/rules/KnownDirectivesRule.js +++ b/src/validation/rules/KnownDirectivesRule.js @@ -1,23 +1,19 @@ -// @flow strict - 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 ASTVisitor } from '../../language/visitor'; -import { type OperationTypeNode } from '../../language/ast'; -import { - type DirectiveLocationEnum, - DirectiveLocation, -} from '../../language/directiveLocation'; +import { DirectiveLocation } from '../../language/directiveLocation'; import { specifiedDirectives } from '../../type/directives'; -import { - type ValidationContext, - type SDLValidationContext, +import type { + ValidationContext, + SDLValidationContext, } from '../ValidationContext'; /** @@ -71,7 +67,9 @@ export function KnownDirectivesRule( }; } -function getDirectiveLocationForASTPath(ancestors) { +function getDirectiveLocationForASTPath( + ancestors: $ReadOnlyArray>, +): DirectiveLocationEnum | void { const appliedTo = ancestors[ancestors.length - 1]; invariant(!Array.isArray(appliedTo)); @@ -134,6 +132,6 @@ function getDirectiveLocationForOperation( return DirectiveLocation.SUBSCRIPTION; } - // Not reachable. All possible types have been considered. + // 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.js b/src/validation/rules/KnownFragmentNamesRule.js index ad7cd5e67f..0f3412bb45 100644 --- a/src/validation/rules/KnownFragmentNamesRule.js +++ b/src/validation/rules/KnownFragmentNamesRule.js @@ -1,9 +1,8 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type ValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ValidationContext } from '../ValidationContext'; /** * Known fragment names diff --git a/src/validation/rules/KnownTypeNamesRule.d.ts b/src/validation/rules/KnownTypeNamesRule.d.ts index 6c4560e787..b7cd75d4a1 100644 --- a/src/validation/rules/KnownTypeNamesRule.d.ts +++ b/src/validation/rules/KnownTypeNamesRule.d.ts @@ -1,5 +1,5 @@ import { ASTVisitor } from '../../language/visitor'; -import { ValidationContext } from '../ValidationContext'; +import { ValidationContext, SDLValidationContext } from '../ValidationContext'; /** * Known type names @@ -7,4 +7,6 @@ import { ValidationContext } from '../ValidationContext'; * 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): ASTVisitor; +export function KnownTypeNamesRule( + context: ValidationContext | SDLValidationContext, +): ASTVisitor; diff --git a/src/validation/rules/KnownTypeNamesRule.js b/src/validation/rules/KnownTypeNamesRule.js index 80f44c3866..38efd5a603 100644 --- a/src/validation/rules/KnownTypeNamesRule.js +++ b/src/validation/rules/KnownTypeNamesRule.js @@ -1,12 +1,10 @@ -// @flow strict - 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 type { ASTNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; import { isTypeDefinitionNode, isTypeSystemDefinitionNode, @@ -14,10 +12,11 @@ import { } from '../../language/predicates'; import { specifiedScalarTypes } from '../../type/scalars'; +import { introspectionTypes } from '../../type/introspection'; -import { - type ValidationContext, - type SDLValidationContext, +import type { + ValidationContext, + SDLValidationContext, } from '../ValidationContext'; /** @@ -49,13 +48,13 @@ export function KnownTypeNamesRule( if (!existingTypesMap[typeName] && !definedTypes[typeName]) { const definitionNode = ancestors[2] ?? parent; const isSDL = definitionNode != null && isSDLNode(definitionNode); - if (isSDL && isSpecifiedScalarName(typeName)) { + if (isSDL && isStandardTypeName(typeName)) { return; } const suggestedTypes = suggestionList( typeName, - isSDL ? specifiedScalarsNames.concat(typeNames) : typeNames, + isSDL ? standardTypeNames.concat(typeNames) : typeNames, ); context.reportError( new GraphQLError( @@ -68,9 +67,12 @@ export function KnownTypeNamesRule( }; } -const specifiedScalarsNames = specifiedScalarTypes.map((type) => type.name); -function isSpecifiedScalarName(typeName) { - return specifiedScalarsNames.indexOf(typeName) !== -1; +const standardTypeNames = [...specifiedScalarTypes, ...introspectionTypes].map( + (type) => type.name, +); + +function isStandardTypeName(typeName: string): boolean { + return standardTypeNames.indexOf(typeName) !== -1; } function isSDLNode(value: ASTNode | $ReadOnlyArray): boolean { diff --git a/src/validation/rules/LoneAnonymousOperationRule.js b/src/validation/rules/LoneAnonymousOperationRule.js index 3105b69e52..617c80639f 100644 --- a/src/validation/rules/LoneAnonymousOperationRule.js +++ b/src/validation/rules/LoneAnonymousOperationRule.js @@ -1,11 +1,9 @@ -// @flow strict - 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'; +import type { ASTValidationContext } from '../ValidationContext'; /** * Lone anonymous operation diff --git a/src/validation/rules/LoneSchemaDefinition.js b/src/validation/rules/LoneSchemaDefinition.js index d5acb8439a..a38ad06a6d 100644 --- a/src/validation/rules/LoneSchemaDefinition.js +++ b/src/validation/rules/LoneSchemaDefinition.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/LoneSchemaDefinitionRule.js b/src/validation/rules/LoneSchemaDefinitionRule.js index cd0ff8b68d..1c2b02371e 100644 --- a/src/validation/rules/LoneSchemaDefinitionRule.js +++ b/src/validation/rules/LoneSchemaDefinitionRule.js @@ -1,9 +1,7 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; +import type { ASTVisitor } from '../../language/visitor'; -import { type SDLValidationContext } from '../ValidationContext'; +import type { SDLValidationContext } from '../ValidationContext'; /** * Lone Schema definition diff --git a/src/validation/rules/NoFragmentCyclesRule.js b/src/validation/rules/NoFragmentCyclesRule.js index 83f6f481d6..54fba26e43 100644 --- a/src/validation/rules/NoFragmentCyclesRule.js +++ b/src/validation/rules/NoFragmentCyclesRule.js @@ -1,11 +1,9 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type FragmentDefinitionNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; +import type { FragmentDefinitionNode } from '../../language/ast'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTValidationContext } from '../ValidationContext'; export function NoFragmentCyclesRule( context: ASTValidationContext, @@ -31,7 +29,7 @@ export function NoFragmentCyclesRule( // This does a straight-forward DFS to find cycles. // It does not terminate when a cycle was found but continues to explore // the graph to find all possible cycles. - function detectCycleRecursive(fragment: FragmentDefinitionNode) { + function detectCycleRecursive(fragment: FragmentDefinitionNode): void { if (visitedFrags[fragment.name.value]) { return; } diff --git a/src/validation/rules/NoUndefinedVariablesRule.js b/src/validation/rules/NoUndefinedVariablesRule.js index be99da08e0..de1a84807f 100644 --- a/src/validation/rules/NoUndefinedVariablesRule.js +++ b/src/validation/rules/NoUndefinedVariablesRule.js @@ -1,9 +1,8 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type ValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ValidationContext } from '../ValidationContext'; /** * No undefined variables diff --git a/src/validation/rules/NoUnusedFragmentsRule.js b/src/validation/rules/NoUnusedFragmentsRule.js index f9772e48a8..d69bf241cf 100644 --- a/src/validation/rules/NoUnusedFragmentsRule.js +++ b/src/validation/rules/NoUnusedFragmentsRule.js @@ -1,9 +1,8 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ASTValidationContext } from '../ValidationContext'; /** * No unused fragments diff --git a/src/validation/rules/NoUnusedVariablesRule.js b/src/validation/rules/NoUnusedVariablesRule.js index d24164ede9..70bc81c941 100644 --- a/src/validation/rules/NoUnusedVariablesRule.js +++ b/src/validation/rules/NoUnusedVariablesRule.js @@ -1,9 +1,8 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type ValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ValidationContext } from '../ValidationContext'; /** * No unused variables diff --git a/src/validation/rules/OverlappingFieldsCanBeMergedRule.js b/src/validation/rules/OverlappingFieldsCanBeMergedRule.js index a8dd722050..2d79dd098f 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMergedRule.js +++ b/src/validation/rules/OverlappingFieldsCanBeMergedRule.js @@ -1,28 +1,29 @@ -// @flow strict - import find from '../../polyfills/find'; import objectEntries from '../../polyfills/objectEntries'; +import type { ObjMap } from '../../jsutils/ObjMap'; import inspect from '../../jsutils/inspect'; -import { type ObjMap } from '../../jsutils/ObjMap'; import { GraphQLError } from '../../error/GraphQLError'; +import type { ASTVisitor } from '../../language/visitor'; +import type { + SelectionSetNode, + ValueNode, + FieldNode, + ArgumentNode, + FragmentDefinitionNode, +} from '../../language/ast'; import { Kind } from '../../language/kinds'; import { print } from '../../language/printer'; -import { type ASTVisitor } from '../../language/visitor'; -import { - type SelectionSetNode, - type FieldNode, - type ArgumentNode, - type FragmentDefinitionNode, -} from '../../language/ast'; +import type { + GraphQLNamedType, + GraphQLOutputType, + GraphQLCompositeType, + GraphQLField, +} from '../../type/definition'; import { - type GraphQLNamedType, - type GraphQLOutputType, - type GraphQLCompositeType, - type GraphQLField, getNamedType, isNonNullType, isLeafType, @@ -33,7 +34,7 @@ import { import { typeFromAST } from '../../utilities/typeFromAST'; -import { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; function reasonMessage(reason: ConflictReasonMessage): string { if (Array.isArray(reason)) { @@ -571,9 +572,9 @@ function findConflict( ]; } - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // 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) */ + // 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)) { @@ -641,7 +642,7 @@ function sameArguments( }); } -function sameValue(value1, value2) { +function sameValue(value1: ValueNode, value2: ValueNode): boolean { return print(value1) === print(value2); } @@ -796,11 +797,11 @@ function subfieldConflicts( class PairSet { _data: ObjMap>; - constructor(): void { + constructor() { this._data = Object.create(null); } - has(a: string, b: string, areMutuallyExclusive: boolean) { + has(a: string, b: string, areMutuallyExclusive: boolean): boolean { const first = this._data[a]; const result = first && first[b]; if (result === undefined) { @@ -815,17 +816,17 @@ class PairSet { return true; } - add(a: string, b: string, areMutuallyExclusive: boolean) { - _pairSetAdd(this._data, a, b, areMutuallyExclusive); - _pairSetAdd(this._data, b, a, areMutuallyExclusive); + add(a: string, b: string, areMutuallyExclusive: boolean): void { + this._pairSetAdd(a, b, areMutuallyExclusive); + this._pairSetAdd(b, a, areMutuallyExclusive); } -} -function _pairSetAdd(data, a, b, areMutuallyExclusive) { - let map = data[a]; - if (!map) { - map = Object.create(null); - data[a] = map; + _pairSetAdd(a: string, b: string, areMutuallyExclusive: boolean): void { + let map = this._data[a]; + if (!map) { + map = Object.create(null); + this._data[a] = map; + } + map[b] = areMutuallyExclusive; } - map[b] = areMutuallyExclusive; } diff --git a/src/validation/rules/PossibleFragmentSpreadsRule.js b/src/validation/rules/PossibleFragmentSpreadsRule.js index e374d59d86..ba4e9ca5ef 100644 --- a/src/validation/rules/PossibleFragmentSpreadsRule.js +++ b/src/validation/rules/PossibleFragmentSpreadsRule.js @@ -1,17 +1,16 @@ -// @flow strict - import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; +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 { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; /** * Possible fragment spread @@ -64,7 +63,10 @@ export function PossibleFragmentSpreadsRule( }; } -function getFragmentType(context, name) { +function getFragmentType( + context: ValidationContext, + name: string, +): ?GraphQLCompositeType { const frag = context.getFragment(name); if (frag) { const type = typeFromAST(context.getSchema(), frag.typeCondition); diff --git a/src/validation/rules/PossibleTypeExtensions.js b/src/validation/rules/PossibleTypeExtensions.js index 0e80b892aa..7573375e6d 100644 --- a/src/validation/rules/PossibleTypeExtensions.js +++ b/src/validation/rules/PossibleTypeExtensions.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/PossibleTypeExtensionsRule.js b/src/validation/rules/PossibleTypeExtensionsRule.js index 1d0db909e9..2f098191ef 100644 --- a/src/validation/rules/PossibleTypeExtensionsRule.js +++ b/src/validation/rules/PossibleTypeExtensionsRule.js @@ -1,5 +1,3 @@ -// @flow strict - import inspect from '../../jsutils/inspect'; import invariant from '../../jsutils/invariant'; import didYouMean from '../../jsutils/didYouMean'; @@ -7,10 +5,13 @@ 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 { Kind } from '../../language/kinds'; -import { type ASTVisitor } from '../../language/visitor'; import { isTypeDefinitionNode } from '../../language/predicates'; +import type { GraphQLNamedType } from '../../type/definition'; import { isScalarType, isObjectType, @@ -20,7 +21,7 @@ import { isInputObjectType, } from '../../type/definition'; -import { type SDLValidationContext } from '../ValidationContext'; +import type { SDLValidationContext } from '../ValidationContext'; /** * Possible type extension @@ -48,7 +49,7 @@ export function PossibleTypeExtensionsRule( InputObjectTypeExtension: checkExtension, }; - function checkExtension(node) { + function checkExtension(node: TypeExtensionNode): void { const typeName = node.name.value; const defNode = definedTypes[typeName]; const existingType = schema?.getType(typeName); @@ -97,7 +98,7 @@ const defKindToExtKind = { [Kind.INPUT_OBJECT_TYPE_DEFINITION]: Kind.INPUT_OBJECT_TYPE_EXTENSION, }; -function typeToExtKind(type) { +function typeToExtKind(type: GraphQLNamedType): KindEnum { if (isScalarType(type)) { return Kind.SCALAR_TYPE_EXTENSION; } @@ -113,15 +114,16 @@ function typeToExtKind(type) { 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; } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false, 'Unexpected type: ' + inspect((type: empty))); } -function extensionKindToTypeName(kind) { +function extensionKindToTypeName(kind: KindEnum): string { switch (kind) { case Kind.SCALAR_TYPE_EXTENSION: return 'scalar'; @@ -137,6 +139,6 @@ function extensionKindToTypeName(kind) { return 'input object'; } - // Not reachable. All possible types have been considered. + // istanbul ignore next (Not reachable. All possible types have been considered) invariant(false, 'Unexpected kind: ' + inspect(kind)); } diff --git a/src/validation/rules/ProvidedRequiredArgumentsRule.js b/src/validation/rules/ProvidedRequiredArgumentsRule.js index d72974fe25..b9ff7a032b 100644 --- a/src/validation/rules/ProvidedRequiredArgumentsRule.js +++ b/src/validation/rules/ProvidedRequiredArgumentsRule.js @@ -1,20 +1,19 @@ -// @flow strict - import inspect from '../../jsutils/inspect'; import keyMap from '../../jsutils/keyMap'; 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 { specifiedDirectives } from '../../type/directives'; import { isType, isRequiredArgument } from '../../type/definition'; -import { - type ValidationContext, - type SDLValidationContext, +import type { + ValidationContext, + SDLValidationContext, } from '../ValidationContext'; /** @@ -27,6 +26,7 @@ export function ProvidedRequiredArgumentsRule( context: ValidationContext, ): ASTVisitor { return { + // eslint-disable-next-line new-cap ...ProvidedRequiredArgumentsOnDirectivesRule(context), Field: { // Validate on leave to allow for deeper errors to appear first. @@ -36,7 +36,7 @@ export function ProvidedRequiredArgumentsRule( return false; } - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const argNodes = fieldNode.arguments ?? []; const argNodeMap = keyMap(argNodes, (arg) => arg.name.value); for (const argDef of fieldDef.args) { @@ -78,7 +78,7 @@ 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) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const argNodes = def.arguments ?? []; requiredArgsMap[def.name.value] = keyMap( @@ -95,7 +95,7 @@ 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) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const argNodes = directiveNode.arguments ?? []; const argNodeMap = keyMap(argNodes, (arg) => arg.name.value); for (const argName of Object.keys(requiredArgs)) { @@ -119,6 +119,6 @@ export function ProvidedRequiredArgumentsOnDirectivesRule( }; } -function isRequiredArgumentNode(arg) { +function isRequiredArgumentNode(arg: InputValueDefinitionNode): boolean { return arg.type.kind === Kind.NON_NULL_TYPE && arg.defaultValue == null; } diff --git a/src/validation/rules/ScalarLeafsRule.js b/src/validation/rules/ScalarLeafsRule.js index abc43556ab..a0c0c6cc40 100644 --- a/src/validation/rules/ScalarLeafsRule.js +++ b/src/validation/rules/ScalarLeafsRule.js @@ -1,15 +1,13 @@ -// @flow strict - import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; -import { type FieldNode } from '../../language/ast'; -import { type ASTVisitor } from '../../language/visitor'; +import type { FieldNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; import { getNamedType, isLeafType } from '../../type/definition'; -import { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; /** * Scalar leafs diff --git a/src/validation/rules/SingleFieldSubscriptionsRule.js b/src/validation/rules/SingleFieldSubscriptionsRule.js index 7773467321..760fe3c144 100644 --- a/src/validation/rules/SingleFieldSubscriptionsRule.js +++ b/src/validation/rules/SingleFieldSubscriptionsRule.js @@ -1,11 +1,9 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type OperationDefinitionNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; +import type { OperationDefinitionNode } from '../../language/ast'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTValidationContext } from '../ValidationContext'; /** * Subscriptions must only include one field. diff --git a/src/validation/rules/UniqueArgumentNamesRule.js b/src/validation/rules/UniqueArgumentNamesRule.js index 27920705fd..73289efd2f 100644 --- a/src/validation/rules/UniqueArgumentNamesRule.js +++ b/src/validation/rules/UniqueArgumentNamesRule.js @@ -1,9 +1,7 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; +import type { ASTVisitor } from '../../language/visitor'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTValidationContext } from '../ValidationContext'; /** * Unique argument names diff --git a/src/validation/rules/UniqueDirectiveNames.js b/src/validation/rules/UniqueDirectiveNames.js index fbbd6fc579..c197e87cb2 100644 --- a/src/validation/rules/UniqueDirectiveNames.js +++ b/src/validation/rules/UniqueDirectiveNames.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/UniqueDirectiveNamesRule.js b/src/validation/rules/UniqueDirectiveNamesRule.js index bad5ca5fc8..0d87d9deb4 100644 --- a/src/validation/rules/UniqueDirectiveNamesRule.js +++ b/src/validation/rules/UniqueDirectiveNamesRule.js @@ -1,9 +1,7 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; +import type { ASTVisitor } from '../../language/visitor'; -import { type SDLValidationContext } from '../ValidationContext'; +import type { SDLValidationContext } from '../ValidationContext'; /** * Unique directive names diff --git a/src/validation/rules/UniqueDirectivesPerLocationRule.js b/src/validation/rules/UniqueDirectivesPerLocationRule.js index 4f74d0fd42..a21c081790 100644 --- a/src/validation/rules/UniqueDirectivesPerLocationRule.js +++ b/src/validation/rules/UniqueDirectivesPerLocationRule.js @@ -1,9 +1,7 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; import { Kind } from '../../language/kinds'; -import { type ASTVisitor } from '../../language/visitor'; +import type { ASTVisitor } from '../../language/visitor'; import { isTypeDefinitionNode, isTypeExtensionNode, @@ -11,9 +9,9 @@ import { import { specifiedDirectives } from '../../type/directives'; -import { - type SDLValidationContext, - type ValidationContext, +import type { + SDLValidationContext, + ValidationContext, } from '../ValidationContext'; /** diff --git a/src/validation/rules/UniqueEnumValueNames.js b/src/validation/rules/UniqueEnumValueNames.js index bf40bb2c33..96d9b787ca 100644 --- a/src/validation/rules/UniqueEnumValueNames.js +++ b/src/validation/rules/UniqueEnumValueNames.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/UniqueEnumValueNamesRule.js b/src/validation/rules/UniqueEnumValueNamesRule.js index dac1939abd..28ba114248 100644 --- a/src/validation/rules/UniqueEnumValueNamesRule.js +++ b/src/validation/rules/UniqueEnumValueNamesRule.js @@ -1,10 +1,14 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; + +import type { ASTVisitor } from '../../language/visitor'; +import type { + EnumTypeDefinitionNode, + EnumTypeExtensionNode, +} from '../../language/ast'; + import { isEnumType } from '../../type/definition'; -import { type SDLValidationContext } from '../ValidationContext'; +import type { SDLValidationContext } from '../ValidationContext'; /** * Unique enum value names @@ -23,14 +27,16 @@ export function UniqueEnumValueNamesRule( EnumTypeExtension: checkValueUniqueness, }; - function checkValueUniqueness(node) { + function checkValueUniqueness( + node: EnumTypeDefinitionNode | EnumTypeExtensionNode, + ) { const typeName = node.name.value; if (!knownValueNames[typeName]) { knownValueNames[typeName] = Object.create(null); } - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const valueNodes = node.values ?? []; const valueNames = knownValueNames[typeName]; diff --git a/src/validation/rules/UniqueFieldDefinitionNames.js b/src/validation/rules/UniqueFieldDefinitionNames.js index 2efdf02a9a..26ebb066ce 100644 --- a/src/validation/rules/UniqueFieldDefinitionNames.js +++ b/src/validation/rules/UniqueFieldDefinitionNames.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/UniqueFieldDefinitionNamesRule.js b/src/validation/rules/UniqueFieldDefinitionNamesRule.js index 2a75e5b89b..f912a8489f 100644 --- a/src/validation/rules/UniqueFieldDefinitionNamesRule.js +++ b/src/validation/rules/UniqueFieldDefinitionNamesRule.js @@ -1,14 +1,20 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; + +import type { ASTVisitor } from '../../language/visitor'; +import type { + NameNode, + FieldDefinitionNode, + InputValueDefinitionNode, +} from '../../language/ast'; + +import type { GraphQLNamedType } from '../../type/definition'; import { isObjectType, isInterfaceType, isInputObjectType, } from '../../type/definition'; -import { type SDLValidationContext } from '../ValidationContext'; +import type { SDLValidationContext } from '../ValidationContext'; /** * Unique field definition names @@ -31,14 +37,18 @@ export function UniqueFieldDefinitionNamesRule( ObjectTypeExtension: checkFieldUniqueness, }; - function checkFieldUniqueness(node) { + function checkFieldUniqueness(node: { + +name: NameNode, + +fields?: $ReadOnlyArray, + ... + }) { const typeName = node.name.value; if (!knownFieldNames[typeName]) { knownFieldNames[typeName] = Object.create(null); } - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const fieldNodes = node.fields ?? []; const fieldNames = knownFieldNames[typeName]; @@ -68,9 +78,9 @@ export function UniqueFieldDefinitionNamesRule( } } -function hasField(type, fieldName) { +function hasField(type: GraphQLNamedType, fieldName: string): boolean { if (isObjectType(type) || isInterfaceType(type) || isInputObjectType(type)) { - return type.getFields()[fieldName]; + return type.getFields()[fieldName] != null; } return false; } diff --git a/src/validation/rules/UniqueFragmentNamesRule.js b/src/validation/rules/UniqueFragmentNamesRule.js index 3150ab698d..144e0e94d5 100644 --- a/src/validation/rules/UniqueFragmentNamesRule.js +++ b/src/validation/rules/UniqueFragmentNamesRule.js @@ -1,9 +1,8 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ASTValidationContext } from '../ValidationContext'; /** * Unique fragment names diff --git a/src/validation/rules/UniqueInputFieldNamesRule.js b/src/validation/rules/UniqueInputFieldNamesRule.js index 9041bdd6bb..413783e930 100644 --- a/src/validation/rules/UniqueInputFieldNamesRule.js +++ b/src/validation/rules/UniqueInputFieldNamesRule.js @@ -1,9 +1,8 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ASTValidationContext } from '../ValidationContext'; /** * Unique input field names diff --git a/src/validation/rules/UniqueOperationNamesRule.js b/src/validation/rules/UniqueOperationNamesRule.js index 3a0e40dec8..6051e91978 100644 --- a/src/validation/rules/UniqueOperationNamesRule.js +++ b/src/validation/rules/UniqueOperationNamesRule.js @@ -1,9 +1,8 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; + +import type { ASTValidationContext } from '../ValidationContext'; /** * Unique operation names diff --git a/src/validation/rules/UniqueOperationTypes.js b/src/validation/rules/UniqueOperationTypes.js index bb3d541cab..423932dba1 100644 --- a/src/validation/rules/UniqueOperationTypes.js +++ b/src/validation/rules/UniqueOperationTypes.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/UniqueOperationTypesRule.js b/src/validation/rules/UniqueOperationTypesRule.js index 2cd40fc532..5b0d2b32cf 100644 --- a/src/validation/rules/UniqueOperationTypesRule.js +++ b/src/validation/rules/UniqueOperationTypesRule.js @@ -1,9 +1,12 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type SDLValidationContext } from '../ValidationContext'; +import type { ASTVisitor } from '../../language/visitor'; +import type { + SchemaDefinitionNode, + SchemaExtensionNode, +} from '../../language/ast'; + +import type { SDLValidationContext } from '../ValidationContext'; /** * Unique operation types @@ -28,8 +31,10 @@ export function UniqueOperationTypesRule( SchemaExtension: checkOperationTypes, }; - function checkOperationTypes(node) { - /* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */ + function checkOperationTypes( + node: SchemaDefinitionNode | SchemaExtensionNode, + ) { + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const operationTypesNodes = node.operationTypes ?? []; for (const operationType of operationTypesNodes) { diff --git a/src/validation/rules/UniqueTypeNames.js b/src/validation/rules/UniqueTypeNames.js index ea708b23ff..1740eef841 100644 --- a/src/validation/rules/UniqueTypeNames.js +++ b/src/validation/rules/UniqueTypeNames.js @@ -1,5 +1,3 @@ -// @flow strict - /** * @deprecated and will be removed in v16 * Please use either: diff --git a/src/validation/rules/UniqueTypeNamesRule.js b/src/validation/rules/UniqueTypeNamesRule.js index a20cde0673..fed280c446 100644 --- a/src/validation/rules/UniqueTypeNamesRule.js +++ b/src/validation/rules/UniqueTypeNamesRule.js @@ -1,11 +1,9 @@ -// @flow strict - 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 { TypeDefinitionNode } from '../../language/ast'; -import { type SDLValidationContext } from '../ValidationContext'; +import type { SDLValidationContext } from '../ValidationContext'; /** * Unique type names diff --git a/src/validation/rules/UniqueVariableNamesRule.js b/src/validation/rules/UniqueVariableNamesRule.js index 26a4dad490..6035cdfa3e 100644 --- a/src/validation/rules/UniqueVariableNamesRule.js +++ b/src/validation/rules/UniqueVariableNamesRule.js @@ -1,11 +1,9 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; -import { type ASTVisitor } from '../../language/visitor'; -import { type VariableDefinitionNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; +import type { VariableDefinitionNode } from '../../language/ast'; -import { type ASTValidationContext } from '../ValidationContext'; +import type { ASTValidationContext } from '../ValidationContext'; /** * Unique variable names diff --git a/src/validation/rules/ValuesOfCorrectTypeRule.js b/src/validation/rules/ValuesOfCorrectTypeRule.js index d2bffe3bb6..d97647a000 100644 --- a/src/validation/rules/ValuesOfCorrectTypeRule.js +++ b/src/validation/rules/ValuesOfCorrectTypeRule.js @@ -1,5 +1,3 @@ -// @flow strict - import objectValues from '../../polyfills/objectValues'; import keyMap from '../../jsutils/keyMap'; @@ -9,9 +7,9 @@ import suggestionList from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; +import type { ValueNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; import { print } from '../../language/printer'; -import { type ValueNode } from '../../language/ast'; -import { type ASTVisitor } from '../../language/visitor'; import { isLeafType, @@ -23,7 +21,7 @@ import { getNamedType, } from '../../type/definition'; -import { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; /** * Value literals of correct type diff --git a/src/validation/rules/VariablesAreInputTypesRule.js b/src/validation/rules/VariablesAreInputTypesRule.js index 05d7d20c8d..f16cb7461d 100644 --- a/src/validation/rules/VariablesAreInputTypesRule.js +++ b/src/validation/rules/VariablesAreInputTypesRule.js @@ -1,16 +1,14 @@ -// @flow strict - import { GraphQLError } from '../../error/GraphQLError'; import { print } from '../../language/printer'; -import { type ASTVisitor } from '../../language/visitor'; -import { type VariableDefinitionNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; +import type { VariableDefinitionNode } from '../../language/ast'; import { isInputType } from '../../type/definition'; import { typeFromAST } from '../../utilities/typeFromAST'; -import { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; /** * Variables are input types diff --git a/src/validation/rules/VariablesInAllowedPositionRule.js b/src/validation/rules/VariablesInAllowedPositionRule.js index bba589af66..8d0cbbf26c 100644 --- a/src/validation/rules/VariablesInAllowedPositionRule.js +++ b/src/validation/rules/VariablesInAllowedPositionRule.js @@ -1,20 +1,19 @@ -// @flow strict - import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; import { Kind } from '../../language/kinds'; -import { type ValueNode } from '../../language/ast'; -import { type ASTVisitor } from '../../language/visitor'; +import type { ValueNode } from '../../language/ast'; +import type { ASTVisitor } from '../../language/visitor'; -import { type GraphQLSchema } from '../../type/schema'; -import { type GraphQLType, isNonNullType } from '../../type/definition'; +import type { GraphQLSchema } from '../../type/schema'; +import type { GraphQLType } from '../../type/definition'; +import { isNonNullType } from '../../type/definition'; import { typeFromAST } from '../../utilities/typeFromAST'; import { isTypeSubTypeOf } from '../../utilities/typeComparators'; -import { type ValidationContext } from '../ValidationContext'; +import type { ValidationContext } from '../ValidationContext'; /** * Variables passed to field arguments conform to type diff --git a/src/validation/rules/custom/NoDeprecatedCustomRule.d.ts b/src/validation/rules/custom/NoDeprecatedCustomRule.d.ts new file mode 100644 index 0000000000..d376cf8572 --- /dev/null +++ b/src/validation/rules/custom/NoDeprecatedCustomRule.d.ts @@ -0,0 +1,14 @@ +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.js new file mode 100644 index 0000000000..7fe6598bc4 --- /dev/null +++ b/src/validation/rules/custom/NoDeprecatedCustomRule.js @@ -0,0 +1,93 @@ +import invariant from '../../../jsutils/invariant'; + +import { GraphQLError } from '../../../error/GraphQLError'; + +import type { ASTVisitor } from '../../../language/visitor'; + +import { getNamedType, isInputObjectType } from '../../../type/definition'; + +import type { 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 { + return { + Field(node) { + const fieldDef = context.getFieldDef(); + const deprecationReason = fieldDef?.deprecationReason; + if (fieldDef && deprecationReason != null) { + const parentType = context.getParentType(); + invariant(parentType != null); + context.reportError( + new GraphQLError( + `The field ${parentType.name}.${fieldDef.name} is deprecated. ${deprecationReason}`, + node, + ), + ); + } + }, + Argument(node) { + const argDef = context.getArgument(); + const deprecationReason = argDef?.deprecationReason; + if (argDef && deprecationReason != null) { + const directiveDef = context.getDirective(); + if (directiveDef != null) { + context.reportError( + new GraphQLError( + `Directive "@${directiveDef.name}" argument "${argDef.name}" is deprecated. ${deprecationReason}`, + node, + ), + ); + } else { + const parentType = context.getParentType(); + const fieldDef = context.getFieldDef(); + invariant(parentType != null && fieldDef != null); + context.reportError( + new GraphQLError( + `Field "${parentType.name}.${fieldDef.name}" argument "${argDef.name}" is deprecated. ${deprecationReason}`, + node, + ), + ); + } + } + }, + ObjectField(node) { + 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, + ), + ); + } + } + }, + EnumValue(node) { + const enumValueDef = context.getEnumValue(); + const deprecationReason = enumValueDef?.deprecationReason; + if (enumValueDef && deprecationReason != null) { + const enumTypeDef = getNamedType(context.getInputType()); + invariant(enumTypeDef != null); + context.reportError( + new GraphQLError( + `The enum value "${enumTypeDef.name}.${enumValueDef.name}" is deprecated. ${deprecationReason}`, + node, + ), + ); + } + }, + }; +} diff --git a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.d.ts b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.d.ts new file mode 100644 index 0000000000..3677fa1c73 --- /dev/null +++ b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.d.ts @@ -0,0 +1,16 @@ +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.js new file mode 100644 index 0000000000..7a1c1f2ab9 --- /dev/null +++ b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.js @@ -0,0 +1,37 @@ +import { GraphQLError } from '../../../error/GraphQLError'; + +import type { FieldNode } from '../../../language/ast'; +import type { ASTVisitor } from '../../../language/visitor'; + +import { getNamedType } from '../../../type/definition'; +import { isIntrospectionType } from '../../../type/introspection'; + +import type { 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 { + return { + Field(node: FieldNode) { + const type = getNamedType(context.getType()); + if (type && isIntrospectionType(type)) { + context.reportError( + new GraphQLError( + `GraphQL introspection has been disabled, but the requested query contained the field "${node.name.value}".`, + node, + ), + ); + } + }, + }; +} diff --git a/src/validation/specifiedRules.js b/src/validation/specifiedRules.js index 54bbf84ae3..72f25d9490 100644 --- a/src/validation/specifiedRules.js +++ b/src/validation/specifiedRules.js @@ -1,5 +1,3 @@ -// @flow strict - // Spec Section: "Executable Definitions" import { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule'; diff --git a/src/validation/validate.d.ts b/src/validation/validate.d.ts index 9230c52814..5e93a8cff0 100644 --- a/src/validation/validate.d.ts +++ b/src/validation/validate.d.ts @@ -1,4 +1,4 @@ -import Maybe from '../tsutils/Maybe'; +import { Maybe } from '../jsutils/Maybe'; import { GraphQLError } from '../error/GraphQLError'; @@ -49,7 +49,7 @@ export function validateSDL( * * @internal */ -export function assertValidSDL(documentAST: DocumentNode): undefined; +export function assertValidSDL(documentAST: DocumentNode): void; /** * Utility function which asserts a SDL document is valid by throwing an error @@ -60,4 +60,4 @@ export function assertValidSDL(documentAST: DocumentNode): undefined; export function assertValidSDLExtension( documentAST: DocumentNode, schema: GraphQLSchema, -): undefined; +): void; diff --git a/src/validation/validate.js b/src/validation/validate.js index 2e5df6bc1c..8cb11a5bcd 100644 --- a/src/validation/validate.js +++ b/src/validation/validate.js @@ -1,24 +1,18 @@ -// @flow strict - import devAssert from '../jsutils/devAssert'; import { GraphQLError } from '../error/GraphQLError'; -import { type DocumentNode } from '../language/ast'; +import type { DocumentNode } from '../language/ast'; import { visit, visitInParallel } from '../language/visitor'; -import { type GraphQLSchema } from '../type/schema'; +import type { GraphQLSchema } from '../type/schema'; 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, - type ValidationRule, - SDLValidationContext, - ValidationContext, -} from './ValidationContext'; +import { SDLValidationContext, ValidationContext } from './ValidationContext'; /** * Implements the "Validation" section of the spec. diff --git a/src/version.js b/src/version.js index df61f772fc..27b130e655 100644 --- a/src/version.js +++ b/src/version.js @@ -1,21 +1,19 @@ -// @flow strict - /** * Note: This file is autogenerated using "resources/gen-version.js" script and - * automatically updated by "yarn version" command. + * automatically updated by "npm version" command. */ /** * A string containing the version of the GraphQL.js library */ -export const version = '15.0.0'; +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: 0, + minor: 4, patch: 0, preReleaseTag: null, }); diff --git a/src/tsconfig.json b/tsconfig.json similarity index 86% rename from src/tsconfig.json rename to tsconfig.json index 422f48c77c..d158e41db9 100644 --- a/src/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "exclude": ["integrationTests/ts/**/*"], "compilerOptions": { "module": "commonjs", "lib": ["es6", "esnext.asynciterable"], @@ -6,8 +7,6 @@ "noImplicitThis": true, "strictNullChecks": true, "strictFunctionTypes": true, - "baseUrl": "../", - "typeRoots": ["../"], "types": [], "noEmit": true, "forceConsistentCasingInFileNames": true diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 94ff6b19b7..0000000000 --- a/yarn.lock +++ /dev/null @@ -1,3950 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" - integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g== - dependencies: - browserslist "^4.9.1" - invariant "^2.2.4" - semver "^5.5.0" - -"@babel/core@7.9.0", "@babel/core@^7.7.5": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce" - integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA== - dependencies: - "@babel/types" "^7.9.0" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" - integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" - integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-compilation-targets@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" - integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== - dependencies: - "@babel/compat-data" "^7.8.6" - browserslist "^4.9.1" - invariant "^2.2.4" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" - integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - regexpu-core "^4.7.0" - -"@babel/helper-define-map@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" - integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/types" "^7.8.3" - lodash "^4.17.13" - -"@babel/helper-explode-assignable-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" - integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== - dependencies: - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" - integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-hoist-variables@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" - integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-member-expression-to-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" - integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-imports@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" - -"@babel/helper-optimise-call-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" - integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" - integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== - -"@babel/helper-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" - integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== - dependencies: - lodash "^4.17.13" - -"@babel/helper-remap-async-to-generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" - integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-wrap-function" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" - integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/helper-simple-access@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" - integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== - dependencies: - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-validator-identifier@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" - integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== - -"@babel/helper-wrap-function@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" - integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helpers@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" - integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== - dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.7.0", "@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" - integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== - -"@babel/plugin-proposal-async-generator-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" - integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-remap-async-to-generator" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - -"@babel/plugin-proposal-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" - integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - -"@babel/plugin-proposal-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" - integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" - integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - -"@babel/plugin-proposal-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" - integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - -"@babel/plugin-proposal-object-rest-spread@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f" - integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - -"@babel/plugin-proposal-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" - integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - -"@babel/plugin-proposal-optional-chaining@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" - integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - -"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" - integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.8" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-async-generators@^7.8.0": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-dynamic-import@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-flow@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz#f2c883bd61a6316f2c89380ae5122f923ba4527f" - integrity sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-json-strings@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" - integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-object-rest-spread@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" - integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-arrow-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" - integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-async-to-generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" - integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-remap-async-to-generator" "^7.8.3" - -"@babel/plugin-transform-block-scoped-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" - integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-block-scoping@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" - integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - lodash "^4.17.13" - -"@babel/plugin-transform-classes@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d" - integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-define-map" "^7.8.3" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-split-export-declaration" "^7.8.3" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" - integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-destructuring@^7.8.3": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b" - integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" - integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-duplicate-keys@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" - integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-exponentiation-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" - integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-flow-strip-types@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz#8a3538aa40434e000b8f44a3c5c9ac7229bd2392" - integrity sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-flow" "^7.8.3" - -"@babel/plugin-transform-for-of@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" - integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" - integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" - integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-member-expression-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" - integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-modules-amd@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" - integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-commonjs@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" - integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-simple-access" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-systemjs@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" - integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== - dependencies: - "@babel/helper-hoist-variables" "^7.8.3" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-umd@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" - integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" - integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - -"@babel/plugin-transform-new-target@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" - integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-object-super@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" - integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" - -"@babel/plugin-transform-parameters@^7.8.7": - version "7.9.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz#3028d0cc20ddc733166c6e9c8534559cee09f54a" - integrity sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-property-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" - integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-regenerator@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" - integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" - integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-shorthand-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" - integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" - integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-sticky-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" - integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - -"@babel/plugin-transform-template-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" - integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-typeof-symbol@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" - integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-unicode-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" - integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/preset-env@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8" - integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== - dependencies: - "@babel/compat-data" "^7.9.0" - "@babel/helper-compilation-targets" "^7.8.7" - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-proposal-async-generator-functions" "^7.8.3" - "@babel/plugin-proposal-dynamic-import" "^7.8.3" - "@babel/plugin-proposal-json-strings" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-numeric-separator" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.9.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-chaining" "^7.9.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.8.0" - "@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.8.3" - "@babel/plugin-transform-arrow-functions" "^7.8.3" - "@babel/plugin-transform-async-to-generator" "^7.8.3" - "@babel/plugin-transform-block-scoped-functions" "^7.8.3" - "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.9.0" - "@babel/plugin-transform-computed-properties" "^7.8.3" - "@babel/plugin-transform-destructuring" "^7.8.3" - "@babel/plugin-transform-dotall-regex" "^7.8.3" - "@babel/plugin-transform-duplicate-keys" "^7.8.3" - "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.9.0" - "@babel/plugin-transform-function-name" "^7.8.3" - "@babel/plugin-transform-literals" "^7.8.3" - "@babel/plugin-transform-member-expression-literals" "^7.8.3" - "@babel/plugin-transform-modules-amd" "^7.9.0" - "@babel/plugin-transform-modules-commonjs" "^7.9.0" - "@babel/plugin-transform-modules-systemjs" "^7.9.0" - "@babel/plugin-transform-modules-umd" "^7.9.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" - "@babel/plugin-transform-new-target" "^7.8.3" - "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.8.7" - "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.7" - "@babel/plugin-transform-reserved-words" "^7.8.3" - "@babel/plugin-transform-shorthand-properties" "^7.8.3" - "@babel/plugin-transform-spread" "^7.8.3" - "@babel/plugin-transform-sticky-regex" "^7.8.3" - "@babel/plugin-transform-template-literals" "^7.8.3" - "@babel/plugin-transform-typeof-symbol" "^7.8.4" - "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.9.0" - browserslist "^4.9.1" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/preset-modules@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" - integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/register@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.9.0.tgz#02464ede57548bddbb5e9f705d263b7c3f43d48b" - integrity sha512-Tv8Zyi2J2VRR8g7pC5gTeIN8Ihultbmk0ocyNz8H2nEZbmhp1N6q0A1UGsQbDvGP/sNinQKUHf3SqXwqjtFv4Q== - dependencies: - find-cache-dir "^2.0.0" - lodash "^4.17.13" - make-dir "^2.1.0" - pirates "^4.0.0" - source-map-support "^0.5.16" - -"@babel/runtime@^7.8.4": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" - integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/traverse@^7.7.0", "@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" - integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" - integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" - integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== - -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - -"@types/json-schema@^7.0.3": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" - integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== - -"@types/parsimmon@^1.3.0": - version "1.10.1" - resolved "https://registry.yarnpkg.com/@types/parsimmon/-/parsimmon-1.10.1.tgz#d46015ad91128fce06a1a688ab39a2516507f740" - integrity sha512-MoF2IC9oGSgArJwlxdst4XsvWuoYfNUWtBw0kpnCi6K05kV+Ecl7siEeJ40tgCbI9uqEMGQL/NlPMRv6KVkY5Q== - -"@typescript-eslint/eslint-plugin@2.26.0": - version "2.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.26.0.tgz#04c96560c8981421e5a9caad8394192363cc423f" - integrity sha512-4yUnLv40bzfzsXcTAtZyTjbiGUXMrcIJcIMioI22tSOyAxpdXiZ4r7YQUU8Jj6XXrLz9d5aMHPQf5JFR7h27Nw== - dependencies: - "@typescript-eslint/experimental-utils" "2.26.0" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@2.26.0": - version "2.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.26.0.tgz#063390c404d9980767d76274df386c0aa675d91d" - integrity sha512-RELVoH5EYd+JlGprEyojUv9HeKcZqF7nZUGSblyAw1FwOGNnmQIU8kxJ69fttQvEwCsX5D6ECJT8GTozxrDKVQ== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.26.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@2.26.0": - version "2.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.26.0.tgz#385463615818b33acb72a25b39c03579df93d76f" - integrity sha512-+Xj5fucDtdKEVGSh9353wcnseMRkPpEAOY96EEenN7kJVrLqy/EVwtIh3mxcUz8lsFXW1mT5nN5vvEam/a5HiQ== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.26.0" - "@typescript-eslint/typescript-estree" "2.26.0" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/typescript-estree@2.26.0": - version "2.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.26.0.tgz#d8132cf1ee8a72234f996519a47d8a9118b57d56" - integrity sha512-3x4SyZCLB4zsKsjuhxDLeVJN6W29VwBnYpCsZ7vIdPel9ZqLfIZJgJXO47MNUkurGpQuIBALdPQKtsSnWpE1Yg== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^6.3.0" - tsutils "^3.17.1" - -acorn-jsx@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" - integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== - -acorn@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" - integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== - -aggregate-error@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" - integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv@^6.10.0, ajv@^6.10.2: - version "6.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" - integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-colors@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" - integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== - -ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== - dependencies: - type-fest "^0.11.0" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" - -anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -append-transform@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" - integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg== - dependencies: - default-require-extensions "^3.0.0" - -archy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -array-includes@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" - integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0" - is-string "^1.0.5" - -array.prototype.flat@^1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" - integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -babel-code-frame@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-eslint@10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== - 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" - -babel-plugin-dynamic-import-node@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" - integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== - dependencies: - object.assign "^4.1.0" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -binary-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" - integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -browserslist@^4.8.3, browserslist@^4.9.1: - version "4.11.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.1.tgz#92f855ee88d6e050e7e7311d987992014f1a1f1b" - integrity sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g== - dependencies: - caniuse-lite "^1.0.30001038" - electron-to-chromium "^1.3.390" - node-releases "^1.1.53" - pkg-up "^2.0.0" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - -caching-transform@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" - integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA== - dependencies: - hasha "^5.0.0" - make-dir "^3.0.0" - package-hash "^4.0.0" - write-file-atomic "^3.0.0" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -caniuse-lite@^1.0.30001038: - version "1.0.30001038" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz#44da3cbca2ab6cb6aa83d1be5d324e17f141caff" - integrity sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ== - -chai@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" - integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== - 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" - type-detect "^4.0.5" - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= - -chokidar@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" - integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.2.0" - optionalDependencies: - fsevents "~2.1.1" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -command-exists@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.8.tgz#715acefdd1223b9c9b37110a149c6392c2852291" - integrity sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw== - -commander@^2.12.1, commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -comment-json@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-1.1.3.tgz#6986c3330fee0c4c9e00c2398cd61afa5d8f239e" - integrity sha1-aYbDMw/uDEyeAMI5jNYa+l2PI54= - dependencies: - json-parser "^1.0.0" - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -configstore@^5.0.0, configstore@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" - integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== - dependencies: - dot-prop "^5.2.0" - graceful-fs "^4.1.2" - make-dir "^3.0.0" - unique-string "^2.0.0" - write-file-atomic "^3.0.0" - xdg-basedir "^4.0.0" - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - -convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - -core-js-compat@^3.6.2: - version "3.6.4" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" - integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== - dependencies: - browserslist "^4.8.3" - semver "7.0.0" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" - integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - -cspell-dict-bash@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cspell-dict-bash/-/cspell-dict-bash-1.0.3.tgz#e3cf0e2dbe56f18c68a16c3eb8037d418e88c3cd" - integrity sha512-pEGuoZXhgqhpmmvdEoNY/XYDrypI37y0Z09VgKTHEblzTHo++vLyd4Z8r1SY3kJ2eQejduz4IL7ZGXqgtEp2vw== - dependencies: - configstore "^5.0.0" - -cspell-dict-companies@^1.0.20: - version "1.0.21" - resolved "https://registry.yarnpkg.com/cspell-dict-companies/-/cspell-dict-companies-1.0.21.tgz#0544ce7ed29061201d2fca9ffe6fb11bf09ec709" - integrity sha512-vHW6pA0cLIT1qUfT6c+xV1IORrmSKuraHPJ7dwdRhWwuc6Ltc7QJWloapufxWgsYUCLllmFcv6E7kzzmue66gw== - dependencies: - configstore "^5.0.0" - -cspell-dict-cpp@^1.1.26: - version "1.1.26" - resolved "https://registry.yarnpkg.com/cspell-dict-cpp/-/cspell-dict-cpp-1.1.26.tgz#67e3f8d26ec2c49d305b086013935f0b0fade2e0" - integrity sha512-ywY7X6UzC5BC7fQhyRAwZHurl52GjwnY6D2wG57JJ/bcT5IsJOWpLAjHORtUH2AcCp6BSAKR6wxl6/bqSuKHJw== - dependencies: - configstore "^5.0.0" - -cspell-dict-django@^1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/cspell-dict-django/-/cspell-dict-django-1.0.15.tgz#a0faec617cab280bd9ef942d1b2a6a5634e5c143" - integrity sha512-heppo6ZEGgv+cVPDLr24miG8xIn3E5SEGFBGHyNLyGqt8sHzeG3eNKhjKOJCC0hG/fq0ZECbE5q4691LvH24/Q== - dependencies: - configstore "^5.0.0" - -cspell-dict-dotnet@^1.0.14: - version "1.0.14" - resolved "https://registry.yarnpkg.com/cspell-dict-dotnet/-/cspell-dict-dotnet-1.0.14.tgz#780c3143d340e3211be27df7cfd2d9d1f82b24c5" - integrity sha512-gTuh94tNAVMS4XmVCK2AsFgKp2mXBk2b8+f2GLCw2K8HY6QUHlvOJg051JJrZABRW/lAoquKZuqssSo9B1mgng== - dependencies: - configstore "^5.0.0" - -cspell-dict-elixir@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/cspell-dict-elixir/-/cspell-dict-elixir-1.0.13.tgz#f3d08b27d2ee2a25fcae5050820d5680028e95d5" - integrity sha512-KWDO4NeV3QuMlZxSWpN0sPiFN4GE5AzlDi75eSKRvq/f1+pxgxgXQ5zLNPnDbr2EOSJBV34paZwI+7PvCiTTgA== - dependencies: - configstore "^5.0.0" - -cspell-dict-en-gb@^1.1.16: - version "1.1.16" - resolved "https://registry.yarnpkg.com/cspell-dict-en-gb/-/cspell-dict-en-gb-1.1.16.tgz#75155e43c21e972ac2f60117b69fd53b5701335f" - integrity sha512-PBzHF40fVj+6Adm3dV3/uhkE2Ptu8W+WJ28socBDDpEfedFMwnC0rpxvAgmKJlLc0OYsn07/yzRnt9srisNrLg== - dependencies: - configstore "^5.0.0" - -cspell-dict-en_us@^1.2.25: - version "1.2.25" - resolved "https://registry.yarnpkg.com/cspell-dict-en_us/-/cspell-dict-en_us-1.2.25.tgz#68803f4e12ba928b2d13e009e9a425458c8f33f9" - integrity sha512-owr04YQAO86wMR0nSup8d7Ogkm23vIOoQsPtIMFou1OA2XLUu13Xhla/Cs+qFzopakpcblvRuMSel0RomkAo7g== - dependencies: - configstore "^5.0.0" - -cspell-dict-fonts@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/cspell-dict-fonts/-/cspell-dict-fonts-1.0.5.tgz#df96979e07d68cd186fe20eae0113e939d880c4f" - integrity sha512-R9A/MVDzqEQbwXaZhmNJ7bSzzkH5YSJ5UDr3wDRk7FXzNNcuJ4J9WRbkDjCDnoVfg0kCx0FeEp0fme+PbLTeng== - dependencies: - configstore "^5.0.0" - -cspell-dict-fullstack@^1.0.22: - version "1.0.22" - resolved "https://registry.yarnpkg.com/cspell-dict-fullstack/-/cspell-dict-fullstack-1.0.22.tgz#54122342ff408082f904c6c20e3facb36df0762c" - integrity sha512-k8Op1ltkgKnMTTo/kgkywE0htwi+3EtYrPPWk+mD9o3IFgC6yLKA89Tkrd0kEEPR3qJvC4gQJmGJns6Y25v0Zg== - dependencies: - configstore "^5.0.0" - -cspell-dict-golang@^1.1.14: - version "1.1.14" - resolved "https://registry.yarnpkg.com/cspell-dict-golang/-/cspell-dict-golang-1.1.14.tgz#5567d823a3e58b8f4c783bea185e95580008d47e" - integrity sha512-V9TQQjoTgdLTpLNczEjoF+BO+CkdmuZlD6J71SCT8sczSP0FLz4QkL1MpqiL0lhdnbtASsjs+oCF53Y+dWdh9g== - dependencies: - configstore "^5.0.0" - -cspell-dict-haskell@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cspell-dict-haskell/-/cspell-dict-haskell-1.0.4.tgz#98a3a00fb72d39f3b94aa019fac7ed86ab73dbd8" - integrity sha512-Wy5EE446icPbsi8bLqSCOtxS5Z6QDLGNBvz6Nh+yvuLf7Nb8mU6NQmfSYH/yMfJoVGa5bpcmv8pQtJV4I2E5Tg== - dependencies: - configstore "^5.0.0" - -cspell-dict-html-symbol-entities@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/cspell-dict-html-symbol-entities/-/cspell-dict-html-symbol-entities-1.0.13.tgz#41b770fa08f82b20f9e3c7f234a320bbb1dee851" - integrity sha512-u8BARt4r5rdUee7Yw6ejsD69WLib9l+pyBr4UUIZovhCUccddm2LkS9GDJUqWtCf/frZpoTnmpuW/NPWVVG6pQ== - dependencies: - configstore "^5.0.0" - -cspell-dict-java@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/cspell-dict-java/-/cspell-dict-java-1.0.12.tgz#d0220153984a0ccf6bbd69617f324ab11ce4a3fe" - integrity sha512-9pg5IrCEZGlWLgv8qGjxzzca19egfBYrbnuiWhJNLbBGBOTWrwYjFqbLQtMJReXUtWikWLY0KCzRZlCGusr7bw== - dependencies: - configstore "^5.0.0" - -cspell-dict-latex@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/cspell-dict-latex/-/cspell-dict-latex-1.0.13.tgz#cdbbc2ebda7b82d44a3574d53b6f5b9a6d0644bb" - integrity sha512-UZqGJQ82mkzseqdF7kWXIrA07VD91W7rWx16DCThDBMohOsFdvCymUUgr0pM90FuqmldSiD+Gi1FayDSyPdNtQ== - dependencies: - configstore "^5.0.0" - -cspell-dict-lorem-ipsum@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/cspell-dict-lorem-ipsum/-/cspell-dict-lorem-ipsum-1.0.10.tgz#3828f43b4df35b258d5d31e4e539c2f6d3f3ce14" - integrity sha512-UlboQ3xH+D3l+hemLO4J5yz8EM60SH91f1dJIy2s94AeePZXtwYh1hTFM5dEsXI2CAQkfTu3ZdPWflLsInPfrA== - dependencies: - configstore "^5.0.0" - -cspell-dict-php@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/cspell-dict-php/-/cspell-dict-php-1.0.13.tgz#83cdab21e52d036303b321bf9bca27a9820661a6" - integrity sha512-RP5XST+hWEqWxlLISS3sXxsQa2YXOWx8X5LcxQHvEGdb1hMNypXxw9V53th7S+hfUTPKJrbUIzckYZp4j8TS4A== - dependencies: - configstore "^5.0.0" - -cspell-dict-powershell@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cspell-dict-powershell/-/cspell-dict-powershell-1.0.6.tgz#2cd32028fb2c7894f4eb7ff202eeec02a8138825" - integrity sha512-rwxt/fG3Nr7tQaV7e38ilz8qWfXrf5Ie+MQC6Mw/ddjT4wLOkGvruUqtJA/USoDE9PFG12KoarFsWlVXv/nwPA== - dependencies: - configstore "^5.0.0" - -cspell-dict-python@^1.0.20: - version "1.0.20" - resolved "https://registry.yarnpkg.com/cspell-dict-python/-/cspell-dict-python-1.0.20.tgz#39509b4cbaf5cbe9b5ceab9440eeeb42c04f6323" - integrity sha512-BiV8LnH9YNxvkUbVwTyDpZhOuRjPr8cE+nxpuPDbCHmVJmlLsDlg8MXTcJH8I+OFjoz6YdBX6yqK1bi55Aioow== - dependencies: - configstore "^5.0.0" - -cspell-dict-ruby@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cspell-dict-ruby/-/cspell-dict-ruby-1.0.3.tgz#bbda30306af9c9274b8848005d9f73f1d3513651" - integrity sha512-uFxUyGj9SRASfnd75lcpkoNvMYHNWmqkFmS9ZruL61M1RmFx9eekuEY74nK11qsb/E4o6yPtGAQH4SrotF9SwQ== - dependencies: - configstore "^5.0.0" - -cspell-dict-rust@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/cspell-dict-rust/-/cspell-dict-rust-1.0.12.tgz#323eedd0137d8019df08f02d9c1956d9778d0baa" - integrity sha512-bMt70/aQL2OcadZRtWfPIF/mHWX9JNOGq92UUU2ka+9C3OPBP/TuyYiHhUWt67y/CoIyEQ7/5uAtjX8paLf14w== - dependencies: - configstore "^5.0.0" - -cspell-dict-scala@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/cspell-dict-scala/-/cspell-dict-scala-1.0.11.tgz#42533b2c850fe6eb64946708fd19e66824b842a7" - integrity sha512-bmAQjapvcceJaiwGTkBd9n2L9GaqpmFDKe5S19WQDsWqjFiDwQ+r47td3TU7yWjOLPqp72h9X/XGzDJFvQEPcg== - dependencies: - configstore "^5.0.0" - -cspell-dict-software-terms@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/cspell-dict-software-terms/-/cspell-dict-software-terms-1.0.7.tgz#74f33a36b470c7344ab8bd0fb1bc4f82dcbf27c8" - integrity sha512-Fh8NmDqY+GZRrJJuFUNoIDbR9WoP9mte+nVVGK5u8vurNInOG/MgRL0O/dhDfTmrMlSyAMhlUWm+852sXietEA== - dependencies: - configstore "^5.0.0" - -cspell-dict-typescript@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cspell-dict-typescript/-/cspell-dict-typescript-1.0.4.tgz#95ca26adf15c5e31cda2506e03ce7b7c18e9fbb0" - integrity sha512-cniGSmTohYriEgGJ0PgcQP2GCGP+PH/0WZ2N7BTTemQr/mHTU6bKWy8DVK63YEtYPEmhZv+G2xPBgBD41QQypQ== - dependencies: - configstore "^5.0.0" - -cspell-glob@^0.1.17: - version "0.1.17" - resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-0.1.17.tgz#e8dad6eedc23bc3e98175f2077df25e7e3212a8a" - integrity sha512-gAiKakWJbHay6cobcJnX1+XhNCFYqR7CJM5GPiEpRZ5RFXYR46fYbkVwTdg3sqbFLErJtghQj/0s5Xa0q9NJpQ== - dependencies: - micromatch "^4.0.2" - -cspell-io@^4.0.20: - version "4.0.20" - resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-4.0.20.tgz#4aecc054852c712e96e075eb270dbbbc4482fca1" - integrity sha512-fomz1P308XgyyxaOEKdNbh82Ac4AKaz26p4JszV7YkJrGDsXMoByTQjVqdDloNN8FchogSEpLPeQoIg648exBA== - dependencies: - iconv-lite "^0.4.24" - iterable-to-stream "^1.0.1" - -cspell-lib@^4.1.21: - version "4.1.21" - resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-4.1.21.tgz#7321652e5bb8d5a1b0a1372d42d125dc275f4161" - integrity sha512-mcbYQRO9GeLjUU3fTrJEwD17pF/t4YlgYoEqVQkLgR0kCQ5exMFlj8II4UQHgNevx8GMJGpqQ9+fM6ZhCYKIzQ== - dependencies: - comment-json "^1.1.3" - configstore "^5.0.1" - cspell-dict-bash "^1.0.3" - cspell-dict-companies "^1.0.20" - cspell-dict-cpp "^1.1.26" - cspell-dict-django "^1.0.15" - cspell-dict-dotnet "^1.0.14" - cspell-dict-elixir "^1.0.13" - cspell-dict-en-gb "^1.1.16" - cspell-dict-en_us "^1.2.25" - cspell-dict-fonts "^1.0.5" - cspell-dict-fullstack "^1.0.22" - cspell-dict-golang "^1.1.14" - cspell-dict-haskell "^1.0.4" - cspell-dict-html-symbol-entities "^1.0.13" - cspell-dict-java "^1.0.12" - cspell-dict-latex "^1.0.13" - cspell-dict-lorem-ipsum "^1.0.10" - cspell-dict-php "^1.0.13" - cspell-dict-powershell "^1.0.6" - cspell-dict-python "^1.0.20" - cspell-dict-ruby "^1.0.3" - cspell-dict-rust "^1.0.12" - cspell-dict-scala "^1.0.11" - cspell-dict-software-terms "^1.0.6" - cspell-dict-typescript "^1.0.3" - cspell-io "^4.0.20" - cspell-trie-lib "^4.1.8" - cspell-util-bundle "^4.0.9" - fs-extra "^8.1.0" - gensequence "^3.0.3" - vscode-uri "^2.1.1" - -cspell-trie-lib@^4.1.8: - version "4.1.8" - resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-4.1.8.tgz#cc40c863c8c03920c61e5330c3acfcaf9871e40f" - integrity sha512-G0Jpybwxyl7rG3c4tzrROEVmiKAsyIjaDdnGxkzOFkl4tjcZeCh7GIVrqLyyk3VWslrWMVvmQi1/eLDccagepw== - dependencies: - gensequence "^3.0.3" - -cspell-util-bundle@^4.0.9: - version "4.0.9" - resolved "https://registry.yarnpkg.com/cspell-util-bundle/-/cspell-util-bundle-4.0.9.tgz#9e6a7f3dcd4aef1b9c6743d33d09379cf94ecd08" - integrity sha512-+xhIGJAkPxD7aKl97S0E34B5dF+HSTSoEL6M2f6Y46tusFGc9VdhA/iIZQooZZx2RQy4WaHw/ABfsRfxtnFVLw== - -cspell@4.0.55: - version "4.0.55" - resolved "https://registry.yarnpkg.com/cspell/-/cspell-4.0.55.tgz#4295b88c9cb7b1bf7290027212913203be5f3f9d" - integrity sha512-LmBk2VNrBSXFPOpmhJalqYGdDF1x68H4wI3c7RDMRLfG/zOaFoZUEuJUYOC07tFXDosczXMu38Qt9cnEVZmrAA== - dependencies: - chalk "^2.4.2" - commander "^2.20.3" - comment-json "^1.1.3" - cspell-glob "^0.1.17" - cspell-lib "^4.1.21" - fs-extra "^8.1.0" - gensequence "^3.0.3" - get-stdin "^7.0.0" - glob "^7.1.6" - minimatch "^3.0.4" - -debug@3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== - dependencies: - type-detect "^4.0.0" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -default-require-extensions@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96" - integrity sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg== - dependencies: - strip-bom "^4.0.0" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -definitelytyped-header-parser@3.9.0, definitelytyped-header-parser@^3.8.2: - version "3.9.0" - resolved "https://registry.yarnpkg.com/definitelytyped-header-parser/-/definitelytyped-header-parser-3.9.0.tgz#f992abb8e62f697ca25e1adbfd5f69ef11621644" - integrity sha512-slbwZ5h5lasB12t+9EAGYr060aCMqEXp6cwD7CoTriK40HNDYU56/XQ6S4sbjBK8ReGRMnB/uDx0elKkb4kuQA== - dependencies: - "@types/parsimmon" "^1.3.0" - parsimmon "^1.2.0" - -diff@3.5.0, diff@^3.2.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dot-prop@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" - integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== - dependencies: - is-obj "^2.0.0" - -dts-critic@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dts-critic/-/dts-critic-3.0.1.tgz#c4f18e08dda91456a14835b700b1f816a77ce299" - integrity sha512-3y34qsytqwEgfoUcYwxVm9Lv54Q+MPEXCOtZpwhl4TNM1SN/yjolWXz7Xw2U0BQv/rGhIdM2ONNTaAxRfQdJ6g== - dependencies: - command-exists "^1.2.8" - definitelytyped-header-parser "^3.8.2" - semver "^6.2.0" - typescript "^3.7.5" - yargs "^12.0.5" - -dtslint@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/dtslint/-/dtslint-3.4.1.tgz#b75c1bcd0d81f2029604f2a322aacb474cfc60ea" - integrity sha512-gIFYwlAO8vY17zGMqdJ7x2DA2swrQsKCwrtX0TUP4A36dlXjdFpj6NWMWc1HW5mYkWOkQFHwTWMOdkP6DLsrfA== - dependencies: - definitelytyped-header-parser "3.9.0" - dts-critic "^3.0.0" - fs-extra "^6.0.1" - json-stable-stringify "^1.0.1" - strip-json-comments "^2.0.1" - tslint "5.14.0" - typescript next - yargs "^15.1.0" - -electron-to-chromium@^1.3.390: - version "1.3.393" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.393.tgz#d13fa4cbf5065e18451c84465d22aef6aca9a911" - integrity sha512-Ko3/VdhZAaMaJBLBFqEJ+M1qMiBI8sJfPY/hSJvDrkB3Do8LJsL9tmXy4w7o9nPXif/jFaZGSlXTQWU8XVsYtg== - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -error-ex@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: - version "1.17.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" - integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.1.5" - is-regex "^1.0.5" - object-inspect "^1.7.0" - object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimleft "^2.1.1" - string.prototype.trimright "^2.1.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-error@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" - integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== - -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-import-resolver-node@^0.3.2: - version "0.3.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" - integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== - dependencies: - debug "^2.6.9" - resolve "^1.13.1" - -eslint-module-utils@^2.4.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== - dependencies: - debug "^2.6.9" - pkg-dir "^2.0.0" - -eslint-plugin-flowtype@4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.7.0.tgz#903a6ea3eb5cbf4c7ba7fa73cc43fc39ab7e4a70" - integrity sha512-M+hxhSCk5QBEValO5/UqrS4UunT+MgplIJK5wA1sCtXjzBcZkpTGRwxmLHhGpbHcrmQecgt6ZL/KDdXWqGB7VA== - dependencies: - lodash "^4.17.15" - -"eslint-plugin-graphql-internal@link:./resources/eslint-rules": - version "0.0.0" - uid "" - -eslint-plugin-import@2.20.2: - version "2.20.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz#91fc3807ce08be4837141272c8b99073906e588d" - integrity sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg== - dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.4.1" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.0" - read-pkg-up "^2.0.0" - resolve "^1.12.0" - -eslint-scope@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" - integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" - integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" - integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== - -eslint@6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - -esprima@^2.7.0: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.2.0.tgz#a010a519c0288f2530b3404124bfb5f02e9797fe" - integrity sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q== - dependencies: - estraverse "^5.0.0" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - dependencies: - estraverse "^4.1.0" - -estraverse@^4.1.0, estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.0.0.tgz#ac81750b482c11cca26e4b07e83ed8f75fbcdc22" - integrity sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.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" - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fast-deep-equal@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" - integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-cache-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-cache-dir@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flat@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" - integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== - dependencies: - is-buffer "~2.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -flow-bin@0.121.0: - version "0.121.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.121.0.tgz#e206bdc3d510277f9a847920540f72c49e87c130" - integrity sha512-QYRMs+AoMLj/OTaSo9+8c3kzM/u8YgvfrInp0qzhtzC02Sc2jb3BV/QZWZGjPo+XK3twyyqXrcI3s8MuL1UQRg== - -foreground-child@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" - integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^3.0.2" - -fromentries@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.2.0.tgz#e6aa06f240d6267f913cea422075ef88b63e7897" - integrity sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ== - -fs-extra@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" - integrity sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" - integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -gensequence@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/gensequence/-/gensequence-3.0.3.tgz#5e76326bb893147e80d6f2ae495c7e9a2795f7cc" - integrity sha512-KM4L8AfWAfjIvdnBhl7erj35iBNf75pP0+8Ww3BKssVEBv95Dqu40cG62kAyVXtuLplb96wh/GUr+GhM6YG9gQ== - -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-caller-file@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= - -get-stdin@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" - integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -glob-parent@^5.0.0, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== - dependencies: - is-glob "^4.0.1" - -glob@7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hasha@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.0.tgz#33094d1f69c40a4a6ac7be53d5fe3ff95a269e0c" - integrity sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw== - dependencies: - is-stream "^2.0.0" - type-fest "^0.8.0" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -import-fresh@^3.0.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inquirer@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" - integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== - dependencies: - ansi-escapes "^4.2.1" - chalk "^3.0.0" - cli-cursor "^3.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.15" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.5.3" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -invariant@^2.2.2, invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-buffer@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" - integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== - -is-callable@^1.1.4, is-callable@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" - integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== - -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - -is-regex@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== - dependencies: - has "^1.0.3" - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== - -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -isarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== - -istanbul-lib-hook@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" - integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ== - dependencies: - append-transform "^2.0.0" - -istanbul-lib-instrument@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" - integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== - dependencies: - "@babel/core" "^7.7.5" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-processinfo@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" - integrity sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw== - 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" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.1.tgz#1343217244ad637e0c3b18e7f6b746941a9b5e9a" - integrity sha512-Vm9xwCiQ8t2cNNnckyeAV0UdxKpcQUz4nMxsBvIu8n2kmPSiyb5uaF/8LpmKr+yqL/MdOXaX2Nmdo4Qyxium9Q== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -iterable-to-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/iterable-to-stream/-/iterable-to-stream-1.0.1.tgz#37e86baacf6b1a0e9233dad4eb526d0423d08bf3" - integrity sha512-O62gD5ADMUGtJoOoM9U6LQ7i4byPXUNoHJ6mqsmkQJcom331ZJGDApWgDESWyBMEHEJRjtHozgIiTzYo9RU4UA== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -js-yaml@3.13.1, js-yaml@^3.13.1, js-yaml@^3.7.0: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parser@^1.0.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/json-parser/-/json-parser-1.1.5.tgz#e62ec5261d1a6a5fc20e812a320740c6d9005677" - integrity sha1-5i7FJh0aal/CDoEqMgdAxtkAVnc= - dependencies: - esprima "^2.7.0" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - -json5@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e" - integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== - dependencies: - minimist "^1.2.5" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levenary@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" - integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== - dependencies: - leven "^3.1.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash.flattendeep@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" - integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= - -lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -log-symbols@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" - integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== - dependencies: - chalk "^2.4.2" - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -make-dir@^2.0.0, make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.0, make-dir@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" - integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== - dependencies: - semver "^6.0.0" - -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -mimic-fn@^2.0.0, mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mkdirp@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.3.tgz#5a514b7179259287952881e94410ec5465659f8c" - integrity sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg== - dependencies: - minimist "^1.2.5" - -mkdirp@^0.5.1: - version "0.5.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" - integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== - dependencies: - minimist "^1.2.5" - -mocha@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.1.tgz#89fbb30d09429845b1bb893a830bf5771049a441" - integrity sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA== - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - chokidar "3.3.0" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "3.0.0" - minimatch "3.0.4" - mkdirp "0.5.3" - ms "2.1.1" - node-environment-flags "1.0.6" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-environment-flags@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" - integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw== - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -node-preload@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" - integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ== - dependencies: - process-on-spawn "^1.0.0" - -node-releases@^1.1.53: - version "1.1.53" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4" - integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ== - -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -nyc@15.0.0: - version "15.0.0" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.0.0.tgz#eb32db2c0f29242c2414fe46357f230121cfc162" - integrity sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg== - 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" - 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.0" - js-yaml "^3.13.1" - make-dir "^3.0.0" - node-preload "^0.2.0" - 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" - uuid "^3.3.3" - yargs "^15.0.2" - -object-inspect@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" - integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@4.1.0, object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.getownpropertydescriptors@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" - integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -object.values@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" - integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -os-locale@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" - integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== - dependencies: - p-try "^2.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== - dependencies: - aggregate-error "^3.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -package-hash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506" - integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ== - dependencies: - graceful-fs "^4.1.15" - hasha "^5.0.0" - lodash.flattendeep "^4.4.0" - release-zalgo "^1.0.0" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - -parsimmon@^1.2.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/parsimmon/-/parsimmon-1.13.0.tgz#6e4ef3dbd45ed6ea6808be600ac4b9c8a44228cf" - integrity sha512-5UIrOCW+gjbILkjKPgTgmq8LKf8TT3Iy7kN2VD7OtQ81facKn8B4gG1X94jWqXYZsxG2KbJhrv/Yq/5H6BQn7A== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - -pathval@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= - -picomatch@^2.0.4, picomatch@^2.0.5: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pirates@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prettier@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.2.tgz#1ba8f3eb92231e769b7fcd7cb73ae1b6b74ade08" - integrity sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg== - -private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -process-on-spawn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" - integrity sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg== - dependencies: - fromentries "^1.2.0" - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - -readdirp@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" - integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== - dependencies: - picomatch "^2.0.4" - -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - -regenerator-runtime@^0.13.4: - version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" - integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== - -regenerator-transform@^0.14.2: - version "0.14.4" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" - integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== - dependencies: - "@babel/runtime" "^7.8.4" - private "^0.1.8" - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" - integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== - -regexpu-core@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" - integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== - 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" - -regjsgen@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" - integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== - -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== - dependencies: - jsesc "~0.5.0" - -release-zalgo@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" - integrity sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA= - dependencies: - es6-error "^4.0.1" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2: - version "1.15.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" - integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== - dependencies: - path-parse "^1.0.6" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-async@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8" - integrity sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg== - dependencies: - is-promise "^2.1.0" - -rxjs@^6.5.3: - version "6.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" - integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== - dependencies: - tslib "^1.9.0" - -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -source-map-support@^0.5.16: - version "0.5.16" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" - integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spawn-wrap@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" - integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg== - 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" - -spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.trimend@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz#ee497fd29768646d84be2c9b819e292439614373" - integrity sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trimleft@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" - integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - string.prototype.trimstart "^1.0.0" - -string.prototype.trimright@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" - integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - string.prototype.trimend "^1.0.0" - -string.prototype.trimstart@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz#afe596a7ce9de905496919406c9734845f01a2f2" - integrity sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-json-comments@2.0.1, strip-json-comments@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -strip-json-comments@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" - integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== - -supports-color@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" - integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== - dependencies: - has-flag "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - -tslint@5.14.0: - version "5.14.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.14.0.tgz#be62637135ac244fc9b37ed6ea5252c9eba1616e" - integrity sha512-IUla/ieHVnB8Le7LdQFRGlVJid2T/gaJe5VkjzRVSRR6pA2ODYrnfR1hmxi+5+au9l50jBwpbBL34txgv4NnTQ== - dependencies: - babel-code-frame "^6.22.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^3.2.0" - glob "^7.1.1" - js-yaml "^3.7.0" - minimatch "^3.0.4" - mkdirp "^0.5.1" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.8.0" - tsutils "^2.29.0" - -tsutils@^2.29.0: - version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== - dependencies: - tslib "^1.8.1" - -tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== - dependencies: - tslib "^1.8.1" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== - -type-fest@^0.8.0, type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typescript@^3.7.5, typescript@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== - -typescript@next: - version "3.9.0-dev.20200402" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200402.tgz#f09c5a7d7ef1370ad7ef46b84e2732002276107c" - integrity sha512-CxOOy4lmaPnuyG34aP1kF2l++aou/IM+T0XsEeXZWb6xbIwx+3rt1DbLNS0pQIsLxi7NITq3x4M1qXhOQOAE6A== - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -uuid@^3.3.3: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" - integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -vscode-uri@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.1.tgz#5aa1803391b6ebdd17d047f51365cf62c38f6e90" - integrity sha512-eY9jmGoEnVf8VE8xr5znSah7Qt1P/xsCdErz+g8HYZtJ7bZqKH5E3d+6oVNm1AC/c6IHUDokbmVXKOi4qPAC9A== - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@1.3.1, which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -xdg-basedir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" - integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== - -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== - -yargs-parser@13.1.2, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^18.1.1: - version "18.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.2.tgz#2f482bea2136dbde0861683abea7756d30b504f1" - integrity sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-unparser@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" - integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== - dependencies: - flat "^4.1.0" - lodash "^4.17.15" - yargs "^13.3.0" - -yargs@13.3.2, yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.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 "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - -yargs@^15.0.2, yargs@^15.1.0: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== - 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.1"