immosquare-cleaner 0.1.32 → 0.1.33
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/immosquare-cleaner/version.rb +1 -1
- data/node_modules/@eslint/eslintrc/README.md +15 -4
- data/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs +57 -18
- data/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs.map +1 -1
- data/node_modules/@eslint/eslintrc/dist/eslintrc.cjs +60 -34
- data/node_modules/@eslint/eslintrc/dist/eslintrc.cjs.map +1 -1
- data/node_modules/@eslint/eslintrc/lib/config-array/config-array.js +3 -16
- data/node_modules/@eslint/eslintrc/lib/shared/config-validator.js +63 -18
- data/node_modules/@eslint/eslintrc/package.json +4 -4
- data/node_modules/@eslint/js/package.json +2 -2
- data/node_modules/@eslint/js/src/configs/eslint-all.js +9 -1
- data/node_modules/@eslint/js/src/configs/eslint-recommended.js +12 -5
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/LICENSE +201 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/README.md +105 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs +384 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts +27 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/index.d.ts +16 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts +12 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/index.js +65 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/visitor-keys.js +315 -0
- data/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/package.json +74 -0
- data/node_modules/@humanwhocodes/config-array/api.js +114 -16
- data/node_modules/@humanwhocodes/config-array/package.json +5 -3
- data/node_modules/@humanwhocodes/object-schema/CHANGELOG.md +7 -0
- data/node_modules/@humanwhocodes/object-schema/package.json +6 -1
- data/node_modules/@humanwhocodes/retry/LICENSE +201 -0
- data/node_modules/@humanwhocodes/retry/README.md +122 -0
- data/node_modules/@humanwhocodes/retry/dist/retrier.cjs +267 -0
- data/node_modules/@humanwhocodes/retry/dist/retrier.d.ts +24 -0
- data/node_modules/@humanwhocodes/retry/dist/retrier.js +265 -0
- data/node_modules/@humanwhocodes/retry/dist/retrier.min.js +1 -0
- data/node_modules/@humanwhocodes/retry/dist/retrier.mjs +265 -0
- data/node_modules/@humanwhocodes/retry/package.json +74 -0
- data/node_modules/@types/semver-utils/LICENSE +21 -0
- data/node_modules/@types/semver-utils/README.md +34 -0
- data/node_modules/@types/semver-utils/index.d.ts +15 -0
- data/node_modules/@types/semver-utils/package.json +25 -0
- data/node_modules/acorn/CHANGELOG.md +36 -0
- data/node_modules/acorn/README.md +8 -3
- data/node_modules/acorn/dist/acorn.d.mts +857 -26
- data/node_modules/acorn/dist/acorn.d.ts +833 -268
- data/node_modules/acorn/dist/acorn.js +33 -21
- data/node_modules/acorn/dist/acorn.mjs +33 -21
- data/node_modules/acorn/package.json +1 -1
- data/node_modules/cacheable-request/node_modules/keyv/README.md +429 -0
- data/node_modules/cacheable-request/node_modules/keyv/package.json +57 -0
- data/node_modules/cacheable-request/node_modules/keyv/src/index.d.ts +112 -0
- data/node_modules/cacheable-request/node_modules/keyv/src/index.js +264 -0
- data/node_modules/doctrine/CHANGELOG.md +0 -7
- data/node_modules/doctrine/lib/doctrine.js +1 -0
- data/node_modules/doctrine/package.json +8 -9
- data/node_modules/eslint/README.md +31 -28
- data/node_modules/eslint/bin/eslint.js +4 -3
- data/node_modules/eslint/conf/ecma-version.js +16 -0
- data/node_modules/eslint/conf/globals.js +1 -0
- data/node_modules/eslint/conf/rule-type-list.json +3 -1
- data/node_modules/eslint/lib/api.js +7 -11
- data/node_modules/eslint/lib/cli-engine/cli-engine.js +14 -3
- data/node_modules/eslint/lib/cli-engine/formatters/formatters-meta.json +1 -29
- data/node_modules/eslint/lib/cli-engine/lint-result-cache.js +2 -2
- data/node_modules/eslint/lib/cli.js +115 -36
- data/node_modules/eslint/lib/config/default-config.js +3 -0
- data/node_modules/eslint/lib/config/flat-config-array.js +110 -24
- data/node_modules/eslint/lib/config/flat-config-helpers.js +41 -20
- data/node_modules/eslint/lib/config/flat-config-schema.js +1 -7
- data/node_modules/eslint/lib/config/rule-validator.js +42 -6
- data/node_modules/eslint/lib/eslint/eslint-helpers.js +116 -58
- data/node_modules/eslint/lib/eslint/eslint.js +892 -377
- data/node_modules/eslint/lib/eslint/index.js +2 -2
- data/node_modules/eslint/lib/eslint/legacy-eslint.js +728 -0
- data/node_modules/eslint/lib/linter/apply-disable-directives.js +59 -31
- data/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js +0 -1
- data/node_modules/eslint/lib/linter/code-path-analysis/code-path.js +32 -30
- data/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js +1 -1
- data/node_modules/eslint/lib/linter/config-comment-parser.js +8 -11
- data/node_modules/eslint/lib/linter/index.js +1 -3
- data/node_modules/eslint/lib/linter/interpolate.js +24 -2
- data/node_modules/eslint/lib/linter/linter.js +428 -207
- data/node_modules/eslint/lib/linter/report-translator.js +3 -3
- data/node_modules/eslint/lib/linter/rules.js +6 -15
- data/node_modules/eslint/lib/linter/source-code-fixer.js +1 -1
- data/node_modules/eslint/lib/linter/timing.js +16 -8
- data/node_modules/eslint/lib/options.js +35 -3
- data/node_modules/eslint/lib/rule-tester/index.js +3 -1
- data/node_modules/eslint/lib/rule-tester/rule-tester.js +424 -347
- data/node_modules/eslint/lib/rules/array-bracket-newline.js +1 -1
- data/node_modules/eslint/lib/rules/array-bracket-spacing.js +1 -1
- data/node_modules/eslint/lib/rules/block-scoped-var.js +1 -1
- data/node_modules/eslint/lib/rules/callback-return.js +2 -2
- data/node_modules/eslint/lib/rules/camelcase.js +3 -5
- data/node_modules/eslint/lib/rules/capitalized-comments.js +10 -7
- data/node_modules/eslint/lib/rules/comma-dangle.js +1 -1
- data/node_modules/eslint/lib/rules/comma-style.js +2 -2
- data/node_modules/eslint/lib/rules/complexity.js +14 -1
- data/node_modules/eslint/lib/rules/constructor-super.js +99 -100
- data/node_modules/eslint/lib/rules/default-case.js +1 -1
- data/node_modules/eslint/lib/rules/eol-last.js +2 -2
- data/node_modules/eslint/lib/rules/function-paren-newline.js +2 -2
- data/node_modules/eslint/lib/rules/indent-legacy.js +5 -5
- data/node_modules/eslint/lib/rules/indent.js +5 -5
- data/node_modules/eslint/lib/rules/index.js +1 -2
- data/node_modules/eslint/lib/rules/key-spacing.js +2 -2
- data/node_modules/eslint/lib/rules/line-comment-position.js +1 -1
- data/node_modules/eslint/lib/rules/lines-around-directive.js +2 -2
- data/node_modules/eslint/lib/rules/max-depth.js +1 -1
- data/node_modules/eslint/lib/rules/max-len.js +3 -3
- data/node_modules/eslint/lib/rules/max-lines.js +3 -3
- data/node_modules/eslint/lib/rules/max-nested-callbacks.js +1 -1
- data/node_modules/eslint/lib/rules/max-params.js +1 -1
- data/node_modules/eslint/lib/rules/max-statements.js +1 -1
- data/node_modules/eslint/lib/rules/multiline-comment-style.js +7 -7
- data/node_modules/eslint/lib/rules/new-cap.js +1 -1
- data/node_modules/eslint/lib/rules/newline-after-var.js +1 -1
- data/node_modules/eslint/lib/rules/newline-before-return.js +1 -1
- data/node_modules/eslint/lib/rules/no-case-declarations.js +13 -1
- data/node_modules/eslint/lib/rules/no-constant-binary-expression.js +7 -8
- data/node_modules/eslint/lib/rules/no-constant-condition.js +18 -7
- data/node_modules/eslint/lib/rules/no-constructor-return.js +2 -2
- data/node_modules/eslint/lib/rules/no-dupe-class-members.js +2 -2
- data/node_modules/eslint/lib/rules/no-else-return.js +1 -1
- data/node_modules/eslint/lib/rules/no-empty-function.js +2 -2
- data/node_modules/eslint/lib/rules/no-empty-static-block.js +1 -1
- data/node_modules/eslint/lib/rules/no-extend-native.js +1 -2
- data/node_modules/eslint/lib/rules/no-extra-semi.js +1 -1
- data/node_modules/eslint/lib/rules/no-fallthrough.js +41 -16
- data/node_modules/eslint/lib/rules/no-implicit-coercion.js +66 -24
- data/node_modules/eslint/lib/rules/no-inner-declarations.js +23 -2
- data/node_modules/eslint/lib/rules/no-invalid-regexp.js +1 -1
- data/node_modules/eslint/lib/rules/no-invalid-this.js +1 -1
- data/node_modules/eslint/lib/rules/no-lone-blocks.js +3 -3
- data/node_modules/eslint/lib/rules/no-loss-of-precision.js +1 -1
- data/node_modules/eslint/lib/rules/no-misleading-character-class.js +225 -69
- data/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
- data/node_modules/eslint/lib/rules/no-multiple-empty-lines.js +1 -1
- data/node_modules/eslint/lib/rules/no-new-native-nonconstructor.js +1 -1
- data/node_modules/eslint/lib/rules/no-new-symbol.js +8 -1
- data/node_modules/eslint/lib/rules/no-restricted-globals.js +1 -1
- data/node_modules/eslint/lib/rules/no-restricted-imports.js +186 -40
- data/node_modules/eslint/lib/rules/no-restricted-modules.js +2 -2
- data/node_modules/eslint/lib/rules/no-return-await.js +1 -1
- data/node_modules/eslint/lib/rules/no-sequences.js +1 -0
- data/node_modules/eslint/lib/rules/no-this-before-super.js +45 -13
- data/node_modules/eslint/lib/rules/no-trailing-spaces.js +2 -3
- data/node_modules/eslint/lib/rules/no-unneeded-ternary.js +1 -1
- data/node_modules/eslint/lib/rules/no-unsafe-optional-chaining.js +1 -1
- data/node_modules/eslint/lib/rules/no-unused-private-class-members.js +1 -1
- data/node_modules/eslint/lib/rules/no-unused-vars.js +197 -36
- data/node_modules/eslint/lib/rules/no-useless-assignment.js +566 -0
- data/node_modules/eslint/lib/rules/no-useless-backreference.js +1 -1
- data/node_modules/eslint/lib/rules/no-useless-computed-key.js +2 -2
- data/node_modules/eslint/lib/rules/no-useless-return.js +7 -2
- data/node_modules/eslint/lib/rules/object-curly-spacing.js +3 -3
- data/node_modules/eslint/lib/rules/object-property-newline.js +1 -1
- data/node_modules/eslint/lib/rules/one-var.js +5 -5
- data/node_modules/eslint/lib/rules/padded-blocks.js +7 -7
- data/node_modules/eslint/lib/rules/prefer-arrow-callback.js +3 -3
- data/node_modules/eslint/lib/rules/prefer-reflect.js +1 -1
- data/node_modules/eslint/lib/rules/prefer-regex-literals.js +1 -1
- data/node_modules/eslint/lib/rules/prefer-template.js +1 -1
- data/node_modules/eslint/lib/rules/radix.js +2 -2
- data/node_modules/eslint/lib/rules/semi-style.js +1 -1
- data/node_modules/eslint/lib/rules/sort-imports.js +1 -1
- data/node_modules/eslint/lib/rules/sort-keys.js +1 -1
- data/node_modules/eslint/lib/rules/sort-vars.js +1 -1
- data/node_modules/eslint/lib/rules/space-unary-ops.js +1 -1
- data/node_modules/eslint/lib/rules/strict.js +1 -1
- data/node_modules/eslint/lib/rules/use-isnan.js +101 -7
- data/node_modules/eslint/lib/rules/utils/ast-utils.js +16 -7
- data/node_modules/eslint/lib/rules/utils/char-source.js +240 -0
- data/node_modules/eslint/lib/rules/utils/lazy-loading-rule-map.js +1 -1
- data/node_modules/eslint/lib/rules/utils/unicode/index.js +9 -4
- data/node_modules/eslint/lib/rules/yield-star-spacing.js +1 -1
- data/node_modules/eslint/lib/shared/runtime-info.js +1 -0
- data/node_modules/eslint/lib/shared/serialization.js +55 -0
- data/node_modules/eslint/lib/shared/stats.js +30 -0
- data/node_modules/eslint/lib/shared/string-utils.js +9 -11
- data/node_modules/eslint/lib/shared/types.js +35 -1
- data/node_modules/eslint/lib/source-code/index.js +3 -1
- data/node_modules/eslint/lib/source-code/source-code.js +299 -85
- data/node_modules/eslint/lib/source-code/token-store/backward-token-cursor.js +3 -3
- data/node_modules/eslint/lib/source-code/token-store/cursors.js +4 -2
- data/node_modules/eslint/lib/source-code/token-store/forward-token-comment-cursor.js +3 -3
- data/node_modules/eslint/lib/source-code/token-store/forward-token-cursor.js +3 -3
- data/node_modules/eslint/lib/source-code/token-store/index.js +2 -2
- data/node_modules/eslint/lib/unsupported-api.js +3 -5
- data/node_modules/eslint/messages/no-config-found.js +1 -1
- data/node_modules/eslint/messages/plugin-conflict.js +1 -1
- data/node_modules/eslint/messages/plugin-invalid.js +1 -1
- data/node_modules/eslint/messages/plugin-missing.js +1 -1
- data/node_modules/eslint/package.json +32 -29
- data/node_modules/eslint-scope/README.md +23 -2
- data/node_modules/eslint-scope/dist/eslint-scope.cjs +84 -58
- data/node_modules/eslint-scope/lib/index.js +0 -3
- data/node_modules/eslint-scope/lib/pattern-visitor.js +4 -3
- data/node_modules/eslint-scope/lib/referencer.js +13 -11
- data/node_modules/eslint-scope/lib/scope-manager.js +2 -8
- data/node_modules/eslint-scope/lib/scope.js +64 -43
- data/node_modules/eslint-scope/lib/version.js +1 -1
- data/node_modules/eslint-scope/package.json +21 -19
- data/node_modules/eslint-visitor-keys/README.md +1 -1
- data/node_modules/eslint-visitor-keys/package.json +2 -2
- data/node_modules/espree/README.md +1 -1
- data/node_modules/espree/dist/espree.cjs +1 -1
- data/node_modules/espree/lib/version.js +1 -1
- data/node_modules/espree/package.json +18 -20
- data/node_modules/file-entry-cache/LICENSE +1 -1
- data/node_modules/file-entry-cache/README.md +6 -3
- data/node_modules/file-entry-cache/package.json +19 -43
- data/node_modules/flat-cache/README.md +8 -6
- data/node_modules/flat-cache/changelog.md +155 -205
- data/node_modules/flat-cache/package.json +16 -39
- data/node_modules/flat-cache/src/cache.js +22 -26
- data/node_modules/flat-cache/src/del.js +28 -11
- data/node_modules/flat-cache/src/utils.js +39 -41
- data/node_modules/globals/globals.json +25 -0
- data/node_modules/globals/index.d.ts +2074 -3
- data/node_modules/globals/package.json +10 -7
- data/node_modules/globals/readme.md +2 -14
- data/node_modules/keyv/package.json +4 -4
- data/node_modules/keyv/src/index.js +6 -11
- data/node_modules/npm-check-updates/build/cli.js +22 -21
- data/node_modules/npm-check-updates/build/cli.js.map +1 -1
- data/node_modules/npm-check-updates/build/index-5sFb3Tvv.js +66 -0
- data/node_modules/npm-check-updates/build/index-5sFb3Tvv.js.map +1 -0
- data/node_modules/npm-check-updates/build/index-BmUFwMVL.js +6 -0
- data/node_modules/npm-check-updates/build/index-BmUFwMVL.js.map +1 -0
- data/node_modules/npm-check-updates/build/index.d.ts +5 -2
- data/node_modules/npm-check-updates/build/index.js +560 -1
- data/node_modules/npm-check-updates/build/index.js.map +1 -1
- data/node_modules/npm-check-updates/build/package.json +4 -3
- data/node_modules/npm-check-updates/build/src/index.js +1 -1
- data/node_modules/npm-check-updates/build/src/index.js.map +1 -1
- data/node_modules/npm-check-updates/build/src/lib/libnpmconfig/index.js +2 -2
- data/node_modules/npm-check-updates/build/src/lib/libnpmconfig/index.js.map +1 -1
- data/node_modules/npm-check-updates/build/src/package-managers/bun.js +0 -6
- data/node_modules/npm-check-updates/build/src/package-managers/bun.js.map +1 -1
- data/node_modules/npm-check-updates/package.json +4 -3
- data/node_modules/type-fest/index.d.ts +95 -2
- data/node_modules/type-fest/package.json +12 -18
- data/node_modules/type-fest/readme.md +299 -52
- data/node_modules/type-fest/source/async-return-type.d.ts +4 -2
- data/node_modules/type-fest/source/asyncify.d.ts +5 -3
- data/node_modules/type-fest/source/basic.d.ts +21 -43
- data/node_modules/type-fest/{ts41 → source}/camel-case.d.ts +18 -17
- data/node_modules/type-fest/source/camel-cased-properties-deep.d.ts +54 -0
- data/node_modules/type-fest/source/camel-cased-properties.d.ts +36 -0
- data/node_modules/type-fest/source/conditional-except.d.ts +6 -4
- data/node_modules/type-fest/source/conditional-keys.d.ts +5 -1
- data/node_modules/type-fest/source/conditional-pick.d.ts +5 -3
- data/node_modules/type-fest/{ts41 → source}/delimiter-case.d.ts +16 -8
- data/node_modules/type-fest/source/delimiter-cased-properties-deep.d.ts +60 -0
- data/node_modules/type-fest/source/delimiter-cased-properties.d.ts +37 -0
- data/node_modules/type-fest/source/entries.d.ts +8 -3
- data/node_modules/type-fest/source/entry.d.ts +8 -3
- data/node_modules/type-fest/source/exact.d.ts +73 -0
- data/node_modules/type-fest/source/except.d.ts +38 -3
- data/node_modules/type-fest/source/fixed-length-array.d.ts +6 -1
- data/node_modules/type-fest/source/get.d.ts +184 -0
- data/node_modules/type-fest/source/has-optional-keys.d.ts +21 -0
- data/node_modules/type-fest/source/has-required-keys.d.ts +59 -0
- data/node_modules/type-fest/source/includes.d.ts +22 -0
- data/node_modules/type-fest/source/internal.d.ts +59 -0
- data/node_modules/type-fest/source/invariant-of.d.ts +76 -0
- data/node_modules/type-fest/source/iterable-element.d.ts +8 -0
- data/node_modules/type-fest/source/join.d.ts +30 -0
- data/node_modules/type-fest/source/jsonify.d.ts +90 -0
- data/node_modules/type-fest/{ts41 → source}/kebab-case.d.ts +7 -5
- data/node_modules/type-fest/source/kebab-cased-properties-deep.d.ts +47 -0
- data/node_modules/type-fest/source/kebab-cased-properties.d.ts +30 -0
- data/node_modules/type-fest/source/last-array-element.d.ts +28 -0
- data/node_modules/type-fest/source/literal-to-primitive.d.ts +36 -0
- data/node_modules/type-fest/source/literal-union.d.ts +7 -5
- data/node_modules/type-fest/source/merge-exclusive.d.ts +3 -1
- data/node_modules/type-fest/source/merge.d.ts +8 -3
- data/node_modules/type-fest/source/multidimensional-array.d.ts +43 -0
- data/node_modules/type-fest/source/multidimensional-readonly-array.d.ts +47 -0
- data/node_modules/type-fest/source/mutable.d.ts +4 -21
- data/node_modules/type-fest/source/numeric.d.ts +170 -0
- data/node_modules/type-fest/source/observable-like.d.ts +62 -0
- data/node_modules/type-fest/source/opaque.d.ts +45 -3
- data/node_modules/type-fest/source/optional-keys-of.d.ts +38 -0
- data/node_modules/type-fest/source/package-json.d.ts +64 -12
- data/node_modules/type-fest/source/partial-deep.d.ts +57 -16
- data/node_modules/type-fest/source/partial-on-undefined-deep.d.ts +70 -0
- data/node_modules/type-fest/{ts41 → source}/pascal-case.d.ts +6 -4
- data/node_modules/type-fest/source/pascal-cased-properties-deep.d.ts +54 -0
- data/node_modules/type-fest/source/pascal-cased-properties.d.ts +34 -0
- data/node_modules/type-fest/source/primitive.d.ts +13 -0
- data/node_modules/type-fest/source/promisable.d.ts +5 -3
- data/node_modules/type-fest/source/promise-value.d.ts +9 -7
- data/node_modules/type-fest/source/readonly-deep.d.ts +33 -7
- data/node_modules/type-fest/source/readonly-tuple.d.ts +41 -0
- data/node_modules/type-fest/source/remove-index-signature.d.ts +104 -0
- data/node_modules/type-fest/source/replace.d.ts +67 -0
- data/node_modules/type-fest/source/require-all-or-none.d.ts +36 -0
- data/node_modules/type-fest/source/require-at-least-one.d.ts +5 -3
- data/node_modules/type-fest/source/require-exactly-one.d.ts +4 -5
- data/node_modules/type-fest/source/required-keys-of.d.ts +29 -0
- data/node_modules/type-fest/source/schema.d.ts +72 -0
- data/node_modules/type-fest/source/screaming-snake-case.d.ts +33 -0
- data/node_modules/type-fest/source/set-non-nullable.d.ts +35 -0
- data/node_modules/type-fest/source/set-optional.d.ts +12 -11
- data/node_modules/type-fest/source/set-required.d.ts +12 -11
- data/node_modules/type-fest/source/set-return-type.d.ts +3 -1
- data/node_modules/type-fest/source/simplify.d.ts +83 -0
- data/node_modules/type-fest/{ts41 → source}/snake-case.d.ts +7 -4
- data/node_modules/type-fest/source/snake-cased-properties-deep.d.ts +47 -0
- data/node_modules/type-fest/source/snake-cased-properties.d.ts +30 -0
- data/node_modules/type-fest/source/split.d.ts +29 -0
- data/node_modules/type-fest/source/spread.d.ts +85 -0
- data/node_modules/type-fest/source/string-key-of.d.ts +25 -0
- data/node_modules/type-fest/source/stringified.d.ts +3 -1
- data/node_modules/type-fest/source/trim.d.ts +25 -0
- data/node_modules/type-fest/source/tsconfig-json.d.ts +316 -14
- data/node_modules/type-fest/source/typed-array.d.ts +17 -0
- data/node_modules/type-fest/source/union-to-intersection.d.ts +4 -2
- data/node_modules/type-fest/source/value-of.d.ts +3 -1
- data/node_modules/type-fest/source/writable.d.ts +40 -0
- data/package.json +2 -2
- metadata +86 -63
- data/linters/rubocop-2.7.6.yml +0 -86
- data/node_modules/@humanwhocodes/object-schema/tests/merge-strategy.js +0 -66
- data/node_modules/@humanwhocodes/object-schema/tests/object-schema.js +0 -659
- data/node_modules/@humanwhocodes/object-schema/tests/validation-strategy.js +0 -186
- data/node_modules/eslint/conf/config-schema.js +0 -93
- data/node_modules/eslint/lib/cli-engine/formatters/checkstyle.js +0 -60
- data/node_modules/eslint/lib/cli-engine/formatters/compact.js +0 -60
- data/node_modules/eslint/lib/cli-engine/formatters/jslint-xml.js +0 -41
- data/node_modules/eslint/lib/cli-engine/formatters/junit.js +0 -82
- data/node_modules/eslint/lib/cli-engine/formatters/tap.js +0 -95
- data/node_modules/eslint/lib/cli-engine/formatters/unix.js +0 -58
- data/node_modules/eslint/lib/cli-engine/formatters/visualstudio.js +0 -63
- data/node_modules/eslint/lib/cli-engine/xml-escape.js +0 -34
- data/node_modules/eslint/lib/eslint/flat-eslint.js +0 -1155
- data/node_modules/eslint/lib/rule-tester/flat-rule-tester.js +0 -1131
- data/node_modules/eslint/lib/rules/require-jsdoc.js +0 -122
- data/node_modules/eslint/lib/rules/utils/patterns/letters.js +0 -36
- data/node_modules/eslint/lib/rules/valid-jsdoc.js +0 -516
- data/node_modules/eslint/lib/shared/config-validator.js +0 -347
- data/node_modules/eslint/lib/shared/deprecation-warnings.js +0 -58
- data/node_modules/eslint/lib/shared/relative-module-resolver.js +0 -50
- data/node_modules/file-entry-cache/changelog.md +0 -163
- data/node_modules/flat-cache/node_modules/rimraf/CHANGELOG.md +0 -65
- data/node_modules/flat-cache/node_modules/rimraf/LICENSE +0 -15
- data/node_modules/flat-cache/node_modules/rimraf/README.md +0 -101
- data/node_modules/flat-cache/node_modules/rimraf/bin.js +0 -68
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/LICENSE +0 -21
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/README.md +0 -378
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/common.js +0 -238
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/glob.js +0 -790
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/LICENSE +0 -15
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/README.md +0 -230
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/minimatch.js +0 -947
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/node_modules/brace-expansion/LICENSE +0 -21
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/node_modules/brace-expansion/README.md +0 -129
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/node_modules/brace-expansion/index.js +0 -201
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/node_modules/brace-expansion/package.json +0 -47
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/node_modules/minimatch/package.json +0 -33
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/package.json +0 -55
- data/node_modules/flat-cache/node_modules/rimraf/node_modules/glob/sync.js +0 -486
- data/node_modules/flat-cache/node_modules/rimraf/package.json +0 -32
- data/node_modules/flat-cache/node_modules/rimraf/rimraf.js +0 -360
- data/node_modules/npm-check-updates/build/index-CI_x-D21.js +0 -593
- data/node_modules/npm-check-updates/build/index-CI_x-D21.js.map +0 -1
- data/node_modules/npm-check-updates/build/index-Ci8A2QXv.js +0 -6
- data/node_modules/npm-check-updates/build/index-Ci8A2QXv.js.map +0 -1
- data/node_modules/npm-check-updates/build/index-DgVn3Gax.js +0 -36
- data/node_modules/npm-check-updates/build/index-DgVn3Gax.js.map +0 -1
- data/node_modules/npm-check-updates/build/src/types/SpawnPleaseOptions.d.ts +0 -6
- data/node_modules/npm-check-updates/build/src/types/SpawnPleaseOptions.js +0 -3
- data/node_modules/npm-check-updates/build/src/types/SpawnPleaseOptions.js.map +0 -1
- data/node_modules/type-fest/base.d.ts +0 -38
- data/node_modules/type-fest/license +0 -9
- data/node_modules/type-fest/source/utilities.d.ts +0 -3
- data/node_modules/type-fest/ts41/index.d.ts +0 -9
@@ -1,68 +1,42 @@
|
|
1
1
|
/**
|
2
|
-
* @fileoverview Mocha test wrapper
|
2
|
+
* @fileoverview Mocha/Jest test wrapper
|
3
3
|
* @author Ilya Volodin
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
7
|
/* globals describe, it -- Mocha globals */
|
8
8
|
|
9
|
-
/*
|
10
|
-
* This is a wrapper around mocha to allow for DRY unittests for eslint
|
11
|
-
* Format:
|
12
|
-
* RuleTester.run("{ruleName}", {
|
13
|
-
* valid: [
|
14
|
-
* "{code}",
|
15
|
-
* { code: "{code}", options: {options}, globals: {globals}, parser: "{parser}", settings: {settings} }
|
16
|
-
* ],
|
17
|
-
* invalid: [
|
18
|
-
* { code: "{code}", errors: {numErrors} },
|
19
|
-
* { code: "{code}", errors: ["{errorMessage}"] },
|
20
|
-
* { code: "{code}", options: {options}, globals: {globals}, parser: "{parser}", settings: {settings}, errors: [{ message: "{errorMessage}", type: "{errorNodeType}"}] }
|
21
|
-
* ]
|
22
|
-
* });
|
23
|
-
*
|
24
|
-
* Variables:
|
25
|
-
* {code} - String that represents the code to be tested
|
26
|
-
* {options} - Arguments that are passed to the configurable rules.
|
27
|
-
* {globals} - An object representing a list of variables that are
|
28
|
-
* registered as globals
|
29
|
-
* {parser} - String representing the parser to use
|
30
|
-
* {settings} - An object representing global settings for all rules
|
31
|
-
* {numErrors} - If failing case doesn't need to check error message,
|
32
|
-
* this integer will specify how many errors should be
|
33
|
-
* received
|
34
|
-
* {errorMessage} - Message that is returned by the rule on failure
|
35
|
-
* {errorNodeType} - AST node type that is returned by they rule as
|
36
|
-
* a cause of the failure.
|
37
|
-
*/
|
38
|
-
|
39
9
|
//------------------------------------------------------------------------------
|
40
10
|
// Requirements
|
41
11
|
//------------------------------------------------------------------------------
|
42
12
|
|
43
13
|
const
|
44
14
|
assert = require("assert"),
|
45
|
-
path = require("path"),
|
46
15
|
util = require("util"),
|
47
|
-
|
16
|
+
path = require("path"),
|
48
17
|
equal = require("fast-deep-equal"),
|
49
|
-
Traverser = require("
|
50
|
-
{ getRuleOptionsSchema
|
51
|
-
{ Linter, SourceCodeFixer
|
52
|
-
|
18
|
+
Traverser = require("../shared/traverser"),
|
19
|
+
{ getRuleOptionsSchema } = require("../config/flat-config-helpers"),
|
20
|
+
{ Linter, SourceCodeFixer } = require("../linter"),
|
21
|
+
{ interpolate, getPlaceholderMatcher } = require("../linter/interpolate"),
|
22
|
+
stringify = require("json-stable-stringify-without-jsonify");
|
23
|
+
|
24
|
+
const { FlatConfigArray } = require("../config/flat-config-array");
|
25
|
+
const { defaultConfig } = require("../config/default-config");
|
53
26
|
|
54
27
|
const ajv = require("../shared/ajv")({ strictDefaults: true });
|
55
28
|
|
56
|
-
const espreePath = require.resolve("espree");
|
57
29
|
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
58
|
-
|
59
30
|
const { SourceCode } = require("../source-code");
|
31
|
+
const { ConfigArraySymbol } = require("@humanwhocodes/config-array");
|
32
|
+
const { isSerializable } = require("../shared/serialization");
|
60
33
|
|
61
34
|
//------------------------------------------------------------------------------
|
62
35
|
// Typedefs
|
63
36
|
//------------------------------------------------------------------------------
|
64
37
|
|
65
38
|
/** @typedef {import("../shared/types").Parser} Parser */
|
39
|
+
/** @typedef {import("../shared/types").LanguageOptions} LanguageOptions */
|
66
40
|
/** @typedef {import("../shared/types").Rule} Rule */
|
67
41
|
|
68
42
|
|
@@ -72,12 +46,9 @@ const { SourceCode } = require("../source-code");
|
|
72
46
|
* @property {string} [name] Name for the test case.
|
73
47
|
* @property {string} code Code for the test case.
|
74
48
|
* @property {any[]} [options] Options for the test case.
|
49
|
+
* @property {LanguageOptions} [languageOptions] The language options to use in the test case.
|
75
50
|
* @property {{ [name: string]: any }} [settings] Settings for the test case.
|
76
51
|
* @property {string} [filename] The fake filename for the test case. Useful for rules that make assertion about filenames.
|
77
|
-
* @property {string} [parser] The absolute path for the parser.
|
78
|
-
* @property {{ [name: string]: any }} [parserOptions] Options for the parser.
|
79
|
-
* @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables.
|
80
|
-
* @property {{ [name: string]: boolean }} [env] Environments for the test case.
|
81
52
|
* @property {boolean} [only] Run only this test case or the subset of test cases with this property.
|
82
53
|
*/
|
83
54
|
|
@@ -91,10 +62,7 @@ const { SourceCode } = require("../source-code");
|
|
91
62
|
* @property {any[]} [options] Options for the test case.
|
92
63
|
* @property {{ [name: string]: any }} [settings] Settings for the test case.
|
93
64
|
* @property {string} [filename] The fake filename for the test case. Useful for rules that make assertion about filenames.
|
94
|
-
* @property {
|
95
|
-
* @property {{ [name: string]: any }} [parserOptions] Options for the parser.
|
96
|
-
* @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables.
|
97
|
-
* @property {{ [name: string]: boolean }} [env] Environments for the test case.
|
65
|
+
* @property {LanguageOptions} [languageOptions] The language options to use in the test case.
|
98
66
|
* @property {boolean} [only] Run only this test case or the subset of test cases with this property.
|
99
67
|
*/
|
100
68
|
|
@@ -120,7 +88,12 @@ const { SourceCode } = require("../source-code");
|
|
120
88
|
* the initial default configuration
|
121
89
|
*/
|
122
90
|
const testerDefaultConfig = { rules: {} };
|
123
|
-
|
91
|
+
|
92
|
+
/*
|
93
|
+
* RuleTester uses this config as its default. This can be overwritten via
|
94
|
+
* setDefaultConfig().
|
95
|
+
*/
|
96
|
+
let sharedDefaultConfig = { rules: {} };
|
124
97
|
|
125
98
|
/*
|
126
99
|
* List every parameters possible on a test case that are not related to eslint
|
@@ -163,42 +136,25 @@ const suggestionObjectParameters = new Set([
|
|
163
136
|
]);
|
164
137
|
const friendlySuggestionObjectParameterList = `[${[...suggestionObjectParameters].map(key => `'${key}'`).join(", ")}]`;
|
165
138
|
|
139
|
+
/*
|
140
|
+
* Ignored test case properties when checking for test case duplicates.
|
141
|
+
*/
|
142
|
+
const duplicationIgnoredParameters = new Set([
|
143
|
+
"name",
|
144
|
+
"errors",
|
145
|
+
"output"
|
146
|
+
]);
|
147
|
+
|
166
148
|
const forbiddenMethods = [
|
167
149
|
"applyInlineConfig",
|
168
150
|
"applyLanguageOptions",
|
169
151
|
"finalize"
|
170
152
|
];
|
171
153
|
|
172
|
-
|
154
|
+
/** @type {Map<string,WeakSet>} */
|
155
|
+
const forbiddenMethodCalls = new Map(forbiddenMethods.map(methodName => ([methodName, new WeakSet()])));
|
173
156
|
|
174
|
-
const
|
175
|
-
getSource: "getText",
|
176
|
-
getSourceLines: "getLines",
|
177
|
-
getAllComments: "getAllComments",
|
178
|
-
getNodeByRangeIndex: "getNodeByRangeIndex",
|
179
|
-
|
180
|
-
// getComments: "getComments", -- already handled by a separate error
|
181
|
-
getCommentsBefore: "getCommentsBefore",
|
182
|
-
getCommentsAfter: "getCommentsAfter",
|
183
|
-
getCommentsInside: "getCommentsInside",
|
184
|
-
getJSDocComment: "getJSDocComment",
|
185
|
-
getFirstToken: "getFirstToken",
|
186
|
-
getFirstTokens: "getFirstTokens",
|
187
|
-
getLastToken: "getLastToken",
|
188
|
-
getLastTokens: "getLastTokens",
|
189
|
-
getTokenAfter: "getTokenAfter",
|
190
|
-
getTokenBefore: "getTokenBefore",
|
191
|
-
getTokenByRangeStart: "getTokenByRangeStart",
|
192
|
-
getTokens: "getTokens",
|
193
|
-
getTokensAfter: "getTokensAfter",
|
194
|
-
getTokensBefore: "getTokensBefore",
|
195
|
-
getTokensBetween: "getTokensBetween",
|
196
|
-
|
197
|
-
getScope: "getScope",
|
198
|
-
getAncestors: "getAncestors",
|
199
|
-
getDeclaredVariables: "getDeclaredVariables",
|
200
|
-
markVariableAsUsed: "markVariableAsUsed"
|
201
|
-
};
|
157
|
+
const hasOwnProperty = Function.call.bind(Object.hasOwnProperty);
|
202
158
|
|
203
159
|
/**
|
204
160
|
* Clones a given value deeply.
|
@@ -331,23 +287,27 @@ function wrapParser(parser) {
|
|
331
287
|
}
|
332
288
|
|
333
289
|
/**
|
334
|
-
* Function to replace `SourceCode.
|
335
|
-
* @returns {void}
|
336
|
-
* @throws {Error} Deprecation message.
|
337
|
-
*/
|
338
|
-
function getCommentsDeprecation() {
|
339
|
-
throw new Error(
|
340
|
-
"`SourceCode#getComments()` is deprecated and will be removed in a future major version. Use `getCommentsBefore()`, `getCommentsAfter()`, and `getCommentsInside()` instead."
|
341
|
-
);
|
342
|
-
}
|
343
|
-
|
344
|
-
/**
|
345
|
-
* Function to replace forbidden `SourceCode` methods.
|
290
|
+
* Function to replace forbidden `SourceCode` methods. Allows just one call per method.
|
346
291
|
* @param {string} methodName The name of the method to forbid.
|
292
|
+
* @param {Function} prototype The prototype with the original method to call.
|
347
293
|
* @returns {Function} The function that throws the error.
|
348
294
|
*/
|
349
|
-
function throwForbiddenMethodError(methodName) {
|
350
|
-
|
295
|
+
function throwForbiddenMethodError(methodName, prototype) {
|
296
|
+
|
297
|
+
const original = prototype[methodName];
|
298
|
+
|
299
|
+
return function(...args) {
|
300
|
+
|
301
|
+
const called = forbiddenMethodCalls.get(methodName);
|
302
|
+
|
303
|
+
/* eslint-disable no-invalid-this -- needed to operate as a method. */
|
304
|
+
if (!called.has(this)) {
|
305
|
+
called.add(this);
|
306
|
+
|
307
|
+
return original.apply(this, args);
|
308
|
+
}
|
309
|
+
/* eslint-enable no-invalid-this -- not needed past this point */
|
310
|
+
|
351
311
|
throw new Error(
|
352
312
|
`\`SourceCode#${methodName}()\` cannot be called inside a rule.`
|
353
313
|
);
|
@@ -355,81 +315,45 @@ function throwForbiddenMethodError(methodName) {
|
|
355
315
|
}
|
356
316
|
|
357
317
|
/**
|
358
|
-
*
|
359
|
-
* @param
|
360
|
-
* @returns {
|
318
|
+
* Extracts names of {{ placeholders }} from the reported message.
|
319
|
+
* @param {string} message Reported message
|
320
|
+
* @returns {string[]} Array of placeholder names
|
361
321
|
*/
|
362
|
-
function
|
363
|
-
|
364
|
-
emitLegacyRuleAPIWarning[`warned-${ruleName}`] = true;
|
365
|
-
process.emitWarning(
|
366
|
-
`"${ruleName}" rule is using the deprecated function-style format and will stop working in ESLint v9. Please use object-style format: https://eslint.org/docs/latest/extend/custom-rules`,
|
367
|
-
"DeprecationWarning"
|
368
|
-
);
|
369
|
-
}
|
370
|
-
}
|
322
|
+
function getMessagePlaceholders(message) {
|
323
|
+
const matcher = getPlaceholderMatcher();
|
371
324
|
|
372
|
-
|
373
|
-
* Emit a deprecation warning if rule has options but is missing the "meta.schema" property
|
374
|
-
* @param {string} ruleName Name of the rule.
|
375
|
-
* @returns {void}
|
376
|
-
*/
|
377
|
-
function emitMissingSchemaWarning(ruleName) {
|
378
|
-
if (!emitMissingSchemaWarning[`warned-${ruleName}`]) {
|
379
|
-
emitMissingSchemaWarning[`warned-${ruleName}`] = true;
|
380
|
-
process.emitWarning(
|
381
|
-
`"${ruleName}" rule has options but is missing the "meta.schema" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/latest/extend/custom-rules#options-schemas`,
|
382
|
-
"DeprecationWarning"
|
383
|
-
);
|
384
|
-
}
|
325
|
+
return Array.from(message.matchAll(matcher), ([, name]) => name.trim());
|
385
326
|
}
|
386
327
|
|
387
328
|
/**
|
388
|
-
*
|
389
|
-
*
|
390
|
-
* @param {string}
|
391
|
-
* @
|
329
|
+
* Returns the placeholders in the reported messages but
|
330
|
+
* only includes the placeholders available in the raw message and not in the provided data.
|
331
|
+
* @param {string} message The reported message
|
332
|
+
* @param {string} raw The raw message specified in the rule meta.messages
|
333
|
+
* @param {undefined|Record<unknown, unknown>} data The passed
|
334
|
+
* @returns {string[]} Missing placeholder names
|
392
335
|
*/
|
393
|
-
function
|
394
|
-
|
395
|
-
emitDeprecatedContextMethodWarning[`warned-${ruleName}-${methodName}`] = true;
|
396
|
-
process.emitWarning(
|
397
|
-
`"${ruleName}" rule is using \`context.${methodName}()\`, which is deprecated and will be removed in ESLint v9. Please use \`sourceCode.${DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]}()\` instead.`,
|
398
|
-
"DeprecationWarning"
|
399
|
-
);
|
400
|
-
}
|
401
|
-
}
|
336
|
+
function getUnsubstitutedMessagePlaceholders(message, raw, data = {}) {
|
337
|
+
const unsubstituted = getMessagePlaceholders(message);
|
402
338
|
|
403
|
-
|
404
|
-
|
405
|
-
* @param {string} ruleName Name of the rule.
|
406
|
-
* @returns {void}
|
407
|
-
*/
|
408
|
-
function emitCodePathCurrentSegmentsWarning(ruleName) {
|
409
|
-
if (!emitCodePathCurrentSegmentsWarning[`warned-${ruleName}`]) {
|
410
|
-
emitCodePathCurrentSegmentsWarning[`warned-${ruleName}`] = true;
|
411
|
-
process.emitWarning(
|
412
|
-
`"${ruleName}" rule uses CodePath#currentSegments and will stop working in ESLint v9. Please read the documentation for how to update your code: https://eslint.org/docs/latest/extend/code-path-analysis#usage-examples`,
|
413
|
-
"DeprecationWarning"
|
414
|
-
);
|
339
|
+
if (unsubstituted.length === 0) {
|
340
|
+
return [];
|
415
341
|
}
|
416
|
-
}
|
417
342
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
function emitParserServicesWarning(ruleName) {
|
424
|
-
if (!emitParserServicesWarning[`warned-${ruleName}`]) {
|
425
|
-
emitParserServicesWarning[`warned-${ruleName}`] = true;
|
426
|
-
process.emitWarning(
|
427
|
-
`"${ruleName}" rule is using \`context.parserServices\`, which is deprecated and will be removed in ESLint v9. Please use \`sourceCode.parserServices\` instead.`,
|
428
|
-
"DeprecationWarning"
|
429
|
-
);
|
430
|
-
}
|
343
|
+
// Remove false positives by only counting placeholders in the raw message, which were not provided in the data matcher or added with a data property
|
344
|
+
const known = getMessagePlaceholders(raw);
|
345
|
+
const provided = Object.keys(data);
|
346
|
+
|
347
|
+
return unsubstituted.filter(name => known.includes(name) && !provided.includes(name));
|
431
348
|
}
|
432
349
|
|
350
|
+
const metaSchemaDescription = `
|
351
|
+
\t- If the rule has options, set \`meta.schema\` to an array or non-empty object to enable options validation.
|
352
|
+
\t- If the rule doesn't have options, omit \`meta.schema\` to enforce that no options can be passed to the rule.
|
353
|
+
\t- You can also set \`meta.schema\` to \`false\` to opt-out of options validation (not recommended).
|
354
|
+
|
355
|
+
\thttps://eslint.org/docs/latest/extend/custom-rules#options-schemas
|
356
|
+
`;
|
433
357
|
|
434
358
|
//------------------------------------------------------------------------------
|
435
359
|
// Public Interface
|
@@ -479,26 +403,20 @@ class RuleTester {
|
|
479
403
|
* Creates a new instance of RuleTester.
|
480
404
|
* @param {Object} [testerConfig] Optional, extra configuration for the tester
|
481
405
|
*/
|
482
|
-
constructor(testerConfig) {
|
406
|
+
constructor(testerConfig = {}) {
|
483
407
|
|
484
408
|
/**
|
485
409
|
* The configuration to use for this tester. Combination of the tester
|
486
410
|
* configuration and the default configuration.
|
487
411
|
* @type {Object}
|
488
412
|
*/
|
489
|
-
this.testerConfig =
|
490
|
-
|
491
|
-
defaultConfig,
|
413
|
+
this.testerConfig = [
|
414
|
+
sharedDefaultConfig,
|
492
415
|
testerConfig,
|
493
416
|
{ rules: { "rule-tester/validate-ast": "error" } }
|
494
|
-
|
417
|
+
];
|
495
418
|
|
496
|
-
|
497
|
-
* Rule definitions to define before tests.
|
498
|
-
* @type {Object}
|
499
|
-
*/
|
500
|
-
this.rules = {};
|
501
|
-
this.linter = new Linter();
|
419
|
+
this.linter = new Linter({ configType: "flat" });
|
502
420
|
}
|
503
421
|
|
504
422
|
/**
|
@@ -511,10 +429,10 @@ class RuleTester {
|
|
511
429
|
if (typeof config !== "object" || config === null) {
|
512
430
|
throw new TypeError("RuleTester.setDefaultConfig: config must be an object");
|
513
431
|
}
|
514
|
-
|
432
|
+
sharedDefaultConfig = config;
|
515
433
|
|
516
434
|
// Make sure the rules object exists since it is assumed to exist later
|
517
|
-
|
435
|
+
sharedDefaultConfig.rules = sharedDefaultConfig.rules || {};
|
518
436
|
}
|
519
437
|
|
520
438
|
/**
|
@@ -522,7 +440,7 @@ class RuleTester {
|
|
522
440
|
* @returns {Object} the current configuration
|
523
441
|
*/
|
524
442
|
static getDefaultConfig() {
|
525
|
-
return
|
443
|
+
return sharedDefaultConfig;
|
526
444
|
}
|
527
445
|
|
528
446
|
/**
|
@@ -531,7 +449,11 @@ class RuleTester {
|
|
531
449
|
* @returns {void}
|
532
450
|
*/
|
533
451
|
static resetDefaultConfig() {
|
534
|
-
|
452
|
+
sharedDefaultConfig = {
|
453
|
+
rules: {
|
454
|
+
...testerDefaultConfig.rules
|
455
|
+
}
|
456
|
+
};
|
535
457
|
}
|
536
458
|
|
537
459
|
|
@@ -602,29 +524,17 @@ class RuleTester {
|
|
602
524
|
this[IT_ONLY] = value;
|
603
525
|
}
|
604
526
|
|
605
|
-
/**
|
606
|
-
* Define a rule for one particular run of tests.
|
607
|
-
* @param {string} name The name of the rule to define.
|
608
|
-
* @param {Function | Rule} rule The rule definition.
|
609
|
-
* @returns {void}
|
610
|
-
*/
|
611
|
-
defineRule(name, rule) {
|
612
|
-
if (typeof rule === "function") {
|
613
|
-
emitLegacyRuleAPIWarning(name);
|
614
|
-
}
|
615
|
-
this.rules[name] = rule;
|
616
|
-
}
|
617
527
|
|
618
528
|
/**
|
619
529
|
* Adds a new rule test to execute.
|
620
530
|
* @param {string} ruleName The name of the rule to run.
|
621
|
-
* @param {
|
531
|
+
* @param {Rule} rule The rule to test.
|
622
532
|
* @param {{
|
623
533
|
* valid: (ValidTestCase | string)[],
|
624
534
|
* invalid: InvalidTestCase[]
|
625
535
|
* }} test The collection of tests to run.
|
626
|
-
* @throws {TypeError|Error} If
|
627
|
-
* scenario of the given type is missing.
|
536
|
+
* @throws {TypeError|Error} If `rule` is not an object with a `create` method,
|
537
|
+
* or if non-object `test`, or if a required scenario of the given type is missing.
|
628
538
|
* @returns {void}
|
629
539
|
*/
|
630
540
|
run(ruleName, rule, test) {
|
@@ -632,7 +542,15 @@ class RuleTester {
|
|
632
542
|
const testerConfig = this.testerConfig,
|
633
543
|
requiredScenarios = ["valid", "invalid"],
|
634
544
|
scenarioErrors = [],
|
635
|
-
linter = this.linter
|
545
|
+
linter = this.linter,
|
546
|
+
ruleId = `rule-to-test/${ruleName}`;
|
547
|
+
|
548
|
+
const seenValidTestCases = new Set();
|
549
|
+
const seenInvalidTestCases = new Set();
|
550
|
+
|
551
|
+
if (!rule || typeof rule !== "object" || typeof rule.create !== "function") {
|
552
|
+
throw new TypeError("Rule must be an object with a `create` method");
|
553
|
+
}
|
636
554
|
|
637
555
|
if (!test || typeof test !== "object") {
|
638
556
|
throw new TypeError(`Test Scenarios for rule ${ruleName} : Could not find test scenario object`);
|
@@ -650,54 +568,55 @@ class RuleTester {
|
|
650
568
|
].concat(scenarioErrors).join("\n"));
|
651
569
|
}
|
652
570
|
|
653
|
-
|
654
|
-
|
655
|
-
|
571
|
+
const baseConfig = [
|
572
|
+
{ files: ["**"] }, // Make sure the default config matches for all files
|
573
|
+
{
|
574
|
+
plugins: {
|
656
575
|
|
657
|
-
|
658
|
-
|
659
|
-
// Create a wrapper rule that freezes the `context` properties.
|
660
|
-
create(context) {
|
661
|
-
freezeDeeply(context.options);
|
662
|
-
freezeDeeply(context.settings);
|
663
|
-
freezeDeeply(context.parserOptions);
|
664
|
-
|
665
|
-
// wrap all deprecated methods
|
666
|
-
const newContext = Object.create(
|
667
|
-
context,
|
668
|
-
Object.fromEntries(Object.keys(DEPRECATED_SOURCECODE_PASSTHROUGHS).map(methodName => [
|
669
|
-
methodName,
|
670
|
-
{
|
671
|
-
value(...args) {
|
672
|
-
|
673
|
-
// emit deprecation warning
|
674
|
-
emitDeprecatedContextMethodWarning(ruleName, methodName);
|
675
|
-
|
676
|
-
// call the original method
|
677
|
-
return context[methodName].call(this, ...args);
|
678
|
-
},
|
679
|
-
enumerable: true
|
680
|
-
}
|
681
|
-
]))
|
682
|
-
);
|
576
|
+
// copy root plugin over
|
577
|
+
"@": {
|
683
578
|
|
684
|
-
|
685
|
-
|
579
|
+
/*
|
580
|
+
* Parsers are wrapped to detect more errors, so this needs
|
581
|
+
* to be a new object for each call to run(), otherwise the
|
582
|
+
* parsers will be wrapped multiple times.
|
583
|
+
*/
|
584
|
+
parsers: {
|
585
|
+
...defaultConfig[0].plugins["@"].parsers
|
586
|
+
},
|
686
587
|
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
588
|
+
/*
|
589
|
+
* The rules key on the default plugin is a proxy to lazy-load
|
590
|
+
* just the rules that are needed. So, don't create a new object
|
591
|
+
* here, just use the default one to keep that performance
|
592
|
+
* enhancement.
|
593
|
+
*/
|
594
|
+
rules: defaultConfig[0].plugins["@"].rules
|
595
|
+
},
|
596
|
+
"rule-to-test": {
|
597
|
+
rules: {
|
598
|
+
[ruleName]: Object.assign({}, rule, {
|
693
599
|
|
694
|
-
|
600
|
+
// Create a wrapper rule that freezes the `context` properties.
|
601
|
+
create(context) {
|
602
|
+
freezeDeeply(context.options);
|
603
|
+
freezeDeeply(context.settings);
|
604
|
+
freezeDeeply(context.parserOptions);
|
695
605
|
|
696
|
-
|
697
|
-
}
|
698
|
-
}));
|
606
|
+
// freezeDeeply(context.languageOptions);
|
699
607
|
|
700
|
-
|
608
|
+
return rule.create(context);
|
609
|
+
}
|
610
|
+
})
|
611
|
+
}
|
612
|
+
}
|
613
|
+
},
|
614
|
+
languageOptions: {
|
615
|
+
...defaultConfig[0].languageOptions
|
616
|
+
}
|
617
|
+
},
|
618
|
+
...defaultConfig.slice(1)
|
619
|
+
];
|
701
620
|
|
702
621
|
/**
|
703
622
|
* Run the rule for the given item
|
@@ -707,8 +626,34 @@ class RuleTester {
|
|
707
626
|
* @private
|
708
627
|
*/
|
709
628
|
function runRuleForItem(item) {
|
710
|
-
|
711
|
-
|
629
|
+
const flatConfigArrayOptions = {
|
630
|
+
baseConfig
|
631
|
+
};
|
632
|
+
|
633
|
+
if (item.filename) {
|
634
|
+
flatConfigArrayOptions.basePath = path.parse(item.filename).root;
|
635
|
+
}
|
636
|
+
|
637
|
+
const configs = new FlatConfigArray(testerConfig, flatConfigArrayOptions);
|
638
|
+
|
639
|
+
/*
|
640
|
+
* Modify the returned config so that the parser is wrapped to catch
|
641
|
+
* access of the start/end properties. This method is called just
|
642
|
+
* once per code snippet being tested, so each test case gets a clean
|
643
|
+
* parser.
|
644
|
+
*/
|
645
|
+
configs[ConfigArraySymbol.finalizeConfig] = function(...args) {
|
646
|
+
|
647
|
+
// can't do super here :(
|
648
|
+
const proto = Object.getPrototypeOf(this);
|
649
|
+
const calculatedConfig = proto[ConfigArraySymbol.finalizeConfig].apply(this, args);
|
650
|
+
|
651
|
+
// wrap the parser to catch start/end property access
|
652
|
+
calculatedConfig.languageOptions.parser = wrapParser(calculatedConfig.languageOptions.parser);
|
653
|
+
return calculatedConfig;
|
654
|
+
};
|
655
|
+
|
656
|
+
let code, filename, output, beforeAST, afterAST;
|
712
657
|
|
713
658
|
if (typeof item === "string") {
|
714
659
|
code = item;
|
@@ -725,64 +670,97 @@ class RuleTester {
|
|
725
670
|
delete itemConfig[parameter];
|
726
671
|
}
|
727
672
|
|
673
|
+
// wrap any parsers
|
674
|
+
if (itemConfig.languageOptions && itemConfig.languageOptions.parser) {
|
675
|
+
|
676
|
+
const parser = itemConfig.languageOptions.parser;
|
677
|
+
|
678
|
+
if (parser && typeof parser !== "object") {
|
679
|
+
throw new Error("Parser must be an object with a parse() or parseForESLint() method.");
|
680
|
+
}
|
681
|
+
|
682
|
+
}
|
683
|
+
|
728
684
|
/*
|
729
685
|
* Create the config object from the tester config and this item
|
730
686
|
* specific configurations.
|
731
687
|
*/
|
732
|
-
|
733
|
-
config,
|
734
|
-
itemConfig
|
735
|
-
);
|
688
|
+
configs.push(itemConfig);
|
736
689
|
}
|
737
690
|
|
738
|
-
if (item
|
691
|
+
if (hasOwnProperty(item, "only")) {
|
692
|
+
assert.ok(typeof item.only === "boolean", "Optional test case property 'only' must be a boolean");
|
693
|
+
}
|
694
|
+
if (hasOwnProperty(item, "filename")) {
|
695
|
+
assert.ok(typeof item.filename === "string", "Optional test case property 'filename' must be a string");
|
739
696
|
filename = item.filename;
|
740
697
|
}
|
741
698
|
|
699
|
+
let ruleConfig = 1;
|
700
|
+
|
742
701
|
if (hasOwnProperty(item, "options")) {
|
743
702
|
assert(Array.isArray(item.options), "options must be an array");
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
) {
|
751
|
-
emitMissingSchemaWarning(ruleName);
|
703
|
+
ruleConfig = [1, ...item.options];
|
704
|
+
}
|
705
|
+
|
706
|
+
configs.push({
|
707
|
+
rules: {
|
708
|
+
[ruleId]: ruleConfig
|
752
709
|
}
|
753
|
-
|
754
|
-
|
755
|
-
|
710
|
+
});
|
711
|
+
|
712
|
+
let schema;
|
713
|
+
|
714
|
+
try {
|
715
|
+
schema = getRuleOptionsSchema(rule);
|
716
|
+
} catch (err) {
|
717
|
+
err.message += metaSchemaDescription;
|
718
|
+
throw err;
|
756
719
|
}
|
757
720
|
|
758
|
-
|
721
|
+
/*
|
722
|
+
* Check and throw an error if the schema is an empty object (`schema:{}`), because such schema
|
723
|
+
* doesn't validate or enforce anything and is therefore considered a possible error. If the intent
|
724
|
+
* was to skip options validation, `schema:false` should be set instead (explicit opt-out).
|
725
|
+
*
|
726
|
+
* For this purpose, a schema object is considered empty if it doesn't have any own enumerable string-keyed
|
727
|
+
* properties. While `ajv.compile()` does use enumerable properties from the prototype chain as well,
|
728
|
+
* it caches compiled schemas by serializing only own enumerable properties, so it's generally not a good idea
|
729
|
+
* to use inherited properties in schemas because schemas that differ only in inherited properties would end up
|
730
|
+
* having the same cache entry that would be correct for only one of them.
|
731
|
+
*
|
732
|
+
* At this point, `schema` can only be an object or `null`.
|
733
|
+
*/
|
734
|
+
if (schema && Object.keys(schema).length === 0) {
|
735
|
+
throw new Error(`\`schema: {}\` is a no-op${metaSchemaDescription}`);
|
736
|
+
}
|
759
737
|
|
760
738
|
/*
|
761
739
|
* Setup AST getters.
|
762
740
|
* The goal is to check whether or not AST was modified when
|
763
741
|
* running the rule under test.
|
764
742
|
*/
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
743
|
+
configs.push({
|
744
|
+
plugins: {
|
745
|
+
"rule-tester": {
|
746
|
+
rules: {
|
747
|
+
"validate-ast": {
|
748
|
+
create() {
|
749
|
+
return {
|
750
|
+
Program(node) {
|
751
|
+
beforeAST = cloneDeeplyExcludesParent(node);
|
752
|
+
},
|
753
|
+
"Program:exit"(node) {
|
754
|
+
afterAST = node;
|
755
|
+
}
|
756
|
+
};
|
757
|
+
}
|
758
|
+
}
|
773
759
|
}
|
774
|
-
}
|
760
|
+
}
|
775
761
|
}
|
776
762
|
});
|
777
763
|
|
778
|
-
if (typeof config.parser === "string") {
|
779
|
-
assert(path.isAbsolute(config.parser), "Parsers provided as strings to RuleTester must be absolute paths");
|
780
|
-
} else {
|
781
|
-
config.parser = espreePath;
|
782
|
-
}
|
783
|
-
|
784
|
-
linter.defineParser(config.parser, wrapParser(require(config.parser)));
|
785
|
-
|
786
764
|
if (schema) {
|
787
765
|
ajv.validateSchema(schema);
|
788
766
|
|
@@ -809,35 +787,32 @@ class RuleTester {
|
|
809
787
|
}
|
810
788
|
}
|
811
789
|
|
812
|
-
|
790
|
+
// check for validation errors
|
791
|
+
try {
|
792
|
+
configs.normalizeSync();
|
793
|
+
configs.getConfig("test.js");
|
794
|
+
} catch (error) {
|
795
|
+
error.message = `ESLint configuration in rule-tester is invalid: ${error.message}`;
|
796
|
+
throw error;
|
797
|
+
}
|
813
798
|
|
814
799
|
// Verify the code.
|
815
|
-
const {
|
816
|
-
const originalCurrentSegments = Object.getOwnPropertyDescriptor(CodePath.prototype, "currentSegments");
|
800
|
+
const { applyLanguageOptions, applyInlineConfig, finalize } = SourceCode.prototype;
|
817
801
|
let messages;
|
818
802
|
|
819
803
|
try {
|
820
|
-
SourceCode.prototype.getComments = getCommentsDeprecation;
|
821
|
-
Object.defineProperty(CodePath.prototype, "currentSegments", {
|
822
|
-
get() {
|
823
|
-
emitCodePathCurrentSegmentsWarning(ruleName);
|
824
|
-
return originalCurrentSegments.get.call(this);
|
825
|
-
}
|
826
|
-
});
|
827
|
-
|
828
804
|
forbiddenMethods.forEach(methodName => {
|
829
|
-
SourceCode.prototype[methodName] = throwForbiddenMethodError(methodName);
|
805
|
+
SourceCode.prototype[methodName] = throwForbiddenMethodError(methodName, SourceCode.prototype);
|
830
806
|
});
|
831
807
|
|
832
|
-
messages = linter.verify(code,
|
808
|
+
messages = linter.verify(code, configs, filename);
|
833
809
|
} finally {
|
834
|
-
SourceCode.prototype.getComments = getComments;
|
835
|
-
Object.defineProperty(CodePath.prototype, "currentSegments", originalCurrentSegments);
|
836
810
|
SourceCode.prototype.applyInlineConfig = applyInlineConfig;
|
837
811
|
SourceCode.prototype.applyLanguageOptions = applyLanguageOptions;
|
838
812
|
SourceCode.prototype.finalize = finalize;
|
839
813
|
}
|
840
814
|
|
815
|
+
|
841
816
|
const fatalErrorMessage = messages.find(m => m.fatal);
|
842
817
|
|
843
818
|
assert(!fatalErrorMessage, `A fatal parsing error occurred: ${fatalErrorMessage && fatalErrorMessage.message}`);
|
@@ -845,7 +820,7 @@ class RuleTester {
|
|
845
820
|
// Verify if autofix makes a syntax error or not.
|
846
821
|
if (messages.some(m => m.fix)) {
|
847
822
|
output = SourceCodeFixer.applyFixes(code, messages).output;
|
848
|
-
const errorMessageInFix = linter.verify(output,
|
823
|
+
const errorMessageInFix = linter.verify(output, configs, filename).find(m => m.fatal);
|
849
824
|
|
850
825
|
assert(!errorMessageInFix, [
|
851
826
|
"A fatal parsing error occurred in autofix.",
|
@@ -861,7 +836,9 @@ class RuleTester {
|
|
861
836
|
messages,
|
862
837
|
output,
|
863
838
|
beforeAST,
|
864
|
-
afterAST: cloneDeeplyExcludesParent(afterAST)
|
839
|
+
afterAST: cloneDeeplyExcludesParent(afterAST),
|
840
|
+
configs,
|
841
|
+
filename
|
865
842
|
};
|
866
843
|
}
|
867
844
|
|
@@ -878,6 +855,39 @@ class RuleTester {
|
|
878
855
|
}
|
879
856
|
}
|
880
857
|
|
858
|
+
/**
|
859
|
+
* Check if this test case is a duplicate of one we have seen before.
|
860
|
+
* @param {string|Object} item test case object
|
861
|
+
* @param {Set<string>} seenTestCases set of serialized test cases we have seen so far (managed by this function)
|
862
|
+
* @returns {void}
|
863
|
+
* @private
|
864
|
+
*/
|
865
|
+
function checkDuplicateTestCase(item, seenTestCases) {
|
866
|
+
if (!isSerializable(item)) {
|
867
|
+
|
868
|
+
/*
|
869
|
+
* If we can't serialize a test case (because it contains a function, RegExp, etc), skip the check.
|
870
|
+
* This might happen with properties like: options, plugins, settings, languageOptions.parser, languageOptions.parserOptions.
|
871
|
+
*/
|
872
|
+
return;
|
873
|
+
}
|
874
|
+
|
875
|
+
const normalizedItem = typeof item === "string" ? { code: item } : item;
|
876
|
+
const serializedTestCase = stringify(normalizedItem, {
|
877
|
+
replacer(key, value) {
|
878
|
+
|
879
|
+
// "this" is the currently stringified object --> only ignore top-level properties
|
880
|
+
return (normalizedItem !== this || !duplicationIgnoredParameters.has(key)) ? value : void 0;
|
881
|
+
}
|
882
|
+
});
|
883
|
+
|
884
|
+
assert(
|
885
|
+
!seenTestCases.has(serializedTestCase),
|
886
|
+
"detected duplicate test case"
|
887
|
+
);
|
888
|
+
seenTestCases.add(serializedTestCase);
|
889
|
+
}
|
890
|
+
|
881
891
|
/**
|
882
892
|
* Check if the template is valid or not
|
883
893
|
* all valid cases go through this
|
@@ -893,6 +903,8 @@ class RuleTester {
|
|
893
903
|
assert.ok(typeof item.name === "string", "Optional test case property 'name' must be a string");
|
894
904
|
}
|
895
905
|
|
906
|
+
checkDuplicateTestCase(item, seenValidTestCases);
|
907
|
+
|
896
908
|
const result = runRuleForItem(item);
|
897
909
|
const messages = result.messages;
|
898
910
|
|
@@ -944,12 +956,30 @@ class RuleTester {
|
|
944
956
|
assert.fail("Invalid cases must have at least one error");
|
945
957
|
}
|
946
958
|
|
959
|
+
checkDuplicateTestCase(item, seenInvalidTestCases);
|
960
|
+
|
947
961
|
const ruleHasMetaMessages = hasOwnProperty(rule, "meta") && hasOwnProperty(rule.meta, "messages");
|
948
962
|
const friendlyIDList = ruleHasMetaMessages ? `[${Object.keys(rule.meta.messages).map(key => `'${key}'`).join(", ")}]` : null;
|
949
963
|
|
950
964
|
const result = runRuleForItem(item);
|
951
965
|
const messages = result.messages;
|
952
966
|
|
967
|
+
for (const message of messages) {
|
968
|
+
if (hasOwnProperty(message, "suggestions")) {
|
969
|
+
|
970
|
+
/** @type {Map<string, number>} */
|
971
|
+
const seenMessageIndices = new Map();
|
972
|
+
|
973
|
+
for (let i = 0; i < message.suggestions.length; i += 1) {
|
974
|
+
const suggestionMessage = message.suggestions[i].desc;
|
975
|
+
const previous = seenMessageIndices.get(suggestionMessage);
|
976
|
+
|
977
|
+
assert.ok(!seenMessageIndices.has(suggestionMessage), `Suggestion message '${suggestionMessage}' reported from suggestion ${i} was previously reported by suggestion ${previous}. Suggestion messages should be unique within an error.`);
|
978
|
+
seenMessageIndices.set(suggestionMessage, i);
|
979
|
+
}
|
980
|
+
}
|
981
|
+
}
|
982
|
+
|
953
983
|
if (typeof item.errors === "number") {
|
954
984
|
|
955
985
|
if (item.errors === 0) {
|
@@ -972,7 +1002,7 @@ class RuleTester {
|
|
972
1002
|
)
|
973
1003
|
);
|
974
1004
|
|
975
|
-
const hasMessageOfThisRule = messages.some(m => m.ruleId ===
|
1005
|
+
const hasMessageOfThisRule = messages.some(m => m.ruleId === ruleId);
|
976
1006
|
|
977
1007
|
for (let i = 0, l = item.errors.length; i < l; i++) {
|
978
1008
|
const error = item.errors[i];
|
@@ -984,6 +1014,7 @@ class RuleTester {
|
|
984
1014
|
|
985
1015
|
// Just an error message.
|
986
1016
|
assertMessageMatches(message.message, error);
|
1017
|
+
assert.ok(message.suggestions === void 0, `Error at index ${i} has suggestions. Please convert the test error into an object and specify 'suggestions' property on it to test suggestions.`);
|
987
1018
|
} else if (typeof error === "object" && error !== null) {
|
988
1019
|
|
989
1020
|
/*
|
@@ -1016,6 +1047,18 @@ class RuleTester {
|
|
1016
1047
|
error.messageId,
|
1017
1048
|
`messageId '${message.messageId}' does not match expected messageId '${error.messageId}'.`
|
1018
1049
|
);
|
1050
|
+
|
1051
|
+
const unsubstitutedPlaceholders = getUnsubstitutedMessagePlaceholders(
|
1052
|
+
message.message,
|
1053
|
+
rule.meta.messages[message.messageId],
|
1054
|
+
error.data
|
1055
|
+
);
|
1056
|
+
|
1057
|
+
assert.ok(
|
1058
|
+
unsubstitutedPlaceholders.length === 0,
|
1059
|
+
`The reported message has ${unsubstitutedPlaceholders.length > 1 ? `unsubstituted placeholders: ${unsubstitutedPlaceholders.map(name => `'${name}'`).join(", ")}` : `an unsubstituted placeholder '${unsubstitutedPlaceholders[0]}'`}. Please provide the missing ${unsubstitutedPlaceholders.length > 1 ? "values" : "value"} via the 'data' property in the context.report() call.`
|
1060
|
+
);
|
1061
|
+
|
1019
1062
|
if (hasOwnProperty(error, "data")) {
|
1020
1063
|
|
1021
1064
|
/*
|
@@ -1032,13 +1075,10 @@ class RuleTester {
|
|
1032
1075
|
`Hydrated message "${rehydratedMessage}" does not match "${message.message}"`
|
1033
1076
|
);
|
1034
1077
|
}
|
1078
|
+
} else {
|
1079
|
+
assert.fail("Test error must specify either a 'messageId' or 'message'.");
|
1035
1080
|
}
|
1036
1081
|
|
1037
|
-
assert.ok(
|
1038
|
-
hasOwnProperty(error, "data") ? hasOwnProperty(error, "messageId") : true,
|
1039
|
-
"Error must specify 'messageId' if 'data' is used."
|
1040
|
-
);
|
1041
|
-
|
1042
1082
|
if (error.type) {
|
1043
1083
|
assert.strictEqual(message.nodeType, error.type, `Error type should be ${error.type}, found ${message.nodeType}`);
|
1044
1084
|
}
|
@@ -1059,81 +1099,117 @@ class RuleTester {
|
|
1059
1099
|
assert.strictEqual(message.endColumn, error.endColumn, `Error endColumn should be ${error.endColumn}`);
|
1060
1100
|
}
|
1061
1101
|
|
1102
|
+
assert.ok(!message.suggestions || hasOwnProperty(error, "suggestions"), `Error at index ${i} has suggestions. Please specify 'suggestions' property on the test error object.`);
|
1062
1103
|
if (hasOwnProperty(error, "suggestions")) {
|
1063
1104
|
|
1064
1105
|
// Support asserting there are no suggestions
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
assert.
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
)
|
1078
|
-
Object.keys(expectedSuggestion).forEach(propertyName => {
|
1079
|
-
assert.ok(
|
1080
|
-
suggestionObjectParameters.has(propertyName),
|
1081
|
-
`Invalid suggestion property name '${propertyName}'. Expected one of ${friendlySuggestionObjectParameterList}.`
|
1082
|
-
);
|
1083
|
-
});
|
1084
|
-
|
1085
|
-
const actualSuggestion = message.suggestions[index];
|
1086
|
-
const suggestionPrefix = `Error Suggestion at index ${index} :`;
|
1087
|
-
|
1088
|
-
if (hasOwnProperty(expectedSuggestion, "desc")) {
|
1106
|
+
const expectsSuggestions = Array.isArray(error.suggestions) ? error.suggestions.length > 0 : Boolean(error.suggestions);
|
1107
|
+
const hasSuggestions = message.suggestions !== void 0;
|
1108
|
+
|
1109
|
+
if (!hasSuggestions && expectsSuggestions) {
|
1110
|
+
assert.ok(!error.suggestions, `Error should have suggestions on error with message: "${message.message}"`);
|
1111
|
+
} else if (hasSuggestions) {
|
1112
|
+
assert.ok(expectsSuggestions, `Error should have no suggestions on error with message: "${message.message}"`);
|
1113
|
+
if (typeof error.suggestions === "number") {
|
1114
|
+
assert.strictEqual(message.suggestions.length, error.suggestions, `Error should have ${error.suggestions} suggestions. Instead found ${message.suggestions.length} suggestions`);
|
1115
|
+
} else if (Array.isArray(error.suggestions)) {
|
1116
|
+
assert.strictEqual(message.suggestions.length, error.suggestions.length, `Error should have ${error.suggestions.length} suggestions. Instead found ${message.suggestions.length} suggestions`);
|
1117
|
+
|
1118
|
+
error.suggestions.forEach((expectedSuggestion, index) => {
|
1089
1119
|
assert.ok(
|
1090
|
-
|
1091
|
-
|
1092
|
-
);
|
1093
|
-
assert.strictEqual(
|
1094
|
-
actualSuggestion.desc,
|
1095
|
-
expectedSuggestion.desc,
|
1096
|
-
`${suggestionPrefix} desc should be "${expectedSuggestion.desc}" but got "${actualSuggestion.desc}" instead.`
|
1120
|
+
typeof expectedSuggestion === "object" && expectedSuggestion !== null,
|
1121
|
+
"Test suggestion in 'suggestions' array must be an object."
|
1097
1122
|
);
|
1098
|
-
|
1123
|
+
Object.keys(expectedSuggestion).forEach(propertyName => {
|
1124
|
+
assert.ok(
|
1125
|
+
suggestionObjectParameters.has(propertyName),
|
1126
|
+
`Invalid suggestion property name '${propertyName}'. Expected one of ${friendlySuggestionObjectParameterList}.`
|
1127
|
+
);
|
1128
|
+
});
|
1099
1129
|
|
1100
|
-
|
1101
|
-
|
1102
|
-
ruleHasMetaMessages,
|
1103
|
-
`${suggestionPrefix} Test can not use 'messageId' if rule under test doesn't define 'meta.messages'.`
|
1104
|
-
);
|
1105
|
-
assert.ok(
|
1106
|
-
hasOwnProperty(rule.meta.messages, expectedSuggestion.messageId),
|
1107
|
-
`${suggestionPrefix} Test has invalid messageId '${expectedSuggestion.messageId}', the rule under test allows only one of ${friendlyIDList}.`
|
1108
|
-
);
|
1109
|
-
assert.strictEqual(
|
1110
|
-
actualSuggestion.messageId,
|
1111
|
-
expectedSuggestion.messageId,
|
1112
|
-
`${suggestionPrefix} messageId should be '${expectedSuggestion.messageId}' but got '${actualSuggestion.messageId}' instead.`
|
1113
|
-
);
|
1114
|
-
if (hasOwnProperty(expectedSuggestion, "data")) {
|
1115
|
-
const unformattedMetaMessage = rule.meta.messages[expectedSuggestion.messageId];
|
1116
|
-
const rehydratedDesc = interpolate(unformattedMetaMessage, expectedSuggestion.data);
|
1130
|
+
const actualSuggestion = message.suggestions[index];
|
1131
|
+
const suggestionPrefix = `Error Suggestion at index ${index}:`;
|
1117
1132
|
|
1133
|
+
if (hasOwnProperty(expectedSuggestion, "desc")) {
|
1134
|
+
assert.ok(
|
1135
|
+
!hasOwnProperty(expectedSuggestion, "data"),
|
1136
|
+
`${suggestionPrefix} Test should not specify both 'desc' and 'data'.`
|
1137
|
+
);
|
1138
|
+
assert.ok(
|
1139
|
+
!hasOwnProperty(expectedSuggestion, "messageId"),
|
1140
|
+
`${suggestionPrefix} Test should not specify both 'desc' and 'messageId'.`
|
1141
|
+
);
|
1118
1142
|
assert.strictEqual(
|
1119
1143
|
actualSuggestion.desc,
|
1120
|
-
|
1121
|
-
`${suggestionPrefix}
|
1144
|
+
expectedSuggestion.desc,
|
1145
|
+
`${suggestionPrefix} desc should be "${expectedSuggestion.desc}" but got "${actualSuggestion.desc}" instead.`
|
1146
|
+
);
|
1147
|
+
} else if (hasOwnProperty(expectedSuggestion, "messageId")) {
|
1148
|
+
assert.ok(
|
1149
|
+
ruleHasMetaMessages,
|
1150
|
+
`${suggestionPrefix} Test can not use 'messageId' if rule under test doesn't define 'meta.messages'.`
|
1151
|
+
);
|
1152
|
+
assert.ok(
|
1153
|
+
hasOwnProperty(rule.meta.messages, expectedSuggestion.messageId),
|
1154
|
+
`${suggestionPrefix} Test has invalid messageId '${expectedSuggestion.messageId}', the rule under test allows only one of ${friendlyIDList}.`
|
1155
|
+
);
|
1156
|
+
assert.strictEqual(
|
1157
|
+
actualSuggestion.messageId,
|
1158
|
+
expectedSuggestion.messageId,
|
1159
|
+
`${suggestionPrefix} messageId should be '${expectedSuggestion.messageId}' but got '${actualSuggestion.messageId}' instead.`
|
1160
|
+
);
|
1161
|
+
|
1162
|
+
const unsubstitutedPlaceholders = getUnsubstitutedMessagePlaceholders(
|
1163
|
+
actualSuggestion.desc,
|
1164
|
+
rule.meta.messages[expectedSuggestion.messageId],
|
1165
|
+
expectedSuggestion.data
|
1166
|
+
);
|
1167
|
+
|
1168
|
+
assert.ok(
|
1169
|
+
unsubstitutedPlaceholders.length === 0,
|
1170
|
+
`The message of the suggestion has ${unsubstitutedPlaceholders.length > 1 ? `unsubstituted placeholders: ${unsubstitutedPlaceholders.map(name => `'${name}'`).join(", ")}` : `an unsubstituted placeholder '${unsubstitutedPlaceholders[0]}'`}. Please provide the missing ${unsubstitutedPlaceholders.length > 1 ? "values" : "value"} via the 'data' property for the suggestion in the context.report() call.`
|
1171
|
+
);
|
1172
|
+
|
1173
|
+
if (hasOwnProperty(expectedSuggestion, "data")) {
|
1174
|
+
const unformattedMetaMessage = rule.meta.messages[expectedSuggestion.messageId];
|
1175
|
+
const rehydratedDesc = interpolate(unformattedMetaMessage, expectedSuggestion.data);
|
1176
|
+
|
1177
|
+
assert.strictEqual(
|
1178
|
+
actualSuggestion.desc,
|
1179
|
+
rehydratedDesc,
|
1180
|
+
`${suggestionPrefix} Hydrated test desc "${rehydratedDesc}" does not match received desc "${actualSuggestion.desc}".`
|
1181
|
+
);
|
1182
|
+
}
|
1183
|
+
} else if (hasOwnProperty(expectedSuggestion, "data")) {
|
1184
|
+
assert.fail(
|
1185
|
+
`${suggestionPrefix} Test must specify 'messageId' if 'data' is used.`
|
1186
|
+
);
|
1187
|
+
} else {
|
1188
|
+
assert.fail(
|
1189
|
+
`${suggestionPrefix} Test must specify either 'messageId' or 'desc'.`
|
1122
1190
|
);
|
1123
1191
|
}
|
1124
|
-
} else {
|
1125
|
-
assert.ok(
|
1126
|
-
!hasOwnProperty(expectedSuggestion, "data"),
|
1127
|
-
`${suggestionPrefix} Test must specify 'messageId' if 'data' is used.`
|
1128
|
-
);
|
1129
|
-
}
|
1130
1192
|
|
1131
|
-
|
1193
|
+
assert.ok(hasOwnProperty(expectedSuggestion, "output"), `${suggestionPrefix} The "output" property is required.`);
|
1132
1194
|
const codeWithAppliedSuggestion = SourceCodeFixer.applyFixes(item.code, [actualSuggestion]).output;
|
1133
1195
|
|
1196
|
+
// Verify if suggestion fix makes a syntax error or not.
|
1197
|
+
const errorMessageInSuggestion =
|
1198
|
+
linter.verify(codeWithAppliedSuggestion, result.configs, result.filename).find(m => m.fatal);
|
1199
|
+
|
1200
|
+
assert(!errorMessageInSuggestion, [
|
1201
|
+
"A fatal parsing error occurred in suggestion fix.",
|
1202
|
+
`Error: ${errorMessageInSuggestion && errorMessageInSuggestion.message}`,
|
1203
|
+
"Suggestion output:",
|
1204
|
+
codeWithAppliedSuggestion
|
1205
|
+
].join("\n"));
|
1206
|
+
|
1134
1207
|
assert.strictEqual(codeWithAppliedSuggestion, expectedSuggestion.output, `Expected the applied suggestion fix to match the test suggestion output for suggestion at index: ${index} on error with message: "${message.message}"`);
|
1135
|
-
|
1136
|
-
|
1208
|
+
assert.notStrictEqual(expectedSuggestion.output, item.code, `The output of a suggestion should differ from the original source code for suggestion at index: ${index} on error with message: "${message.message}"`);
|
1209
|
+
});
|
1210
|
+
} else {
|
1211
|
+
assert.fail("Test error object property 'suggestions' should be an array or a number");
|
1212
|
+
}
|
1137
1213
|
}
|
1138
1214
|
}
|
1139
1215
|
} else {
|
@@ -1153,6 +1229,7 @@ class RuleTester {
|
|
1153
1229
|
);
|
1154
1230
|
} else {
|
1155
1231
|
assert.strictEqual(result.output, item.output, "Output is incorrect.");
|
1232
|
+
assert.notStrictEqual(item.code, item.output, "Test property 'output' matches 'code'. If no autofix is expected, then omit the 'output' property or set it to null.");
|
1156
1233
|
}
|
1157
1234
|
} else {
|
1158
1235
|
assert.strictEqual(
|