From e313c0286b1c1a7267516a7b2b4c01fa76c71ec0 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 6 Aug 2016 12:11:02 -0700 Subject: [PATCH] tools: update to ESLint 3.2.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/7999 Reviewed-By: Colin Ihrig Reviewed-By: Roman Reiss Reviewed-By: James M Snell Reviewed-By: Johan Bergström --- Makefile | 2 +- tools/eslint/README.md | 10 +- tools/eslint/bin/eslint.js | 80 - tools/eslint/conf/category-list.json | 35 + tools/eslint/conf/environments.js | 2 +- tools/eslint/conf/eslint-all.js | 10 +- tools/eslint/conf/eslint.json | 2 + tools/eslint/lib/ast-utils.js | 66 +- tools/eslint/lib/cli-engine.js | 97 +- tools/eslint/lib/cli.js | 10 +- .../code-path-analysis/code-path-analyzer.js | 49 +- .../code-path-analysis/code-path-segment.js | 20 +- .../lib/code-path-analysis/code-path-state.js | 239 +- .../lib/code-path-analysis/code-path.js | 34 +- .../lib/code-path-analysis/debug-helpers.js | 34 +- .../lib/code-path-analysis/fork-context.js | 28 +- tools/eslint/lib/config.js | 20 +- tools/eslint/lib/config/autoconfig.js | 34 +- tools/eslint/lib/config/config-file.js | 40 +- tools/eslint/lib/config/config-initializer.js | 36 +- tools/eslint/lib/config/config-ops.js | 22 +- tools/eslint/lib/config/config-rule.js | 30 +- tools/eslint/lib/config/config-validator.js | 16 +- tools/eslint/lib/config/environments.js | 22 +- tools/eslint/lib/config/plugins.js | 10 +- tools/eslint/lib/eslint.js | 129 +- tools/eslint/lib/file-finder.js | 12 +- tools/eslint/lib/formatters/checkstyle.js | 33 +- tools/eslint/lib/formatters/compact.js | 6 +- tools/eslint/lib/formatters/html.js | 20 +- tools/eslint/lib/formatters/jslint-xml.js | 10 +- tools/eslint/lib/formatters/junit.js | 14 +- tools/eslint/lib/formatters/stylish.js | 8 +- tools/eslint/lib/formatters/table.js | 10 +- tools/eslint/lib/formatters/tap.js | 22 +- tools/eslint/lib/formatters/unix.js | 8 +- tools/eslint/lib/formatters/visualstudio.js | 6 +- tools/eslint/lib/ignored-paths.js | 30 +- .../internal-no-invalid-meta.js | 212 + tools/eslint/lib/load-rules.js | 4 +- tools/eslint/lib/options.js | 2 +- tools/eslint/lib/rule-context.js | 6 +- tools/eslint/lib/rules.js | 8 +- tools/eslint/lib/rules/.eslintrc.yml | 2 + tools/eslint/lib/rules/accessor-pairs.js | 24 +- .../eslint/lib/rules/array-bracket-spacing.js | 24 +- .../eslint/lib/rules/array-callback-return.js | 15 +- tools/eslint/lib/rules/arrow-body-style.js | 14 +- tools/eslint/lib/rules/arrow-parens.js | 16 +- tools/eslint/lib/rules/arrow-spacing.js | 26 +- tools/eslint/lib/rules/block-scoped-var.js | 12 +- tools/eslint/lib/rules/block-spacing.js | 12 +- tools/eslint/lib/rules/brace-style.js | 18 +- tools/eslint/lib/rules/callback-return.js | 8 +- tools/eslint/lib/rules/camelcase.js | 8 +- tools/eslint/lib/rules/comma-dangle.js | 22 +- tools/eslint/lib/rules/comma-spacing.js | 20 +- tools/eslint/lib/rules/comma-style.js | 12 +- tools/eslint/lib/rules/complexity.js | 6 +- .../lib/rules/computed-property-spacing.js | 20 +- tools/eslint/lib/rules/consistent-return.js | 14 +- tools/eslint/lib/rules/consistent-this.js | 16 +- tools/eslint/lib/rules/constructor-super.js | 60 +- tools/eslint/lib/rules/curly.js | 30 +- tools/eslint/lib/rules/default-case.js | 16 +- tools/eslint/lib/rules/dot-location.js | 10 +- tools/eslint/lib/rules/dot-notation.js | 10 +- tools/eslint/lib/rules/eol-last.js | 2 +- tools/eslint/lib/rules/eqeqeq.js | 6 +- tools/eslint/lib/rules/func-names.js | 24 +- tools/eslint/lib/rules/func-style.js | 6 +- .../lib/rules/generator-star-spacing.js | 18 +- tools/eslint/lib/rules/global-require.js | 8 +- tools/eslint/lib/rules/guard-for-in.js | 2 +- tools/eslint/lib/rules/handle-callback-err.js | 10 +- tools/eslint/lib/rules/id-blacklist.js | 10 +- tools/eslint/lib/rules/id-length.js | 26 +- tools/eslint/lib/rules/id-match.js | 12 +- tools/eslint/lib/rules/indent.js | 220 +- tools/eslint/lib/rules/init-declarations.js | 16 +- tools/eslint/lib/rules/jsx-quotes.js | 8 +- tools/eslint/lib/rules/key-spacing.js | 213 +- tools/eslint/lib/rules/keyword-spacing.js | 72 +- tools/eslint/lib/rules/linebreak-style.js | 10 +- .../eslint/lib/rules/lines-around-comment.js | 48 +- tools/eslint/lib/rules/max-depth.js | 4 +- tools/eslint/lib/rules/max-len.js | 31 +- tools/eslint/lib/rules/max-lines.js | 26 +- .../eslint/lib/rules/max-nested-callbacks.js | 8 +- tools/eslint/lib/rules/max-params.js | 2 +- .../lib/rules/max-statements-per-line.js | 10 +- tools/eslint/lib/rules/max-statements.js | 8 +- tools/eslint/lib/rules/multiline-ternary.js | 66 + tools/eslint/lib/rules/new-cap.js | 42 +- tools/eslint/lib/rules/new-parens.js | 8 +- tools/eslint/lib/rules/newline-after-var.js | 14 +- .../eslint/lib/rules/newline-before-return.js | 10 +- .../lib/rules/newline-per-chained-call.js | 16 +- tools/eslint/lib/rules/no-alert.js | 8 +- tools/eslint/lib/rules/no-bitwise.js | 8 +- tools/eslint/lib/rules/no-caller.js | 2 +- .../eslint/lib/rules/no-case-declarations.js | 4 +- tools/eslint/lib/rules/no-catch-shadow.js | 6 +- tools/eslint/lib/rules/no-class-assign.js | 2 +- tools/eslint/lib/rules/no-cond-assign.js | 14 +- tools/eslint/lib/rules/no-confusing-arrow.js | 8 +- tools/eslint/lib/rules/no-console.js | 8 +- tools/eslint/lib/rules/no-const-assign.js | 2 +- .../eslint/lib/rules/no-constant-condition.js | 15 +- tools/eslint/lib/rules/no-continue.js | 2 +- tools/eslint/lib/rules/no-control-regex.js | 14 +- tools/eslint/lib/rules/no-div-regex.js | 4 +- tools/eslint/lib/rules/no-dupe-args.js | 8 +- .../eslint/lib/rules/no-dupe-class-members.js | 14 +- tools/eslint/lib/rules/no-dupe-keys.js | 4 +- tools/eslint/lib/rules/no-duplicate-case.js | 6 +- .../eslint/lib/rules/no-duplicate-imports.js | 8 +- tools/eslint/lib/rules/no-else-return.js | 4 +- .../lib/rules/no-empty-character-class.js | 6 +- tools/eslint/lib/rules/no-empty-function.js | 18 +- tools/eslint/lib/rules/no-empty.js | 14 +- tools/eslint/lib/rules/no-eq-null.js | 2 +- tools/eslint/lib/rules/no-eval.js | 48 +- tools/eslint/lib/rules/no-ex-assign.js | 2 +- tools/eslint/lib/rules/no-extend-native.js | 12 +- tools/eslint/lib/rules/no-extra-bind.js | 6 +- .../eslint/lib/rules/no-extra-boolean-cast.js | 8 +- tools/eslint/lib/rules/no-extra-label.js | 10 +- tools/eslint/lib/rules/no-extra-parens.js | 34 +- tools/eslint/lib/rules/no-extra-semi.js | 6 +- tools/eslint/lib/rules/no-fallthrough.js | 20 +- tools/eslint/lib/rules/no-func-assign.js | 2 +- .../eslint/lib/rules/no-implicit-coercion.js | 16 +- tools/eslint/lib/rules/no-implicit-globals.js | 4 +- tools/eslint/lib/rules/no-implied-eval.js | 10 +- tools/eslint/lib/rules/no-inline-comments.js | 14 +- .../eslint/lib/rules/no-inner-declarations.js | 4 +- tools/eslint/lib/rules/no-invalid-regexp.js | 10 +- tools/eslint/lib/rules/no-invalid-this.js | 10 +- .../lib/rules/no-irregular-whitespace.js | 46 +- tools/eslint/lib/rules/no-label-var.js | 6 +- tools/eslint/lib/rules/no-labels.js | 20 +- tools/eslint/lib/rules/no-lone-blocks.js | 8 +- tools/eslint/lib/rules/no-lonely-if.js | 2 +- tools/eslint/lib/rules/no-loop-func.js | 24 +- tools/eslint/lib/rules/no-magic-numbers.js | 8 +- tools/eslint/lib/rules/no-mixed-operators.js | 46 +- tools/eslint/lib/rules/no-mixed-requires.js | 16 +- .../lib/rules/no-mixed-spaces-and-tabs.js | 10 +- tools/eslint/lib/rules/no-multi-spaces.js | 8 +- tools/eslint/lib/rules/no-multi-str.js | 2 +- .../lib/rules/no-multiple-empty-lines.js | 14 +- tools/eslint/lib/rules/no-native-reassign.js | 8 +- tools/eslint/lib/rules/no-negated-in-lhs.js | 2 +- tools/eslint/lib/rules/no-nested-ternary.js | 2 +- tools/eslint/lib/rules/no-new-symbol.js | 6 +- tools/eslint/lib/rules/no-new-wrappers.js | 2 +- tools/eslint/lib/rules/no-obj-calls.js | 2 +- tools/eslint/lib/rules/no-octal-escape.js | 2 +- tools/eslint/lib/rules/no-param-reassign.js | 10 +- tools/eslint/lib/rules/no-path-concat.js | 4 +- tools/eslint/lib/rules/no-plusplus.js | 2 +- tools/eslint/lib/rules/no-process-env.js | 2 +- tools/eslint/lib/rules/no-process-exit.js | 2 +- .../eslint/lib/rules/no-prototype-builtins.js | 8 +- tools/eslint/lib/rules/no-redeclare.js | 12 +- tools/eslint/lib/rules/no-regex-spaces.js | 6 +- .../eslint/lib/rules/no-restricted-globals.js | 7 +- .../eslint/lib/rules/no-restricted-imports.js | 4 +- .../eslint/lib/rules/no-restricted-modules.js | 10 +- .../eslint/lib/rules/no-restricted-syntax.js | 2 +- tools/eslint/lib/rules/no-return-assign.js | 12 +- tools/eslint/lib/rules/no-script-url.js | 2 +- tools/eslint/lib/rules/no-self-assign.js | 10 +- tools/eslint/lib/rules/no-self-compare.js | 2 +- tools/eslint/lib/rules/no-sequences.js | 10 +- .../lib/rules/no-shadow-restricted-names.js | 2 +- tools/eslint/lib/rules/no-shadow.js | 40 +- tools/eslint/lib/rules/no-spaced-func.js | 4 +- tools/eslint/lib/rules/no-sparse-arrays.js | 2 +- tools/eslint/lib/rules/no-sync.js | 2 +- tools/eslint/lib/rules/no-tabs.js | 47 + .../eslint/lib/rules/no-this-before-super.js | 30 +- tools/eslint/lib/rules/no-throw-literal.js | 5 +- tools/eslint/lib/rules/no-trailing-spaces.js | 14 +- tools/eslint/lib/rules/no-undef-init.js | 2 +- tools/eslint/lib/rules/no-undef.js | 10 +- tools/eslint/lib/rules/no-undefined.js | 2 +- .../eslint/lib/rules/no-underscore-dangle.js | 22 +- .../lib/rules/no-unexpected-multiline.js | 12 +- .../lib/rules/no-unmodified-loop-condition.js | 65 +- tools/eslint/lib/rules/no-unneeded-ternary.js | 8 +- tools/eslint/lib/rules/no-unreachable.js | 116 +- tools/eslint/lib/rules/no-unsafe-finally.js | 22 +- .../eslint/lib/rules/no-unused-expressions.js | 10 +- tools/eslint/lib/rules/no-unused-labels.js | 6 +- tools/eslint/lib/rules/no-unused-vars.js | 116 +- .../eslint/lib/rules/no-use-before-define.js | 40 +- tools/eslint/lib/rules/no-useless-call.js | 16 +- .../lib/rules/no-useless-computed-key.js | 10 +- tools/eslint/lib/rules/no-useless-concat.js | 14 +- .../lib/rules/no-useless-constructor.js | 8 +- tools/eslint/lib/rules/no-useless-escape.js | 14 +- tools/eslint/lib/rules/no-useless-rename.js | 6 +- tools/eslint/lib/rules/no-var.js | 135 +- tools/eslint/lib/rules/no-warning-comments.js | 14 +- .../rules/no-whitespace-before-property.js | 12 +- .../eslint/lib/rules/object-curly-newline.js | 38 +- .../eslint/lib/rules/object-curly-spacing.js | 32 +- .../lib/rules/object-property-newline.js | 18 +- tools/eslint/lib/rules/object-shorthand.js | 20 +- .../lib/rules/one-var-declaration-per-line.js | 8 +- tools/eslint/lib/rules/one-var.js | 28 +- tools/eslint/lib/rules/operator-assignment.js | 2 +- tools/eslint/lib/rules/operator-linebreak.js | 26 +- tools/eslint/lib/rules/padded-blocks.js | 20 +- .../eslint/lib/rules/prefer-arrow-callback.js | 34 +- tools/eslint/lib/rules/prefer-const.js | 63 +- tools/eslint/lib/rules/prefer-reflect.js | 22 +- tools/eslint/lib/rules/prefer-rest-params.js | 8 +- tools/eslint/lib/rules/prefer-spread.js | 16 +- tools/eslint/lib/rules/prefer-template.js | 6 +- tools/eslint/lib/rules/quote-props.js | 12 +- tools/eslint/lib/rules/quotes.js | 27 +- tools/eslint/lib/rules/radix.js | 16 +- tools/eslint/lib/rules/require-jsdoc.js | 12 +- tools/eslint/lib/rules/require-yield.js | 4 +- tools/eslint/lib/rules/rest-spread-spacing.js | 8 +- tools/eslint/lib/rules/semi-spacing.js | 22 +- tools/eslint/lib/rules/semi.js | 18 +- tools/eslint/lib/rules/sort-imports.js | 14 +- tools/eslint/lib/rules/sort-vars.js | 6 +- tools/eslint/lib/rules/space-before-blocks.js | 8 +- .../lib/rules/space-before-function-paren.js | 6 +- tools/eslint/lib/rules/space-in-parens.js | 10 +- tools/eslint/lib/rules/space-infix-ops.js | 32 +- tools/eslint/lib/rules/space-unary-ops.js | 30 +- tools/eslint/lib/rules/spaced-comment.js | 172 +- tools/eslint/lib/rules/strict.js | 16 +- .../lib/rules/template-curly-spacing.js | 18 +- tools/eslint/lib/rules/unicode-bom.js | 2 +- tools/eslint/lib/rules/valid-jsdoc.js | 24 +- tools/eslint/lib/rules/valid-typeof.js | 6 +- tools/eslint/lib/rules/vars-on-top.js | 16 +- tools/eslint/lib/rules/wrap-iife.js | 8 +- tools/eslint/lib/rules/wrap-regex.js | 4 +- tools/eslint/lib/rules/yield-star-spacing.js | 22 +- tools/eslint/lib/rules/yoda.js | 30 +- .../lib/testers/event-generator-tester.js | 8 +- tools/eslint/lib/testers/rule-tester.js | 62 +- tools/eslint/lib/timing.js | 24 +- tools/eslint/lib/token-store.js | 14 +- .../lib/util/comment-event-generator.js | 6 +- tools/eslint/lib/util/glob-util.js | 26 +- tools/eslint/lib/util/hash.js | 2 +- tools/eslint/lib/util/module-resolver.js | 8 +- tools/eslint/lib/util/npm-util.js | 12 +- tools/eslint/lib/util/path-util.js | 8 +- tools/eslint/lib/util/source-code-fixer.js | 18 +- tools/eslint/lib/util/source-code-util.js | 16 +- tools/eslint/lib/util/source-code.js | 16 +- tools/eslint/lib/util/traverser.js | 6 +- tools/eslint/lib/util/xml-escape.js | 34 + .../node_modules/acorn-jsx/package.json | 23 +- tools/eslint/node_modules/acorn/AUTHORS | 6 +- tools/eslint/node_modules/acorn/bin/acorn | 94 +- .../node_modules/acorn/bin/build-acorn.js | 82 - .../acorn/bin/generate-identifier-regex.js | 12 +- .../node_modules/acorn/dist/acorn.es.js | 3112 +++++++++ tools/eslint/node_modules/acorn/dist/acorn.js | 6012 ++++++++--------- .../node_modules/acorn/dist/acorn_loose.es.js | 1261 ++++ .../node_modules/acorn/dist/acorn_loose.js | 2305 ++++--- .../eslint/node_modules/acorn/dist/walk.es.js | 342 + tools/eslint/node_modules/acorn/dist/walk.js | 693 +- tools/eslint/node_modules/acorn/package.json | 86 +- .../node_modules/acorn/rollup/config.bin.js | 15 + .../node_modules/acorn/rollup/config.loose.js | 20 + .../node_modules/acorn/rollup/config.main.js | 11 + .../node_modules/acorn/rollup/config.walk.js | 11 + .../node_modules/acorn/src/bin/acorn.js | 4 +- .../node_modules/acorn/src/expression.js | 14 +- .../node_modules/acorn/src/identifier.js | 8 +- tools/eslint/node_modules/acorn/src/index.js | 2 +- .../acorn/src/loose/acorn_loose.js | 0 .../acorn/src/loose/expression.js | 2 +- .../node_modules/acorn/src/loose/index.js | 2 +- .../node_modules/acorn/src/loose/state.js | 2 +- .../node_modules/acorn/src/loose/statement.js | 2 +- .../node_modules/acorn/src/loose/tokenize.js | 2 +- tools/eslint/node_modules/acorn/src/lval.js | 4 +- .../node_modules/acorn/src/statement.js | 2 +- .../node_modules/acorn/src/tokencontext.js | 2 +- .../node_modules/acorn/src/tokentype.js | 93 +- .../node_modules/ansi-escapes/package.json | 25 +- .../node_modules/ansi-regex/package.json | 31 +- .../node_modules/ansi-styles/package.json | 27 +- .../eslint/node_modules/argparse/package.json | 23 +- .../node_modules/array-union/package.json | 25 +- .../node_modules/array-uniq/package.json | 25 +- tools/eslint/node_modules/arrify/package.json | 27 +- .../node_modules/balanced-match/README.md | 4 +- .../node_modules/balanced-match/index.js | 2 +- .../node_modules/balanced-match/package.json | 53 +- .../eslint/node_modules/bluebird/package.json | 25 +- .../node_modules/brace-expansion/index.js | 10 + .../node_modules/brace-expansion/package.json | 55 +- .../node_modules/caller-path/package.json | 25 +- .../node_modules/callsites/package.json | 25 +- tools/eslint/node_modules/chalk/package.json | 31 +- .../node_modules/circular-json/LICENSE.txt | 19 + .../node_modules/circular-json/README.md | 135 + .../circular-json/build/circular-json.js | 2 + .../circular-json/build/circular-json.max.js | 189 + .../circular-json/build/circular-json.node.js | 185 + .../node_modules/circular-json/package.json | 97 + .../circular-json/template/license.after | 2 + .../circular-json/template/license.before | 1 + .../node_modules/cli-cursor/package.json | 25 +- .../node_modules/cli-width/package.json | 29 +- .../node_modules/code-point-at/package.json | 25 +- .../node_modules/concat-map/package.json | 51 +- .../node_modules/concat-stream/package.json | 31 +- .../node_modules/core-util-is/package.json | 25 +- tools/eslint/node_modules/d/package.json | 25 +- tools/eslint/node_modules/debug/package.json | 37 +- .../eslint/node_modules/deep-is/package.json | 55 +- tools/eslint/node_modules/del/package.json | 25 +- .../node_modules/esutils/package.json | 25 +- .../eslint/node_modules/doctrine/package.json | 27 +- .../eslint/node_modules/es5-ext/package.json | 25 +- .../node_modules/es6-iterator/package.json | 25 +- .../eslint/node_modules/es6-map/package.json | 32 +- .../eslint/node_modules/es6-set/package.json | 25 +- .../node_modules/es6-symbol/package.json | 25 +- .../node_modules/es6-weak-map/package.json | 27 +- .../escape-string-regexp/package.json | 29 +- tools/eslint/node_modules/escope/package.json | 31 +- tools/eslint/node_modules/espree/package.json | 58 +- .../eslint/node_modules/esprima/package.json | 27 +- .../node_modules/estraverse/package.json | 33 +- .../node_modules/esrecurse/package.json | 31 +- .../node_modules/estraverse/package.json | 33 +- .../eslint/node_modules/esutils/package.json | 29 +- .../node_modules/event-emitter/package.json | 25 +- .../node_modules/exit-hook/package.json | 25 +- .../fast-levenshtein/levenshtein.js | 2 +- .../fast-levenshtein/package.json | 47 +- .../eslint/node_modules/figures/package.json | 25 +- .../node_modules/file-entry-cache/README.md | 39 +- .../node_modules/file-entry-cache/cache.js | 10 +- .../file-entry-cache/changelog.md | 10 + .../file-entry-cache/package.json | 70 +- .../eslint/node_modules/flat-cache/README.md | 3 + tools/eslint/node_modules/flat-cache/cache.js | 11 +- .../node_modules/flat-cache/changelog.md | 41 + .../node_modules/flat-cache/package.json | 66 +- tools/eslint/node_modules/flat-cache/utils.js | 29 + .../node_modules/fs.realpath/package.json | 25 +- .../generate-function/package.json | 25 +- .../generate-object-property/package.json | 25 +- tools/eslint/node_modules/glob/package.json | 25 +- .../eslint/node_modules/globals/package.json | 37 +- tools/eslint/node_modules/globby/package.json | 33 +- .../eslint/node_modules/graceful-fs/README.md | 2 +- .../node_modules/graceful-fs/package.json | 46 +- .../node_modules/graceful-fs/polyfills.js | 55 +- .../eslint/node_modules/has-ansi/package.json | 29 +- tools/eslint/node_modules/ignore/package.json | 23 +- .../node_modules/imurmurhash/package.json | 25 +- .../eslint/node_modules/inflight/package.json | 37 +- .../eslint/node_modules/inherits/package.json | 23 +- .../eslint/node_modules/inquirer/package.json | 27 +- .../is-fullwidth-code-point/package.json | 25 +- .../is-my-json-valid/package.json | 35 +- .../node_modules/is-path-cwd/package.json | 25 +- .../node_modules/is-path-in-cwd/package.json | 27 +- .../node_modules/is-path-inside/package.json | 25 +- .../node_modules/is-property/package.json | 25 +- .../node_modules/is-resolvable/package.json | 25 +- .../eslint/node_modules/isarray/package.json | 31 +- .../eslint/node_modules/js-yaml/package.json | 33 +- .../json-stable-stringify/package.json | 29 +- .../eslint/node_modules/jsonify/package.json | 21 +- .../node_modules/jsonpointer/package.json | 35 +- tools/eslint/node_modules/levn/package.json | 29 +- tools/eslint/node_modules/lodash/README.md | 6 +- .../node_modules/lodash/_addMapEntry.js | 2 +- .../node_modules/lodash/_addSetEntry.js | 1 + tools/eslint/node_modules/lodash/_apply.js | 3 +- .../eslint/node_modules/lodash/_baseClamp.js | 2 +- .../eslint/node_modules/lodash/_baseClone.js | 2 +- .../node_modules/lodash/_baseConforms.js | 23 +- .../node_modules/lodash/_baseConformsTo.js | 28 + .../eslint/node_modules/lodash/_baseDelay.js | 6 +- .../eslint/node_modules/lodash/_baseGetTag.js | 22 + tools/eslint/node_modules/lodash/_baseGt.js | 2 +- .../node_modules/lodash/_baseInRange.js | 2 +- .../node_modules/lodash/_baseIndexOf.js | 5 +- .../node_modules/lodash/_baseIsArrayBuffer.js | 26 + .../eslint/node_modules/lodash/_baseIsDate.js | 27 + .../eslint/node_modules/lodash/_baseIsMap.js | 18 + .../eslint/node_modules/lodash/_baseIsNaN.js | 12 + .../node_modules/lodash/_baseIsRegExp.js | 27 + .../eslint/node_modules/lodash/_baseIsSet.js | 18 + .../node_modules/lodash/_baseIsTypedArray.js | 69 + tools/eslint/node_modules/lodash/_baseKeys.js | 6 +- tools/eslint/node_modules/lodash/_baseLt.js | 2 +- .../node_modules/lodash/_baseMergeDeep.js | 5 +- tools/eslint/node_modules/lodash/_baseNth.js | 2 +- tools/eslint/node_modules/lodash/_basePick.js | 11 +- .../eslint/node_modules/lodash/_basePickBy.js | 6 +- .../node_modules/lodash/_basePropertyOf.js | 14 + .../eslint/node_modules/lodash/_baseRange.js | 2 +- tools/eslint/node_modules/lodash/_baseRest.js | 35 + .../eslint/node_modules/lodash/_baseUnary.js | 2 +- .../node_modules/lodash/_checkGlobal.js | 12 - .../eslint/node_modules/lodash/_copyObject.js | 4 +- .../node_modules/lodash/_createAggregator.js | 2 +- .../node_modules/lodash/_createAssigner.js | 6 +- .../{_createBaseWrapper.js => _createBind.js} | 13 +- .../{_createCtorWrapper.js => _createCtor.js} | 4 +- ..._createCurryWrapper.js => _createCurry.js} | 19 +- .../eslint/node_modules/lodash/_createFind.js | 15 +- .../eslint/node_modules/lodash/_createFlow.js | 8 +- ...reateHybridWrapper.js => _createHybrid.js} | 21 +- .../lodash/_createMathOperation.js | 5 +- .../eslint/node_modules/lodash/_createOver.js | 11 +- ...atePartialWrapper.js => _createPartial.js} | 13 +- .../node_modules/lodash/_createRange.js | 9 +- ...ateRecurryWrapper.js => _createRecurry.js} | 14 +- .../eslint/node_modules/lodash/_createSet.js | 2 +- .../{_createWrapper.js => _createWrap.js} | 27 +- .../node_modules/lodash/_deburrLetter.js | 6 +- .../node_modules/lodash/_defineProperty.js | 11 + .../node_modules/lodash/_equalArrays.js | 4 +- .../eslint/node_modules/lodash/_equalByTag.js | 19 +- .../node_modules/lodash/_equalObjects.js | 4 +- .../node_modules/lodash/_escapeHtmlChar.js | 6 +- .../eslint/node_modules/lodash/_freeGlobal.js | 4 + .../node_modules/lodash/_getPrototype.js | 6 +- .../eslint/node_modules/lodash/_getSymbols.js | 18 +- .../node_modules/lodash/_getSymbolsIn.js | 9 +- tools/eslint/node_modules/lodash/_getTag.js | 5 +- .../node_modules/lodash/_getWrapDetails.js | 17 + .../eslint/node_modules/lodash/_indexOfNaN.js | 23 - .../node_modules/lodash/_insertWrapDetails.js | 21 + .../node_modules/lodash/_isFlattenable.js | 9 +- .../lodash/_isFlattenableIteratee.js | 16 - .../eslint/node_modules/lodash/_mergeData.js | 2 +- .../node_modules/lodash/_mergeDefaults.js | 5 +- tools/eslint/node_modules/lodash/_nodeUtil.js | 22 + tools/eslint/node_modules/lodash/_overArg.js | 15 + tools/eslint/node_modules/lodash/_root.js | 12 +- .../node_modules/lodash/_setWrapToString.js | 27 + tools/eslint/node_modules/lodash/_stackSet.js | 10 +- .../node_modules/lodash/_stringToPath.js | 10 +- .../node_modules/lodash/_unescapeHtmlChar.js | 6 +- .../node_modules/lodash/_updateWrapDetails.js | 46 + tools/eslint/node_modules/lodash/add.js | 2 +- tools/eslint/node_modules/lodash/ary.js | 6 +- tools/eslint/node_modules/lodash/assign.js | 12 +- tools/eslint/node_modules/lodash/assignIn.js | 12 +- tools/eslint/node_modules/lodash/at.js | 4 +- tools/eslint/node_modules/lodash/attempt.js | 6 +- tools/eslint/node_modules/lodash/before.js | 2 +- tools/eslint/node_modules/lodash/bind.js | 16 +- tools/eslint/node_modules/lodash/bindAll.js | 10 +- tools/eslint/node_modules/lodash/bindKey.js | 12 +- .../eslint/node_modules/lodash/collection.js | 1 - tools/eslint/node_modules/lodash/cond.js | 6 +- tools/eslint/node_modules/lodash/conforms.js | 13 +- .../eslint/node_modules/lodash/conformsTo.js | 32 + tools/eslint/node_modules/lodash/core.js | 417 +- tools/eslint/node_modules/lodash/core.min.js | 46 +- tools/eslint/node_modules/lodash/countBy.js | 2 +- tools/eslint/node_modules/lodash/curry.js | 6 +- .../eslint/node_modules/lodash/curryRight.js | 6 +- tools/eslint/node_modules/lodash/debounce.js | 21 +- tools/eslint/node_modules/lodash/defaultTo.js | 25 + tools/eslint/node_modules/lodash/defaults.js | 8 +- .../node_modules/lodash/defaultsDeep.js | 11 +- tools/eslint/node_modules/lodash/defer.js | 4 +- tools/eslint/node_modules/lodash/delay.js | 4 +- .../eslint/node_modules/lodash/difference.js | 12 +- .../node_modules/lodash/differenceBy.js | 13 +- .../node_modules/lodash/differenceWith.js | 8 +- tools/eslint/node_modules/lodash/divide.js | 2 +- .../node_modules/lodash/dropRightWhile.js | 3 +- tools/eslint/node_modules/lodash/dropWhile.js | 2 +- tools/eslint/node_modules/lodash/endsWith.js | 3 +- tools/eslint/node_modules/lodash/eq.js | 4 +- tools/eslint/node_modules/lodash/every.js | 2 +- tools/eslint/node_modules/lodash/filter.js | 4 +- tools/eslint/node_modules/lodash/find.js | 2 +- tools/eslint/node_modules/lodash/findIndex.js | 2 +- tools/eslint/node_modules/lodash/findKey.js | 3 +- tools/eslint/node_modules/lodash/findLast.js | 2 +- .../node_modules/lodash/findLastIndex.js | 2 +- .../eslint/node_modules/lodash/findLastKey.js | 3 +- tools/eslint/node_modules/lodash/flatMap.js | 2 +- .../eslint/node_modules/lodash/flatMapDeep.js | 2 +- .../node_modules/lodash/flatMapDepth.js | 2 +- tools/eslint/node_modules/lodash/flip.js | 6 +- tools/eslint/node_modules/lodash/flow.js | 2 +- tools/eslint/node_modules/lodash/flowRight.js | 2 +- tools/eslint/node_modules/lodash/fp/F.js | 1 + tools/eslint/node_modules/lodash/fp/T.js | 1 + .../node_modules/lodash/fp/_baseConvert.js | 125 +- .../eslint/node_modules/lodash/fp/_mapping.js | 107 +- .../node_modules/lodash/fp/assignAll.js | 5 + .../node_modules/lodash/fp/assignAllWith.js | 5 + .../node_modules/lodash/fp/assignInAll.js | 5 + .../node_modules/lodash/fp/assignInAllWith.js | 5 + .../eslint/node_modules/lodash/fp/conforms.js | 6 +- .../node_modules/lodash/fp/conformsTo.js | 5 + .../node_modules/lodash/fp/defaultTo.js | 5 + .../node_modules/lodash/fp/defaultsAll.js | 5 + .../node_modules/lodash/fp/defaultsDeepAll.js | 5 + .../eslint/node_modules/lodash/fp/dropLast.js | 1 + .../node_modules/lodash/fp/dropLastWhile.js | 1 + .../node_modules/lodash/fp/extendAll.js | 1 + .../node_modules/lodash/fp/extendAllWith.js | 1 + .../eslint/node_modules/lodash/fp/indexBy.js | 1 + .../eslint/node_modules/lodash/fp/matches.js | 6 +- .../eslint/node_modules/lodash/fp/mergeAll.js | 5 + .../node_modules/lodash/fp/mergeAllWith.js | 5 + .../eslint/node_modules/lodash/fp/property.js | 6 +- .../node_modules/lodash/fp/propertyOf.js | 2 +- .../lodash/fp/symmetricDifference.js | 1 + .../lodash/fp/symmetricDifferenceBy.js | 1 + .../lodash/fp/symmetricDifferenceWith.js | 1 + .../eslint/node_modules/lodash/fp/takeLast.js | 1 + .../node_modules/lodash/fp/takeLastWhile.js | 1 + tools/eslint/node_modules/lodash/fp/where.js | 1 + .../eslint/node_modules/lodash/fp/whereEq.js | 2 +- tools/eslint/node_modules/lodash/fp/zipAll.js | 5 + tools/eslint/node_modules/lodash/fromPairs.js | 4 +- tools/eslint/node_modules/lodash/get.js | 2 +- tools/eslint/node_modules/lodash/groupBy.js | 2 +- tools/eslint/node_modules/lodash/identity.js | 4 +- tools/eslint/node_modules/lodash/inRange.js | 5 +- tools/eslint/node_modules/lodash/includes.js | 4 +- .../node_modules/lodash/intersection.js | 6 +- .../node_modules/lodash/intersectionBy.js | 11 +- .../node_modules/lodash/intersectionWith.js | 6 +- tools/eslint/node_modules/lodash/invertBy.js | 3 +- tools/eslint/node_modules/lodash/invoke.js | 4 +- tools/eslint/node_modules/lodash/invokeMap.js | 10 +- .../eslint/node_modules/lodash/isArguments.js | 2 +- tools/eslint/node_modules/lodash/isArray.js | 4 +- .../node_modules/lodash/isArrayBuffer.js | 24 +- tools/eslint/node_modules/lodash/isBoolean.js | 3 +- tools/eslint/node_modules/lodash/isBuffer.js | 11 +- tools/eslint/node_modules/lodash/isDate.js | 25 +- tools/eslint/node_modules/lodash/isEqual.js | 4 +- .../eslint/node_modules/lodash/isFunction.js | 3 +- tools/eslint/node_modules/lodash/isMap.js | 16 +- tools/eslint/node_modules/lodash/isMatch.js | 12 +- tools/eslint/node_modules/lodash/isNative.js | 16 +- tools/eslint/node_modules/lodash/isNumber.js | 3 +- tools/eslint/node_modules/lodash/isRegExp.js | 25 +- tools/eslint/node_modules/lodash/isSet.js | 16 +- tools/eslint/node_modules/lodash/isString.js | 3 +- tools/eslint/node_modules/lodash/isSymbol.js | 3 +- .../node_modules/lodash/isTypedArray.js | 67 +- tools/eslint/node_modules/lodash/isWeakMap.js | 3 +- tools/eslint/node_modules/lodash/isWeakSet.js | 3 +- tools/eslint/node_modules/lodash/keyBy.js | 2 +- tools/eslint/node_modules/lodash/lang.js | 1 + .../eslint/node_modules/lodash/lastIndexOf.js | 5 +- tools/eslint/node_modules/lodash/lodash.js | 1411 ++-- .../eslint/node_modules/lodash/lodash.min.js | 245 +- tools/eslint/node_modules/lodash/map.js | 3 +- tools/eslint/node_modules/lodash/mapKeys.js | 3 +- tools/eslint/node_modules/lodash/mapValues.js | 3 +- tools/eslint/node_modules/lodash/matches.js | 16 +- .../node_modules/lodash/matchesProperty.js | 10 +- tools/eslint/node_modules/lodash/maxBy.js | 5 +- tools/eslint/node_modules/lodash/meanBy.js | 5 +- tools/eslint/node_modules/lodash/merge.js | 12 +- tools/eslint/node_modules/lodash/mergeWith.js | 13 +- tools/eslint/node_modules/lodash/method.js | 4 +- tools/eslint/node_modules/lodash/methodOf.js | 4 +- tools/eslint/node_modules/lodash/minBy.js | 5 +- tools/eslint/node_modules/lodash/multiply.js | 2 +- tools/eslint/node_modules/lodash/negate.js | 9 +- tools/eslint/node_modules/lodash/noop.js | 2 +- tools/eslint/node_modules/lodash/nthArg.js | 4 +- tools/eslint/node_modules/lodash/object.js | 1 + tools/eslint/node_modules/lodash/omit.js | 4 +- tools/eslint/node_modules/lodash/omitBy.js | 11 +- tools/eslint/node_modules/lodash/once.js | 2 +- tools/eslint/node_modules/lodash/over.js | 4 +- tools/eslint/node_modules/lodash/overArgs.js | 18 +- tools/eslint/node_modules/lodash/overEvery.js | 4 +- tools/eslint/node_modules/lodash/overSome.js | 4 +- tools/eslint/node_modules/lodash/package.json | 55 +- tools/eslint/node_modules/lodash/partial.js | 16 +- .../node_modules/lodash/partialRight.js | 16 +- tools/eslint/node_modules/lodash/partition.js | 3 +- tools/eslint/node_modules/lodash/pick.js | 4 +- tools/eslint/node_modules/lodash/pickBy.js | 8 +- tools/eslint/node_modules/lodash/pull.js | 6 +- tools/eslint/node_modules/lodash/pullAllBy.js | 4 +- tools/eslint/node_modules/lodash/pullAt.js | 6 +- tools/eslint/node_modules/lodash/random.js | 6 +- tools/eslint/node_modules/lodash/rearg.js | 10 +- tools/eslint/node_modules/lodash/reject.js | 11 +- tools/eslint/node_modules/lodash/remove.js | 2 +- tools/eslint/node_modules/lodash/rest.js | 30 +- tools/eslint/node_modules/lodash/some.js | 3 +- tools/eslint/node_modules/lodash/sortBy.js | 18 +- .../node_modules/lodash/sortedIndexBy.js | 4 +- .../node_modules/lodash/sortedLastIndexBy.js | 4 +- .../node_modules/lodash/sortedUniqBy.js | 2 +- tools/eslint/node_modules/lodash/spread.js | 4 +- .../eslint/node_modules/lodash/startsWith.js | 3 +- tools/eslint/node_modules/lodash/stubArray.js | 2 +- tools/eslint/node_modules/lodash/stubFalse.js | 2 +- .../eslint/node_modules/lodash/stubObject.js | 2 +- .../eslint/node_modules/lodash/stubString.js | 2 +- tools/eslint/node_modules/lodash/stubTrue.js | 2 +- tools/eslint/node_modules/lodash/subtract.js | 2 +- tools/eslint/node_modules/lodash/sumBy.js | 5 +- .../node_modules/lodash/takeRightWhile.js | 2 +- tools/eslint/node_modules/lodash/takeWhile.js | 2 +- tools/eslint/node_modules/lodash/throttle.js | 7 +- tools/eslint/node_modules/lodash/toArray.js | 2 +- tools/eslint/node_modules/lodash/union.js | 6 +- tools/eslint/node_modules/lodash/unionBy.js | 13 +- tools/eslint/node_modules/lodash/unionWith.js | 9 +- tools/eslint/node_modules/lodash/uniqBy.js | 4 +- tools/eslint/node_modules/lodash/unzip.js | 6 +- tools/eslint/node_modules/lodash/util.js | 1 + tools/eslint/node_modules/lodash/without.js | 8 +- tools/eslint/node_modules/lodash/wrap.js | 8 +- tools/eslint/node_modules/lodash/wrapperAt.js | 4 +- .../node_modules/lodash/wrapperLodash.js | 20 +- tools/eslint/node_modules/lodash/xor.js | 6 +- tools/eslint/node_modules/lodash/xorBy.js | 10 +- tools/eslint/node_modules/lodash/xorWith.js | 6 +- tools/eslint/node_modules/lodash/zip.js | 8 +- tools/eslint/node_modules/lodash/zipWith.js | 4 +- .../node_modules/minimatch/package.json | 25 +- .../eslint/node_modules/minimist/package.json | 29 +- tools/eslint/node_modules/mkdirp/package.json | 25 +- tools/eslint/node_modules/ms/package.json | 23 +- .../node_modules/mute-stream/package.json | 27 +- .../node_modules/number-is-nan/package.json | 25 +- .../node_modules/object-assign/package.json | 29 +- tools/eslint/node_modules/once/package.json | 25 +- .../eslint/node_modules/onetime/package.json | 25 +- .../node_modules/optionator/package.json | 27 +- .../node_modules/os-homedir/package.json | 25 +- .../path-is-absolute/package.json | 27 +- .../node_modules/path-is-inside/package.json | 27 +- tools/eslint/node_modules/pify/package.json | 25 +- .../node_modules/pinkie-promise/package.json | 25 +- tools/eslint/node_modules/pinkie/package.json | 25 +- .../node_modules/pluralize/package.json | 25 +- .../node_modules/prelude-ls/package.json | 29 +- .../process-nextick-args/package.json | 23 +- .../eslint/node_modules/progress/package.json | 43 +- .../node_modules/read-json-sync/LICENSE | 20 - .../node_modules/read-json-sync/README.md | 44 - .../node_modules/read-json-sync/index.js | 11 - .../node_modules/read-json-sync/package.json | 95 - .../node_modules/readable-stream/package.json | 35 +- .../node_modules/readline2/package.json | 27 +- .../require-uncached/package.json | 25 +- .../node_modules/resolve-from/package.json | 27 +- .../node_modules/restore-cursor/package.json | 25 +- tools/eslint/node_modules/rimraf/package.json | 43 +- tools/eslint/node_modules/rimraf/rimraf.js | 4 +- .../node_modules/run-async/package.json | 27 +- .../eslint/node_modules/rx-lite/package.json | 23 +- .../eslint/node_modules/shelljs/package.json | 41 +- .../node_modules/slice-ansi/package.json | 27 +- .../node_modules/sprintf-js/package.json | 25 +- .../node_modules/string-width/package.json | 27 +- .../node_modules/string_decoder/package.json | 27 +- .../node_modules/strip-ansi/package.json | 29 +- .../node_modules/strip-bom/package.json | 25 +- .../strip-json-comments/package.json | 25 +- .../node_modules/supports-color/package.json | 29 +- tools/eslint/node_modules/table/package.json | 25 +- .../node_modules/text-table/package.json | 29 +- .../eslint/node_modules/through/package.json | 25 +- tools/eslint/node_modules/tryit/package.json | 29 +- tools/eslint/node_modules/tv4/package.json | 27 +- .../node_modules/type-check/package.json | 27 +- .../node_modules/typedarray/package.json | 29 +- .../node_modules/user-home/package.json | 25 +- .../node_modules/util-deprecate/package.json | 27 +- .../eslint/node_modules/wordwrap/package.json | 29 +- tools/eslint/node_modules/wrappy/package.json | 29 +- tools/eslint/node_modules/write/package.json | 23 +- .../eslint/node_modules/xregexp/package.json | 27 +- tools/eslint/node_modules/xtend/package.json | 35 +- tools/eslint/package.json | 62 +- vcbuild.bat | 2 +- 701 files changed, 18378 insertions(+), 10561 deletions(-) delete mode 100755 tools/eslint/bin/eslint.js create mode 100644 tools/eslint/conf/category-list.json create mode 100644 tools/eslint/lib/internal-rules/internal-no-invalid-meta.js create mode 100644 tools/eslint/lib/rules/.eslintrc.yml create mode 100644 tools/eslint/lib/rules/multiline-ternary.js create mode 100644 tools/eslint/lib/rules/no-tabs.js create mode 100644 tools/eslint/lib/util/xml-escape.js delete mode 100644 tools/eslint/node_modules/acorn/bin/build-acorn.js create mode 100644 tools/eslint/node_modules/acorn/dist/acorn.es.js create mode 100644 tools/eslint/node_modules/acorn/dist/acorn_loose.es.js create mode 100644 tools/eslint/node_modules/acorn/dist/walk.es.js create mode 100644 tools/eslint/node_modules/acorn/rollup/config.bin.js create mode 100644 tools/eslint/node_modules/acorn/rollup/config.loose.js create mode 100644 tools/eslint/node_modules/acorn/rollup/config.main.js create mode 100644 tools/eslint/node_modules/acorn/rollup/config.walk.js delete mode 100644 tools/eslint/node_modules/acorn/src/loose/acorn_loose.js create mode 100644 tools/eslint/node_modules/circular-json/LICENSE.txt create mode 100644 tools/eslint/node_modules/circular-json/README.md create mode 100644 tools/eslint/node_modules/circular-json/build/circular-json.js create mode 100644 tools/eslint/node_modules/circular-json/build/circular-json.max.js create mode 100644 tools/eslint/node_modules/circular-json/build/circular-json.node.js create mode 100644 tools/eslint/node_modules/circular-json/package.json create mode 100644 tools/eslint/node_modules/circular-json/template/license.after create mode 100644 tools/eslint/node_modules/circular-json/template/license.before create mode 100644 tools/eslint/node_modules/flat-cache/utils.js create mode 100644 tools/eslint/node_modules/lodash/_baseConformsTo.js create mode 100644 tools/eslint/node_modules/lodash/_baseGetTag.js create mode 100644 tools/eslint/node_modules/lodash/_baseIsArrayBuffer.js create mode 100644 tools/eslint/node_modules/lodash/_baseIsDate.js create mode 100644 tools/eslint/node_modules/lodash/_baseIsMap.js create mode 100644 tools/eslint/node_modules/lodash/_baseIsNaN.js create mode 100644 tools/eslint/node_modules/lodash/_baseIsRegExp.js create mode 100644 tools/eslint/node_modules/lodash/_baseIsSet.js create mode 100644 tools/eslint/node_modules/lodash/_baseIsTypedArray.js create mode 100644 tools/eslint/node_modules/lodash/_basePropertyOf.js create mode 100644 tools/eslint/node_modules/lodash/_baseRest.js delete mode 100644 tools/eslint/node_modules/lodash/_checkGlobal.js rename tools/eslint/node_modules/lodash/{_createBaseWrapper.js => _createBind.js} (62%) rename tools/eslint/node_modules/lodash/{_createCtorWrapper.js => _createCtor.js} (95%) rename tools/eslint/node_modules/lodash/{_createCurryWrapper.js => _createCurry.js} (66%) rename tools/eslint/node_modules/lodash/{_createHybridWrapper.js => _createHybrid.js} (80%) rename tools/eslint/node_modules/lodash/{_createPartialWrapper.js => _createPartial.js} (75%) rename tools/eslint/node_modules/lodash/{_createRecurryWrapper.js => _createRecurry.js} (79%) rename tools/eslint/node_modules/lodash/{_createWrapper.js => _createWrap.js} (79%) create mode 100644 tools/eslint/node_modules/lodash/_defineProperty.js create mode 100644 tools/eslint/node_modules/lodash/_freeGlobal.js create mode 100644 tools/eslint/node_modules/lodash/_getWrapDetails.js delete mode 100644 tools/eslint/node_modules/lodash/_indexOfNaN.js create mode 100644 tools/eslint/node_modules/lodash/_insertWrapDetails.js delete mode 100644 tools/eslint/node_modules/lodash/_isFlattenableIteratee.js create mode 100644 tools/eslint/node_modules/lodash/_nodeUtil.js create mode 100644 tools/eslint/node_modules/lodash/_overArg.js create mode 100644 tools/eslint/node_modules/lodash/_setWrapToString.js create mode 100644 tools/eslint/node_modules/lodash/_updateWrapDetails.js create mode 100644 tools/eslint/node_modules/lodash/conformsTo.js create mode 100644 tools/eslint/node_modules/lodash/defaultTo.js create mode 100644 tools/eslint/node_modules/lodash/fp/F.js create mode 100644 tools/eslint/node_modules/lodash/fp/T.js create mode 100644 tools/eslint/node_modules/lodash/fp/assignAll.js create mode 100644 tools/eslint/node_modules/lodash/fp/assignAllWith.js create mode 100644 tools/eslint/node_modules/lodash/fp/assignInAll.js create mode 100644 tools/eslint/node_modules/lodash/fp/assignInAllWith.js create mode 100644 tools/eslint/node_modules/lodash/fp/conformsTo.js create mode 100644 tools/eslint/node_modules/lodash/fp/defaultTo.js create mode 100644 tools/eslint/node_modules/lodash/fp/defaultsAll.js create mode 100644 tools/eslint/node_modules/lodash/fp/defaultsDeepAll.js create mode 100644 tools/eslint/node_modules/lodash/fp/dropLast.js create mode 100644 tools/eslint/node_modules/lodash/fp/dropLastWhile.js create mode 100644 tools/eslint/node_modules/lodash/fp/extendAll.js create mode 100644 tools/eslint/node_modules/lodash/fp/extendAllWith.js create mode 100644 tools/eslint/node_modules/lodash/fp/indexBy.js create mode 100644 tools/eslint/node_modules/lodash/fp/mergeAll.js create mode 100644 tools/eslint/node_modules/lodash/fp/mergeAllWith.js create mode 100644 tools/eslint/node_modules/lodash/fp/symmetricDifference.js create mode 100644 tools/eslint/node_modules/lodash/fp/symmetricDifferenceBy.js create mode 100644 tools/eslint/node_modules/lodash/fp/symmetricDifferenceWith.js create mode 100644 tools/eslint/node_modules/lodash/fp/takeLast.js create mode 100644 tools/eslint/node_modules/lodash/fp/takeLastWhile.js create mode 100644 tools/eslint/node_modules/lodash/fp/where.js create mode 100644 tools/eslint/node_modules/lodash/fp/zipAll.js delete mode 100755 tools/eslint/node_modules/read-json-sync/LICENSE delete mode 100755 tools/eslint/node_modules/read-json-sync/README.md delete mode 100755 tools/eslint/node_modules/read-json-sync/index.js delete mode 100644 tools/eslint/node_modules/read-json-sync/package.json diff --git a/Makefile b/Makefile index 8a232c0e3478cf..fac19326946302 100644 --- a/Makefile +++ b/Makefile @@ -697,7 +697,7 @@ cpplint: @$(PYTHON) tools/cpplint.py $(CPPLINT_FILES) @$(PYTHON) tools/check-imports.py -ifneq ("","$(wildcard tools/eslint/bin/eslint.js)") +ifneq ("","$(wildcard tools/eslint/lib/eslint.js)") lint: jslint cpplint CONFLICT_RE=^>>>>>>> [0-9A-Fa-f]+|^<<<<<<< [A-Za-z]+ lint-ci: jslint-ci cpplint diff --git a/tools/eslint/README.md b/tools/eslint/README.md index 5493563c4e3479..8ba9eaf0b5f1bd 100644 --- a/tools/eslint/README.md +++ b/tools/eslint/README.md @@ -126,9 +126,6 @@ These folks keep the project moving and are resources for help. * Henry Zhu ([@hzoo](https://github.com/hzoo)) * Marat Dulin ([@mdevils](https://github.com/mdevils)) * Alexej Yaroshevich ([@zxqfox](https://github.com/zxqfox)) - -### Issues Team - * Kevin Partington ([@platinumazure](https://github.com/platinumazure)) * Vitor Balocco ([@vitorbal](https://github.com/vitorbal)) @@ -169,6 +166,8 @@ ESLint follows [semantic versioning](http://semver.org). However, due to the nat * An existing formatter is removed. * Part of the public API is removed or changed in an incompatible way. +According to our policy, any minor update may report more errors than the previous release (ex: from a bug fix). As such, we recommend using the tilde (`~`) in `package.json` e.g. `"eslint": "~3.1.0"` to guarantee the results of your builds. + ## Frequently Asked Questions ### How is ESLint different from JSHint? @@ -187,7 +186,10 @@ Yes. Since we are solving the same problems, ESLint and JSCS teams have decided ### So, should I stop using JSCS and start using ESLint? -Not yet. We are still working to smooth the transition. You can see our progress [here](https://github.com/eslint/eslint/milestones/JSCS%20Compatibility). We’ll announce when all of the changes necessary to support JSCS users in ESLint are complete and will start encouraging JSCS users to switch to ESLint at that time. Meanwhile, we recommend you to upgrade to JSCS 3.0 and provide feedback to the team. +Maybe, depending on how much you need it. [JSCS has reached end of life](http://eslint.org/blog/2016/07/jscs-end-of-life), but if it is working for you then there is no reason to move yet. We are still working to smooth the transition. You can see our progress [here](https://github.com/eslint/eslint/milestones/JSCS%20Compatibility). We’ll announce when all of the changes necessary to support JSCS users in ESLint are complete and will start encouraging JSCS users to switch to ESLint at that time. + +If you are having issues with JSCS, you can try to move to ESLint. We are focusing our time and energy on JSCS compatibility issues. + ### Is ESLint just linting or does it also check style? diff --git a/tools/eslint/bin/eslint.js b/tools/eslint/bin/eslint.js deleted file mode 100755 index e03ab6f426e0ef..00000000000000 --- a/tools/eslint/bin/eslint.js +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env node - -/** - * @fileoverview Main CLI that is run via the eslint command. - * @author Nicholas C. Zakas - */ - -"use strict"; - -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -var exitCode = 0, - useStdIn = (process.argv.indexOf("--stdin") > -1), - init = (process.argv.indexOf("--init") > -1), - debug = (process.argv.indexOf("--debug") > -1); - -// must do this initialization *before* other requires in order to work -if (debug) { - require("debug").enable("eslint:*,-eslint:code-path"); -} - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -// now we can safely include the other modules that use debug -var concat = require("concat-stream"), - cli = require("../lib/cli"), - path = require("path"), - fs = require("fs"); - -//------------------------------------------------------------------------------ -// Execution -//------------------------------------------------------------------------------ - -process.on("uncaughtException", function(err){ - // lazy load - var lodash = require("lodash"); - - if (typeof err.messageTemplate === "string" && err.messageTemplate.length > 0) { - var template = lodash.template(fs.readFileSync(path.resolve(__dirname, "../messages/" + err.messageTemplate + ".txt"), "utf-8")); - - console.log("\nOops! Something went wrong! :("); - console.log("\n" + template(err.messageData || {})); - } else { - console.log(err.message); - console.log(err.stack); - } - - process.exit(1); -}); - -if (useStdIn) { - process.stdin.pipe(concat({ encoding: "string" }, function(text) { - try { - exitCode = cli.execute(process.argv, text); - } catch (ex) { - console.error(ex.message); - console.error(ex.stack); - exitCode = 1; - } - })); -} else if (init) { - var configInit = require("../lib/config/config-initializer"); - configInit.initializeConfig(function(err) { - if (err) { - exitCode = 1; - console.error(err.message); - console.error(err.stack); - } else { - exitCode = 0; - } - }); -} else { - exitCode = cli.execute(process.argv); -} - -process.exitCode = exitCode; diff --git a/tools/eslint/conf/category-list.json b/tools/eslint/conf/category-list.json new file mode 100644 index 00000000000000..d7e84b6c15fe93 --- /dev/null +++ b/tools/eslint/conf/category-list.json @@ -0,0 +1,35 @@ +{ + "categories": [ + { "name": "Possible Errors", "description": "These rules relate to possible syntax or logic errors in JavaScript code:" }, + { "name": "Best Practices", "description": "These rules relate to better ways of doing things to help you avoid problems:" }, + { "name": "Strict Mode", "description": "These rules relate to strict mode directives:" }, + { "name": "Variables", "description": "These rules relate to variable declarations:" }, + { "name": "Node.js and CommonJS", "description": "These rules relate to code running in Node.js, or in browsers with CommonJS:" }, + { "name": "Stylistic Issues", "description": "These rules relate to style guidelines, and are therefore quite subjective:" }, + { "name": "ECMAScript 6", "description": "These rules relate to ES6, also known as ES2015:" } + ], + "removed": { + "name": "Removed", + "description": "These rules from older versions of ESLint have been replaced by newer rules:", + "rules": [ + { "removed": "generator-star", "replacedBy": ["generator-star-spacing"] }, + { "removed": "global-strict", "replacedBy": ["strict"] }, + { "removed": "no-arrow-condition", "replacedBy": ["no-confusing-arrow", "no-constant-condition"] }, + { "removed": "no-comma-dangle", "replacedBy": ["comma-dangle"] }, + { "removed": "no-empty-class", "replacedBy": ["no-empty-character-class"] }, + { "removed": "no-empty-label", "replacedBy": ["no-labels"] }, + { "removed": "no-extra-strict", "replacedBy": ["strict"] }, + { "removed": "no-reserved-keys", "replacedBy": ["quote-props"] }, + { "removed": "no-space-before-semi", "replacedBy": ["semi-spacing"] }, + { "removed": "no-wrap-func", "replacedBy": ["no-extra-parens"] }, + { "removed": "space-after-function-name", "replacedBy": ["space-before-function-paren"] }, + { "removed": "space-after-keywords", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-before-function-parentheses", "replacedBy": ["space-before-function-paren"] }, + { "removed": "space-before-keywords", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] }, + { "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] }, + { "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] } + ] + } +} \ No newline at end of file diff --git a/tools/eslint/conf/environments.js b/tools/eslint/conf/environments.js index ee76503827cb24..d938a6cfaa941d 100644 --- a/tools/eslint/conf/environments.js +++ b/tools/eslint/conf/environments.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var globals = require("globals"); +let globals = require("globals"); //------------------------------------------------------------------------------ // Public Interface diff --git a/tools/eslint/conf/eslint-all.js b/tools/eslint/conf/eslint-all.js index 8740e8c07d46e8..53d5cdb82d8c28 100644 --- a/tools/eslint/conf/eslint-all.js +++ b/tools/eslint/conf/eslint-all.js @@ -9,16 +9,18 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var ruleFiles = fs.readdirSync(path.resolve(__dirname, "../lib/rules")); -var enabledRules = ruleFiles.reduce(function(result, filename) { - result[path.basename(filename, ".js")] = "error"; +let ruleFiles = fs.readdirSync(path.resolve(__dirname, "../lib/rules")); +let enabledRules = ruleFiles.reduce(function(result, filename) { + if (path.extname(filename) === ".js") { + result[path.basename(filename, ".js")] = "error"; + } return result; }, {}); diff --git a/tools/eslint/conf/eslint.json b/tools/eslint/conf/eslint.json index 94317bcd89aa61..53b2e7559066ab 100644 --- a/tools/eslint/conf/eslint.json +++ b/tools/eslint/conf/eslint.json @@ -99,6 +99,7 @@ "no-spaced-func": "off", "no-sparse-arrays": "error", "no-sync": "off", + "no-tabs": "off", "no-ternary": "off", "no-trailing-spaces": "off", "no-this-before-super": "error", @@ -174,6 +175,7 @@ "max-params": "off", "max-statements": "off", "max-statements-per-line": "off", + "multiline-ternary": "off", "new-cap": "off", "new-parens": "off", "newline-after-var": "off", diff --git a/tools/eslint/lib/ast-utils.js b/tools/eslint/lib/ast-utils.js index c8d6dcb4915e21..881cc26c5f08a4 100644 --- a/tools/eslint/lib/ast-utils.js +++ b/tools/eslint/lib/ast-utils.js @@ -9,18 +9,19 @@ // Requirements //------------------------------------------------------------------------------ -var esutils = require("esutils"); +let esutils = require("esutils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/; -var arrayOrTypedArrayPattern = /Array$/; -var arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/; -var bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/; -var breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/; -var thisTagPattern = /^[\s\*]*@this/m; +let anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/; +let anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/; +let arrayOrTypedArrayPattern = /Array$/; +let arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/; +let bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/; +let breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/; +let thisTagPattern = /^[\s\*]*@this/m; /** * Checks reference if is non initializer and writable. @@ -31,7 +32,7 @@ var thisTagPattern = /^[\s\*]*@this/m; * @private */ function isModifyingReference(reference, index, references) { - var identifier = reference.identifier, + let identifier = reference.identifier, modifyingDifferentIdentifier; /* @@ -159,7 +160,7 @@ function isMethodWhichHasThisArg(node) { * @returns {boolean} Whether or not the node has a `@this` tag in its comments. */ function hasJSDocThisTag(node, sourceCode) { - var jsdocComment = sourceCode.getJSDocComment(node); + let jsdocComment = sourceCode.getJSDocComment(node); if (jsdocComment && thisTagPattern.test(jsdocComment.value)) { return true; @@ -182,7 +183,7 @@ function hasJSDocThisTag(node, sourceCode) { * @private */ function isParenthesised(sourceCode, node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return Boolean(previousToken && nextToken) && @@ -284,7 +285,7 @@ module.exports = { * @returns {boolean} `true` if the node is an ESLint directive comment */ isDirectiveComment: function(node) { - var comment = node.value.trim(); + let comment = node.value.trim(); return ( node.type === "Line" && comment.indexOf("eslint-") === 0 || @@ -317,10 +318,10 @@ module.exports = { * @returns {escope.Variable|null} A found variable or `null`. */ getVariableByName: function(initScope, name) { - var scope = initScope; + let scope = initScope; while (scope) { - var variable = scope.set.get(name); + let variable = scope.set.get(name); if (variable) { return variable; @@ -359,7 +360,7 @@ module.exports = { } while (node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { @@ -378,14 +379,15 @@ module.exports = { // // setup... // return function foo() { ... }; // })(); - case "ReturnStatement": - var func = getUpperFunction(parent); + case "ReturnStatement": { + const func = getUpperFunction(parent); if (func === null || !isCallee(func)) { return true; } node = func.parent; break; + } // e.g. // var obj = { foo() { ... } }; @@ -551,5 +553,37 @@ module.exports = { // no default } return 18; + }, + + /** + * Checks whether a given node is a loop node or not. + * The following types are loop nodes: + * + * - DoWhileStatement + * - ForInStatement + * - ForOfStatement + * - ForStatement + * - WhileStatement + * + * @param {ASTNode|null} node - A node to check. + * @returns {boolean} `true` if the node is a loop node. + */ + isLoop: function(node) { + return Boolean(node && anyLoopPattern.test(node.type)); + }, + + /** + * Checks whether a given node is a function node or not. + * The following types are function nodes: + * + * - ArrowFunctionExpression + * - FunctionDeclaration + * - FunctionExpression + * + * @param {ASTNode|null} node - A node to check. + * @returns {boolean} `true` if the node is a function node. + */ + isFunction: function(node) { + return Boolean(node && anyFunctionPattern.test(node.type)); } }; diff --git a/tools/eslint/lib/cli-engine.js b/tools/eslint/lib/cli-engine.js index 410fd7f3674156..cf28aa1d592c16 100644 --- a/tools/eslint/lib/cli-engine.js +++ b/tools/eslint/lib/cli-engine.js @@ -15,7 +15,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"), lodash = require("lodash"), @@ -44,16 +44,25 @@ var fs = require("fs"), /** * The options to configure a CLI engine with. * @typedef {Object} CLIEngineOptions + * @property {boolean} allowInlineConfig Enable or disable inline configuration comments. + * @property {boolean|Object} baseConfig Base config object. True enables recommend rules and environments. + * @property {boolean} cache Enable result caching. + * @property {string} cacheLocation The cache file to use instead of .eslintcache. * @property {string} configFile The configuration file to use. - * @property {boolean|object} baseConfig Base config object. True enables recommend rules and environments. - * @property {boolean} ignore False disables use of .eslintignore. - * @property {string[]} rulePaths An array of directories to load custom rules from. - * @property {boolean} useEslintrc False disables looking for .eslintrc + * @property {string} cwd The value to use for the current working directory. * @property {string[]} envs An array of environments to load. - * @property {string[]} globals An array of global variables to declare. * @property {string[]} extensions An array of file extensions to check. - * @property {Object} rules An object of rules to use. + * @property {boolean} fix Execute in autofix mode. + * @property {string[]} globals An array of global variables to declare. + * @property {boolean} ignore False disables use of .eslintignore. * @property {string} ignorePath The ignore file to use instead of .eslintignore. + * @property {string} ignorePattern A glob pattern of files to ignore. + * @property {boolean} useEslintrc False disables looking for .eslintrc + * @property {string} parser The name of the parser to use. + * @property {Object} parserOptions An object of parserOption settings to use. + * @property {string[]} plugins An array of plugins to load. + * @property {Object} rules An object of rules to use. + * @property {string[]} rulePaths An array of directories to load custom rules from. */ /** @@ -129,7 +138,7 @@ function calculateStatsPerRun(results) { */ function multipassFix(text, config, options) { - var messages = [], + let messages = [], fixedResult, fixed = false, passNumber = 0, @@ -203,7 +212,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { // clear all existing settings for a new file eslint.reset(); - var filePath, + let filePath, config, messages, stats, @@ -227,7 +236,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { loadedPlugins = Plugins.getAll(); - for (var plugin in loadedPlugins) { + for (let plugin in loadedPlugins) { if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) { processor = loadedPlugins[plugin].processors[fileExtension]; break; @@ -236,8 +245,8 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { if (processor) { debug("Using processor"); - var parsedBlocks = processor.preprocess(text, filename); - var unprocessedMessages = []; + let parsedBlocks = processor.preprocess(text, filename); + let unprocessedMessages = []; parsedBlocks.forEach(function(block) { unprocessedMessages.push(eslint.verify(block, config, { @@ -268,7 +277,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { stats = calculateStatsPerFile(messages); - var result = { + let result = { filePath: filename, messages: messages, errorCount: stats.errorCount, @@ -293,7 +302,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { */ function processFile(filename, configHelper, options) { - var text = fs.readFileSync(path.resolve(filename), "utf8"), + let text = fs.readFileSync(path.resolve(filename), "utf8"), result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig); return result; @@ -308,10 +317,10 @@ function processFile(filename, configHelper, options) { * @private */ function createIgnoreResult(filePath, baseDir) { - var message; - var isHidden = /^\./.test(path.basename(filePath)); - var isInNodeModules = baseDir && /^node_modules/.test(path.relative(baseDir, filePath)); - var isInBowerComponents = baseDir && /^bower_components/.test(path.relative(baseDir, filePath)); + let message; + let isHidden = /^\./.test(path.basename(filePath)); + let isInNodeModules = baseDir && /^node_modules/.test(path.relative(baseDir, filePath)); + let isInBowerComponents = baseDir && /^bower_components/.test(path.relative(baseDir, filePath)); if (isHidden) { message = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern \'!\'\") to override."; @@ -340,7 +349,7 @@ function createIgnoreResult(filePath, baseDir) { /** * Checks if the given message is an error message. - * @param {object} message The message to check. + * @param {Object} message The message to check. * @returns {boolean} Whether or not the message is an error message. * @private */ @@ -368,8 +377,8 @@ function getCacheFile(cacheFile, cwd) { */ cacheFile = path.normalize(cacheFile); - var resolvedCacheFile = path.resolve(cwd, cacheFile); - var looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep; + let resolvedCacheFile = path.resolve(cwd, cacheFile); + let looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep; /** * return the name for the cache file in case the provided parameter is a directory @@ -379,7 +388,7 @@ function getCacheFile(cacheFile, cwd) { return path.join(resolvedCacheFile, ".cache_" + hash(cwd)); } - var fileStats; + let fileStats; try { fileStats = fs.lstatSync(resolvedCacheFile); @@ -446,7 +455,7 @@ function CLIEngine(options) { */ this.options = options; - var cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd); + let cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd); /** * Cache used to avoid operating on files that haven't changed since the @@ -458,7 +467,7 @@ function CLIEngine(options) { // load in additional rules if (this.options.rulePaths) { - var cwd = this.options.cwd; + let cwd = this.options.cwd; this.options.rulePaths.forEach(function(rulesdir) { debug("Loading rules from " + rulesdir); @@ -480,7 +489,7 @@ function CLIEngine(options) { */ CLIEngine.getFormatter = function(format) { - var formatterPath; + let formatterPath; // default is stylish format = format || "stylish"; @@ -493,7 +502,7 @@ CLIEngine.getFormatter = function(format) { // if there's a slash, then it's a file if (format.indexOf("/") > -1) { - var cwd = this.options ? this.options.cwd : process.cwd(); + let cwd = this.options ? this.options.cwd : process.cwd(); formatterPath = path.resolve(cwd, format); } else { @@ -518,10 +527,10 @@ CLIEngine.getFormatter = function(format) { * @returns {LintResult[]} The filtered results. */ CLIEngine.getErrorResults = function(results) { - var filtered = []; + let filtered = []; results.forEach(function(result) { - var filteredMessages = result.messages.filter(isErrorMessage); + let filteredMessages = result.messages.filter(isErrorMessage); if (filteredMessages.length > 0) { filtered.push({ @@ -579,7 +588,7 @@ CLIEngine.prototype = { * @returns {Object} The results for all files that were linted. */ executeOnFiles: function(patterns) { - var results = [], + let results = [], options = this.options, fileCache = this._fileCache, configHelper = new Config(options), @@ -594,7 +603,7 @@ CLIEngine.prototype = { * @returns {string} the hash of the config */ function hashOfConfigFor(filename) { - var config = configHelper.getConfig(filename); + let config = configHelper.getConfig(filename); if (!prevConfig) { prevConfig = {}; @@ -609,7 +618,7 @@ CLIEngine.prototype = { */ prevConfig.config = config; - var eslintVersion = pkg.version; + let eslintVersion = pkg.version; prevConfig.hash = hash(eslintVersion + "_" + stringify(config)); } @@ -625,7 +634,8 @@ CLIEngine.prototype = { * @returns {void} */ function executeOnFile(filename, warnIgnored) { - var hashOfConfig; + let hashOfConfig, + descriptor; if (warnIgnored) { results.push(createIgnoreResult(filename, options.cwd)); @@ -639,12 +649,12 @@ CLIEngine.prototype = { * with the metadata and the flag that determines if * the file has changed */ - var descriptor = fileCache.getFileDescriptor(filename); - var meta = descriptor.meta || {}; + descriptor = fileCache.getFileDescriptor(filename); + let meta = descriptor.meta || {}; hashOfConfig = hashOfConfigFor(filename); - var changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig; + let changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig; if (!changed) { debug("Skipping file since hasn't changed: " + filename); @@ -666,7 +676,7 @@ CLIEngine.prototype = { debug("Processing " + filename); - var res = processFile(filename, configHelper, options); + let res = processFile(filename, configHelper, options); if (options.cache) { @@ -732,7 +742,7 @@ CLIEngine.prototype = { */ executeOnText: function(text, filename, warnIgnored) { - var results = [], + let results = [], stats, options = this.options, configHelper = new Config(options), @@ -742,8 +752,11 @@ CLIEngine.prototype = { if (filename && !path.isAbsolute(filename)) { filename = path.resolve(options.cwd, filename); } - if (filename && warnIgnored && ignoredPaths.contains(filename)) { - results.push(createIgnoreResult(filename, options.cwd)); + + if (filename && ignoredPaths.contains(filename)) { + if (warnIgnored) { + results.push(createIgnoreResult(filename, options.cwd)); + } } else { results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig)); } @@ -765,7 +778,7 @@ CLIEngine.prototype = { * @returns {Object} A configuration object for the file. */ getConfigForFile: function(filePath) { - var configHelper = new Config(this.options); + let configHelper = new Config(this.options); return configHelper.getConfig(filePath); }, @@ -776,8 +789,8 @@ CLIEngine.prototype = { * @returns {boolean} Whether or not the given path is ignored. */ isPathIgnored: function(filePath) { - var ignoredPaths; - var resolvedPath = path.resolve(this.options.cwd, filePath); + let ignoredPaths; + let resolvedPath = path.resolve(this.options.cwd, filePath); ignoredPaths = new IgnoredPaths(this.options); return ignoredPaths.contains(resolvedPath); diff --git a/tools/eslint/lib/cli.js b/tools/eslint/lib/cli.js index 887c3c7671f612..b8bbda4cae8c19 100644 --- a/tools/eslint/lib/cli.js +++ b/tools/eslint/lib/cli.js @@ -15,7 +15,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"), debug = require("debug"), @@ -70,7 +70,7 @@ function translateOptions(cliOptions) { * @private */ function printResults(engine, results, format, outputFile) { - var formatter, + let formatter, output, filePath; @@ -116,7 +116,7 @@ function printResults(engine, results, format, outputFile) { * Encapsulates all CLI behavior for eslint. Makes it easier to test as well as * for other Node.js programs to effectively run the CLI. */ -var cli = { +let cli = { /** * Executes the CLI based on an array of arguments that is passed in. @@ -126,7 +126,7 @@ var cli = { */ execute: function(args, text) { - var currentOptions, + let currentOptions, files, report, engine, @@ -172,7 +172,7 @@ var cli = { return 1; } - var fileConfig = engine.getConfigForFile(files[0]); + let fileConfig = engine.getConfigForFile(files[0]); log.info(JSON.stringify(fileConfig, null, " ")); return 0; diff --git a/tools/eslint/lib/code-path-analysis/code-path-analyzer.js b/tools/eslint/lib/code-path-analysis/code-path-analyzer.js index 4e55cccee64869..00db3064dc4e87 100644 --- a/tools/eslint/lib/code-path-analysis/code-path-analyzer.js +++ b/tools/eslint/lib/code-path-analysis/code-path-analyzer.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"), +let assert = require("assert"), CodePath = require("./code-path"), CodePathSegment = require("./code-path-segment"), IdGenerator = require("./id-generator"), @@ -38,7 +38,7 @@ function isCaseNode(node) { * @returns {boolean} `true` if the node is a test of a choice statement. */ function isForkingByTrueOrFalse(node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { case "ConditionalExpression": @@ -83,7 +83,7 @@ function getBooleanValueIfSimpleConstant(node) { * @returns {boolean} `true` if the node is a reference. */ function isIdentifierReference(node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { case "LabeledStatement": @@ -135,12 +135,12 @@ function isIdentifierReference(node) { * @returns {void} */ function forwardCurrentToHead(analyzer, node) { - var codePath = analyzer.codePath; - var state = CodePath.getState(codePath); - var currentSegments = state.currentSegments; - var headSegments = state.headSegments; - var end = Math.max(currentSegments.length, headSegments.length); - var i, currentSegment, headSegment; + let codePath = analyzer.codePath; + let state = CodePath.getState(codePath); + let currentSegments = state.currentSegments; + let headSegments = state.headSegments; + let end = Math.max(currentSegments.length, headSegments.length); + let i, currentSegment, headSegment; // Fires leaving events. for (i = 0; i < end; ++i) { @@ -191,11 +191,11 @@ function forwardCurrentToHead(analyzer, node) { * @returns {void} */ function leaveFromCurrentSegment(analyzer, node) { - var state = CodePath.getState(analyzer.codePath); - var currentSegments = state.currentSegments; + let state = CodePath.getState(analyzer.codePath); + let currentSegments = state.currentSegments; - for (var i = 0; i < currentSegments.length; ++i) { - var currentSegment = currentSegments[i]; + for (let i = 0; i < currentSegments.length; ++i) { + let currentSegment = currentSegments[i]; debug.dump("onCodePathSegmentEnd " + currentSegment.id); if (currentSegment.reachable) { @@ -221,9 +221,9 @@ function leaveFromCurrentSegment(analyzer, node) { * @returns {void} */ function preprocess(analyzer, node) { - var codePath = analyzer.codePath; - var state = CodePath.getState(codePath); - var parent = node.parent; + let codePath = analyzer.codePath; + let state = CodePath.getState(codePath); + let parent = node.parent; switch (parent.type) { case "LogicalExpression": @@ -328,9 +328,9 @@ function preprocess(analyzer, node) { * @returns {void} */ function processCodePathToEnter(analyzer, node) { - var codePath = analyzer.codePath; - var state = codePath && CodePath.getState(codePath); - var parent = node.parent; + let codePath = analyzer.codePath; + let state = codePath && CodePath.getState(codePath); + let parent = node.parent; switch (node.type) { case "Program": @@ -419,9 +419,9 @@ function processCodePathToEnter(analyzer, node) { * @returns {void} */ function processCodePathToExit(analyzer, node) { - var codePath = analyzer.codePath; - var state = CodePath.getState(codePath); - var dontForward = false; + let codePath = analyzer.codePath; + let state = CodePath.getState(codePath); + let dontForward = false; switch (node.type) { case "IfStatement": @@ -536,8 +536,8 @@ function postprocess(analyzer, node) { case "Program": case "FunctionDeclaration": case "FunctionExpression": - case "ArrowFunctionExpression": - var codePath = analyzer.codePath; + case "ArrowFunctionExpression": { + let codePath = analyzer.codePath; // Mark the current path as the final node. CodePath.getState(codePath).makeFinal(); @@ -555,6 +555,7 @@ function postprocess(analyzer, node) { debug.dumpState(node, CodePath.getState(codePath), true); } break; + } default: break; diff --git a/tools/eslint/lib/code-path-analysis/code-path-segment.js b/tools/eslint/lib/code-path-analysis/code-path-segment.js index d5361ccd07413b..544a9da2784743 100644 --- a/tools/eslint/lib/code-path-analysis/code-path-segment.js +++ b/tools/eslint/lib/code-path-analysis/code-path-segment.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("./debug-helpers"); +let debug = require("./debug-helpers"); //------------------------------------------------------------------------------ // Helpers @@ -22,11 +22,11 @@ var debug = require("./debug-helpers"); * @returns {CodePathSegment[]} The replaced array. */ function flattenUnusedSegments(segments) { - var done = Object.create(null); - var retv = []; + let done = Object.create(null); + let retv = []; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; // Ignores duplicated. if (done[segment.id]) { @@ -35,8 +35,8 @@ function flattenUnusedSegments(segments) { // Use previous segments if unused. if (!segment.internal.used) { - for (var j = 0; j < segment.allPrevSegments.length; ++j) { - var prevSegment = segment.allPrevSegments[j]; + for (let j = 0; j < segment.allPrevSegments.length; ++j) { + let prevSegment = segment.allPrevSegments[j]; if (!done[prevSegment.id]) { done[prevSegment.id] = true; @@ -175,7 +175,7 @@ CodePathSegment.newNext = function(id, allPrevSegments) { * @returns {CodePathSegment} The created segment. */ CodePathSegment.newUnreachable = function(id, allPrevSegments) { - var segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false); + let segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false); // In `if (a) return a; foo();` case, the unreachable segment preceded by // the return statement is not used but must not be remove. @@ -211,11 +211,11 @@ CodePathSegment.markUsed = function(segment) { } segment.internal.used = true; - var i; + let i; if (segment.reachable) { for (i = 0; i < segment.allPrevSegments.length; ++i) { - var prevSegment = segment.allPrevSegments[i]; + let prevSegment = segment.allPrevSegments[i]; prevSegment.allNextSegments.push(segment); prevSegment.nextSegments.push(segment); diff --git a/tools/eslint/lib/code-path-analysis/code-path-state.js b/tools/eslint/lib/code-path-analysis/code-path-state.js index 0492d832c2c40f..7c3d4a35e62f03 100644 --- a/tools/eslint/lib/code-path-analysis/code-path-state.js +++ b/tools/eslint/lib/code-path-analysis/code-path-state.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var CodePathSegment = require("./code-path-segment"), +let CodePathSegment = require("./code-path-segment"), ForkContext = require("./fork-context"); //------------------------------------------------------------------------------ @@ -30,8 +30,8 @@ var CodePathSegment = require("./code-path-segment"), * @returns {void} */ function addToReturnedOrThrown(dest, others, all, segments) { - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; dest.push(segment); if (others.indexOf(segment) === -1) { @@ -52,7 +52,7 @@ function getContinueContext(state, label) { return state.loopContext; } - var context = state.loopContext; + let context = state.loopContext; while (context) { if (context.label === label) { @@ -73,7 +73,7 @@ function getContinueContext(state, label) { * @returns {LoopContext|SwitchContext} A context for a `break` statement. */ function getBreakContext(state, label) { - var context = state.breakContext; + let context = state.breakContext; while (context) { if (label ? context.label === label : context.breakable) { @@ -93,7 +93,7 @@ function getBreakContext(state, label) { * @returns {TryContext|CodePathState} A context for a `return` statement. */ function getReturnContext(state) { - var context = state.tryContext; + let context = state.tryContext; while (context) { if (context.hasFinalizer && context.position !== "finally") { @@ -112,7 +112,7 @@ function getReturnContext(state) { * @returns {TryContext|CodePathState} A context for a `throw` statement. */ function getThrowContext(state) { - var context = state.tryContext; + let context = state.tryContext; while (context) { if (context.position === "try" || @@ -149,9 +149,9 @@ function remove(xs, x) { * @returns {void} */ function removeConnection(prevSegments, nextSegments) { - for (var i = 0; i < prevSegments.length; ++i) { - var prevSegment = prevSegments[i]; - var nextSegment = nextSegments[i]; + for (let i = 0; i < prevSegments.length; ++i) { + let prevSegment = prevSegments[i]; + let nextSegment = nextSegments[i]; remove(prevSegment.nextSegments, nextSegment); remove(prevSegment.allNextSegments, nextSegment); @@ -169,11 +169,11 @@ function removeConnection(prevSegments, nextSegments) { * @returns {void} */ function makeLooped(state, fromSegments, toSegments) { - var end = Math.min(fromSegments.length, toSegments.length); + let end = Math.min(fromSegments.length, toSegments.length); - for (var i = 0; i < end; ++i) { - var fromSegment = fromSegments[i]; - var toSegment = toSegments[i]; + for (let i = 0; i < end; ++i) { + let fromSegment = fromSegments[i]; + let toSegment = toSegments[i]; if (toSegment.reachable) { fromSegment.nextSegments.push(toSegment); @@ -225,7 +225,7 @@ function finalizeTestSegmentsOfFor(context, choiceContext, head) { * @constructor * @param {IdGenerator} idGenerator - An id generator to generate id for code * path segments. - * @param {function} onLooped - A callback function to notify looping. + * @param {Function} onLooped - A callback function to notify looping. */ function CodePathState(idGenerator, onLooped) { this.idGenerator = idGenerator; @@ -241,9 +241,9 @@ function CodePathState(idGenerator, onLooped) { this.initialSegment = this.forkContext.head[0]; // returnedSegments and thrownSegments push elements into finalSegments also. - var final = this.finalSegments = []; - var returned = this.returnedForkContext = []; - var thrown = this.thrownForkContext = []; + let final = this.finalSegments = []; + let returned = this.returnedForkContext = []; + let thrown = this.thrownForkContext = []; returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final); thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final); @@ -266,7 +266,7 @@ CodePathState.prototype = { * @type {ForkContext} */ get parentForkContext() { - var current = this.forkContext; + let current = this.forkContext; return current && current.upper; }, @@ -292,7 +292,7 @@ CodePathState.prototype = { * @returns {ForkContext} The last context. */ popForkContext: function() { - var lastContext = this.forkContext; + let lastContext = this.forkContext; this.forkContext = lastContext.upper; this.forkContext.replaceHead(lastContext.makeNext(0, -1)); @@ -370,12 +370,12 @@ CodePathState.prototype = { * @returns {ChoiceContext} The popped context. */ popChoiceContext: function() { - var context = this.choiceContext; + let context = this.choiceContext; this.choiceContext = context.upper; - var forkContext = this.forkContext; - var headSegments = forkContext.head; + let forkContext = this.forkContext; + let headSegments = forkContext.head; switch (context.kind) { case "&&": @@ -396,7 +396,7 @@ CodePathState.prototype = { * test chunk. */ if (context.isForkingAsResult) { - var parentContext = this.choiceContext; + let parentContext = this.choiceContext; parentContext.trueForkContext.addAll(context.trueForkContext); parentContext.falseForkContext.addAll(context.falseForkContext); @@ -443,7 +443,7 @@ CodePathState.prototype = { } // Merges all paths. - var prevForkContext = context.trueForkContext; + let prevForkContext = context.trueForkContext; prevForkContext.addAll(context.falseForkContext); forkContext.replaceHead(prevForkContext.makeNext(0, -1)); @@ -458,8 +458,8 @@ CodePathState.prototype = { * @returns {void} */ makeLogicalRight: function() { - var context = this.choiceContext; - var forkContext = this.forkContext; + let context = this.choiceContext; + let forkContext = this.forkContext; if (context.processed) { @@ -467,7 +467,7 @@ CodePathState.prototype = { * This got segments already from the child choice context. * Creates the next path from own true/false fork context. */ - var prevForkContext = + let prevForkContext = context.kind === "&&" ? context.trueForkContext : /* kind === "||" */ context.falseForkContext; @@ -502,8 +502,8 @@ CodePathState.prototype = { * @returns {void} */ makeIfConsequent: function() { - var context = this.choiceContext; - var forkContext = this.forkContext; + let context = this.choiceContext; + let forkContext = this.forkContext; /* * If any result were not transferred from child contexts, @@ -529,8 +529,8 @@ CodePathState.prototype = { * @returns {void} */ makeIfAlternate: function() { - var context = this.choiceContext; - var forkContext = this.forkContext; + let context = this.choiceContext; + let forkContext = this.forkContext; /* * The head segments are the path of the `if` block. @@ -583,12 +583,12 @@ CodePathState.prototype = { * @returns {void} */ popSwitchContext: function() { - var context = this.switchContext; + let context = this.switchContext; this.switchContext = context.upper; - var forkContext = this.forkContext; - var brokenForkContext = this.popBreakContext().brokenForkContext; + let forkContext = this.forkContext; + let brokenForkContext = this.popBreakContext().brokenForkContext; if (context.countForks === 0) { @@ -605,10 +605,10 @@ CodePathState.prototype = { return; } - var lastSegments = forkContext.head; + let lastSegments = forkContext.head; this.forkBypassPath(); - var lastCaseSegments = forkContext.head; + let lastCaseSegments = forkContext.head; /* * `brokenForkContext` is used to make the next segment. @@ -640,7 +640,7 @@ CodePathState.prototype = { } // Pops the segment context stack until the entry segment. - for (var i = 0; i < context.countForks; ++i) { + for (let i = 0; i < context.countForks; ++i) { this.forkContext = this.forkContext.upper; } @@ -659,7 +659,7 @@ CodePathState.prototype = { * @returns {void} */ makeSwitchCaseBody: function(isEmpty, isDefault) { - var context = this.switchContext; + let context = this.switchContext; if (!context.hasCase) { return; @@ -670,8 +670,8 @@ CodePathState.prototype = { * The parent fork context has two segments. * Those are from the current case and the body of the previous case. */ - var parentForkContext = this.forkContext; - var forkContext = this.pushForkContext(); + let parentForkContext = this.forkContext; + let forkContext = this.pushForkContext(); forkContext.add(parentForkContext.makeNext(0, -1)); @@ -731,7 +731,7 @@ CodePathState.prototype = { * @returns {void} */ popTryContext: function() { - var context = this.tryContext; + let context = this.tryContext; this.tryContext = context.upper; @@ -747,19 +747,19 @@ CodePathState.prototype = { * block. */ - var returned = context.returnedForkContext; - var thrown = context.thrownForkContext; + let returned = context.returnedForkContext; + let thrown = context.thrownForkContext; if (returned.empty && thrown.empty) { return; } // Separate head to normal paths and leaving paths. - var headSegments = this.forkContext.head; + let headSegments = this.forkContext.head; this.forkContext = this.forkContext.upper; - var normalSegments = headSegments.slice(0, headSegments.length / 2 | 0); - var leavingSegments = headSegments.slice(headSegments.length / 2 | 0); + let normalSegments = headSegments.slice(0, headSegments.length / 2 | 0); + let leavingSegments = headSegments.slice(headSegments.length / 2 | 0); // Forwards the leaving path to upper contexts. if (!returned.empty) { @@ -785,9 +785,9 @@ CodePathState.prototype = { * @returns {void} */ makeCatchBlock: function() { - var context = this.tryContext; - var forkContext = this.forkContext; - var thrown = context.thrownForkContext; + let context = this.tryContext; + let forkContext = this.forkContext; + let thrown = context.thrownForkContext; // Update state. context.position = "catch"; @@ -796,7 +796,7 @@ CodePathState.prototype = { // Merge thrown paths. thrown.add(forkContext.head); - var thrownSegments = thrown.makeNext(0, -1); + let thrownSegments = thrown.makeNext(0, -1); // Fork to a bypass and the merged thrown path. this.pushForkContext(); @@ -814,11 +814,11 @@ CodePathState.prototype = { * @returns {void} */ makeFinallyBlock: function() { - var context = this.tryContext; - var forkContext = this.forkContext; - var returned = context.returnedForkContext; - var thrown = context.thrownForkContext; - var headOfLeavingSegments = forkContext.head; + let context = this.tryContext; + let forkContext = this.forkContext; + let returned = context.returnedForkContext; + let thrown = context.thrownForkContext; + let headOfLeavingSegments = forkContext.head; // Update state. if (context.position === "catch") { @@ -843,11 +843,11 @@ CodePathState.prototype = { * Create a parallel segment from merging returned and thrown. * This segment will leave at the end of this finally block. */ - var segments = forkContext.makeNext(-1, -1); - var j; + let segments = forkContext.makeNext(-1, -1); + let j; - for (var i = 0; i < forkContext.count; ++i) { - var prevSegsOfLeavingSegment = [headOfLeavingSegments[i]]; + for (let i = 0; i < forkContext.count; ++i) { + let prevSegsOfLeavingSegment = [headOfLeavingSegments[i]]; for (j = 0; j < returned.segmentsList.length; ++j) { prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]); @@ -872,13 +872,13 @@ CodePathState.prototype = { * @returns {void} */ makeFirstThrowablePathInTryBlock: function() { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (!forkContext.reachable) { return; } - var context = getThrowContext(this); + let context = getThrowContext(this); if (context === this || context.position !== "try" || @@ -905,8 +905,8 @@ CodePathState.prototype = { * @returns {void} */ pushLoopContext: function(type, label) { - var forkContext = this.forkContext; - var breakContext = this.pushBreakContext(true, label); + let forkContext = this.forkContext; + let breakContext = this.pushBreakContext(true, label); switch (type) { case "WhileStatement": @@ -977,13 +977,13 @@ CodePathState.prototype = { * @returns {void} */ popLoopContext: function() { - var context = this.loopContext; + let context = this.loopContext; this.loopContext = context.upper; - var forkContext = this.forkContext; - var brokenForkContext = this.popBreakContext().brokenForkContext; - var choiceContext; + let forkContext = this.forkContext; + let brokenForkContext = this.popBreakContext().brokenForkContext; + let choiceContext; // Creates a looped path. switch (context.type) { @@ -996,7 +996,7 @@ CodePathState.prototype = { context.continueDestSegments); break; - case "DoWhileStatement": + case "DoWhileStatement": { choiceContext = this.popChoiceContext(); if (!choiceContext.processed) { @@ -1008,15 +1008,16 @@ CodePathState.prototype = { } // `true` paths go to looping. - var segmentsList = choiceContext.trueForkContext.segmentsList; + const segmentsList = choiceContext.trueForkContext.segmentsList; - for (var i = 0; i < segmentsList.length; ++i) { + for (let i = 0; i < segmentsList.length; ++i) { makeLooped( this, segmentsList[i], context.entrySegments); } break; + } case "ForInStatement": case "ForOfStatement": @@ -1047,9 +1048,9 @@ CodePathState.prototype = { * @returns {void} */ makeWhileTest: function(test) { - var context = this.loopContext; - var forkContext = this.forkContext; - var testSegments = forkContext.makeNext(0, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let testSegments = forkContext.makeNext(0, -1); // Update state. context.test = test; @@ -1063,9 +1064,9 @@ CodePathState.prototype = { * @returns {void} */ makeWhileBody: function() { - var context = this.loopContext; - var choiceContext = this.choiceContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let choiceContext = this.choiceContext; + let forkContext = this.forkContext; if (!choiceContext.processed) { choiceContext.trueForkContext.add(forkContext.head); @@ -1085,9 +1086,9 @@ CodePathState.prototype = { * @returns {void} */ makeDoWhileBody: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var bodySegments = forkContext.makeNext(-1, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let bodySegments = forkContext.makeNext(-1, -1); // Update state. context.entrySegments = bodySegments; @@ -1101,15 +1102,15 @@ CodePathState.prototype = { * @returns {void} */ makeDoWhileTest: function(test) { - var context = this.loopContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let forkContext = this.forkContext; context.test = test; // Creates paths of `continue` statements. if (!context.continueForkContext.empty) { context.continueForkContext.add(forkContext.head); - var testSegments = context.continueForkContext.makeNext(0, -1); + let testSegments = context.continueForkContext.makeNext(0, -1); forkContext.replaceHead(testSegments); } @@ -1122,10 +1123,10 @@ CodePathState.prototype = { * @returns {void} */ makeForTest: function(test) { - var context = this.loopContext; - var forkContext = this.forkContext; - var endOfInitSegments = forkContext.head; - var testSegments = forkContext.makeNext(-1, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let endOfInitSegments = forkContext.head; + let testSegments = forkContext.makeNext(-1, -1); // Update state. context.test = test; @@ -1140,9 +1141,9 @@ CodePathState.prototype = { * @returns {void} */ makeForUpdate: function() { - var context = this.loopContext; - var choiceContext = this.choiceContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let choiceContext = this.choiceContext; + let forkContext = this.forkContext; // Make the next paths of the test. if (context.testSegments) { @@ -1155,7 +1156,7 @@ CodePathState.prototype = { } // Update state. - var updateSegments = forkContext.makeDisconnected(-1, -1); + let updateSegments = forkContext.makeDisconnected(-1, -1); context.continueDestSegments = context.updateSegments = updateSegments; forkContext.replaceHead(updateSegments); @@ -1167,9 +1168,9 @@ CodePathState.prototype = { * @returns {void} */ makeForBody: function() { - var context = this.loopContext; - var choiceContext = this.choiceContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let choiceContext = this.choiceContext; + let forkContext = this.forkContext; // Update state. if (context.updateSegments) { @@ -1191,7 +1192,7 @@ CodePathState.prototype = { context.endOfInitSegments = forkContext.head; } - var bodySegments = context.endOfTestSegments; + let bodySegments = context.endOfTestSegments; if (!bodySegments) { @@ -1199,7 +1200,7 @@ CodePathState.prototype = { * If there is not the `test` part, the `body` path comes from the * `init` part and the `update` part. */ - var prevForkContext = ForkContext.newEmpty(forkContext); + let prevForkContext = ForkContext.newEmpty(forkContext); prevForkContext.add(context.endOfInitSegments); if (context.endOfUpdateSegments) { @@ -1219,9 +1220,9 @@ CodePathState.prototype = { * @returns {void} */ makeForInOfLeft: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var leftSegments = forkContext.makeDisconnected(-1, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let leftSegments = forkContext.makeDisconnected(-1, -1); // Update state. context.prevSegments = forkContext.head; @@ -1236,12 +1237,12 @@ CodePathState.prototype = { * @returns {void} */ makeForInOfRight: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var temp = ForkContext.newEmpty(forkContext); + let context = this.loopContext; + let forkContext = this.forkContext; + let temp = ForkContext.newEmpty(forkContext); temp.add(context.prevSegments); - var rightSegments = temp.makeNext(-1, -1); + let rightSegments = temp.makeNext(-1, -1); // Update state. context.endOfLeftSegments = forkContext.head; @@ -1255,12 +1256,12 @@ CodePathState.prototype = { * @returns {void} */ makeForInOfBody: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var temp = ForkContext.newEmpty(forkContext); + let context = this.loopContext; + let forkContext = this.forkContext; + let temp = ForkContext.newEmpty(forkContext); temp.add(context.endOfLeftSegments); - var bodySegments = temp.makeNext(-1, -1); + let bodySegments = temp.makeNext(-1, -1); // Make a path: `right` -> `left`. makeLooped(this, forkContext.head, context.leftSegments); @@ -1280,7 +1281,7 @@ CodePathState.prototype = { * @param {boolean} breakable - The flag to indicate it can break by * an unlabeled BreakStatement. * @param {string|null} label - The label of this context. - * @returns {object} The new context. + * @returns {Object} The new context. */ pushBreakContext: function(breakable, label) { this.breakContext = { @@ -1295,17 +1296,17 @@ CodePathState.prototype = { /** * Removes the top item of the break context stack. * - * @returns {object} The removed context. + * @returns {Object} The removed context. */ popBreakContext: function() { - var context = this.breakContext; - var forkContext = this.forkContext; + let context = this.breakContext; + let forkContext = this.forkContext; this.breakContext = context.upper; // Process this context here for other than switches and loops. if (!context.breakable) { - var brokenForkContext = context.brokenForkContext; + let brokenForkContext = context.brokenForkContext; if (!brokenForkContext.empty) { brokenForkContext.add(forkContext.head); @@ -1326,13 +1327,13 @@ CodePathState.prototype = { * @returns {void} */ makeBreak: function(label) { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (!forkContext.reachable) { return; } - var context = getBreakContext(this, label); + let context = getBreakContext(this, label); /* istanbul ignore else: foolproof (syntax error) */ if (context) { @@ -1352,13 +1353,13 @@ CodePathState.prototype = { * @returns {void} */ makeContinue: function(label) { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (!forkContext.reachable) { return; } - var context = getContinueContext(this, label); + let context = getContinueContext(this, label); /* istanbul ignore else: foolproof (syntax error) */ if (context) { @@ -1387,7 +1388,7 @@ CodePathState.prototype = { * @returns {void} */ makeReturn: function() { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (forkContext.reachable) { getReturnContext(this).returnedForkContext.add(forkContext.head); @@ -1404,7 +1405,7 @@ CodePathState.prototype = { * @returns {void} */ makeThrow: function() { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (forkContext.reachable) { getThrowContext(this).thrownForkContext.add(forkContext.head); @@ -1417,7 +1418,7 @@ CodePathState.prototype = { * @returns {void} */ makeFinal: function() { - var segments = this.currentSegments; + let segments = this.currentSegments; if (segments.length > 0 && segments[0].reachable) { this.returnedForkContext.add(segments); diff --git a/tools/eslint/lib/code-path-analysis/code-path.js b/tools/eslint/lib/code-path-analysis/code-path.js index 035e34e712e002..3fdc99afc3f658 100644 --- a/tools/eslint/lib/code-path-analysis/code-path.js +++ b/tools/eslint/lib/code-path-analysis/code-path.js @@ -9,8 +9,8 @@ // Requirements //------------------------------------------------------------------------------ -var CodePathState = require("./code-path-state"); -var IdGenerator = require("./id-generator"); +let CodePathState = require("./code-path-state"); +let IdGenerator = require("./id-generator"); //------------------------------------------------------------------------------ // Public Interface @@ -22,7 +22,7 @@ var IdGenerator = require("./id-generator"); * @constructor * @param {string} id - An identifier. * @param {CodePath|null} upper - The code path of the upper function scope. - * @param {function} onLooped - A callback function to notify looping. + * @param {Function} onLooped - A callback function to notify looping. */ function CodePath(id, upper, onLooped) { @@ -117,10 +117,10 @@ CodePath.prototype = { * - `controller.skip()` - Skip the following segments in this branch. * - `controller.break()` - Skip all following segments. * - * @param {object} [options] - Omittable. + * @param {Object} [options] - Omittable. * @param {CodePathSegment} [options.first] - The first segment to traverse. * @param {CodePathSegment} [options.last] - The last segment to traverse. - * @param {function} callback - A callback function. + * @param {Function} callback - A callback function. * @returns {void} */ traverseSegments: function(options, callback) { @@ -130,18 +130,18 @@ CodePath.prototype = { } options = options || {}; - var startSegment = options.first || this.internal.initialSegment; - var lastSegment = options.last; - - var item = null; - var index = 0; - var end = 0; - var segment = null; - var visited = Object.create(null); - var stack = [[startSegment, 0]]; - var skippedSegment = null; - var broken = false; - var controller = { + let startSegment = options.first || this.internal.initialSegment; + let lastSegment = options.last; + + let item = null; + let index = 0; + let end = 0; + let segment = null; + let visited = Object.create(null); + let stack = [[startSegment, 0]]; + let skippedSegment = null; + let broken = false; + let controller = { skip: function() { if (stack.length <= 1) { broken = true; diff --git a/tools/eslint/lib/code-path-analysis/debug-helpers.js b/tools/eslint/lib/code-path-analysis/debug-helpers.js index e68c94bc496a0d..ea31a1a9d73816 100644 --- a/tools/eslint/lib/code-path-analysis/debug-helpers.js +++ b/tools/eslint/lib/code-path-analysis/debug-helpers.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug")("eslint:code-path"); +let debug = require("debug")("eslint:code-path"); //------------------------------------------------------------------------------ // Helpers @@ -54,8 +54,8 @@ module.exports = { * @returns {void} */ dumpState: !debug.enabled ? debug : /* istanbul ignore next */ function(node, state, leaving) { - for (var i = 0; i < state.currentSegments.length; ++i) { - var segInternal = state.currentSegments[i].internal; + for (let i = 0; i < state.currentSegments.length; ++i) { + let segInternal = state.currentSegments[i].internal; if (leaving) { segInternal.exitNodes.push(node); @@ -80,7 +80,7 @@ module.exports = { * @see http://www.webgraphviz.com */ dumpDot: !debug.enabled ? debug : /* istanbul ignore next */ function(codePath) { - var text = + let text = "\n" + "digraph {\n" + "node[shape=box,style=\"rounded,filled\",fillcolor=white];\n" + @@ -93,11 +93,11 @@ module.exports = { text += "thrown[label=\"✘\",shape=circle,width=0.3,height=0.3,fixedsize];\n"; } - var traceMap = Object.create(null); - var arrows = this.makeDotArrows(codePath, traceMap); + let traceMap = Object.create(null); + let arrows = this.makeDotArrows(codePath, traceMap); - for (var id in traceMap) { // eslint-disable-line guard-for-in - var segment = traceMap[id]; + for (let id in traceMap) { // eslint-disable-line guard-for-in + let segment = traceMap[id]; text += id + "["; @@ -140,26 +140,26 @@ module.exports = { * The DOT code can be visialized with Graphvis. * * @param {CodePath} codePath - A code path to make DOT. - * @param {object} traceMap - Optional. A map to check whether or not segments had been done. + * @param {Object} traceMap - Optional. A map to check whether or not segments had been done. * @returns {string} A DOT code of the code path. */ makeDotArrows: function(codePath, traceMap) { - var stack = [[codePath.initialSegment, 0]]; - var done = traceMap || Object.create(null); - var lastId = codePath.initialSegment.id; - var text = "initial->" + codePath.initialSegment.id; + let stack = [[codePath.initialSegment, 0]]; + let done = traceMap || Object.create(null); + let lastId = codePath.initialSegment.id; + let text = "initial->" + codePath.initialSegment.id; while (stack.length > 0) { - var item = stack.pop(); - var segment = item[0]; - var index = item[1]; + let item = stack.pop(); + let segment = item[0]; + let index = item[1]; if (done[segment.id] && index === 0) { continue; } done[segment.id] = segment; - var nextSegment = segment.allNextSegments[index]; + let nextSegment = segment.allNextSegments[index]; if (!nextSegment) { continue; diff --git a/tools/eslint/lib/code-path-analysis/fork-context.js b/tools/eslint/lib/code-path-analysis/fork-context.js index 00e0f97c40300f..93e59e7a028fde 100644 --- a/tools/eslint/lib/code-path-analysis/fork-context.js +++ b/tools/eslint/lib/code-path-analysis/fork-context.js @@ -13,7 +13,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"), +let assert = require("assert"), CodePathSegment = require("./code-path-segment"); //------------------------------------------------------------------------------ @@ -40,11 +40,11 @@ function isReachable(segment) { * @param {ForkContext} context - An instance. * @param {number} begin - The first index of the previous segments. * @param {number} end - The last index of the previous segments. - * @param {function} create - A factory function of new segments. + * @param {Function} create - A factory function of new segments. * @returns {CodePathSegment[]} New segments. */ function makeSegments(context, begin, end, create) { - var list = context.segmentsList; + let list = context.segmentsList; if (begin < 0) { begin = list.length + begin; @@ -53,12 +53,12 @@ function makeSegments(context, begin, end, create) { end = list.length + end; } - var segments = []; + let segments = []; - for (var i = 0; i < context.count; ++i) { - var allPrevSegments = []; + for (let i = 0; i < context.count; ++i) { + let allPrevSegments = []; - for (var j = begin; j <= end; ++j) { + for (let j = begin; j <= end; ++j) { allPrevSegments.push(list[j][i]); } @@ -80,9 +80,9 @@ function makeSegments(context, begin, end, create) { */ function mergeExtraSegments(context, segments) { while (segments.length > context.count) { - var merged = []; + let merged = []; - for (var i = 0, length = segments.length / 2 | 0; i < length; ++i) { + for (let i = 0, length = segments.length / 2 | 0; i < length; ++i) { merged.push(CodePathSegment.newNext( context.idGenerator.next(), [segments[i], segments[i + length]] @@ -120,7 +120,7 @@ ForkContext.prototype = { * @type {CodePathSegment[]} */ get head() { - var list = this.segmentsList; + let list = this.segmentsList; return list.length === 0 ? [] : list[list.length - 1]; }, @@ -138,7 +138,7 @@ ForkContext.prototype = { * @type {boolean} */ get reachable() { - var segments = this.head; + let segments = this.head; return segments.length > 0 && segments.some(isReachable); }, @@ -214,9 +214,9 @@ ForkContext.prototype = { addAll: function(context) { assert(context.count === this.count); - var source = context.segmentsList; + let source = context.segmentsList; - for (var i = 0; i < source.length; ++i) { + for (let i = 0; i < source.length; ++i) { this.segmentsList.push(source[i]); } }, @@ -238,7 +238,7 @@ ForkContext.prototype = { * @returns {ForkContext} New fork context. */ ForkContext.newRoot = function(idGenerator) { - var context = new ForkContext(idGenerator, null, 1); + let context = new ForkContext(idGenerator, null, 1); context.add([CodePathSegment.newRoot(idGenerator.next())]); diff --git a/tools/eslint/lib/config.js b/tools/eslint/lib/config.js index a485774d7757bb..8c8533a22830ba 100644 --- a/tools/eslint/lib/config.js +++ b/tools/eslint/lib/config.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var path = require("path"), +let path = require("path"), ConfigOps = require("./config/config-ops"), ConfigFile = require("./config/config-file"), Plugins = require("./config/plugins"), @@ -23,7 +23,7 @@ var path = require("path"), // Constants //------------------------------------------------------------------------------ -var PERSONAL_CONFIG_DIR = userHome || null; +let PERSONAL_CONFIG_DIR = userHome || null; //------------------------------------------------------------------------------ // Helpers @@ -48,7 +48,7 @@ function isObject(item) { * @private */ function loadConfig(configToLoad) { - var config = {}, + let config = {}, filePath = ""; if (configToLoad) { @@ -75,7 +75,7 @@ function loadConfig(configToLoad) { * @private */ function getPersonalConfig() { - var config, + let config, filename; if (PERSONAL_CONFIG_DIR) { @@ -106,7 +106,7 @@ function hasRules(options) { * @returns {Object} The local config object, or an empty object if there is no local config. */ function getLocalConfig(thisConfig, directory) { - var found, + let found, i, localConfig, localConfigFile, @@ -162,10 +162,10 @@ function getLocalConfig(thisConfig, directory) { if (personalConfig) { config = ConfigOps.merge(config, personalConfig); - } else if (!hasRules(thisConfig.options)) { + } else if (!hasRules(thisConfig.options) && !thisConfig.options.baseConfig) { // No config file, no manual configuration, and no rules, so error. - var noConfigError = new Error("No ESLint configuration found."); + let noConfigError = new Error("No ESLint configuration found."); noConfigError.messageTemplate = "no-config-found"; noConfigError.messageData = { @@ -191,7 +191,7 @@ function getLocalConfig(thisConfig, directory) { * @param {Object} options Options to be passed in */ function Config(options) { - var useConfig; + let useConfig; options = options || {}; @@ -217,7 +217,7 @@ function Config(options) { * If user declares "foo", convert to "foo:false". */ this.globals = (options.globals || []).reduce(function(globals, def) { - var parts = def.split(":"); + let parts = def.split(":"); globals[parts[0]] = (parts.length > 1 && parts[1] === "true"); @@ -244,7 +244,7 @@ function Config(options) { * @returns {Object} config object */ Config.prototype.getConfig = function(filePath) { - var config, + let config, userConfig, directory = filePath ? path.dirname(filePath) : this.options.cwd; diff --git a/tools/eslint/lib/config/autoconfig.js b/tools/eslint/lib/config/autoconfig.js index be3d0970741935..2cd753e95dd9f8 100644 --- a/tools/eslint/lib/config/autoconfig.js +++ b/tools/eslint/lib/config/autoconfig.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), debug = require("debug"), eslint = require("../eslint"), configRule = require("./config-rule"), @@ -20,7 +20,7 @@ var lodash = require("lodash"), // Data //------------------------------------------------------------------------------ -var MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only +let MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only RECOMMENDED_CONFIG_NAME = "eslint:recommended"; //------------------------------------------------------------------------------ @@ -89,7 +89,7 @@ Registry.prototype = { * @returns {void} */ populateFromCoreRules: function() { - var rulesConfig = configRule.createCoreRuleConfigs(); + let rulesConfig = configRule.createCoreRuleConfigs(); this.rules = makeRegistryItems(rulesConfig); }, @@ -109,7 +109,7 @@ Registry.prototype = { * @returns {Object[]} "rules" configurations to use for linting */ buildRuleSets: function() { - var idx = 0, + let idx = 0, ruleIds = Object.keys(this.rules), ruleSets = []; @@ -122,7 +122,7 @@ Registry.prototype = { * @param {string} rule The ruleId to add. * @returns {void} */ - var addRuleToRuleSet = function(rule) { + let addRuleToRuleSet = function(rule) { /* * This check ensures that there is a rule configuration and that @@ -130,7 +130,7 @@ Registry.prototype = { * If it has too many configs, we will only use the most basic of * the possible configurations. */ - var hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS); + let hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS); if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) { @@ -170,12 +170,12 @@ Registry.prototype = { * @returns {void} */ stripFailingConfigs: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), newRegistry = new Registry(); newRegistry.rules = lodash.assign({}, this.rules); ruleIds.forEach(function(ruleId) { - var errorFreeItems = newRegistry.rules[ruleId].filter(function(registryItem) { + let errorFreeItems = newRegistry.rules[ruleId].filter(function(registryItem) { return (registryItem.errorCount === 0); }); @@ -195,7 +195,7 @@ Registry.prototype = { * @returns {void} */ stripExtraConfigs: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), newRegistry = new Registry(); newRegistry.rules = lodash.assign({}, this.rules); @@ -216,11 +216,11 @@ Registry.prototype = { * @returns {Registry} A registry of failing rules. */ getFailingRulesRegistry: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), failingRegistry = new Registry(); ruleIds.forEach(function(ruleId) { - var failingConfigs = this.rules[ruleId].filter(function(registryItem) { + let failingConfigs = this.rules[ruleId].filter(function(registryItem) { return (registryItem.errorCount > 0); }); @@ -239,7 +239,7 @@ Registry.prototype = { * @returns {Object} An eslint config with rules section populated */ createConfig: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), config = {rules: {}}; ruleIds.forEach(function(ruleId) { @@ -258,7 +258,7 @@ Registry.prototype = { * @returns {Registry} A registry of rules */ filterBySpecificity: function(specificity) { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), newRegistry = new Registry(); newRegistry.rules = lodash.assign({}, this.rules); @@ -280,7 +280,7 @@ Registry.prototype = { * @returns {Registry} New registry with errorCount populated */ lintSourceCode: function(sourceCodes, config, cb) { - var totalFilesLinting, + let totalFilesLinting, lintConfig, ruleSets, ruleSetIdx, @@ -307,7 +307,7 @@ Registry.prototype = { ruleSets.forEach(function(ruleSet) { lintConfig = lodash.assign({}, config, {rules: ruleSet}); - var lintResults = eslint.verify(sourceCodes[filename], lintConfig); + let lintResults = eslint.verify(sourceCodes[filename], lintConfig); lintResults.forEach(function(result) { @@ -344,11 +344,11 @@ Registry.prototype = { * @returns {Object} config object using `"extends": "eslint:recommended"` */ function extendFromRecommended(config) { - var newConfig = lodash.assign({}, config); + let newConfig = lodash.assign({}, config); ConfigOps.normalizeToStrings(newConfig); - var recRules = Object.keys(recConfig.rules).filter(function(ruleId) { + let recRules = Object.keys(recConfig.rules).filter(function(ruleId) { return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]); }); diff --git a/tools/eslint/lib/config/config-file.js b/tools/eslint/lib/config/config-file.js index e2996e3eb90e64..9120c12f3c49cd 100644 --- a/tools/eslint/lib/config/config-file.js +++ b/tools/eslint/lib/config/config-file.js @@ -11,7 +11,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug"), +let debug = require("debug"), fs = require("fs"), path = require("path"), ConfigOps = require("./config-ops"), @@ -48,7 +48,7 @@ function sortByKey(a, b) { // Private //------------------------------------------------------------------------------ -var CONFIG_FILES = [ +let CONFIG_FILES = [ ".eslintrc.js", ".eslintrc.yaml", ".eslintrc.yml", @@ -57,7 +57,7 @@ var CONFIG_FILES = [ "package.json" ]; -var resolver = new ModuleResolver(); +let resolver = new ModuleResolver(); debug = debug("eslint:config-file"); @@ -94,7 +94,7 @@ function loadYAMLConfigFile(filePath) { debug("Loading YAML config file: " + filePath); // lazy load YAML to improve performance when not used - var yaml = require("js-yaml"); + let yaml = require("js-yaml"); try { @@ -137,7 +137,7 @@ function loadLegacyConfigFile(filePath) { debug("Loading config file: " + filePath); // lazy load YAML to improve performance when not used - var yaml = require("js-yaml"); + let yaml = require("js-yaml"); try { return yaml.safeLoad(stripComments(readFile(filePath))) || /* istanbul ignore next */ {}; @@ -192,7 +192,7 @@ function loadPackageJSONConfigFile(filePath) { * @private */ function loadConfigFile(file) { - var config, + let config, filePath = file.filePath; switch (path.extname(filePath)) { @@ -236,7 +236,7 @@ function loadConfigFile(file) { function writeJSONConfigFile(config, filePath) { debug("Writing JSON config file: " + filePath); - var content = stringify(config, {cmp: sortByKey, space: 4}); + let content = stringify(config, {cmp: sortByKey, space: 4}); fs.writeFileSync(filePath, content, "utf8"); } @@ -252,9 +252,9 @@ function writeYAMLConfigFile(config, filePath) { debug("Writing YAML config file: " + filePath); // lazy load YAML to improve performance when not used - var yaml = require("js-yaml"); + let yaml = require("js-yaml"); - var content = yaml.safeDump(config, {sortKeys: true}); + let content = yaml.safeDump(config, {sortKeys: true}); fs.writeFileSync(filePath, content, "utf8"); } @@ -269,7 +269,7 @@ function writeYAMLConfigFile(config, filePath) { function writeJSConfigFile(config, filePath) { debug("Writing JS config file: " + filePath); - var content = "module.exports = " + stringify(config, {cmp: sortByKey, space: 4}) + ";"; + let content = "module.exports = " + stringify(config, {cmp: sortByKey, space: 4}) + ";"; fs.writeFileSync(filePath, content, "utf8"); } @@ -313,7 +313,7 @@ function write(config, filePath) { function getBaseDir(configFilePath) { // calculates the path of the project including ESLint as dependency - var projectPath = path.resolve(__dirname, "../../../"); + let projectPath = path.resolve(__dirname, "../../../"); if (configFilePath && pathIsInside(configFilePath, projectPath)) { @@ -336,7 +336,7 @@ function getBaseDir(configFilePath) { * @private */ function getLookupPath(configFilePath) { - var basedir = getBaseDir(configFilePath); + let basedir = getBaseDir(configFilePath); return path.join(basedir, "node_modules"); } @@ -352,7 +352,7 @@ function getLookupPath(configFilePath) { * @private */ function applyExtends(config, filePath, relativeTo) { - var configExtends = config.extends; + let configExtends = config.extends; // normalize into an array for easier handling if (!Array.isArray(config.extends)) { @@ -431,7 +431,7 @@ function normalizePackageName(name, prefix) { * it's a scoped package * package name is "eslint-config", or just a username */ - var scopedPackageShortcutRegex = new RegExp("^(@[^\/]+)(?:\/(?:" + prefix + ")?)?$"), + let scopedPackageShortcutRegex = new RegExp("^(@[^\/]+)(?:\/(?:" + prefix + ")?)?$"), scopedPackageNameRegex = new RegExp("^" + prefix + "(-|$)"); if (scopedPackageShortcutRegex.test(name)) { @@ -463,11 +463,11 @@ function resolve(filePath, relativeTo) { if (isFilePath(filePath)) { return { filePath: path.resolve(relativeTo || "", filePath) }; } else { - var normalizedPackageName; + let normalizedPackageName; if (filePath.indexOf("plugin:") === 0) { - var packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7); - var configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1); + let packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7); + let configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1); normalizedPackageName = normalizePackageName(packagePath, "eslint-plugin"); debug("Attempting to resolve " + normalizedPackageName); @@ -493,7 +493,7 @@ function resolve(filePath, relativeTo) { * @private */ function load(filePath, applyEnvironments, relativeTo) { - var resolvedPath = resolve(filePath, relativeTo), + let resolvedPath = resolve(filePath, relativeTo), dirname = path.dirname(resolvedPath.filePath), lookupPath = getLookupPath(dirname), config = loadConfigFile(resolvedPath); @@ -565,9 +565,9 @@ module.exports = { */ getFilenameForDirectory: function(directory) { - var filename; + let filename; - for (var i = 0, len = CONFIG_FILES.length; i < len; i++) { + for (let i = 0, len = CONFIG_FILES.length; i < len; i++) { filename = path.join(directory, CONFIG_FILES[i]); if (fs.existsSync(filename)) { return filename; diff --git a/tools/eslint/lib/config/config-initializer.js b/tools/eslint/lib/config/config-initializer.js index 91d2454a8a44f3..ca52a06c657b31 100644 --- a/tools/eslint/lib/config/config-initializer.js +++ b/tools/eslint/lib/config/config-initializer.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var util = require("util"), +let util = require("util"), debug = require("debug"), lodash = require("lodash"), inquirer = require("inquirer"), @@ -38,7 +38,7 @@ debug = debug("eslint:config-initializer"); function writeFile(config, format) { // default is .js - var extname = ".js"; + let extname = ".js"; if (format === "YAML") { extname = ".yml"; @@ -60,7 +60,7 @@ function writeFile(config, format) { * @returns {void} */ function installModules(config) { - var modules = [], + let modules = [], installStatus, modulesToInstall; @@ -86,7 +86,7 @@ function installModules(config) { // Install packages which aren't already installed modulesToInstall = Object.keys(installStatus).filter(function(module) { - var notInstalled = installStatus[module] === false; + let notInstalled = installStatus[module] === false; if (module === "eslint" && notInstalled) { log.info("Local ESLint installation not found."); @@ -113,10 +113,10 @@ function installModules(config) { * @returns {Object} config object with configured rules */ function configureRules(answers, config) { - var BAR_TOTAL = 20, + let BAR_TOTAL = 20, BAR_SOURCE_CODE_TOTAL = 4; - var newConfig = lodash.assign({}, config), + let newConfig = lodash.assign({}, config), bar, patterns, sourceCodes, @@ -163,7 +163,7 @@ function configureRules(answers, config) { debug("\nRegistry: " + util.inspect(registry.rules, {depth: null})); // Create a list of recommended rules, because we don't want to disable them - var recRules = Object.keys(recConfig.rules).filter(function(ruleId) { + let recRules = Object.keys(recConfig.rules).filter(function(ruleId) { return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]); }); @@ -202,12 +202,12 @@ function configureRules(answers, config) { bar.update(BAR_TOTAL); // Log out some stats to let the user know what happened - var finalRuleIds = Object.keys(newConfig.rules), + let finalRuleIds = Object.keys(newConfig.rules), totalRules = finalRuleIds.length; - var enabledRules = finalRuleIds.filter(function(ruleId) { + let enabledRules = finalRuleIds.filter(function(ruleId) { return (newConfig.rules[ruleId] !== 0); }).length; - var resultMessage = [ + let resultMessage = [ "\nEnabled " + enabledRules + " out of " + totalRules, "rules based on " + fileQty, "file" + ((fileQty === 1) ? "." : "s.") @@ -225,7 +225,7 @@ function configureRules(answers, config) { * @returns {Object} config object */ function processAnswers(answers) { - var config = {rules: {}, env: {}}; + let config = {rules: {}, env: {}}; if (answers.es6) { config.env.es6 = true; @@ -275,10 +275,10 @@ function processAnswers(answers) { * @returns {Object} config object */ function getConfigForStyleGuide(guide) { - var guides = { + let guides = { google: {extends: "google"}, airbnb: {extends: "airbnb", plugins: ["react"]}, - standard: {extends: "standard", plugins: ["standard"]} + standard: {extends: "standard", plugins: ["standard", "promise"]} }; if (!guides[guide]) { @@ -293,11 +293,11 @@ function getConfigForStyleGuide(guide) { /* istanbul ignore next: no need to test inquirer*/ /** * Ask use a few questions on command prompt - * @param {function} callback callback function when file has been written + * @param {Function} callback callback function when file has been written * @returns {void} */ function promptUser(callback) { - var config; + let config; inquirer.prompt([ { @@ -419,7 +419,7 @@ function promptUser(callback) { // early exit if you are using automatic style generation if (earlyAnswers.source === "auto") { try { - var combinedAnswers = lodash.assign({}, earlyAnswers, secondAnswers); + let combinedAnswers = lodash.assign({}, earlyAnswers, secondAnswers); config = processAnswers(combinedAnswers); installModules(config); @@ -469,7 +469,7 @@ function promptUser(callback) { } ], function(answers) { try { - var totalAnswers = lodash.assign({}, earlyAnswers, secondAnswers, answers); + let totalAnswers = lodash.assign({}, earlyAnswers, secondAnswers, answers); config = processAnswers(totalAnswers); installModules(config); @@ -488,7 +488,7 @@ function promptUser(callback) { // Public Interface //------------------------------------------------------------------------------ -var init = { +let init = { getConfigForStyleGuide: getConfigForStyleGuide, processAnswers: processAnswers, initializeConfig: /* istanbul ignore next */ function(callback) { diff --git a/tools/eslint/lib/config/config-ops.js b/tools/eslint/lib/config/config-ops.js index d62169502b7497..2e0c29a752d3f6 100644 --- a/tools/eslint/lib/config/config-ops.js +++ b/tools/eslint/lib/config/config-ops.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), debug = require("debug"), Environments = require("./environments"); @@ -19,7 +19,7 @@ var lodash = require("lodash"), debug = debug("eslint:config-ops"); -var RULE_SEVERITY_STRINGS = ["off", "warn", "error"], +let RULE_SEVERITY_STRINGS = ["off", "warn", "error"], RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce(function(map, value, index) { map[value] = index; return map; @@ -53,7 +53,7 @@ module.exports = { */ createEnvironmentConfig: function(env) { - var envConfig = this.createEmptyConfig(); + let envConfig = this.createEmptyConfig(); if (env) { @@ -62,7 +62,7 @@ module.exports = { Object.keys(env).filter(function(name) { return env[name]; }).forEach(function(name) { - var environment = Environments.get(name); + let environment = Environments.get(name); if (environment) { debug("Creating config for environment " + name); @@ -134,8 +134,8 @@ module.exports = { * (https://github.com/KyleAMathews/deepmerge) * and modified to meet our needs. */ - var array = Array.isArray(src) || Array.isArray(target); - var dst = array && [] || {}; + let array = Array.isArray(src) || Array.isArray(target); + let dst = array && [] || {}; combine = !!combine; isRule = !!isRule; @@ -202,7 +202,7 @@ module.exports = { if (config.rules) { Object.keys(config.rules).forEach(function(ruleId) { - var ruleConfig = config.rules[ruleId]; + let ruleConfig = config.rules[ruleId]; if (typeof ruleConfig === "string") { config.rules[ruleId] = RULE_SEVERITY[ruleConfig.toLowerCase()] || 0; @@ -224,7 +224,7 @@ module.exports = { if (config.rules) { Object.keys(config.rules).forEach(function(ruleId) { - var ruleConfig = config.rules[ruleId]; + let ruleConfig = config.rules[ruleId]; if (typeof ruleConfig === "number") { config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0]; @@ -242,7 +242,7 @@ module.exports = { */ isErrorSeverity: function(ruleConfig) { - var severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; + let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; if (typeof severity === "string") { severity = RULE_SEVERITY[severity.toLowerCase()] || 0; @@ -257,7 +257,7 @@ module.exports = { * @returns {boolean} `true` if the configuration has valid severity. */ isValidSeverity: function(ruleConfig) { - var severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; + let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; if (typeof severity === "string") { severity = severity.toLowerCase(); @@ -267,7 +267,7 @@ module.exports = { /** * Checks whether every rule of a given config has valid severity or not. - * @param {object} config - The configuration for rules. + * @param {Object} config - The configuration for rules. * @returns {boolean} `true` if the configuration has valid severity. */ isEverySeverityValid: function(config) { diff --git a/tools/eslint/lib/config/config-rule.js b/tools/eslint/lib/config/config-rule.js index c0a394efee10fd..f4c2803ff7e24d 100644 --- a/tools/eslint/lib/config/config-rule.js +++ b/tools/eslint/lib/config/config-rule.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var rules = require("../rules"), +let rules = require("../rules"), loadRules = require("../load-rules"); @@ -41,7 +41,7 @@ function explodeArray(xs) { * @returns {array} A mixture of the elements of the first and second arrays. */ function combineArrays(arr1, arr2) { - var res = []; + let res = []; if (arr1.length === 0) { return explodeArray(arr2); @@ -78,8 +78,8 @@ function combineArrays(arr1, arr2) { * @returns {Array[]} Array of arrays of objects grouped by property */ function groupByProperty(objects) { - var groupedObj = objects.reduce(function(accumulator, obj) { - var prop = Object.keys(obj)[0]; + let groupedObj = objects.reduce(function(accumulator, obj) { + let prop = Object.keys(obj)[0]; accumulator[prop] = accumulator[prop] ? accumulator[prop].concat(obj) : [obj]; return accumulator; @@ -144,7 +144,7 @@ function groupByProperty(objects) { * @returns {Object[]} Combined objects for each combination of input properties and values */ function combinePropertyObjects(objArr1, objArr2) { - var res = []; + let res = []; if (objArr1.length === 0) { return objArr2; @@ -154,9 +154,9 @@ function combinePropertyObjects(objArr1, objArr2) { } objArr1.forEach(function(obj1) { objArr2.forEach(function(obj2) { - var combinedObj = {}; - var obj1Props = Object.keys(obj1); - var obj2Props = Object.keys(obj2); + let combinedObj = {}; + let obj1Props = Object.keys(obj1); + let obj2Props = Object.keys(obj2); obj1Props.forEach(function(prop1) { combinedObj[prop1] = obj1[prop1]; @@ -229,12 +229,12 @@ RuleConfigSet.prototype = { * @returns {void} */ addObject: function(obj) { - var objectConfigSet = { + let objectConfigSet = { objectConfigs: [], add: function(property, values) { - var optionObj; + let optionObj; - for (var idx = 0; idx < values.length; idx++) { + for (let idx = 0; idx < values.length; idx++) { optionObj = {}; optionObj[property] = values[idx]; this.objectConfigs.push(optionObj); @@ -274,7 +274,7 @@ RuleConfigSet.prototype = { * @returns {array[]} Valid rule configurations */ function generateConfigsFromSchema(schema) { - var configSet = new RuleConfigSet(); + let configSet = new RuleConfigSet(); if (Array.isArray(schema)) { schema.forEach(function(opt) { @@ -301,11 +301,11 @@ function generateConfigsFromSchema(schema) { * @returns {rulesConfig} Hash of rule names and arrays of possible configurations */ function createCoreRuleConfigs() { - var ruleList = loadRules(); + let ruleList = loadRules(); return Object.keys(ruleList).reduce(function(accumulator, id) { - var rule = rules.get(id); - var schema = (typeof rule === "function") ? rule.schema : rule.meta.schema; + let rule = rules.get(id); + let schema = (typeof rule === "function") ? rule.schema : rule.meta.schema; accumulator[id] = generateConfigsFromSchema(schema); return accumulator; diff --git a/tools/eslint/lib/config/config-validator.js b/tools/eslint/lib/config/config-validator.js index ebc70516c195d5..6695260a23a8fa 100644 --- a/tools/eslint/lib/config/config-validator.js +++ b/tools/eslint/lib/config/config-validator.js @@ -9,12 +9,12 @@ // Requirements //------------------------------------------------------------------------------ -var rules = require("../rules"), +let rules = require("../rules"), Environments = require("./environments"), schemaValidator = require("is-my-json-valid"), util = require("util"); -var validators = { +let validators = { rules: Object.create(null) }; @@ -25,10 +25,10 @@ var validators = { /** * Gets a complete options schema for a rule. * @param {string} id The rule's unique name. - * @returns {object} JSON Schema for the rule's options. + * @returns {Object} JSON Schema for the rule's options. */ function getRuleOptionsSchema(id) { - var rule = rules.get(id), + let rule = rules.get(id), schema = rule && rule.schema || rule && rule.meta && rule.meta.schema; // Given a tuple of schemas, insert warning level at the beginning @@ -61,7 +61,7 @@ function getRuleOptionsSchema(id) { * @returns {void} */ function validateRuleOptions(id, options, source) { - var validateRule = validators.rules[id], + let validateRule = validators.rules[id], message, severity, localOptions, @@ -119,7 +119,7 @@ function validateRuleOptions(id, options, source) { /** * Validates an environment object - * @param {object} environment The environment config object to validate. + * @param {Object} environment The environment config object to validate. * @param {string} source The location to report with any errors. * @returns {void} */ @@ -137,7 +137,7 @@ function validateEnvironment(environment, source) { if (typeof environment === "object") { Object.keys(environment).forEach(function(env) { if (!Environments.get(env)) { - var message = [ + let message = [ source, ":\n", "\tEnvironment key \"", env, "\" is unknown\n" ]; @@ -152,7 +152,7 @@ function validateEnvironment(environment, source) { /** * Validates an entire config object. - * @param {object} config The config object to validate. + * @param {Object} config The config object to validate. * @param {string} source The location to report with any errors. * @returns {void} */ diff --git a/tools/eslint/lib/config/environments.js b/tools/eslint/lib/config/environments.js index 8daef864e3179c..9a5defbfc27e05 100644 --- a/tools/eslint/lib/config/environments.js +++ b/tools/eslint/lib/config/environments.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var envs = require("../../conf/environments"); +let envs = require("../../conf/environments"); //------------------------------------------------------------------------------ // Private //------------------------------------------------------------------------------ -var environments = Object.create(null); +let environments = new Map(); /** * Loads the default environments. @@ -23,7 +23,7 @@ var environments = Object.create(null); */ function load() { Object.keys(envs).forEach(function(envName) { - environments[envName] = envs[envName]; + environments.set(envName, envs[envName]); }); } @@ -36,15 +36,15 @@ load(); module.exports = { - load: load, + load, /** * Gets the environment with the given name. * @param {string} name The name of the environment to retrieve. * @returns {Object?} The environment object or null if not found. */ - get: function(name) { - return environments[name] || null; + get(name) { + return environments.get(name) || null; }, /** @@ -53,8 +53,8 @@ module.exports = { * @param {Object} env The environment settings. * @returns {void} */ - define: function(name, env) { - environments[name] = env; + define(name, env) { + environments.set(name, env); }, /** @@ -63,7 +63,7 @@ module.exports = { * @param {string} pluginName The name of the plugin. * @returns {void} */ - importPlugin: function(plugin, pluginName) { + importPlugin(plugin, pluginName) { if (plugin.environments) { Object.keys(plugin.environments).forEach(function(envName) { this.define(pluginName + "/" + envName, plugin.environments[envName]); @@ -75,8 +75,8 @@ module.exports = { * Resets all environments. Only use for tests! * @returns {void} */ - testReset: function() { - environments = Object.create(null); + testReset() { + environments = new Map(); load(); } }; diff --git a/tools/eslint/lib/config/plugins.js b/tools/eslint/lib/config/plugins.js index e157eb123c9df5..7065045c1216c8 100644 --- a/tools/eslint/lib/config/plugins.js +++ b/tools/eslint/lib/config/plugins.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug"), +let debug = require("debug"), Environments = require("./environments"), rules = require("../rules"); @@ -18,9 +18,9 @@ var debug = require("debug"), debug = debug("eslint:plugins"); -var plugins = Object.create(null); +let plugins = Object.create(null); -var PLUGIN_NAME_PREFIX = "eslint-plugin-", +let PLUGIN_NAME_PREFIX = "eslint-plugin-", NAMESPACE_REGEX = /^@.*\//i; /** @@ -67,7 +67,7 @@ module.exports = { * @returns {void} */ define: function(pluginName, plugin) { - var pluginNameWithoutNamespace = removeNamespace(pluginName), + let pluginNameWithoutNamespace = removeNamespace(pluginName), pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace); plugins[pluginNameWithoutPrefix] = plugin; @@ -104,7 +104,7 @@ module.exports = { * @throws {Error} If the plugin cannot be loaded. */ load: function(pluginName) { - var pluginNamespace = getNamespace(pluginName), + let pluginNamespace = getNamespace(pluginName), pluginNameWithoutNamespace = removeNamespace(pluginName), pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace), plugin = null; diff --git a/tools/eslint/lib/eslint.js b/tools/eslint/lib/eslint.js index 69ad96e820bf5d..01b43eb4ee192e 100644 --- a/tools/eslint/lib/eslint.js +++ b/tools/eslint/lib/eslint.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"), +let assert = require("assert"), EventEmitter = require("events").EventEmitter, escope = require("escope"), levn = require("levn"), @@ -41,19 +41,16 @@ var assert = require("assert"), * @returns {Object} Result map object of names and boolean values */ function parseBooleanConfig(string, comment) { - var items = {}; + let items = {}; - // Collapse whitespace around : to make parsing easier - string = string.replace(/\s*:\s*/g, ":"); - - // Collapse whitespace around , - string = string.replace(/\s*,\s*/g, ","); + // Collapse whitespace around `:` and `,` to make parsing easier + string = string.replace(/\s*([:,])\s*/g, "$1"); string.split(/\s|,+/).forEach(function(name) { if (!name) { return; } - var pos = name.indexOf(":"), + let pos = name.indexOf(":"), value; if (pos !== -1) { @@ -78,7 +75,7 @@ function parseBooleanConfig(string, comment) { * @returns {Object} Result map object */ function parseJsonConfig(string, location, messages) { - var items = {}; + let items = {}; // Parses a JSON-like comment by the same way as parsing CLI option. try { @@ -125,7 +122,7 @@ function parseJsonConfig(string, location, messages) { * @returns {Object} Result map of values and true values */ function parseListConfig(string) { - var items = {}; + let items = {}; // Collapse whitespace around , string = string.replace(/\s*,\s*/g, ","); @@ -150,7 +147,7 @@ function parseListConfig(string) { * @returns {void} */ function addDeclaredGlobals(program, globalScope, config) { - var declaredGlobals = {}, + let declaredGlobals = {}, exportedGlobals = {}, explicitGlobals = {}, builtin = Environments.get("builtin"); @@ -159,7 +156,7 @@ function addDeclaredGlobals(program, globalScope, config) { Object.keys(config.env).forEach(function(name) { if (config.env[name]) { - var env = Environments.get(name), + let env = Environments.get(name), environmentGlobals = env && env.globals; if (environmentGlobals) { @@ -173,7 +170,7 @@ function addDeclaredGlobals(program, globalScope, config) { lodash.assign(explicitGlobals, config.astGlobals); Object.keys(declaredGlobals).forEach(function(name) { - var variable = globalScope.set.get(name); + let variable = globalScope.set.get(name); if (!variable) { variable = new escope.Variable(name, globalScope); @@ -185,7 +182,7 @@ function addDeclaredGlobals(program, globalScope, config) { }); Object.keys(explicitGlobals).forEach(function(name) { - var variable = globalScope.set.get(name); + let variable = globalScope.set.get(name); if (!variable) { variable = new escope.Variable(name, globalScope); @@ -199,7 +196,7 @@ function addDeclaredGlobals(program, globalScope, config) { // mark all exported variables as such Object.keys(exportedGlobals).forEach(function(name) { - var variable = globalScope.set.get(name); + let variable = globalScope.set.get(name); if (variable) { variable.eslintUsed = true; @@ -212,8 +209,8 @@ function addDeclaredGlobals(program, globalScope, config) { * references and remove the ones that were added by configuration. */ globalScope.through = globalScope.through.filter(function(reference) { - var name = reference.identifier.name; - var variable = globalScope.set.get(name); + let name = reference.identifier.name; + let variable = globalScope.set.get(name); if (variable) { @@ -267,7 +264,7 @@ function disableReporting(reportingConfig, start, rulesToDisable) { * @returns {void} */ function enableReporting(reportingConfig, start, rulesToEnable) { - var i; + let i; if (rulesToEnable.length) { rulesToEnable.forEach(function(rule) { @@ -281,7 +278,7 @@ function enableReporting(reportingConfig, start, rulesToEnable) { } else { // find all previous disabled locations if they was started as list of rules - var prevStart; + let prevStart; for (i = reportingConfig.length - 1; i >= 0; i--) { if (prevStart && prevStart !== reportingConfig[i].start) { @@ -305,22 +302,22 @@ function enableReporting(reportingConfig, start, rulesToEnable) { * @param {Object} config The existing configuration data. * @param {Object[]} reportingConfig The existing reporting configuration data. * @param {Object[]} messages The messages queue. - * @returns {object} Modified config object + * @returns {Object} Modified config object */ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messages) { - var commentConfig = { + let commentConfig = { exported: {}, astGlobals: {}, rules: {}, env: {} }; - var commentRules = {}; + let commentRules = {}; ast.comments.forEach(function(comment) { - var value = comment.value.trim(); - var match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value); + let value = comment.value.trim(); + let match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value); if (match) { value = value.substring(match.index + match[1].length); @@ -348,16 +345,17 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa enableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value))); break; - case "eslint": - var items = parseJsonConfig(value, comment.loc, messages); + case "eslint": { + const items = parseJsonConfig(value, comment.loc, messages); Object.keys(items).forEach(function(name) { - var ruleValue = items[name]; + let ruleValue = items[name]; validator.validateRuleOptions(name, ruleValue, filename + " line " + comment.loc.start.line); commentRules[name] = ruleValue; }); break; + } // no default } @@ -375,7 +373,7 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa // apply environment configs Object.keys(commentConfig.env).forEach(function(name) { - var env = Environments.get(name); + let env = Environments.get(name); if (env) { commentConfig = ConfigOps.merge(commentConfig, env); @@ -395,9 +393,9 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa */ function isDisabledByReportingConfig(reportingConfig, ruleId, location) { - for (var i = 0, c = reportingConfig.length; i < c; i++) { + for (let i = 0, c = reportingConfig.length; i < c; i++) { - var ignore = reportingConfig[i]; + let ignore = reportingConfig[i]; if ((!ignore.rule || ignore.rule === ruleId) && (location.line > ignore.start.line || (location.line === ignore.start.line && location.column >= ignore.start.column)) && @@ -419,13 +417,13 @@ function prepareConfig(config) { config.globals = config.globals || config.global || {}; delete config.global; - var copiedRules = {}, + let copiedRules = {}, parserOptions = {}, preparedConfig; if (typeof config.rules === "object") { Object.keys(config.rules).forEach(function(k) { - var rule = config.rules[k]; + let rule = config.rules[k]; if (rule === null) { throw new Error("Invalid config for rule '" + k + "'\."); @@ -441,7 +439,7 @@ function prepareConfig(config) { // merge in environment parserOptions if (typeof config.env === "object") { Object.keys(config.env).forEach(function(envName) { - var env = Environments.get(envName); + let env = Environments.get(envName); if (config.env[envName] && env && env.parserOptions) { parserOptions = ConfigOps.merge(parserOptions, env.parserOptions); @@ -484,8 +482,8 @@ function createStubRule(message) { /** * Creates a fake rule object - * @param {object} context context object for each rule - * @returns {object} collection of node to listen on + * @param {Object} context context object for each rule + * @returns {Object} collection of node to listen on */ function createRuleModule(context) { return { @@ -509,7 +507,7 @@ function createStubRule(message) { */ function getRuleReplacementMessage(ruleId) { if (ruleId in replacements.rules) { - var newRules = replacements.rules[ruleId]; + let newRules = replacements.rules[ruleId]; return "Rule \'" + ruleId + "\' was removed and replaced by: " + newRules.join(", "); } @@ -517,15 +515,15 @@ function getRuleReplacementMessage(ruleId) { return null; } -var eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g; +let eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g; /** * Checks whether or not there is a comment which has "eslint-env *" in a given text. * @param {string} text - A source code text to check. - * @returns {object|null} A result of parseListConfig() with "eslint-env *" comment. + * @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment. */ function findEslintEnv(text) { - var match, retv; + let match, retv; eslintEnvPattern.lastIndex = 0; @@ -565,7 +563,7 @@ function stripUnicodeBOM(text) { */ module.exports = (function() { - var api = Object.create(new EventEmitter()), + let api = Object.create(new EventEmitter()), messages = [], currentConfig = null, currentScopes = null, @@ -587,7 +585,7 @@ module.exports = (function() { */ function parse(text, config) { - var parser, + let parser, parserOptions = { loc: true, range: true, @@ -629,8 +627,8 @@ module.exports = (function() { } catch (ex) { // If the message includes a leading line number, strip it: - var message = ex.message.replace(/^line \d+:/i, "").trim(); - var source = (ex.lineNumber) ? SourceCode.splitLines(text)[ex.lineNumber - 1] : null; + let message = ex.message.replace(/^line \d+:/i, "").trim(); + let source = (ex.lineNumber) ? SourceCode.splitLines(text)[ex.lineNumber - 1] : null; messages.push({ ruleId: null, @@ -721,7 +719,7 @@ module.exports = (function() { */ api.verify = function(textOrSourceCode, config, filenameOrOptions, saveState) { - var ast, + let ast, shebang, ecmaFeatures, ecmaVersion, @@ -742,7 +740,7 @@ module.exports = (function() { } // search and apply "eslint-env *". - var envInFile = findEslintEnv(text || textOrSourceCode.text); + let envInFile = findEslintEnv(text || textOrSourceCode.text); if (envInFile) { if (!config || !config.env) { @@ -797,7 +795,7 @@ module.exports = (function() { Object.keys(config.rules).filter(function(key) { return getRuleSeverity(config.rules[key]) > 0; }).forEach(function(key) { - var ruleCreator, + let ruleCreator, severity, options, rule; @@ -805,7 +803,7 @@ module.exports = (function() { ruleCreator = rules.get(key); if (!ruleCreator) { - var replacementMsg = getRuleReplacementMessage(key); + let replacementMsg = getRuleReplacementMessage(key); if (replacementMsg) { ruleCreator = createStubRule(replacementMsg); @@ -819,7 +817,7 @@ module.exports = (function() { options = getRuleOptions(config.rules[key]); try { - var ruleContext = new RuleContext( + let ruleContext = new RuleContext( key, api, severity, options, config.settings, config.parserOptions, config.parser, ruleCreator.meta); @@ -865,7 +863,7 @@ module.exports = (function() { scopeMap = []; currentScopes.forEach(function(scope, index) { - var range = scope.block.range[0]; + let range = scope.block.range[0]; /* * Sometimes two scopes are returned for a given node. This is @@ -888,7 +886,7 @@ module.exports = (function() { } } - var eventGenerator = new NodeEventGenerator(api); + let eventGenerator = new NodeEventGenerator(api); eventGenerator = new CodePathAnalyzer(eventGenerator); eventGenerator = new CommentEventGenerator(eventGenerator, sourceCode); @@ -912,7 +910,7 @@ module.exports = (function() { // sort by line and column messages.sort(function(a, b) { - var lineDiff = a.line - b.line; + let lineDiff = a.line - b.line; if (lineDiff === 0) { return a.column - b.column; @@ -954,7 +952,10 @@ module.exports = (function() { location = node.loc.start; } - // else, assume location was provided, so node may be omitted + // Store end location. + let endLocation = location.end; + + location = location.start || location; if (isDisabledByReportingConfig(reportingConfig, ruleId, location)) { return; @@ -971,7 +972,7 @@ module.exports = (function() { }); } - var problem = { + let problem = { ruleId: ruleId, severity: severity, message: message, @@ -981,6 +982,12 @@ module.exports = (function() { source: sourceCode.lines[location.line - 1] || "" }; + // Define endLine and endColumn if exists. + if (endLocation) { + problem.endLine = endLocation.line; + problem.endColumn = endLocation.column + 1; // switch to 1-base instead of 0-base + } + // ensure there's range and text properties, otherwise it's not a valid fix if (fix && Array.isArray(fix.range) && (typeof fix.text === "string")) { @@ -1004,7 +1011,7 @@ module.exports = (function() { }; // methods that exist on SourceCode object - var externalMethods = { + let externalMethods = { getSource: "getText", getSourceLines: "getLines", getAllComments: "getAllComments", @@ -1026,7 +1033,7 @@ module.exports = (function() { // copy over methods Object.keys(externalMethods).forEach(function(methodName) { - var exMethodName = externalMethods[methodName]; + let exMethodName = externalMethods[methodName]; // All functions expected to have less arguments than 5. api[methodName] = function(a, b, c, d, e) { @@ -1050,14 +1057,14 @@ module.exports = (function() { * @returns {Object} An object representing the current node's scope. */ api.getScope = function() { - var parents = traverser.parents(), + let parents = traverser.parents(), scope = currentScopes[0]; // Don't do this for Program nodes - they have no parents if (parents.length) { // if current node introduces a scope, add it to the list - var current = traverser.current(); + let current = traverser.current(); if (currentConfig.parserOptions.ecmaVersion >= 6) { if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) { @@ -1070,7 +1077,7 @@ module.exports = (function() { } // Ascend the current node's parents - for (var i = parents.length - 1; i >= 0; --i) { + for (let i = parents.length - 1; i >= 0; --i) { // Get the innermost scope scope = scopeManager.acquire(parents[i], true); @@ -1096,7 +1103,7 @@ module.exports = (function() { * false if not. */ api.markVariableAsUsed = function(name) { - var scope = this.getScope(), + let scope = this.getScope(), hasGlobalReturn = currentConfig.parserOptions.ecmaFeatures && currentConfig.parserOptions.ecmaFeatures.globalReturn, specialScope = hasGlobalReturn || currentConfig.parserOptions.sourceType === "module", variables, @@ -1140,13 +1147,13 @@ module.exports = (function() { * @param {Function} ruleModule Function from context to object mapping AST node types to event handlers * @returns {void} */ - var defineRule = api.defineRule = function(ruleId, ruleModule) { + let defineRule = api.defineRule = function(ruleId, ruleModule) { rules.define(ruleId, ruleModule); }; /** * Defines many new linting rules. - * @param {object} rulesToDefine map from unique rule identifier to rule + * @param {Object} rulesToDefine map from unique rule identifier to rule * @returns {void} */ api.defineRules = function(rulesToDefine) { diff --git a/tools/eslint/lib/file-finder.js b/tools/eslint/lib/file-finder.js index 45594057000b21..f003504c25e08e 100644 --- a/tools/eslint/lib/file-finder.js +++ b/tools/eslint/lib/file-finder.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"); //------------------------------------------------------------------------------ @@ -55,11 +55,11 @@ function FileFinder(files, cwd) { * @returns {Object} Hashmap of filenames */ function normalizeDirectoryEntries(entries, directory, supportedConfigs) { - var fileHash = {}; + let fileHash = {}; entries.forEach(function(entry) { if (supportedConfigs.indexOf(entry) >= 0) { - var resolvedEntry = path.resolve(directory, entry); + let resolvedEntry = path.resolve(directory, entry); if (fs.statSync(resolvedEntry).isFile()) { fileHash[entry] = resolvedEntry; @@ -79,7 +79,7 @@ function normalizeDirectoryEntries(entries, directory, supportedConfigs) { * @returns {string[]} The file paths found. */ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) { - var cache = this.cache, + let cache = this.cache, child, dirs, fileNames, @@ -106,10 +106,10 @@ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) { dirs[searched++] = directory; cache[directory] = []; - var filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames); + let filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames); if (Object.keys(filesMap).length) { - for (var k = 0; k < fileNames.length; k++) { + for (let k = 0; k < fileNames.length; k++) { if (filesMap[fileNames[k]]) { filePath = filesMap[fileNames[k]]; diff --git a/tools/eslint/lib/formatters/checkstyle.js b/tools/eslint/lib/formatters/checkstyle.js index 0bb9627adf2bd5..11ee60490a0ba6 100644 --- a/tools/eslint/lib/formatters/checkstyle.js +++ b/tools/eslint/lib/formatters/checkstyle.js @@ -4,13 +4,15 @@ */ "use strict"; +let xmlEscape = require("../util/xml-escape"); + //------------------------------------------------------------------------------ // Helper Functions //------------------------------------------------------------------------------ /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -22,44 +24,19 @@ function getMessageType(message) { } } -/** - * Returns the escaped value for a character - * @param {string} s string to examine - * @returns {string} severity level - * @private - */ -function xmlEscape(s) { - return ("" + s).replace(/[<>&"']/g, function(c) { - switch (c) { - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - case "\"": - return """; - case "'": - return "'"; - default: - throw new Error("unreachable"); - } - }); -} - //------------------------------------------------------------------------------ // Public Interface //------------------------------------------------------------------------------ module.exports = function(results) { - var output = ""; + let output = ""; output += ""; output += ""; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; output += ""; diff --git a/tools/eslint/lib/formatters/compact.js b/tools/eslint/lib/formatters/compact.js index 0c31b073e3fefd..72233f6f363026 100644 --- a/tools/eslint/lib/formatters/compact.js +++ b/tools/eslint/lib/formatters/compact.js @@ -10,7 +10,7 @@ /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -29,12 +29,12 @@ function getMessageType(message) { module.exports = function(results) { - var output = "", + let output = "", total = 0; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; total += messages.length; diff --git a/tools/eslint/lib/formatters/html.js b/tools/eslint/lib/formatters/html.js index da3f7596fd04b6..87d2910b48a7f5 100644 --- a/tools/eslint/lib/formatters/html.js +++ b/tools/eslint/lib/formatters/html.js @@ -4,17 +4,17 @@ */ "use strict"; -var lodash = require("lodash"); -var fs = require("fs"); -var path = require("path"); +let lodash = require("lodash"); +let fs = require("fs"); +let path = require("path"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var pageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-page.html"), "utf-8")); -var messageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-message.html"), "utf-8")); -var resultTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-result.html"), "utf-8")); +let pageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-page.html"), "utf-8")); +let messageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-message.html"), "utf-8")); +let resultTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-result.html"), "utf-8")); /** * Given a word and a count, append an s if count is not one. @@ -33,8 +33,8 @@ function pluralize(word, count) { * @returns {string} The formatted string, pluralized where necessary */ function renderSummary(totalErrors, totalWarnings) { - var totalProblems = totalErrors + totalWarnings; - var renderedText = totalProblems + " " + pluralize("problem", totalProblems); + let totalProblems = totalErrors + totalWarnings; + let renderedText = totalProblems + " " + pluralize("problem", totalProblems); if (totalProblems !== 0) { renderedText += " (" + totalErrors + " " + pluralize("error", totalErrors) + ", " + totalWarnings + " " + pluralize("warning", totalWarnings) + ")"; @@ -71,7 +71,7 @@ function renderMessages(messages, parentIndex) { * @returns {string} HTML (table row) describing a message. */ return lodash.map(messages, function(message) { - var lineNumber, + let lineNumber, columnNumber; lineNumber = message.line || 0; @@ -110,7 +110,7 @@ function renderResults(results) { //------------------------------------------------------------------------------ module.exports = function(results) { - var totalErrors, + let totalErrors, totalWarnings; totalErrors = 0; diff --git a/tools/eslint/lib/formatters/jslint-xml.js b/tools/eslint/lib/formatters/jslint-xml.js index 483172ca5d8f23..11fe812d063156 100644 --- a/tools/eslint/lib/formatters/jslint-xml.js +++ b/tools/eslint/lib/formatters/jslint-xml.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let xmlEscape = require("../util/xml-escape"); //------------------------------------------------------------------------------ // Public Interface @@ -12,21 +12,21 @@ var lodash = require("lodash"); module.exports = function(results) { - var output = ""; + let output = ""; output += ""; output += ""; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; output += ""; messages.forEach(function(message) { output += ""; }); diff --git a/tools/eslint/lib/formatters/junit.js b/tools/eslint/lib/formatters/junit.js index c53fd8141baf5a..6b7bed30a15600 100644 --- a/tools/eslint/lib/formatters/junit.js +++ b/tools/eslint/lib/formatters/junit.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let xmlEscape = require("../util/xml-escape"); //------------------------------------------------------------------------------ // Helper Functions @@ -12,7 +12,7 @@ var lodash = require("lodash"); /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -30,28 +30,28 @@ function getMessageType(message) { module.exports = function(results) { - var output = ""; + let output = ""; output += "\n"; output += "\n"; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; if (messages.length) { output += "\n"; } messages.forEach(function(message) { - var type = message.fatal ? "error" : "failure"; + let type = message.fatal ? "error" : "failure"; output += ""; - output += "<" + type + " message=\"" + lodash.escape(message.message || "") + "\">"; + output += "<" + type + " message=\"" + xmlEscape(message.message || "") + "\">"; output += ""; output += ""; diff --git a/tools/eslint/lib/formatters/stylish.js b/tools/eslint/lib/formatters/stylish.js index d8645755bf9dc4..ebcea1ccdbd3f8 100644 --- a/tools/eslint/lib/formatters/stylish.js +++ b/tools/eslint/lib/formatters/stylish.js @@ -4,7 +4,7 @@ */ "use strict"; -var chalk = require("chalk"), +let chalk = require("chalk"), table = require("text-table"); //------------------------------------------------------------------------------ @@ -27,14 +27,14 @@ function pluralize(word, count) { module.exports = function(results) { - var output = "\n", + let output = "\n", total = 0, errors = 0, warnings = 0, summaryColor = "yellow"; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; if (messages.length === 0) { return; @@ -45,7 +45,7 @@ module.exports = function(results) { output += table( messages.map(function(message) { - var messageType; + let messageType; if (message.fatal || message.severity === 2) { messageType = chalk.red("error"); diff --git a/tools/eslint/lib/formatters/table.js b/tools/eslint/lib/formatters/table.js index e2876444556b24..d760c18ec5ff81 100644 --- a/tools/eslint/lib/formatters/table.js +++ b/tools/eslint/lib/formatters/table.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var chalk, +let chalk, table, pluralize; @@ -26,7 +26,7 @@ pluralize = require("pluralize"); * @returns {string} A text table. */ function drawTable(messages) { - var rows; + let rows; rows = []; @@ -43,7 +43,7 @@ function drawTable(messages) { ]); messages.forEach(function(message) { - var messageType; + let messageType; if (message.fatal || message.severity === 2) { messageType = chalk.red("error"); @@ -96,7 +96,7 @@ function drawTable(messages) { * @returns {string} A column of text tables. */ function drawReport(results) { - var files; + let files; files = results.map(function(result) { if (!result.messages.length) { @@ -118,7 +118,7 @@ function drawReport(results) { //------------------------------------------------------------------------------ module.exports = function(report) { - var result, + let result, errorCount, warningCount; diff --git a/tools/eslint/lib/formatters/tap.js b/tools/eslint/lib/formatters/tap.js index d898e30393ec5e..c5c70171f1ff23 100644 --- a/tools/eslint/lib/formatters/tap.js +++ b/tools/eslint/lib/formatters/tap.js @@ -4,7 +4,7 @@ */ "use strict"; -var yaml = require("js-yaml"); +let yaml = require("js-yaml"); //------------------------------------------------------------------------------ // Helper Functions @@ -12,8 +12,8 @@ var yaml = require("js-yaml"); /** * Returns a canonical error level string based upon the error message passed in. - * @param {object} message Individual error message provided by eslint - * @returns {String} Error level string + * @param {Object} message Individual error message provided by eslint + * @returns {string} Error level string */ function getMessageType(message) { if (message.fatal || message.severity === 2) { @@ -25,12 +25,12 @@ function getMessageType(message) { /** * Takes in a JavaScript object and outputs a TAP diagnostics string - * @param {object} diagnostic JavaScript object to be embedded as YAML into output. + * @param {Object} diagnostic JavaScript object to be embedded as YAML into output. * @returns {string} diagnostics string with YAML embedded - TAP version 13 compliant */ function outputDiagnostics(diagnostic) { - var prefix = " "; - var output = prefix + "---\n"; + let prefix = " "; + let output = prefix + "---\n"; output += prefix + yaml.safeDump(diagnostic).split("\n").join("\n" + prefix); output += "...\n"; @@ -42,18 +42,18 @@ function outputDiagnostics(diagnostic) { //------------------------------------------------------------------------------ module.exports = function(results) { - var output = "TAP version 13\n1.." + results.length + "\n"; + let output = "TAP version 13\n1.." + results.length + "\n"; results.forEach(function(result, id) { - var messages = result.messages; - var testResult = "ok"; - var diagnostics = {}; + let messages = result.messages; + let testResult = "ok"; + let diagnostics = {}; if (messages.length > 0) { testResult = "not ok"; messages.forEach(function(message) { - var diagnostic = { + let diagnostic = { message: message.message, severity: getMessageType(message), data: { diff --git a/tools/eslint/lib/formatters/unix.js b/tools/eslint/lib/formatters/unix.js index ce429fee25b9ce..ee4e14929b50e2 100644 --- a/tools/eslint/lib/formatters/unix.js +++ b/tools/eslint/lib/formatters/unix.js @@ -10,8 +10,8 @@ /** * Returns a canonical error level string based upon the error message passed in. - * @param {object} message Individual error message provided by eslint - * @returns {String} Error level string + * @param {Object} message Individual error message provided by eslint + * @returns {string} Error level string */ function getMessageType(message) { if (message.fatal || message.severity === 2) { @@ -28,12 +28,12 @@ function getMessageType(message) { module.exports = function(results) { - var output = "", + let output = "", total = 0; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; total += messages.length; diff --git a/tools/eslint/lib/formatters/visualstudio.js b/tools/eslint/lib/formatters/visualstudio.js index 5d53dde289ed04..836577271ea14f 100644 --- a/tools/eslint/lib/formatters/visualstudio.js +++ b/tools/eslint/lib/formatters/visualstudio.js @@ -11,7 +11,7 @@ /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -30,12 +30,12 @@ function getMessageType(message) { module.exports = function(results) { - var output = "", + let output = "", total = 0; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; total += messages.length; diff --git a/tools/eslint/lib/ignored-paths.js b/tools/eslint/lib/ignored-paths.js index 9a7739ebee963f..729bddd20a3d5f 100644 --- a/tools/eslint/lib/ignored-paths.js +++ b/tools/eslint/lib/ignored-paths.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), fs = require("fs"), path = require("path"), debug = require("debug"), @@ -23,12 +23,12 @@ debug = debug("eslint:ignored-paths"); // Constants //------------------------------------------------------------------------------ -var ESLINT_IGNORE_FILENAME = ".eslintignore"; -var DEFAULT_IGNORE_DIRS = [ +let ESLINT_IGNORE_FILENAME = ".eslintignore"; +let DEFAULT_IGNORE_DIRS = [ "node_modules/", "bower_components/" ]; -var DEFAULT_OPTIONS = { +let DEFAULT_OPTIONS = { dotfiles: false, cwd: process.cwd() }; @@ -47,15 +47,15 @@ var DEFAULT_OPTIONS = { function findIgnoreFile(cwd) { cwd = cwd || DEFAULT_OPTIONS.cwd; - var ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME); + let ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME); return fs.existsSync(ignoreFilePath) ? ignoreFilePath : ""; } /** * Merge options with defaults - * @param {object} options Options to merge with DEFAULT_OPTIONS constant - * @returns {object} Merged options + * @param {Object} options Options to merge with DEFAULT_OPTIONS constant + * @returns {Object} Merged options */ function mergeDefaultOptions(options) { options = (options || {}); @@ -78,7 +78,7 @@ function IgnoredPaths(options) { /** * add pattern to node-ignore instance - * @param {object} ig, instance of node-ignore + * @param {Object} ig, instance of node-ignore * @param {string} pattern, pattern do add to ig * @returns {array} raw ignore rules */ @@ -88,7 +88,7 @@ function IgnoredPaths(options) { /** * add ignore file to node-ignore instance - * @param {object} ig, instance of node-ignore + * @param {Object} ig, instance of node-ignore * @param {string} filepath, file to add to ig * @returns {array} raw ignore rules */ @@ -124,7 +124,7 @@ function IgnoredPaths(options) { addPattern(this.ig.default, this.defaultPatterns); if (options.ignore !== false) { - var ignorePath; + let ignorePath; if (options.ignorePath) { debug("Using specific ignore file"); @@ -174,9 +174,9 @@ function IgnoredPaths(options) { */ IgnoredPaths.prototype.contains = function(filepath, category) { - var result = false; - var absolutePath = path.resolve(this.options.cwd, filepath); - var relativePath = pathUtil.getRelativePath(absolutePath, this.options.cwd); + let result = false; + let absolutePath = path.resolve(this.options.cwd, filepath); + let relativePath = pathUtil.getRelativePath(absolutePath, this.options.cwd); if ((typeof category === "undefined") || (category === "default")) { result = result || (this.ig.default.filter([relativePath]).length === 0); @@ -195,13 +195,13 @@ IgnoredPaths.prototype.contains = function(filepath, category) { * @returns {string[]} list of glob ignore patterns */ IgnoredPaths.prototype.getIgnoredFoldersGlobPatterns = function() { - var dirs = DEFAULT_IGNORE_DIRS; + let dirs = DEFAULT_IGNORE_DIRS; if (this.options.ignore) { /* eslint-disable no-underscore-dangle */ - var patterns = this.ig.custom._rules.filter(function(rule) { + let patterns = this.ig.custom._rules.filter(function(rule) { return rule.negative; }).map(function(rule) { return rule.origin; diff --git a/tools/eslint/lib/internal-rules/internal-no-invalid-meta.js b/tools/eslint/lib/internal-rules/internal-no-invalid-meta.js new file mode 100644 index 00000000000000..820218dc47e71d --- /dev/null +++ b/tools/eslint/lib/internal-rules/internal-no-invalid-meta.js @@ -0,0 +1,212 @@ +/** + * @fileoverview Internal rule to prevent missing or invalid meta property in core rules. + * @author Vitor Balocco + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Gets the property of the Object node passed in that has the name specified. + * + * @param {string} property Name of the property to return. + * @param {ASTNode} node The ObjectExpression node. + * @returns {ASTNode} The Property node or null if not found. + */ +function getPropertyFromObject(property, node) { + let properties = node.properties; + + for (let i = 0; i < properties.length; i++) { + if (properties[i].key.name === property) { + return properties[i]; + } + } + + return null; +} + +/** + * Extracts the `meta` property from the ObjectExpression that all rules export. + * + * @param {ASTNode} exportsNode ObjectExpression node that the rule exports. + * @returns {ASTNode} The `meta` Property node or null if not found. + */ +function getMetaPropertyFromExportsNode(exportsNode) { + return getPropertyFromObject("meta", exportsNode); +} + +/** + * Whether this `meta` ObjectExpression has a `docs` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs` property exists. + */ +function hasMetaDocs(metaPropertyNode) { + return Boolean(getPropertyFromObject("docs", metaPropertyNode.value)); +} + +/** + * Whether this `meta` ObjectExpression has a `docs.description` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs.description` property exists. + */ +function hasMetaDocsDescription(metaPropertyNode) { + let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); + + return metaDocs && getPropertyFromObject("description", metaDocs.value); +} + +/** + * Whether this `meta` ObjectExpression has a `docs.category` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs.category` property exists. + */ +function hasMetaDocsCategory(metaPropertyNode) { + let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); + + return metaDocs && getPropertyFromObject("category", metaDocs.value); +} + +/** + * Whether this `meta` ObjectExpression has a `docs.recommended` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs.recommended` property exists. + */ +function hasMetaDocsRecommended(metaPropertyNode) { + let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); + + return metaDocs && getPropertyFromObject("recommended", metaDocs.value); +} + +/** + * Whether this `meta` ObjectExpression has a `schema` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `schema` property exists. + */ +function hasMetaSchema(metaPropertyNode) { + return getPropertyFromObject("schema", metaPropertyNode.value); +} + +/** + * Whether this `meta` ObjectExpression has a `fixable` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `fixable` property exists. + */ +function hasMetaFixable(metaPropertyNode) { + return getPropertyFromObject("fixable", metaPropertyNode.value); +} + +/** + * Checks the validity of the meta definition of this rule and reports any errors found. + * + * @param {RuleContext} context The ESLint rule context. + * @param {ASTNode} exportsNode ObjectExpression node that the rule exports. + * @param {boolean} ruleIsFixable whether the rule is fixable or not. + * @returns {void} + */ +function checkMetaValidity(context, exportsNode, ruleIsFixable) { + let metaProperty = getMetaPropertyFromExportsNode(exportsNode); + + if (!metaProperty) { + context.report(exportsNode, "Rule is missing a meta property."); + return; + } + + if (!hasMetaDocs(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs property."); + return; + } + + if (!hasMetaDocsDescription(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs.description property."); + return; + } + + if (!hasMetaDocsCategory(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs.category property."); + return; + } + + if (!hasMetaDocsRecommended(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs.recommended property."); + return; + } + + if (!hasMetaSchema(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.schema property."); + return; + } + + if (ruleIsFixable && !hasMetaFixable(metaProperty)) { + context.report(metaProperty, "Rule is fixable, but is missing a meta.fixable property."); + return; + } +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "enforce correct use of `meta` property in core rules", + category: "Internal", + recommended: false + }, + + schema: [] + }, + + create: function(context) { + let metaExportsValue; + let ruleIsFixable = false; + + return { + AssignmentExpression: function(node) { + if (node.left && + node.right && + node.left.type === "MemberExpression" && + node.left.object.name === "module" && + node.left.property.name === "exports") { + + metaExportsValue = node.right; + } + }, + + CallExpression: function(node) { + + // If the rule has a call for `context.report` and a property `fix` + // is being passed in, then we consider that the rule is fixable. + // + // Note that we only look for context.report() calls in the new + // style (with single MessageDescriptor argument), because only + // calls in the new style can specify a fix. + if (node.callee.type === "MemberExpression" && + node.callee.object.type === "Identifier" && + node.callee.object.name === "context" && + node.callee.property.type === "Identifier" && + node.callee.property.name === "report" && + node.arguments.length === 1 && + node.arguments[0].type === "ObjectExpression") { + + if (getPropertyFromObject("fix", node.arguments[0])) { + ruleIsFixable = true; + } + } + }, + + "Program:exit": function() { + checkMetaValidity(context, metaExportsValue, ruleIsFixable); + } + }; + } +}; diff --git a/tools/eslint/lib/load-rules.js b/tools/eslint/lib/load-rules.js index 6691dbba4b350a..ed7732db3fe230 100644 --- a/tools/eslint/lib/load-rules.js +++ b/tools/eslint/lib/load-rules.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"); //------------------------------------------------------------------------------ @@ -29,7 +29,7 @@ module.exports = function(rulesDir, cwd) { rulesDir = path.resolve(cwd, rulesDir); } - var rules = Object.create(null); + let rules = Object.create(null); fs.readdirSync(rulesDir).forEach(function(file) { if (path.extname(file) !== ".js") { diff --git a/tools/eslint/lib/options.js b/tools/eslint/lib/options.js index eb58a623330b1b..b1ab7eb9675391 100644 --- a/tools/eslint/lib/options.js +++ b/tools/eslint/lib/options.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var optionator = require("optionator"); +let optionator = require("optionator"); //------------------------------------------------------------------------------ // Initialization and Public Interface diff --git a/tools/eslint/lib/rule-context.js b/tools/eslint/lib/rule-context.js index 49b4dfc77d5f5d..e0428744b9256e 100644 --- a/tools/eslint/lib/rule-context.js +++ b/tools/eslint/lib/rule-context.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var RuleFixer = require("./util/rule-fixer"); +let RuleFixer = require("./util/rule-fixer"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var PASSTHROUGHS = [ +let PASSTHROUGHS = [ "getAncestors", "getDeclaredVariables", "getFilename", @@ -111,7 +111,7 @@ RuleContext.prototype = { * @returns {void} */ report: function(nodeOrDescriptor, location, message, opts) { - var descriptor, + let descriptor, fix = null; // check to see if it's a new style call diff --git a/tools/eslint/lib/rules.js b/tools/eslint/lib/rules.js index 24a8fd8a497bb9..3552d494a00ab3 100644 --- a/tools/eslint/lib/rules.js +++ b/tools/eslint/lib/rules.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var loadRules = require("./load-rules"); +let loadRules = require("./load-rules"); //------------------------------------------------------------------------------ // Privates //------------------------------------------------------------------------------ -var rules = Object.create(null); +let rules = Object.create(null); //------------------------------------------------------------------------------ // Public Interface @@ -38,7 +38,7 @@ function define(ruleId, ruleModule) { * @returns {void} */ function load(rulesDir, cwd) { - var newRules = loadRules(rulesDir, cwd); + let newRules = loadRules(rulesDir, cwd); Object.keys(newRules).forEach(function(ruleId) { define(ruleId, newRules[ruleId]); @@ -53,7 +53,7 @@ function load(rulesDir, cwd) { */ function importPlugin(pluginRules, pluginName) { Object.keys(pluginRules).forEach(function(ruleId) { - var qualifiedRuleId = pluginName + "/" + ruleId, + let qualifiedRuleId = pluginName + "/" + ruleId, rule = pluginRules[ruleId]; define(qualifiedRuleId, rule); diff --git a/tools/eslint/lib/rules/.eslintrc.yml b/tools/eslint/lib/rules/.eslintrc.yml new file mode 100644 index 00000000000000..fded5b84978444 --- /dev/null +++ b/tools/eslint/lib/rules/.eslintrc.yml @@ -0,0 +1,2 @@ +rules: + internal-no-invalid-meta: "error" diff --git a/tools/eslint/lib/rules/accessor-pairs.js b/tools/eslint/lib/rules/accessor-pairs.js index 3ed9f0dc0ccd8d..b80b44dc9fb941 100644 --- a/tools/eslint/lib/rules/accessor-pairs.js +++ b/tools/eslint/lib/rules/accessor-pairs.js @@ -28,7 +28,7 @@ function isIdentifier(node, name) { * @returns {boolean} `true` if the node is an argument of the specified method call. */ function isArgumentOfMethodCall(node, index, object, property) { - var parent = node.parent; + let parent = node.parent; return ( parent.type === "CallExpression" && @@ -91,9 +91,9 @@ module.exports = { }] }, create: function(context) { - var config = context.options[0] || {}; - var checkGetWithoutSet = config.getWithoutSet === true; - var checkSetWithoutGet = config.setWithoutGet !== false; + let config = context.options[0] || {}; + let checkGetWithoutSet = config.getWithoutSet === true; + let checkSetWithoutGet = config.setWithoutGet !== false; /** * Checks a object expression to see if it has setter and getter both present or none. @@ -102,14 +102,14 @@ module.exports = { * @private */ function checkLonelySetGet(node) { - var isSetPresent = false; - var isGetPresent = false; - var isDescriptor = isPropertyDescriptor(node); + let isSetPresent = false; + let isGetPresent = false; + let isDescriptor = isPropertyDescriptor(node); - for (var i = 0, end = node.properties.length; i < end; i++) { - var property = node.properties[i]; + for (let i = 0, end = node.properties.length; i < end; i++) { + let property = node.properties[i]; - var propToCheck = ""; + let propToCheck = ""; if (property.kind === "init") { if (isDescriptor && !property.computed) { @@ -139,9 +139,9 @@ module.exports = { } if (checkSetWithoutGet && isSetPresent && !isGetPresent) { - context.report(node, "Getter is not present"); + context.report(node, "Getter is not present."); } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) { - context.report(node, "Setter is not present"); + context.report(node, "Setter is not present."); } } diff --git a/tools/eslint/lib/rules/array-bracket-spacing.js b/tools/eslint/lib/rules/array-bracket-spacing.js index 09598031b4942e..6e26e0cbd50b98 100644 --- a/tools/eslint/lib/rules/array-bracket-spacing.js +++ b/tools/eslint/lib/rules/array-bracket-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -40,7 +40,7 @@ module.exports = { ] }, create: function(context) { - var spaced = context.options[0] === "always", + let spaced = context.options[0] === "always", sourceCode = context.getSourceCode(); /** @@ -54,7 +54,7 @@ module.exports = { return context.options[1] ? context.options[1][option] === !spaced : false; } - var options = { + let options = { spaced: spaced, singleElementException: isOptionSet("singleValue"), objectsInArraysException: isOptionSet("objectsInArrays"), @@ -75,9 +75,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space after '" + token.value + "'", + message: "There should be no space after '" + token.value + "'.", fix: function(fixer) { - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); return fixer.removeRange([token.range[1], nextToken.range[0]]); } @@ -94,9 +94,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space before '" + token.value + "'", + message: "There should be no space before '" + token.value + "'.", fix: function(fixer) { - var previousToken = sourceCode.getTokenBefore(token); + let previousToken = sourceCode.getTokenBefore(token); return fixer.removeRange([previousToken.range[1], token.range[0]]); } @@ -113,7 +113,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required after '" + token.value + "'", + message: "A space is required after '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextAfter(token, " "); } @@ -130,7 +130,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required before '" + token.value + "'", + message: "A space is required before '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextBefore(token, " "); } @@ -165,20 +165,20 @@ module.exports = { return; } - var first = sourceCode.getFirstToken(node), + let first = sourceCode.getFirstToken(node), second = sourceCode.getFirstToken(node, 1), penultimate = sourceCode.getLastToken(node, 1), last = sourceCode.getLastToken(node), firstElement = node.elements[0], lastElement = node.elements[node.elements.length - 1]; - var openingBracketMustBeSpaced = + let openingBracketMustBeSpaced = options.objectsInArraysException && isObjectType(firstElement) || options.arraysInArraysException && isArrayType(firstElement) || options.singleElementException && node.elements.length === 1 ? !options.spaced : options.spaced; - var closingBracketMustBeSpaced = + let closingBracketMustBeSpaced = options.objectsInArraysException && isObjectType(lastElement) || options.arraysInArraysException && isArrayType(lastElement) || options.singleElementException && node.elements.length === 1 diff --git a/tools/eslint/lib/rules/array-callback-return.js b/tools/eslint/lib/rules/array-callback-return.js index 714c189c6b5495..d72fd57b2e8c1a 100644 --- a/tools/eslint/lib/rules/array-callback-return.js +++ b/tools/eslint/lib/rules/array-callback-return.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/; -var TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/; +let TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/; +let TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/; /** * Checks a given code path segment is reachable. @@ -104,7 +104,7 @@ function isTargetMethod(node) { */ function isCallbackOfArrayMethod(node) { while (node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { @@ -123,14 +123,15 @@ function isCallbackOfArrayMethod(node) { // // setup... // return function callback() { ... }; // })()); - case "ReturnStatement": - var func = astUtils.getUpperFunction(parent); + case "ReturnStatement": { + const func = astUtils.getUpperFunction(parent); if (func === null || !astUtils.isCallee(func)) { return false; } node = func.parent; break; + } // e.g. // Array.from([], function() {}); @@ -176,7 +177,7 @@ module.exports = { }, create: function(context) { - var funcInfo = { + let funcInfo = { upper: null, codePath: null, hasReturn: false, diff --git a/tools/eslint/lib/rules/arrow-body-style.js b/tools/eslint/lib/rules/arrow-body-style.js index 13486fa74bc69d..16f082edae5c3e 100644 --- a/tools/eslint/lib/rules/arrow-body-style.js +++ b/tools/eslint/lib/rules/arrow-body-style.js @@ -50,11 +50,11 @@ module.exports = { }, create: function(context) { - var options = context.options; - var always = options[0] === "always"; - var asNeeded = !options[0] || options[0] === "as-needed"; - var never = options[0] === "never"; - var requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral; + let options = context.options; + let always = options[0] === "always"; + let asNeeded = !options[0] || options[0] === "as-needed"; + let never = options[0] === "never"; + let requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral; /** * Determines whether a arrow function body needs braces @@ -62,7 +62,7 @@ module.exports = { * @returns {void} */ function validate(node) { - var arrowBody = node.body; + let arrowBody = node.body; if (arrowBody.type === "BlockStatement") { if (never) { @@ -72,7 +72,7 @@ module.exports = { message: "Unexpected block statement surrounding arrow body." }); } else { - var blockBody = arrowBody.body; + let blockBody = arrowBody.body; if (blockBody.length !== 1) { return; diff --git a/tools/eslint/lib/rules/arrow-parens.js b/tools/eslint/lib/rules/arrow-parens.js index 86b972e80093b5..fd70ee3465a2a0 100644 --- a/tools/eslint/lib/rules/arrow-parens.js +++ b/tools/eslint/lib/rules/arrow-parens.js @@ -26,11 +26,11 @@ module.exports = { }, create: function(context) { - var message = "Expected parentheses around arrow function argument."; - var asNeededMessage = "Unexpected parentheses around single function argument"; - var asNeeded = context.options[0] === "as-needed"; + let message = "Expected parentheses around arrow function argument."; + let asNeededMessage = "Unexpected parentheses around single function argument."; + let asNeeded = context.options[0] === "as-needed"; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines whether a arrow function argument end with `)` @@ -38,7 +38,7 @@ module.exports = { * @returns {void} */ function parens(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); // as-needed: x => x if (asNeeded && node.params.length === 1 && node.params[0].type === "Identifier") { @@ -47,8 +47,8 @@ module.exports = { node: node, message: asNeededMessage, fix: function(fixer) { - var paramToken = context.getTokenAfter(token); - var closingParenToken = context.getTokenAfter(paramToken); + let paramToken = context.getTokenAfter(token); + let closingParenToken = context.getTokenAfter(paramToken); return fixer.replaceTextRange([ token.range[0], @@ -61,7 +61,7 @@ module.exports = { } if (token.type === "Identifier") { - var after = sourceCode.getTokenAfter(token); + let after = sourceCode.getTokenAfter(token); // (x) => x if (after.value !== ")") { diff --git a/tools/eslint/lib/rules/arrow-spacing.js b/tools/eslint/lib/rules/arrow-spacing.js index 3af5ae1f84463d..354c860c7b0a7c 100644 --- a/tools/eslint/lib/rules/arrow-spacing.js +++ b/tools/eslint/lib/rules/arrow-spacing.js @@ -37,13 +37,13 @@ module.exports = { create: function(context) { // merge rules with default - var rule = { before: true, after: true }, + let rule = { before: true, after: true }, option = context.options[0] || {}; rule.before = option.before !== false; rule.after = option.after !== false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Get tokens of arrow(`=>`) and before/after arrow. @@ -51,14 +51,14 @@ module.exports = { * @returns {Object} Tokens of arrow and before/after arrow. */ function getTokens(node) { - var t = sourceCode.getFirstToken(node); - var before; + let t = sourceCode.getFirstToken(node); + let before; while (t.type !== "Punctuator" || t.value !== "=>") { before = t; t = sourceCode.getTokenAfter(t); } - var after = sourceCode.getTokenAfter(t); + let after = sourceCode.getTokenAfter(t); return { before: before, arrow: t, after: after }; } @@ -69,8 +69,8 @@ module.exports = { * @returns {Object} count of space before/after arrow. */ function countSpaces(tokens) { - var before = tokens.arrow.range[0] - tokens.before.range[1]; - var after = tokens.after.range[0] - tokens.arrow.range[1]; + let before = tokens.arrow.range[0] - tokens.before.range[1]; + let after = tokens.after.range[0] - tokens.arrow.range[1]; return { before: before, after: after }; } @@ -83,8 +83,8 @@ module.exports = { * @returns {void} */ function spaces(node) { - var tokens = getTokens(node); - var countSpace = countSpaces(tokens); + let tokens = getTokens(node); + let countSpace = countSpaces(tokens); if (rule.before) { @@ -92,7 +92,7 @@ module.exports = { if (countSpace.before === 0) { context.report({ node: tokens.before, - message: "Missing space before =>", + message: "Missing space before =>.", fix: function(fixer) { return fixer.insertTextBefore(tokens.arrow, " "); } @@ -104,7 +104,7 @@ module.exports = { if (countSpace.before > 0) { context.report({ node: tokens.before, - message: "Unexpected space before =>", + message: "Unexpected space before =>.", fix: function(fixer) { return fixer.removeRange([tokens.before.range[1], tokens.arrow.range[0]]); } @@ -118,7 +118,7 @@ module.exports = { if (countSpace.after === 0) { context.report({ node: tokens.after, - message: "Missing space after =>", + message: "Missing space after =>.", fix: function(fixer) { return fixer.insertTextAfter(tokens.arrow, " "); } @@ -130,7 +130,7 @@ module.exports = { if (countSpace.after > 0) { context.report({ node: tokens.after, - message: "Unexpected space after =>", + message: "Unexpected space after =>.", fix: function(fixer) { return fixer.removeRange([tokens.arrow.range[1], tokens.after.range[0]]); } diff --git a/tools/eslint/lib/rules/block-scoped-var.js b/tools/eslint/lib/rules/block-scoped-var.js index 3da07adcba1a1f..f8198ea10ac14a 100644 --- a/tools/eslint/lib/rules/block-scoped-var.js +++ b/tools/eslint/lib/rules/block-scoped-var.js @@ -20,7 +20,7 @@ module.exports = { }, create: function(context) { - var stack = []; + let stack = []; /** * Makes a block scope. @@ -45,7 +45,7 @@ module.exports = { * @returns {void} */ function report(reference) { - var identifier = reference.identifier; + let identifier = reference.identifier; context.report( identifier, @@ -64,7 +64,7 @@ module.exports = { } // Defines a predicate to check whether or not a given reference is outside of valid scope. - var scopeRange = stack[stack.length - 1]; + let scopeRange = stack[stack.length - 1]; /** * Check if a reference is out of scope @@ -73,15 +73,15 @@ module.exports = { * @private */ function isOutsideOfScope(reference) { - var idRange = reference.identifier.range; + let idRange = reference.identifier.range; return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1]; } // Gets declared variables, and checks its references. - var variables = context.getDeclaredVariables(node); + let variables = context.getDeclaredVariables(node); - for (var i = 0; i < variables.length; ++i) { + for (let i = 0; i < variables.length; ++i) { // Reports. variables[i] diff --git a/tools/eslint/lib/rules/block-spacing.js b/tools/eslint/lib/rules/block-spacing.js index 54ae83d117d497..eb24cea319d51c 100644 --- a/tools/eslint/lib/rules/block-spacing.js +++ b/tools/eslint/lib/rules/block-spacing.js @@ -5,7 +5,7 @@ "use strict"; -var util = require("../ast-utils"); +let util = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var always = (context.options[0] !== "never"), + let always = (context.options[0] !== "never"), message = always ? "Requires a space" : "Unexpected space(s)", sourceCode = context.getSourceCode(); @@ -72,10 +72,10 @@ module.exports = { function checkSpacingInsideBraces(node) { // Gets braces and the first/last token of content. - var openBrace = getOpenBrace(node); - var closeBrace = sourceCode.getLastToken(node); - var firstToken = sourceCode.getTokenOrCommentAfter(openBrace); - var lastToken = sourceCode.getTokenOrCommentBefore(closeBrace); + let openBrace = getOpenBrace(node); + let closeBrace = sourceCode.getLastToken(node); + let firstToken = sourceCode.getTokenOrCommentAfter(openBrace); + let lastToken = sourceCode.getTokenOrCommentBefore(closeBrace); // Skip if the node is invalid or empty. if (openBrace.type !== "Punctuator" || diff --git a/tools/eslint/lib/rules/brace-style.js b/tools/eslint/lib/rules/brace-style.js index 785a71e4e7b0aa..325130a4a2f86f 100644 --- a/tools/eslint/lib/rules/brace-style.js +++ b/tools/eslint/lib/rules/brace-style.js @@ -34,11 +34,11 @@ module.exports = { }, create: function(context) { - var style = context.options[0] || "1tbs", + let style = context.options[0] || "1tbs", params = context.options[1] || {}, sourceCode = context.getSourceCode(); - var OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.", + let OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.", OPEN_MESSAGE_ALLMAN = "Opening curly brace appears on the same line as controlling statement.", BODY_MESSAGE = "Statement inside of curly braces should be on next line.", CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.", @@ -61,7 +61,7 @@ module.exports = { /** * Check if the token is an punctuator with a value of curly brace - * @param {object} token - Token to check + * @param {Object} token - Token to check * @returns {boolean} true if its a curly punctuator * @private */ @@ -78,11 +78,11 @@ module.exports = { * @private */ function checkBlock() { - var blockProperties = arguments; + let blockProperties = arguments; return function(node) { Array.prototype.forEach.call(blockProperties, function(blockProp) { - var block = node[blockProp], + let block = node[blockProp], previousToken, curlyToken, curlyTokenEnd, @@ -129,7 +129,7 @@ module.exports = { * @private */ function checkIfStatement(node) { - var tokens; + let tokens; checkBlock("consequent", "alternate")(node); @@ -157,7 +157,7 @@ module.exports = { * @private */ function checkTryStatement(node) { - var tokens; + let tokens; checkBlock("block", "finalizer")(node); @@ -180,7 +180,7 @@ module.exports = { * @private */ function checkCatchClause(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), firstToken = sourceCode.getFirstToken(node); checkBlock("body")(node); @@ -205,7 +205,7 @@ module.exports = { * @private */ function checkSwitchStatement(node) { - var tokens; + let tokens; if (node.cases && node.cases.length) { tokens = sourceCode.getTokensBefore(node.cases[0], 2); diff --git a/tools/eslint/lib/rules/callback-return.js b/tools/eslint/lib/rules/callback-return.js index 1d70d0c637308f..0b9d4a48941182 100644 --- a/tools/eslint/lib/rules/callback-return.js +++ b/tools/eslint/lib/rules/callback-return.js @@ -24,7 +24,7 @@ module.exports = { create: function(context) { - var callbacks = context.options[0] || ["callback", "cb", "next"], + let callbacks = context.options[0] || ["callback", "cb", "next"], sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- @@ -50,7 +50,7 @@ module.exports = { /** * Check to see if a node contains only identifers * @param {ASTNode} node The node to check - * @returns {Boolean} Whether or not the node contains only identifers + * @returns {boolean} Whether or not the node contains only identifers */ function containsOnlyIdentifiers(node) { if (node.type === "Identifier") { @@ -71,7 +71,7 @@ module.exports = { /** * Check to see if a CallExpression is in our callback list. * @param {ASTNode} node The node to check against our callback names list. - * @returns {Boolean} Whether or not this function matches our callback name. + * @returns {boolean} Whether or not this function matches our callback name. */ function isCallback(node) { return containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1; @@ -118,7 +118,7 @@ module.exports = { } // find the closest block, return or loop - var closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {}, + let closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {}, lastItem, parentType; // if our parent is a return we know we're ok diff --git a/tools/eslint/lib/rules/camelcase.js b/tools/eslint/lib/rules/camelcase.js index 28f9e8296b1926..b336e595dc964b 100644 --- a/tools/eslint/lib/rules/camelcase.js +++ b/tools/eslint/lib/rules/camelcase.js @@ -37,11 +37,11 @@ module.exports = { //-------------------------------------------------------------------------- // contains reported nodes to avoid reporting twice on destructuring with shorthand notation - var reported = []; + let reported = []; /** * Checks if a string contains an underscore and isn't all upper-case - * @param {String} name The string to check. + * @param {string} name The string to check. * @returns {boolean} if the string is underscored * @private */ @@ -64,7 +64,7 @@ module.exports = { } } - var options = context.options[0] || {}, + let options = context.options[0] || {}, properties = options.properties || ""; if (properties !== "always" && properties !== "never") { @@ -79,7 +79,7 @@ module.exports = { * Leading and trailing underscores are commonly used to flag * private/protected identifiers, strip them */ - var name = node.name.replace(/^_+|_+$/g, ""), + let name = node.name.replace(/^_+|_+$/g, ""), effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; // MemberExpressions get special rules diff --git a/tools/eslint/lib/rules/comma-dangle.js b/tools/eslint/lib/rules/comma-dangle.js index d2478cacfb0748..69a72e8fcad5d1 100644 --- a/tools/eslint/lib/rules/comma-dangle.js +++ b/tools/eslint/lib/rules/comma-dangle.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); /** * Checks whether or not a trailing comma is allowed in a given node. @@ -45,9 +45,9 @@ module.exports = { }, create: function(context) { - var mode = context.options[0]; - var UNEXPECTED_MESSAGE = "Unexpected trailing comma."; - var MISSING_MESSAGE = "Missing trailing comma."; + let mode = context.options[0]; + let UNEXPECTED_MESSAGE = "Unexpected trailing comma."; + let MISSING_MESSAGE = "Missing trailing comma."; /** * Checks whether or not a given node is multiline. @@ -58,13 +58,13 @@ module.exports = { * @returns {boolean} `true` if the node is multiline. */ function isMultiline(node) { - var lastItem = lodash.last(node.properties || node.elements || node.specifiers); + let lastItem = lodash.last(node.properties || node.elements || node.specifiers); if (!lastItem) { return false; } - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), penultimateToken = sourceCode.getLastToken(lastItem), lastToken = sourceCode.getTokenAfter(penultimateToken); @@ -91,13 +91,13 @@ module.exports = { * @returns {void} */ function forbidTrailingComma(node) { - var lastItem = lodash.last(node.properties || node.elements || node.specifiers); + let lastItem = lodash.last(node.properties || node.elements || node.specifiers); if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { return; } - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), trailingToken; // last item can be surrounded by parentheses for object and array literals @@ -132,7 +132,7 @@ module.exports = { * @returns {void} */ function forceTrailingComma(node) { - var lastItem = lodash.last(node.properties || node.elements || node.specifiers); + let lastItem = lodash.last(node.properties || node.elements || node.specifiers); if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { return; @@ -142,7 +142,7 @@ module.exports = { return; } - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), penultimateToken = lastItem, trailingToken = sourceCode.getTokenAfter(lastItem); @@ -199,7 +199,7 @@ module.exports = { } // Chooses a checking function. - var checkForTrailingComma; + let checkForTrailingComma; if (mode === "always") { checkForTrailingComma = forceTrailingComma; diff --git a/tools/eslint/lib/rules/comma-spacing.js b/tools/eslint/lib/rules/comma-spacing.js index 22fb8b235f5c9d..ea516e03335277 100644 --- a/tools/eslint/lib/rules/comma-spacing.js +++ b/tools/eslint/lib/rules/comma-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -38,10 +38,10 @@ module.exports = { create: function(context) { - var sourceCode = context.getSourceCode(); - var tokensAndComments = sourceCode.tokensAndComments; + let sourceCode = context.getSourceCode(); + let tokensAndComments = sourceCode.tokensAndComments; - var options = { + let options = { before: context.options[0] ? !!context.options[0].before : false, after: context.options[0] ? !!context.options[0].after : true }; @@ -51,7 +51,7 @@ module.exports = { //-------------------------------------------------------------------------- // list of comma tokens to ignore for the check of leading whitespace - var commaTokensToIgnore = []; + let commaTokensToIgnore = []; /** * Determines if a given token is a comma operator. @@ -82,8 +82,8 @@ module.exports = { return fixer.insertTextAfter(node, " "); } } else { - var start, end; - var newText = ""; + let start, end; + let newText = ""; if (dir === "before") { start = otherNode.range[1]; @@ -136,10 +136,10 @@ module.exports = { * @returns {void} */ function addNullElementsToIgnoreList(node) { - var previousToken = sourceCode.getFirstToken(node); + let previousToken = sourceCode.getFirstToken(node); node.elements.forEach(function(element) { - var token; + let token; if (element === null) { token = sourceCode.getTokenAfter(previousToken); @@ -162,7 +162,7 @@ module.exports = { return { "Program:exit": function() { - var previousToken, + let previousToken, nextToken; tokensAndComments.forEach(function(token, i) { diff --git a/tools/eslint/lib/rules/comma-style.js b/tools/eslint/lib/rules/comma-style.js index 173df90c33e813..69b657f62d46be 100644 --- a/tools/eslint/lib/rules/comma-style.js +++ b/tools/eslint/lib/rules/comma-style.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -39,7 +39,7 @@ module.exports = { }, create: function(context) { - var style = context.options[0] || "last", + let style = context.options[0] || "last", exceptions = {}, sourceCode = context.getSourceCode(); @@ -108,7 +108,7 @@ module.exports = { * @returns {void} */ function validateComma(node, property) { - var items = node[property], + let items = node[property], arrayLiteral = (node.type === "ArrayExpression"), previousItemToken; @@ -118,7 +118,7 @@ module.exports = { previousItemToken = sourceCode.getFirstToken(node); items.forEach(function(item) { - var commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken, + let commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken, currentItemToken = item ? sourceCode.getFirstToken(item) : sourceCode.getTokenAfter(commaToken), reportItem = item || currentItemToken, tokenBeforeComma = sourceCode.getTokenBefore(commaToken); @@ -158,7 +158,7 @@ module.exports = { */ if (arrayLiteral) { - var lastToken = sourceCode.getLastToken(node), + let lastToken = sourceCode.getLastToken(node), nextToLastToken = sourceCode.getTokenBefore(lastToken); if (isComma(nextToLastToken)) { @@ -177,7 +177,7 @@ module.exports = { // Public //-------------------------------------------------------------------------- - var nodes = {}; + let nodes = {}; if (!exceptions.VariableDeclaration) { nodes.VariableDeclaration = function(node) { diff --git a/tools/eslint/lib/rules/complexity.js b/tools/eslint/lib/rules/complexity.js index 029b739808d6d7..394df98c44aac1 100644 --- a/tools/eslint/lib/rules/complexity.js +++ b/tools/eslint/lib/rules/complexity.js @@ -45,7 +45,7 @@ module.exports = { }, create: function(context) { - var option = context.options[0], + let option = context.options[0], THRESHOLD = 20; if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { @@ -63,7 +63,7 @@ module.exports = { //-------------------------------------------------------------------------- // Using a stack to store complexity (handling nested functions) - var fns = []; + let fns = []; /** * When parsing a new function, store it in our function stack @@ -81,7 +81,7 @@ module.exports = { * @private */ function endFunction(node) { - var complexity = fns.pop(), + let complexity = fns.pop(), name = "anonymous"; if (node.id) { diff --git a/tools/eslint/lib/rules/computed-property-spacing.js b/tools/eslint/lib/rules/computed-property-spacing.js index 89f0cc87b1e932..1122c5c83c3946 100644 --- a/tools/eslint/lib/rules/computed-property-spacing.js +++ b/tools/eslint/lib/rules/computed-property-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -28,8 +28,8 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" + let sourceCode = context.getSourceCode(); + let propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" //-------------------------------------------------------------------------- // Helpers @@ -46,7 +46,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space after '" + token.value + "'", + message: "There should be no space after '" + token.value + "'.", fix: function(fixer) { return fixer.removeRange([token.range[1], tokenAfter.range[0]]); } @@ -64,7 +64,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space before '" + token.value + "'", + message: "There should be no space before '" + token.value + "'.", fix: function(fixer) { return fixer.removeRange([tokenBefore.range[1], token.range[0]]); } @@ -81,7 +81,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required after '" + token.value + "'", + message: "A space is required after '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextAfter(token, " "); } @@ -98,7 +98,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required before '" + token.value + "'", + message: "A space is required before '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextBefore(token, " "); } @@ -108,7 +108,7 @@ module.exports = { /** * Returns a function that checks the spacing of a node on the property name * that was passed in. - * @param {String} propertyName The property on the node to check for spacing + * @param {string} propertyName The property on the node to check for spacing * @returns {Function} A function that will check spacing on a node */ function checkSpacing(propertyName) { @@ -117,9 +117,9 @@ module.exports = { return; } - var property = node[propertyName]; + let property = node[propertyName]; - var before = sourceCode.getTokenBefore(property), + let before = sourceCode.getTokenBefore(property), first = sourceCode.getFirstToken(property), last = sourceCode.getLastToken(property), after = sourceCode.getTokenAfter(property); diff --git a/tools/eslint/lib/rules/consistent-return.js b/tools/eslint/lib/rules/consistent-return.js index 10f1d41cf4b65b..ffadd31bfd73db 100644 --- a/tools/eslint/lib/rules/consistent-return.js +++ b/tools/eslint/lib/rules/consistent-return.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -57,9 +57,9 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true; - var funcInfo = null; + let options = context.options[0] || {}; + let treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true; + let funcInfo = null; /** * Checks whether of not the implicit returning is consistent if the last @@ -69,7 +69,7 @@ module.exports = { * @returns {void} */ function checkLastSegment(node) { - var loc, type; + let loc, type; /* * Skip if it expected no return value or unreachable. @@ -135,8 +135,8 @@ module.exports = { // Reports a given return statement if it's inconsistent. ReturnStatement: function(node) { - var argument = node.argument; - var hasReturnValue = Boolean(argument); + let argument = node.argument; + let hasReturnValue = Boolean(argument); if (treatUndefinedAsUnspecified && hasReturnValue) { hasReturnValue = !isIdentifier(argument, "undefined") && argument.operator !== "void"; diff --git a/tools/eslint/lib/rules/consistent-this.js b/tools/eslint/lib/rules/consistent-this.js index 042e1a0aaeddd5..339c43995e8467 100644 --- a/tools/eslint/lib/rules/consistent-this.js +++ b/tools/eslint/lib/rules/consistent-this.js @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var aliases = []; + let aliases = []; if (context.options.length === 0) { aliases.push("that"); @@ -57,7 +57,7 @@ module.exports = { * @returns {void} */ function checkAssignment(node, name, value) { - var isThis = value.type === "ThisExpression"; + let isThis = value.type === "ThisExpression"; if (aliases.indexOf(name) !== -1) { if (!isThis || node.operator && node.operator !== "=") { @@ -73,12 +73,12 @@ module.exports = { * Ensures that a variable declaration of the alias in a program or function * is assigned to the correct value. * @param {string} alias alias the check the assignment of. - * @param {object} scope scope of the current code we are checking. + * @param {Object} scope scope of the current code we are checking. * @private * @returns {void} */ function checkWasAssigned(alias, scope) { - var variable = scope.set.get(alias); + let variable = scope.set.get(alias); if (!variable) { return; @@ -94,7 +94,7 @@ module.exports = { // The alias has been declared and not assigned: check it was // assigned later in the same scope. if (!variable.references.some(function(reference) { - var write = reference.writeExpr; + let write = reference.writeExpr; return ( reference.from === scope && @@ -115,7 +115,7 @@ module.exports = { * @returns {void} */ function ensureWasAssigned() { - var scope = context.getScope(); + let scope = context.getScope(); aliases.forEach(function(alias) { checkWasAssigned(alias, scope); @@ -128,8 +128,8 @@ module.exports = { "FunctionDeclaration:exit": ensureWasAssigned, VariableDeclarator: function(node) { - var id = node.id; - var isDestructuring = + let id = node.id; + let isDestructuring = id.type === "ArrayPattern" || id.type === "ObjectPattern"; if (node.init !== null && !isDestructuring) { diff --git a/tools/eslint/lib/rules/constructor-super.js b/tools/eslint/lib/rules/constructor-super.js index 4b2aacf5755281..7b7e8cfd3e9b80 100644 --- a/tools/eslint/lib/rules/constructor-super.js +++ b/tools/eslint/lib/rules/constructor-super.js @@ -75,10 +75,11 @@ function isPossibleConstructor(node) { isPossibleConstructor(node.consequent) ); - case "SequenceExpression": - var lastExpression = node.expressions[node.expressions.length - 1]; + case "SequenceExpression": { + const lastExpression = node.expressions[node.expressions.length - 1]; return isPossibleConstructor(lastExpression); + } default: return false; @@ -111,7 +112,7 @@ module.exports = { * - scope: The scope of own class. * - codePath: The code path object of the constructor. */ - var funcInfo = null; + let funcInfo = null; /* * {Map} @@ -120,7 +121,7 @@ module.exports = { * - calledInEveryPaths: A flag of be called `super()` in all code paths. * - validNodes: */ - var segInfoMap = Object.create(null); + let segInfoMap = Object.create(null); /** * Gets the flag which shows `super()` is called in some paths. @@ -163,8 +164,8 @@ module.exports = { if (isConstructorFunction(node)) { // Class > ClassBody > MethodDefinition > FunctionExpression - var classNode = node.parent.parent.parent; - var superClass = classNode.superClass; + let classNode = node.parent.parent.parent; + let superClass = classNode.superClass; funcInfo = { upper: funcInfo, @@ -192,7 +193,7 @@ module.exports = { * @returns {void} */ onCodePathEnd: function(codePath, node) { - var hasExtends = funcInfo.hasExtends; + let hasExtends = funcInfo.hasExtends; // Pop. funcInfo = funcInfo.upper; @@ -202,9 +203,9 @@ module.exports = { } // Reports if `super()` lacked. - var segments = codePath.returnedSegments; - var calledInEveryPaths = segments.every(isCalledInEveryPath); - var calledInSomePaths = segments.some(isCalledInSomePath); + let segments = codePath.returnedSegments; + let calledInEveryPaths = segments.every(isCalledInEveryPath); + let calledInSomePaths = segments.some(isCalledInSomePath); if (!calledInEveryPaths) { context.report({ @@ -227,14 +228,14 @@ module.exports = { } // Initialize info. - var info = segInfoMap[segment.id] = { + let info = segInfoMap[segment.id] = { calledInSomePaths: false, calledInEveryPaths: false, validNodes: [] }; // When there are previous segments, aggregates these. - var prevSegments = segment.prevSegments; + let prevSegments = segment.prevSegments; if (prevSegments.length > 0) { info.calledInSomePaths = prevSegments.some(isCalledInSomePath); @@ -257,13 +258,13 @@ module.exports = { } // Update information inside of the loop. - var isRealLoop = toSegment.prevSegments.length >= 2; + let isRealLoop = toSegment.prevSegments.length >= 2; funcInfo.codePath.traverseSegments( {first: toSegment, last: fromSegment}, function(segment) { - var info = segInfoMap[segment.id]; - var prevSegments = segment.prevSegments; + let info = segInfoMap[segment.id]; + let prevSegments = segment.prevSegments; // Updates flags. info.calledInSomePaths = prevSegments.some(isCalledInSomePath); @@ -271,12 +272,12 @@ module.exports = { // If flags become true anew, reports the valid nodes. if (info.calledInSomePaths || isRealLoop) { - var nodes = info.validNodes; + let nodes = info.validNodes; info.validNodes = []; - for (var i = 0; i < nodes.length; ++i) { - var node = nodes[i]; + for (let i = 0; i < nodes.length; ++i) { + let node = nodes[i]; context.report({ message: "Unexpected duplicate 'super()'.", @@ -305,23 +306,22 @@ module.exports = { // Reports if needed. if (funcInfo.hasExtends) { - var segments = funcInfo.codePath.currentSegments; - var reachable = false; - var duplicate = false; + let segments = funcInfo.codePath.currentSegments; + let duplicate = false; + let info = null; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { - var info = segInfoMap[segment.id]; + info = segInfoMap[segment.id]; - reachable = true; duplicate = duplicate || info.calledInSomePaths; info.calledInSomePaths = info.calledInEveryPaths = true; } } - if (reachable) { + if (info) { if (duplicate) { context.report({ message: "Unexpected duplicate 'super()'.", @@ -360,13 +360,13 @@ module.exports = { } // Returning argument is a substitute of 'super()'. - var segments = funcInfo.codePath.currentSegments; + let segments = funcInfo.codePath.currentSegments; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { - var info = segInfoMap[segment.id]; + let info = segInfoMap[segment.id]; info.calledInSomePaths = info.calledInEveryPaths = true; } diff --git a/tools/eslint/lib/rules/curly.js b/tools/eslint/lib/rules/curly.js index 257366fabe844c..912f321565e80f 100644 --- a/tools/eslint/lib/rules/curly.js +++ b/tools/eslint/lib/rules/curly.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -53,12 +53,12 @@ module.exports = { create: function(context) { - var multiOnly = (context.options[0] === "multi"); - var multiLine = (context.options[0] === "multi-line"); - var multiOrNest = (context.options[0] === "multi-or-nest"); - var consistent = (context.options[1] === "consistent"); + let multiOnly = (context.options[0] === "multi"); + let multiLine = (context.options[0] === "multi-line"); + let multiOrNest = (context.options[0] === "multi-or-nest"); + let consistent = (context.options[1] === "consistent"); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -71,7 +71,7 @@ module.exports = { * @private */ function isCollapsedOneLiner(node) { - var before = sourceCode.getTokenBefore(node), + let before = sourceCode.getTokenBefore(node), last = sourceCode.getLastToken(node); return before.loc.start.line === last.loc.end.line; @@ -84,7 +84,7 @@ module.exports = { * @private */ function isOneLiner(node) { - var first = sourceCode.getFirstToken(node), + let first = sourceCode.getFirstToken(node), last = sourceCode.getLastToken(node); return first.loc.start.line === last.loc.end.line; @@ -96,7 +96,7 @@ module.exports = { * @returns {Token} The `else` keyword token. */ function getElseKeyword(node) { - var token = sourceCode.getTokenAfter(node.consequent); + let token = sourceCode.getTokenAfter(node.consequent); while (token.type !== "Keyword" || token.value !== "else") { token = sourceCode.getTokenAfter(token); @@ -180,7 +180,7 @@ module.exports = { * @param {ASTNode} body The body node to check for blocks. * @param {string} name The name to report if there's a problem. * @param {string} suffix Additional string to add to the end of a report. - * @returns {object} a prepared check object, with "actual", "expected", "check" properties. + * @returns {Object} a prepared check object, with "actual", "expected", "check" properties. * "actual" will be `true` or `false` whether the body is already a block statement. * "expected" will be `true` or `false` if the body should be a block statement or not, or * `null` if it doesn't matter, depending on the rule options. It can be modified to change @@ -189,8 +189,8 @@ module.exports = { * properties. */ function prepareCheck(node, body, name, suffix) { - var hasBlock = (body.type === "BlockStatement"); - var expected = null; + let hasBlock = (body.type === "BlockStatement"); + let expected = null; if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) { expected = true; @@ -230,11 +230,11 @@ module.exports = { /** * Prepares to check the bodies of a "if", "else if" and "else" chain. * @param {ASTNode} node The first IfStatement node of the chain. - * @returns {object[]} prepared checks for each body of the chain. See `prepareCheck` for more + * @returns {Object[]} prepared checks for each body of the chain. See `prepareCheck` for more * information. */ function prepareIfChecks(node) { - var preparedChecks = []; + let preparedChecks = []; do { preparedChecks.push(prepareCheck(node, node.consequent, "if", "condition")); @@ -252,7 +252,7 @@ module.exports = { * all have braces. * If all nodes shouldn't have braces, make sure they don't. */ - var expected = preparedChecks.some(function(preparedCheck) { + let expected = preparedChecks.some(function(preparedCheck) { if (preparedCheck.expected !== null) { return preparedCheck.expected; } diff --git a/tools/eslint/lib/rules/default-case.js b/tools/eslint/lib/rules/default-case.js index ae70a59284fb4a..9bcb1c065b8c49 100644 --- a/tools/eslint/lib/rules/default-case.js +++ b/tools/eslint/lib/rules/default-case.js @@ -4,7 +4,7 @@ */ "use strict"; -var DEFAULT_COMMENT_PATTERN = /^no default$/; +let DEFAULT_COMMENT_PATTERN = /^no default$/; //------------------------------------------------------------------------------ // Rule Definition @@ -30,12 +30,12 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var commentPattern = options.commentPattern ? + let options = context.options[0] || {}; + let commentPattern = options.commentPattern ? new RegExp(options.commentPattern) : DEFAULT_COMMENT_PATTERN; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -67,16 +67,16 @@ module.exports = { return; } - var hasDefault = node.cases.some(function(v) { + let hasDefault = node.cases.some(function(v) { return v.test === null; }); if (!hasDefault) { - var comment; - var comments; + let comment; + let comments; - var lastCase = last(node.cases); + let lastCase = last(node.cases); comments = sourceCode.getComments(lastCase).trailing; diff --git a/tools/eslint/lib/rules/dot-location.js b/tools/eslint/lib/rules/dot-location.js index 2b29e0f49bf285..5a5ad353bfd4ff 100644 --- a/tools/eslint/lib/rules/dot-location.js +++ b/tools/eslint/lib/rules/dot-location.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -28,12 +28,12 @@ module.exports = { create: function(context) { - var config = context.options[0]; + let config = context.options[0]; // default to onObject if no preference is passed - var onObject = config === "object" || !config; + let onObject = config === "object" || !config; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports if the dot between object and property is on the correct loccation. @@ -43,7 +43,7 @@ module.exports = { * @returns {void} */ function checkDotLocation(obj, prop, node) { - var dot = sourceCode.getTokenBefore(prop); + let dot = sourceCode.getTokenBefore(prop); if (dot.type === "Punctuator" && dot.value === ".") { if (onObject) { diff --git a/tools/eslint/lib/rules/dot-notation.js b/tools/eslint/lib/rules/dot-notation.js index 07e0b0a8db82a7..e359b118ccbf46 100644 --- a/tools/eslint/lib/rules/dot-notation.js +++ b/tools/eslint/lib/rules/dot-notation.js @@ -8,8 +8,8 @@ // Rule Definition //------------------------------------------------------------------------------ -var validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; -var keywords = require("../util/keywords"); +let validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; +let keywords = require("../util/keywords"); module.exports = { meta: { @@ -36,10 +36,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords; + let options = context.options[0] || {}; + let allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords; - var allowPattern; + let allowPattern; if (options.allowPattern) { allowPattern = new RegExp(options.allowPattern); diff --git a/tools/eslint/lib/rules/eol-last.js b/tools/eslint/lib/rules/eol-last.js index 60b070f1abe8a6..faa4521cf1265d 100644 --- a/tools/eslint/lib/rules/eol-last.js +++ b/tools/eslint/lib/rules/eol-last.js @@ -35,7 +35,7 @@ module.exports = { Program: function checkBadEOF(node) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), src = sourceCode.getText(), location = {column: 1}, linebreakStyle = context.options[0] || "unix", diff --git a/tools/eslint/lib/rules/eqeqeq.js b/tools/eslint/lib/rules/eqeqeq.js index 441f5b751cf20d..124c9dd61a3e53 100644 --- a/tools/eslint/lib/rules/eqeqeq.js +++ b/tools/eslint/lib/rules/eqeqeq.js @@ -25,7 +25,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Checks if an expression is a typeof expression @@ -71,12 +71,12 @@ module.exports = { /** * Gets the location (line and column) of the binary expression's operator * @param {ASTNode} node The binary expression node to check - * @param {String} operator The operator to find + * @param {string} operator The operator to find * @returns {Object} { line, column } location of operator * @private */ function getOperatorLocation(node) { - var opToken = sourceCode.getTokenAfter(node.left); + let opToken = sourceCode.getTokenAfter(node.left); return {line: opToken.loc.start.line, column: opToken.loc.start.column}; } diff --git a/tools/eslint/lib/rules/func-names.js b/tools/eslint/lib/rules/func-names.js index 44b989b2c47116..12d8d34d5da3e3 100644 --- a/tools/eslint/lib/rules/func-names.js +++ b/tools/eslint/lib/rules/func-names.js @@ -5,6 +5,15 @@ "use strict"; +/** + * Checks whether or not a given variable is a function name. + * @param {escope.Variable} variable - A variable to check. + * @returns {boolean} `true` if the variable is a function name. + */ +function isFunctionName(variable) { + return variable && variable.defs[0].type === "FunctionName"; +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -25,7 +34,7 @@ module.exports = { }, create: function(context) { - var never = context.options[0] === "never"; + let never = context.options[0] === "never"; /** * Determines whether the current FunctionExpression node is a get, set, or @@ -33,7 +42,7 @@ module.exports = { * @returns {boolean} True if the node is a get, set, or shorthand method. */ function isObjectOrClassMethod() { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); return (parent.type === "MethodDefinition" || ( parent.type === "Property" && ( @@ -45,9 +54,16 @@ module.exports = { } return { - FunctionExpression: function(node) { + "FunctionExpression:exit": function(node) { + + // Skip recursive functions. + let nameVar = context.getDeclaredVariables(node)[0]; + + if (isFunctionName(nameVar) && nameVar.references.length > 0) { + return; + } - var name = node.id && node.id.name; + let name = node.id && node.id.name; if (never) { if (name) { diff --git a/tools/eslint/lib/rules/func-style.js b/tools/eslint/lib/rules/func-style.js index 9dad6c0755656d..e1cdc1d1bd199b 100644 --- a/tools/eslint/lib/rules/func-style.js +++ b/tools/eslint/lib/rules/func-style.js @@ -34,12 +34,12 @@ module.exports = { create: function(context) { - var style = context.options[0], + let style = context.options[0], allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions === true, enforceDeclarations = (style === "declaration"), stack = []; - var nodesToCheck = { + let nodesToCheck = { Program: function() { stack = []; }, @@ -79,7 +79,7 @@ module.exports = { }; nodesToCheck["ArrowFunctionExpression:exit"] = function(node) { - var hasThisExpr = stack.pop(); + let hasThisExpr = stack.pop(); if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") { context.report(node.parent, "Expected a function declaration."); diff --git a/tools/eslint/lib/rules/generator-star-spacing.js b/tools/eslint/lib/rules/generator-star-spacing.js index 0cab2be50eb9dc..e55fe9b512136c 100644 --- a/tools/eslint/lib/rules/generator-star-spacing.js +++ b/tools/eslint/lib/rules/generator-star-spacing.js @@ -40,7 +40,7 @@ module.exports = { create: function(context) { - var mode = (function(option) { + let mode = (function(option) { if (!option || typeof option === "string") { return { before: { before: true, after: false }, @@ -52,7 +52,7 @@ module.exports = { return option; }(context.options[0])); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Gets `*` token from a given node. @@ -63,7 +63,7 @@ module.exports = { * @returns {Token} `*` token. */ function getStarToken(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); while (token.value !== "*") { token = sourceCode.getTokenAfter(token); @@ -83,11 +83,11 @@ module.exports = { */ function checkSpacing(side, leftToken, rightToken) { if (!!(rightToken.range[0] - leftToken.range[1]) !== mode[side]) { - var after = leftToken.value === "*"; - var spaceRequired = mode[side]; - var node = after ? leftToken : rightToken; - var type = spaceRequired ? "Missing" : "Unexpected"; - var message = type + " space " + side + " *."; + let after = leftToken.value === "*"; + let spaceRequired = mode[side]; + let node = after ? leftToken : rightToken; + let type = spaceRequired ? "Missing" : "Unexpected"; + let message = type + " space " + side + " *."; context.report({ node: node, @@ -111,7 +111,7 @@ module.exports = { * @returns {void} */ function checkFunction(node) { - var prevToken, starToken, nextToken; + let prevToken, starToken, nextToken; if (!node.generator) { return; diff --git a/tools/eslint/lib/rules/global-require.js b/tools/eslint/lib/rules/global-require.js index d1298719a9a80d..0a104bc3493a0c 100644 --- a/tools/eslint/lib/rules/global-require.js +++ b/tools/eslint/lib/rules/global-require.js @@ -5,7 +5,7 @@ "use strict"; -var ACCEPTABLE_PARENTS = [ +let ACCEPTABLE_PARENTS = [ "AssignmentExpression", "VariableDeclarator", "MemberExpression", @@ -23,7 +23,7 @@ var ACCEPTABLE_PARENTS = [ * @returns {Reference|null} Returns the found reference or null if none were found. */ function findReference(scope, node) { - var references = scope.references.filter(function(reference) { + let references = scope.references.filter(function(reference) { return reference.identifier.range[0] === node.range[0] && reference.identifier.range[1] === node.range[1]; }); @@ -43,7 +43,7 @@ function findReference(scope, node) { * @returns {boolean} Whether or not the name is shadowed. */ function isShadowed(scope, node) { - var reference = findReference(scope, node); + let reference = findReference(scope, node); return reference && reference.resolved && reference.resolved.defs.length > 0; } @@ -62,7 +62,7 @@ module.exports = { create: function(context) { return { CallExpression: function(node) { - var currentScope = context.getScope(), + let currentScope = context.getScope(), isGoodRequire; if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) { diff --git a/tools/eslint/lib/rules/guard-for-in.js b/tools/eslint/lib/rules/guard-for-in.js index b43dda39e46968..7e4dfbc43e3087 100644 --- a/tools/eslint/lib/rules/guard-for-in.js +++ b/tools/eslint/lib/rules/guard-for-in.js @@ -30,7 +30,7 @@ module.exports = { * If the for-in statement has {}, then the real body is the body * of the BlockStatement. Otherwise, just use body as provided. */ - var body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body; + let body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body; if (body && body.type !== "IfStatement") { context.report(node, "The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype."); diff --git a/tools/eslint/lib/rules/handle-callback-err.js b/tools/eslint/lib/rules/handle-callback-err.js index 09bf0da9771428..836d3a6de761e3 100644 --- a/tools/eslint/lib/rules/handle-callback-err.js +++ b/tools/eslint/lib/rules/handle-callback-err.js @@ -26,7 +26,7 @@ module.exports = { create: function(context) { - var errorArgument = context.options[0] || "err"; + let errorArgument = context.options[0] || "err"; /** * Checks if the given argument should be interpreted as a regexp pattern. @@ -34,7 +34,7 @@ module.exports = { * @returns {boolean} Whether or not the string should be interpreted as a pattern. */ function isPattern(stringToCheck) { - var firstChar = stringToCheck[0]; + let firstChar = stringToCheck[0]; return firstChar === "^"; } @@ -46,7 +46,7 @@ module.exports = { */ function matchesConfiguredErrorName(name) { if (isPattern(errorArgument)) { - var regexp = new RegExp(errorArgument); + let regexp = new RegExp(errorArgument); return regexp.test(name); } @@ -55,7 +55,7 @@ module.exports = { /** * Get the parameters of a given function scope. - * @param {object} scope The function scope. + * @param {Object} scope The function scope. * @returns {array} All parameters of the given scope. */ function getParameters(scope) { @@ -70,7 +70,7 @@ module.exports = { * @returns {void} */ function checkForError(node) { - var scope = context.getScope(), + let scope = context.getScope(), parameters = getParameters(scope), firstParameter = parameters[0]; diff --git a/tools/eslint/lib/rules/id-blacklist.js b/tools/eslint/lib/rules/id-blacklist.js index 142d8d21f4bc63..d2be0d12c3064d 100644 --- a/tools/eslint/lib/rules/id-blacklist.js +++ b/tools/eslint/lib/rules/id-blacklist.js @@ -34,12 +34,12 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var blacklist = context.options; + let blacklist = context.options; /** * Checks if a string matches the provided pattern - * @param {String} name The string to check. + * @param {string} name The string to check. * @returns {boolean} if the string is a match * @private */ @@ -51,7 +51,7 @@ module.exports = { * Verifies if we should report an error or not based on the effective * parent node and the identifier name. * @param {ASTNode} effectiveParent The effective parent node of the node to be reported - * @param {String} name The identifier name of the identifier node + * @param {string} name The identifier name of the identifier node * @returns {boolean} whether an error should be reported or not */ function shouldReport(effectiveParent, name) { @@ -67,7 +67,7 @@ module.exports = { * @private */ function report(node) { - context.report(node, "Identifier '{{name}}' is blacklisted", { + context.report(node, "Identifier '{{name}}' is blacklisted.", { name: node.name }); } @@ -75,7 +75,7 @@ module.exports = { return { Identifier: function(node) { - var name = node.name, + let name = node.name, effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; // MemberExpressions get special rules diff --git a/tools/eslint/lib/rules/id-length.js b/tools/eslint/lib/rules/id-length.js index 43437513acb480..d337cdaccef7e3 100644 --- a/tools/eslint/lib/rules/id-length.js +++ b/tools/eslint/lib/rules/id-length.js @@ -45,18 +45,18 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var minLength = typeof options.min !== "undefined" ? options.min : 2; - var maxLength = typeof options.max !== "undefined" ? options.max : Infinity; - var properties = options.properties !== "never"; - var exceptions = (options.exceptions ? options.exceptions : []) + let options = context.options[0] || {}; + let minLength = typeof options.min !== "undefined" ? options.min : 2; + let maxLength = typeof options.max !== "undefined" ? options.max : Infinity; + let properties = options.properties !== "never"; + let exceptions = (options.exceptions ? options.exceptions : []) .reduce(function(obj, item) { obj[item] = true; return obj; }, {}); - var SUPPORTED_EXPRESSIONS = { + let SUPPORTED_EXPRESSIONS = { MemberExpression: properties && function(parent) { return !parent.computed && ( @@ -87,24 +87,24 @@ module.exports = { return { Identifier: function(node) { - var name = node.name; - var parent = node.parent; + let name = node.name; + let parent = node.parent; - var isShort = name.length < minLength; - var isLong = name.length > maxLength; + let isShort = name.length < minLength; + let isLong = name.length > maxLength; if (!(isShort || isLong) || exceptions[name]) { return; // Nothing to report } - var isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; + let isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) { context.report( node, isShort ? - "Identifier name '{{name}}' is too short. (< {{min}})" : - "Identifier name '{{name}}' is too long. (> {{max}})", + "Identifier name '{{name}}' is too short (< {{min}})." : + "Identifier name '{{name}}' is too long (> {{max}}).", { name: name, min: minLength, max: maxLength } ); } diff --git a/tools/eslint/lib/rules/id-match.js b/tools/eslint/lib/rules/id-match.js index 4c9f4351088c57..4128cbf3d1aaae 100644 --- a/tools/eslint/lib/rules/id-match.js +++ b/tools/eslint/lib/rules/id-match.js @@ -38,16 +38,16 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var pattern = context.options[0] || "^.+$", + let pattern = context.options[0] || "^.+$", regexp = new RegExp(pattern); - var options = context.options[1] || {}, + let options = context.options[1] || {}, properties = !!options.properties, onlyDeclarations = !!options.onlyDeclarations; /** * Checks if a string matches the provided pattern - * @param {String} name The string to check. + * @param {string} name The string to check. * @returns {boolean} if the string is a match * @private */ @@ -59,7 +59,7 @@ module.exports = { * Verifies if we should report an error or not based on the effective * parent node and the identifier name. * @param {ASTNode} effectiveParent The effective parent node of the node to be reported - * @param {String} name The identifier name of the identifier node + * @param {string} name The identifier name of the identifier node * @returns {boolean} whether an error should be reported or not */ function shouldReport(effectiveParent, name) { @@ -84,7 +84,7 @@ module.exports = { return { Identifier: function(node) { - var name = node.name, + let name = node.name, parent = node.parent, effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent; @@ -122,7 +122,7 @@ module.exports = { } } else { - var isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator"; + let isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator"; if (onlyDeclarations && !isDeclaration) { return; diff --git a/tools/eslint/lib/rules/indent.js b/tools/eslint/lib/rules/indent.js index 3c0c9827d84859..b24f942d1aedac 100644 --- a/tools/eslint/lib/rules/indent.js +++ b/tools/eslint/lib/rules/indent.js @@ -11,8 +11,8 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -var util = require("util"); -var lodash = require("lodash"); +let util = require("util"); +let lodash = require("lodash"); module.exports = { meta: { @@ -71,6 +71,10 @@ module.exports = { outerIIFEBody: { type: "integer", minimum: 0 + }, + MemberExpression: { + type: "integer", + minimum: 0 } }, additionalProperties: false @@ -80,12 +84,12 @@ module.exports = { create: function(context) { - var MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}."; - var DEFAULT_VARIABLE_INDENT = 1; + let MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}."; + let DEFAULT_VARIABLE_INDENT = 1; - var indentType = "space"; - var indentSize = 4; - var options = { + let indentType = "space"; + let indentSize = 4; + let options = { SwitchCase: 0, VariableDeclarator: { var: DEFAULT_VARIABLE_INDENT, @@ -95,7 +99,7 @@ module.exports = { outerIIFEBody: null }; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); if (context.options.length) { if (context.options[0] === "tab") { @@ -107,10 +111,10 @@ module.exports = { } if (context.options[1]) { - var opts = context.options[1]; + let opts = context.options[1]; options.SwitchCase = opts.SwitchCase || 0; - var variableDeclaratorRules = opts.VariableDeclarator; + let variableDeclaratorRules = opts.VariableDeclarator; if (typeof variableDeclaratorRules === "number") { options.VariableDeclarator = { @@ -125,15 +129,19 @@ module.exports = { if (typeof opts.outerIIFEBody === "number") { options.outerIIFEBody = opts.outerIIFEBody; } + + if (typeof opts.MemberExpression === "number") { + options.MemberExpression = opts.MemberExpression; + } } } - var indentPattern = { + let indentPattern = { normal: indentType === "space" ? /^ +/ : /^\t+/, excludeCommas: indentType === "space" ? /^[ ,]+/ : /^[\t,]+/ }; - var caseIndentStore = {}; + let caseIndentStore = {}; /** * Reports a given indent violation and properly pluralizes the message @@ -145,13 +153,13 @@ module.exports = { * @returns {void} */ function report(node, needed, gotten, loc, isLastNodeCheck) { - var msgContext = { + let msgContext = { needed: needed, type: indentType, characters: needed === 1 ? "character" : "characters", gotten: gotten }; - var indentChar = indentType === "space" ? " " : "\t"; + let indentChar = indentType === "space" ? " " : "\t"; /** * Responsible for fixing the indentation issue fix @@ -159,10 +167,10 @@ module.exports = { * @private */ function getFixerFunction() { - var rangeToFix = []; + let rangeToFix = []; if (needed > gotten) { - var spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future + let spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future if (isLastNodeCheck === true) { rangeToFix = [ @@ -224,10 +232,10 @@ module.exports = { * @returns {int} Indent */ function getNodeIndent(node, byLastLine, excludeCommas) { - var token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node); - var src = sourceCode.getText(token, token.loc.start.column); - var regExp = excludeCommas ? indentPattern.excludeCommas : indentPattern.normal; - var indent = regExp.exec(src); + let token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node); + let src = sourceCode.getText(token, token.loc.start.column); + let regExp = excludeCommas ? indentPattern.excludeCommas : indentPattern.normal; + let indent = regExp.exec(src); return indent ? indent[0].length : 0; } @@ -239,7 +247,7 @@ module.exports = { * @returns {boolean} true if its the first in the its start line */ function isNodeFirstInLine(node, byEndLocation) { - var firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node), + let firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node), startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line, endLine = firstToken ? firstToken.loc.end.line : -1; @@ -254,7 +262,7 @@ module.exports = { * @returns {void} */ function checkNodeIndent(node, indent, excludeCommas) { - var nodeIndent = getNodeIndent(node, false, excludeCommas); + let nodeIndent = getNodeIndent(node, false, excludeCommas); if ( node.type !== "ArrayExpression" && node.type !== "ObjectExpression" && @@ -274,7 +282,7 @@ module.exports = { function checkNodesIndent(nodes, indent, excludeCommas) { nodes.forEach(function(node) { if (node.type === "IfStatement" && node.alternate) { - var elseToken = sourceCode.getTokenBefore(node.alternate); + let elseToken = sourceCode.getTokenBefore(node.alternate); checkNodeIndent(elseToken, indent, excludeCommas); } @@ -289,8 +297,8 @@ module.exports = { * @returns {void} */ function checkLastNodeLineIndent(node, lastLineIndent) { - var lastToken = sourceCode.getLastToken(node); - var endIndent = getNodeIndent(lastToken, true); + let lastToken = sourceCode.getLastToken(node); + let endIndent = getNodeIndent(lastToken, true); if (endIndent !== lastLineIndent && isNodeFirstInLine(node, true)) { report( @@ -310,7 +318,7 @@ module.exports = { * @returns {void} */ function checkFirstNodeLineIndent(node, firstLineIndent) { - var startIndent = getNodeIndent(node, false); + let startIndent = getNodeIndent(node, false); if (startIndent !== firstLineIndent && isNodeFirstInLine(node)) { report( @@ -323,19 +331,40 @@ module.exports = { } /** - * Returns the VariableDeclarator based on the current node + * Returns a parent node of given node based on a specified type * if not present then return null * @param {ASTNode} node node to examine + * @param {string} type type that is being looked for * @returns {ASTNode|void} if found then node otherwise null */ - function getVariableDeclaratorNode(node) { - var parent = node.parent; + function getParentNodeByType(node, type) { + let parent = node.parent; - while (parent.type !== "VariableDeclarator" && parent.type !== "Program") { + while (parent.type !== type && parent.type !== "Program") { parent = parent.parent; } - return parent.type === "VariableDeclarator" ? parent : null; + return parent.type === type ? parent : null; + } + + /** + * Returns the VariableDeclarator based on the current node + * if not present then return null + * @param {ASTNode} node node to examine + * @returns {ASTNode|void} if found then node otherwise null + */ + function getVariableDeclaratorNode(node) { + return getParentNodeByType(node, "VariableDeclarator"); + } + + /** + * Returns the ExpressionStatement based on the current node + * if not present then return null + * @param {ASTNode} node node to examine + * @returns {ASTNode|void} if found then node otherwise null + */ + function getAssignmentExpressionNode(node) { + return getParentNodeByType(node, "AssignmentExpression"); } /** @@ -358,7 +387,7 @@ module.exports = { * @returns {boolean} True if arguments are multi-line */ function isArgBeforeCalleeNodeMultiline(node) { - var parent = node.parent; + let parent = node.parent; if (parent.arguments.length >= 2 && parent.arguments[1] === node) { return parent.arguments[0].loc.end.line > parent.arguments[0].loc.start.line; @@ -367,19 +396,46 @@ module.exports = { return false; } - /** + /** * Check to see if the node is a file level IIFE * @param {ASTNode} node The function node to check. * @returns {boolean} True if the node is the outer IIFE */ function isOuterIIFE(node) { - var parent = node.parent; + let parent = node.parent; + let stmt = parent.parent; - return ( - parent.type === "CallExpression" && - parent.callee === node && - parent.parent.type === "ExpressionStatement" && - parent.parent.parent && parent.parent.parent.type === "Program" + /* + * Verify that the node is an IIEF + */ + if ( + parent.type !== "CallExpression" || + parent.callee !== node) { + + return false; + } + + /* + * Navigate legal ancestors to determine whether this IIEF is outer + */ + while ( + stmt.type === "UnaryExpression" && ( + stmt.operator === "!" || + stmt.operator === "~" || + stmt.operator === "+" || + stmt.operator === "-") || + stmt.type === "AssignmentExpression" || + stmt.type === "LogicalExpression" || + stmt.type === "SequenceExpression" || + stmt.type === "VariableDeclarator") { + + stmt = stmt.parent; + } + + return (( + stmt.type === "ExpressionStatement" || + stmt.type === "VariableDeclaration") && + stmt.parent && stmt.parent.type === "Program" ); } @@ -403,8 +459,8 @@ module.exports = { * * Looks for 'Models' */ - var calleeNode = node.parent; // FunctionExpression - var indent; + let calleeNode = node.parent; // FunctionExpression + let indent; if (calleeNode.parent && (calleeNode.parent.type === "Property" || @@ -419,7 +475,7 @@ module.exports = { } if (calleeNode.parent.type === "CallExpression") { - var calleeParent = calleeNode.parent; + let calleeParent = calleeNode.parent; if (calleeNode.type !== "FunctionExpression" && calleeNode.type !== "ArrowFunctionExpression") { if (calleeParent && calleeParent.loc.start.line < node.loc.start.line) { @@ -436,7 +492,7 @@ module.exports = { // function body indent should be indent + indent size, unless this // is the outer IIFE and that option is enabled. - var functionOffset = indentSize; + let functionOffset = indentSize; if (options.outerIIFEBody !== null && isOuterIIFE(calleeNode)) { functionOffset = options.outerIIFEBody * indentSize; @@ -444,7 +500,7 @@ module.exports = { indent += functionOffset; // check if the node is inside a variable - var parentVarNode = getVariableDeclaratorNode(node); + let parentVarNode = getVariableDeclaratorNode(node); if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) { indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind]; @@ -464,7 +520,7 @@ module.exports = { * @returns {boolean} Whether or not the block starts and ends on the same line. */ function isSingleLineNode(node) { - var lastToken = sourceCode.getLastToken(node), + let lastToken = sourceCode.getLastToken(node), startLine = node.loc.start.line, endLine = lastToken.loc.end.line; @@ -497,7 +553,7 @@ module.exports = { return; } - var elements = (node.type === "ArrayExpression") ? node.elements : node.properties; + let elements = (node.type === "ArrayExpression") ? node.elements : node.properties; // filter out empty elements example would be [ , 2] so remove first element as espree considers it as null elements = elements.filter(function(elem) { @@ -509,14 +565,14 @@ module.exports = { return; } - var nodeIndent; - var elementsIndent; - var parentVarNode = getVariableDeclaratorNode(node); + let nodeIndent; + let elementsIndent; + let parentVarNode = getVariableDeclaratorNode(node); // TODO - come up with a better strategy in future if (isNodeFirstInLine(node)) { - var parent = node.parent; - var effectiveParent = parent; + let parent = node.parent; + let effectiveParent = parent; if (parent.type === "MemberExpression") { if (isNodeFirstInLine(parent)) { @@ -605,14 +661,14 @@ module.exports = { return; } - var indent; - var nodesToCheck = []; + let indent; + let nodesToCheck = []; /* * For this statements we should check indent from statement beginning, * not from the beginning of the block. */ - var statementsWithProperties = [ + let statementsWithProperties = [ "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration" ]; @@ -647,7 +703,7 @@ module.exports = { */ function filterOutSameLineVars(node) { return node.declarations.reduce(function(finalCollection, elem) { - var lastElem = finalCollection[finalCollection.length - 1]; + let lastElem = finalCollection[finalCollection.length - 1]; if ((elem.loc.start.line !== node.loc.start.line && !lastElem) || (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) { @@ -664,11 +720,11 @@ module.exports = { * @returns {void} */ function checkIndentInVariableDeclarations(node) { - var elements = filterOutSameLineVars(node); - var nodeIndent = getNodeIndent(node); - var lastElement = elements[elements.length - 1]; + let elements = filterOutSameLineVars(node); + let nodeIndent = getNodeIndent(node); + let lastElement = elements[elements.length - 1]; - var elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind]; + let elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind]; // Comma can be placed before declaration checkNodesIndent(elements, elementsIndent, true); @@ -678,7 +734,7 @@ module.exports = { return; } - var tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement); + let tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement); if (tokenBeforeLastElement.value === ",") { @@ -708,8 +764,8 @@ module.exports = { * @returns {int} indent size */ function expectedCaseIndent(node, switchIndent) { - var switchNode = (node.type === "SwitchStatement") ? node : node.parent; - var caseIndent; + let switchNode = (node.type === "SwitchStatement") ? node : node.parent; + let caseIndent; if (caseIndentStore[switchNode.loc.start.line]) { return caseIndentStore[switchNode.loc.start.line]; @@ -772,11 +828,45 @@ module.exports = { checkIndentInArrayOrObjectBlock(node); }, + MemberExpression: function(node) { + if (typeof options.MemberExpression === "undefined") { + return; + } + + if (isSingleLineNode(node)) { + return; + } + + // The typical layout of variable declarations and assignments + // alter the expectation of correct indentation. Skip them. + // TODO: Add appropriate configuration options for variable + // declarations and assignments. + if (getVariableDeclaratorNode(node)) { + return; + } + + if (getAssignmentExpressionNode(node)) { + return; + } + + let propertyIndent = getNodeIndent(node) + indentSize * options.MemberExpression; + + let checkNodes = [node.property]; + + let dot = context.getTokenBefore(node.property); + + if (dot.type === "Punctuator" && dot.value === ".") { + checkNodes.push(dot); + } + + checkNodesIndent(checkNodes, propertyIndent); + }, + SwitchStatement: function(node) { // Switch is not a 'BlockStatement' - var switchIndent = getNodeIndent(node); - var caseIndent = expectedCaseIndent(node, switchIndent); + let switchIndent = getNodeIndent(node); + let caseIndent = expectedCaseIndent(node, switchIndent); checkNodesIndent(node.cases, caseIndent); @@ -790,7 +880,7 @@ module.exports = { if (isSingleLineNode(node)) { return; } - var caseIndent = expectedCaseIndent(node); + let caseIndent = expectedCaseIndent(node); checkNodesIndent(node.consequent, caseIndent + indentSize); } diff --git a/tools/eslint/lib/rules/init-declarations.js b/tools/eslint/lib/rules/init-declarations.js index 66b0a0aea43c1a..e51596f7af5bfd 100644 --- a/tools/eslint/lib/rules/init-declarations.js +++ b/tools/eslint/lib/rules/init-declarations.js @@ -26,8 +26,8 @@ function isForLoop(block) { * @returns {boolean} `true` when the node has its initializer. */ function isInitialized(node) { - var declaration = node.parent; - var block = declaration.parent; + let declaration = node.parent; + let block = declaration.parent; if (isForLoop(block)) { if (block.type === "ForStatement") { @@ -87,11 +87,11 @@ module.exports = { create: function(context) { - var MODE_ALWAYS = "always", + let MODE_ALWAYS = "always", MODE_NEVER = "never"; - var mode = context.options[0] || MODE_ALWAYS; - var params = context.options[1] || {}; + let mode = context.options[0] || MODE_ALWAYS; + let params = context.options[1] || {}; //-------------------------------------------------------------------------- // Public API @@ -100,11 +100,11 @@ module.exports = { return { "VariableDeclaration:exit": function(node) { - var kind = node.kind, + let kind = node.kind, declarations = node.declarations; - for (var i = 0; i < declarations.length; ++i) { - var declaration = declarations[i], + for (let i = 0; i < declarations.length; ++i) { + let declaration = declarations[i], id = declaration.id, initialized = isInitialized(declaration), isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent); diff --git a/tools/eslint/lib/rules/jsx-quotes.js b/tools/eslint/lib/rules/jsx-quotes.js index 6b3a2efef7143c..c3d87623cdfec2 100644 --- a/tools/eslint/lib/rules/jsx-quotes.js +++ b/tools/eslint/lib/rules/jsx-quotes.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var QUOTE_SETTINGS = { +let QUOTE_SETTINGS = { "prefer-double": { quote: "\"", description: "singlequote", @@ -54,7 +54,7 @@ module.exports = { }, create: function(context) { - var quoteOption = context.options[0] || "prefer-double", + let quoteOption = context.options[0] || "prefer-double", setting = QUOTE_SETTINGS[quoteOption]; /** @@ -69,7 +69,7 @@ module.exports = { return { JSXAttribute: function(node) { - var attributeValue = node.value; + let attributeValue = node.value; if (attributeValue && astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) { context.report({ diff --git a/tools/eslint/lib/rules/key-spacing.js b/tools/eslint/lib/rules/key-spacing.js index 1cf677865d2281..25aba47ba00a42 100644 --- a/tools/eslint/lib/rules/key-spacing.js +++ b/tools/eslint/lib/rules/key-spacing.js @@ -34,7 +34,7 @@ function last(arr) { * @returns {boolean} True if the candidate property is part of the group. */ function continuesPropertyGroup(lastMember, candidate) { - var groupEndLine = lastMember.loc.start.line, + let groupEndLine = lastMember.loc.start.line, candidateStartLine = candidate.loc.start.line, comments, i; @@ -71,19 +71,15 @@ function isSingleLine(node) { return (node.loc.end.line === node.loc.start.line); } -/** Sets option values from the configured options with defaults +/** + * Initializes a single option property from the configuration with defaults for undefined values * @param {Object} toOptions Object to be initialized * @param {Object} fromOptions Object to be initialized from * @returns {Object} The object with correctly initialized options and values */ -function initOptions(toOptions, fromOptions) { +function initOptionProperty(toOptions, fromOptions) { toOptions.mode = fromOptions.mode || "strict"; - // Set align if exists - multiLine case - if (typeof fromOptions.align !== "undefined") { - toOptions.align = fromOptions.align; - } - // Set value of beforeColon if (typeof fromOptions.beforeColon !== "undefined") { toOptions.beforeColon = +fromOptions.beforeColon; @@ -98,6 +94,55 @@ function initOptions(toOptions, fromOptions) { toOptions.afterColon = 1; } + // Set align if exists + if (typeof fromOptions.align !== "undefined") { + if (typeof fromOptions.align === "object") { + toOptions.align = fromOptions.align; + } else { // "string" + toOptions.align = { + on: fromOptions.align, + mode: toOptions.mode, + beforeColon: toOptions.beforeColon, + afterColon: toOptions.afterColon + }; + } + } + + return toOptions; +} + +/** + * Initializes all the option values (singleLine, multiLine and align) from the configuration with defaults for undefined values + * @param {Object} toOptions Object to be initialized + * @param {Object} fromOptions Object to be initialized from + * @returns {Object} The object with correctly initialized options and values + */ +function initOptions(toOptions, fromOptions) { + if (typeof fromOptions.align === "object") { + + // Initialize the alignment configuration + toOptions.align = initOptionProperty({}, fromOptions.align); + toOptions.align.on = fromOptions.align.on || "colon"; + toOptions.align.mode = fromOptions.align.mode || "strict"; + + toOptions.multiLine = initOptionProperty({}, (fromOptions.multiLine || fromOptions)); + toOptions.singleLine = initOptionProperty({}, (fromOptions.singleLine || fromOptions)); + + } else { // string or undefined + toOptions.multiLine = initOptionProperty({}, (fromOptions.multiLine || fromOptions)); + toOptions.singleLine = initOptionProperty({}, (fromOptions.singleLine || fromOptions)); + + // If alignment options are defined in multiLine, pull them out into the general align configuration + if (toOptions.multiLine.align) { + toOptions.align = { + on: toOptions.multiLine.align.on, + mode: toOptions.multiLine.mode, + beforeColon: toOptions.multiLine.align.beforeColon, + afterColon: toOptions.multiLine.align.afterColon + }; + } + } + return toOptions; } @@ -105,7 +150,7 @@ function initOptions(toOptions, fromOptions) { // Rule Definition //------------------------------------------------------------------------------ -var messages = { +let messages = { key: "{{error}} space after {{computed}}key '{{key}}'.", value: "{{error}} space before value for {{computed}}key '{{key}}'." }; @@ -126,7 +171,29 @@ module.exports = { type: "object", properties: { align: { - enum: ["colon", "value"] + anyOf: [ + { + enum: ["colon", "value"] + }, + { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + on: { + enum: ["colon", "value"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + } + ] }, mode: { enum: ["strict", "minimum"] @@ -162,7 +229,29 @@ module.exports = { type: "object", properties: { align: { - enum: ["colon", "value"] + anyOf: [ + { + enum: ["colon", "value"] + }, + { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + on: { + enum: ["colon", "value"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + } + ] }, mode: { enum: ["strict", "minimum"] @@ -178,6 +267,57 @@ module.exports = { } }, additionalProperties: false + }, + { + type: "object", + properties: { + singleLine: { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + }, + multiLine: { + type: "object", + properties: { + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + }, + align: { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + on: { + enum: ["colon", "value"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + } + }, + additionalProperties: false } ] }] @@ -193,17 +333,18 @@ module.exports = { * align: "colon" // Optional, or "value" * } */ + let options = context.options[0] || {}, + ruleOptions = initOptions({}, options), + multiLineOptions = ruleOptions.multiLine, + singleLineOptions = ruleOptions.singleLine, + alignmentOptions = ruleOptions.align || null; - var options = context.options[0] || {}, - multiLineOptions = initOptions({}, (options.multiLine || options)), - singleLineOptions = initOptions({}, (options.singleLine || options)); - - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines if the given property is key-value property. * @param {ASTNode} property Property node to check. - * @returns {Boolean} Whether the property is a key-value property. + * @returns {boolean} Whether the property is a key-value property. */ function isKeyValueProperty(property) { return !( @@ -220,7 +361,7 @@ module.exports = { * @returns {ASTNode} The last token before a colon punctuator. */ function getLastTokenBeforeColon(node) { - var prevNode; + let prevNode; while (node && (node.type !== "Punctuator" || node.value !== ":")) { prevNode = node; @@ -251,7 +392,7 @@ module.exports = { * @returns {string} The property's key. */ function getKey(property) { - var key = property.key; + let key = property.key; if (property.computed) { return sourceCode.getText().slice(key.range[0], key.range[1]); @@ -271,7 +412,7 @@ module.exports = { * @returns {void} */ function report(property, side, whitespace, expected, mode) { - var diff = whitespace.length - expected, + let diff = whitespace.length - expected, nextColon = getNextColon(property.key), tokenBeforeColon = sourceCode.getTokenBefore(nextColon), tokenAfterColon = sourceCode.getTokenAfter(nextColon), @@ -335,7 +476,7 @@ module.exports = { * @returns {int} Width of the key. */ function getKeyWidth(property) { - var startToken, endToken; + let startToken, endToken; startToken = sourceCode.getFirstToken(property); endToken = getLastTokenBeforeColon(property.key); @@ -349,7 +490,7 @@ module.exports = { * @returns {Object} Whitespace before and after the property's colon. */ function getPropertyWhitespace(property) { - var whitespace = /(\s*):(\s*)/.exec(sourceCode.getText().slice( + let whitespace = /(\s*):(\s*)/.exec(sourceCode.getText().slice( property.key.range[1], property.value.range[0] )); @@ -373,7 +514,7 @@ module.exports = { } return node.properties.reduce(function(groups, property) { - var currentGroup = last(groups), + let currentGroup = last(groups), prev = last(currentGroup); if (!prev || continuesPropertyGroup(prev, property)) { @@ -394,14 +535,22 @@ module.exports = { * @returns {void} */ function verifyGroupAlignment(properties) { - var length = properties.length, + let length = properties.length, widths = properties.map(getKeyWidth), // Width of keys, including quotes targetWidth = Math.max.apply(null, widths), + align = alignmentOptions.on, // "value" or "colon" i, property, whitespace, width, - align = multiLineOptions.align, - beforeColon = multiLineOptions.beforeColon, - afterColon = multiLineOptions.afterColon, - mode = multiLineOptions.mode; + beforeColon, afterColon, mode; + + if (alignmentOptions && length > 1) { // When aligning values within a group, use the alignment configuration. + beforeColon = alignmentOptions.beforeColon; + afterColon = alignmentOptions.afterColon; + mode = alignmentOptions.mode; + } else { + beforeColon = multiLineOptions.beforeColon; + afterColon = multiLineOptions.afterColon; + mode = alignmentOptions.mode; + } // Conditionally include one space before or after colon targetWidth += (align === "colon" ? beforeColon : afterColon); @@ -441,7 +590,7 @@ module.exports = { * @returns {void} */ function verifySpacing(node, lineOptions) { - var actual = getPropertyWhitespace(node); + let actual = getPropertyWhitespace(node); if (actual) { // Object literal getters/setters lack colons report(node, "key", actual.beforeColon, lineOptions.beforeColon, lineOptions.mode); @@ -455,9 +604,9 @@ module.exports = { * @returns {void} */ function verifyListSpacing(properties) { - var length = properties.length; + let length = properties.length; - for (var i = 0; i < length; i++) { + for (let i = 0; i < length; i++) { verifySpacing(properties[i], singleLineOptions); } } @@ -466,7 +615,7 @@ module.exports = { // Public API //-------------------------------------------------------------------------- - if (multiLineOptions.align) { // Verify vertical alignment + if (alignmentOptions) { // Verify vertical alignment return { ObjectExpression: function(node) { diff --git a/tools/eslint/lib/rules/keyword-spacing.js b/tools/eslint/lib/rules/keyword-spacing.js index f771029a581d44..3c8d171ce868a6 100644 --- a/tools/eslint/lib/rules/keyword-spacing.js +++ b/tools/eslint/lib/rules/keyword-spacing.js @@ -9,26 +9,26 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"), +let astUtils = require("../ast-utils"), keywords = require("../util/keywords"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var PREV_TOKEN = /^[\)\]\}>]$/; -var NEXT_TOKEN = /^(?:[\(\[\{<~!]|\+\+?|--?)$/; -var PREV_TOKEN_M = /^[\)\]\}>*]$/; -var NEXT_TOKEN_M = /^[\{*]$/; -var TEMPLATE_OPEN_PAREN = /\$\{$/; -var TEMPLATE_CLOSE_PAREN = /^\}/; -var CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/; -var KEYS = keywords.concat(["as", "await", "from", "get", "let", "of", "set", "yield"]); +let PREV_TOKEN = /^[\)\]\}>]$/; +let NEXT_TOKEN = /^(?:[\(\[\{<~!]|\+\+?|--?)$/; +let PREV_TOKEN_M = /^[\)\]\}>*]$/; +let NEXT_TOKEN_M = /^[\{*]$/; +let TEMPLATE_OPEN_PAREN = /\$\{$/; +let TEMPLATE_CLOSE_PAREN = /^\}/; +let CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/; +let KEYS = keywords.concat(["as", "await", "from", "get", "let", "of", "set", "yield"]); // check duplications. (function() { KEYS.sort(); - for (var i = 1; i < KEYS.length; ++i) { + for (let i = 1; i < KEYS.length; ++i) { if (KEYS[i] === KEYS[i - 1]) { throw new Error("Duplication was found in the keyword list: " + KEYS[i]); } @@ -101,7 +101,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports a given token if there are not space(s) before the token. @@ -114,7 +114,7 @@ module.exports = { function expectSpaceBefore(token, pattern) { pattern = pattern || PREV_TOKEN; - var prevToken = sourceCode.getTokenBefore(token); + let prevToken = sourceCode.getTokenBefore(token); if (prevToken && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && @@ -144,7 +144,7 @@ module.exports = { function unexpectSpaceBefore(token, pattern) { pattern = pattern || PREV_TOKEN; - var prevToken = sourceCode.getTokenBefore(token); + let prevToken = sourceCode.getTokenBefore(token); if (prevToken && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && @@ -174,7 +174,7 @@ module.exports = { function expectSpaceAfter(token, pattern) { pattern = pattern || NEXT_TOKEN; - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); if (nextToken && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && @@ -204,7 +204,7 @@ module.exports = { function unexpectSpaceAfter(token, pattern) { pattern = pattern || NEXT_TOKEN; - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); if (nextToken && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && @@ -226,28 +226,28 @@ module.exports = { /** * Parses the option object and determines check methods for each keyword. * - * @param {object|undefined} options - The option object to parse. - * @returns {object} - Normalized option object. + * @param {Object|undefined} options - The option object to parse. + * @returns {Object} - Normalized option object. * Keys are keywords (there are for every keyword). * Values are instances of `{"before": function, "after": function}`. */ function parseOptions(options) { - var before = !options || options.before !== false; - var after = !options || options.after !== false; - var defaultValue = { + let before = !options || options.before !== false; + let after = !options || options.after !== false; + let defaultValue = { before: before ? expectSpaceBefore : unexpectSpaceBefore, after: after ? expectSpaceAfter : unexpectSpaceAfter }; - var overrides = (options && options.overrides) || {}; - var retv = Object.create(null); + let overrides = (options && options.overrides) || {}; + let retv = Object.create(null); - for (var i = 0; i < KEYS.length; ++i) { - var key = KEYS[i]; - var override = overrides[key]; + for (let i = 0; i < KEYS.length; ++i) { + let key = KEYS[i]; + let override = overrides[key]; if (override) { - var thisBefore = ("before" in override) ? override.before : before; - var thisAfter = ("after" in override) ? override.after : after; + let thisBefore = ("before" in override) ? override.before : before; + let thisAfter = ("after" in override) ? override.after : after; retv[key] = { before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore, @@ -261,7 +261,7 @@ module.exports = { return retv; } - var checkMethodMap = parseOptions(context.options[0]); + let checkMethodMap = parseOptions(context.options[0]); /** * Reports a given token if usage of spacing followed by the token is @@ -308,7 +308,7 @@ module.exports = { * @returns {void} */ function checkSpacingAroundFirstToken(node) { - var firstToken = node && sourceCode.getFirstToken(node); + let firstToken = node && sourceCode.getFirstToken(node); if (firstToken && firstToken.type === "Keyword") { checkSpacingAround(firstToken); @@ -326,7 +326,7 @@ module.exports = { * @returns {void} */ function checkSpacingBeforeFirstToken(node) { - var firstToken = node && sourceCode.getFirstToken(node); + let firstToken = node && sourceCode.getFirstToken(node); if (firstToken && firstToken.type === "Keyword") { checkSpacingBefore(firstToken); @@ -342,7 +342,7 @@ module.exports = { */ function checkSpacingAroundTokenBefore(node) { if (node) { - var token = sourceCode.getTokenBefore(node); + let token = sourceCode.getTokenBefore(node); while (token.type !== "Keyword") { token = sourceCode.getTokenBefore(token); @@ -424,7 +424,7 @@ module.exports = { checkSpacingAroundFirstToken(node); // `of` is not a keyword token. - var token = sourceCode.getTokenBefore(node.right); + let token = sourceCode.getTokenBefore(node.right); while (token.value !== "of") { token = sourceCode.getTokenBefore(token); @@ -445,13 +445,13 @@ module.exports = { * @returns {void} */ function checkSpacingForModuleDeclaration(node) { - var firstToken = sourceCode.getFirstToken(node); + let firstToken = sourceCode.getFirstToken(node); checkSpacingBefore(firstToken, PREV_TOKEN_M); checkSpacingAfter(firstToken, NEXT_TOKEN_M); if (node.source) { - var fromToken = sourceCode.getTokenBefore(node.source); + let fromToken = sourceCode.getTokenBefore(node.source); checkSpacingBefore(fromToken, PREV_TOKEN_M); checkSpacingAfter(fromToken, NEXT_TOKEN_M); @@ -466,7 +466,7 @@ module.exports = { * @returns {void} */ function checkSpacingForImportNamespaceSpecifier(node) { - var asToken = sourceCode.getFirstToken(node, 1); + let asToken = sourceCode.getFirstToken(node, 1); checkSpacingBefore(asToken, PREV_TOKEN_M); } @@ -483,7 +483,7 @@ module.exports = { checkSpacingAroundFirstToken(node); } if (node.kind === "get" || node.kind === "set") { - var token = sourceCode.getFirstToken( + let token = sourceCode.getFirstToken( node, node.static ? 1 : 0 ); diff --git a/tools/eslint/lib/rules/linebreak-style.js b/tools/eslint/lib/rules/linebreak-style.js index 5e6b819f3fe616..a8a5e4ed88483e 100644 --- a/tools/eslint/lib/rules/linebreak-style.js +++ b/tools/eslint/lib/rules/linebreak-style.js @@ -28,10 +28,10 @@ module.exports = { create: function(context) { - var EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.", + let EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.", EXPECTED_CRLF_MSG = "Expected linebreaks to be 'CRLF' but found 'LF'."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -41,7 +41,7 @@ module.exports = { * Builds a fix function that replaces text at the specified range in the source text. * @param {int[]} range The range to replace * @param {string} text The text to insert. - * @returns {function} Fixer function + * @returns {Function} Fixer function * @private */ function createFix(range, text) { @@ -56,7 +56,7 @@ module.exports = { return { Program: function checkForlinebreakStyle(node) { - var linebreakStyle = context.options[0] || "unix", + let linebreakStyle = context.options[0] || "unix", expectedLF = linebreakStyle === "unix", expectedLFChars = expectedLF ? "\n" : "\r\n", source = sourceCode.getText(), @@ -65,7 +65,7 @@ module.exports = { index, range; - var i = 0; + let i = 0; while ((match = pattern.exec(source)) !== null) { i++; diff --git a/tools/eslint/lib/rules/lines-around-comment.js b/tools/eslint/lib/rules/lines-around-comment.js index a227fe4184f995..70775b42132fca 100644 --- a/tools/eslint/lib/rules/lines-around-comment.js +++ b/tools/eslint/lib/rules/lines-around-comment.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ @@ -21,7 +21,7 @@ var lodash = require("lodash"), * @returns {Array} An array of line numbers. */ function getEmptyLineNums(lines) { - var emptyLines = lines.map(function(line, i) { + let emptyLines = lines.map(function(line, i) { return { code: line.trim(), num: i + 1 @@ -41,11 +41,11 @@ function getEmptyLineNums(lines) { * @returns {Array} An array of line numbers. */ function getCommentLineNums(comments) { - var lines = []; + let lines = []; comments.forEach(function(token) { - var start = token.loc.start.line; - var end = token.loc.end.line; + let start = token.loc.start.line; + let end = token.loc.end.line; lines.push(start, end); }); @@ -108,7 +108,7 @@ module.exports = { create: function(context) { - var options = context.options[0] ? lodash.assign({}, context.options[0]) : {}; + let options = context.options[0] ? lodash.assign({}, context.options[0]) : {}; options.beforeLineComment = options.beforeLineComment || false; options.afterLineComment = options.afterLineComment || false; @@ -117,9 +117,9 @@ module.exports = { options.allowBlockStart = options.allowBlockStart || false; options.allowBlockEnd = options.allowBlockEnd || false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var lines = sourceCode.lines, + let lines = sourceCode.lines, numLines = lines.length + 1, comments = sourceCode.getAllComments(), commentLines = getCommentLineNums(comments), @@ -141,7 +141,7 @@ module.exports = { * @returns {boolean} True if the comment is not alone. */ function codeAroundComment(node) { - var token; + let token; token = node; do { @@ -184,8 +184,8 @@ module.exports = { * @returns {boolean} True if the comment is at parent start. */ function isCommentAtParentStart(node, nodeType) { - var ancestors = context.getAncestors(); - var parent; + let ancestors = context.getAncestors(); + let parent; if (ancestors.length) { parent = ancestors.pop(); @@ -202,8 +202,8 @@ module.exports = { * @returns {boolean} True if the comment is at parent end. */ function isCommentAtParentEnd(node, nodeType) { - var ancestors = context.getAncestors(); - var parent; + let ancestors = context.getAncestors(); + let parent; if (ancestors.length) { parent = ancestors.pop(); @@ -271,27 +271,27 @@ module.exports = { * Checks if a comment node has lines around it (ignores inline comments) * @param {ASTNode} node The Comment node. * @param {Object} opts Options to determine the newline. - * @param {Boolean} opts.after Should have a newline after this line. - * @param {Boolean} opts.before Should have a newline before this line. + * @param {boolean} opts.after Should have a newline after this line. + * @param {boolean} opts.before Should have a newline before this line. * @returns {void} */ function checkForEmptyLine(node, opts) { - var after = opts.after, + let after = opts.after, before = opts.before; - var prevLineNum = node.loc.start.line - 1, + let prevLineNum = node.loc.start.line - 1, nextLineNum = node.loc.end.line + 1, commentIsNotAlone = codeAroundComment(node); - var blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node), + let blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node), blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(node), objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(node), objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(node), arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(node), arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(node); - var exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed; - var exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed; + let exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed; + let exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed; // ignore top of the file and bottom of the file if (prevLineNum < 1) { @@ -306,14 +306,14 @@ module.exports = { return; } - var previousTokenOrComment = sourceCode.getTokenOrCommentBefore(node); - var nextTokenOrComment = sourceCode.getTokenOrCommentAfter(node); + let previousTokenOrComment = sourceCode.getTokenOrCommentBefore(node); + let nextTokenOrComment = sourceCode.getTokenOrCommentAfter(node); // check for newline before if (!exceptionStartAllowed && before && !lodash.includes(commentAndEmptyLines, prevLineNum) && !(isCommentNodeType(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, node))) { - var lineStart = node.range[0] - node.loc.start.column; - var range = [lineStart, lineStart]; + let lineStart = node.range[0] - node.loc.start.column; + let range = [lineStart, lineStart]; context.report({ node: node, diff --git a/tools/eslint/lib/rules/max-depth.js b/tools/eslint/lib/rules/max-depth.js index 317f06c68f397a..dbc1f6d48c5de3 100644 --- a/tools/eslint/lib/rules/max-depth.js +++ b/tools/eslint/lib/rules/max-depth.js @@ -49,7 +49,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var functionStack = [], + let functionStack = [], option = context.options[0], maxDepth = 4; @@ -88,7 +88,7 @@ module.exports = { * @private */ function pushBlock(node) { - var len = ++functionStack[functionStack.length - 1]; + let len = ++functionStack[functionStack.length - 1]; if (len > maxDepth) { context.report(node, "Blocks are nested too deeply ({{depth}}).", diff --git a/tools/eslint/lib/rules/max-len.js b/tools/eslint/lib/rules/max-len.js index b5813bbfaa77c8..1bb63990d80cdc 100644 --- a/tools/eslint/lib/rules/max-len.js +++ b/tools/eslint/lib/rules/max-len.js @@ -9,7 +9,7 @@ // Constants //------------------------------------------------------------------------------ -var OPTIONS_SCHEMA = { +let OPTIONS_SCHEMA = { type: "object", properties: { code: { @@ -40,7 +40,7 @@ var OPTIONS_SCHEMA = { additionalProperties: false }; -var OPTIONS_OR_INTEGER_SCHEMA = { +let OPTIONS_OR_INTEGER_SCHEMA = { anyOf: [ OPTIONS_SCHEMA, { @@ -79,9 +79,9 @@ module.exports = { * too many false positives * - We don't care about matching the entire URL, any small segment is fine */ - var URL_REGEXP = /[^:/?#]:\/\/[^?#]/; + let URL_REGEXP = /[^:/?#]:\/\/[^?#]/; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Computes the length of a line that may contain tabs. The width of each @@ -92,10 +92,10 @@ module.exports = { * @private */ function computeLineLength(line, tabWidth) { - var extraCharacterCount = 0; + let extraCharacterCount = 0; line.replace(/\t/g, function(match, offset) { - var totalOffset = offset + extraCharacterCount, + let totalOffset = offset + extraCharacterCount, previousTabStopOffset = tabWidth ? totalOffset % tabWidth : 0, spaceCount = tabWidth - previousTabStopOffset; @@ -105,8 +105,8 @@ module.exports = { } // The options object must be the last option specified… - var lastOption = context.options[context.options.length - 1]; - var options = typeof lastOption === "object" ? Object.create(lastOption) : {}; + let lastOption = context.options[context.options.length - 1]; + let options = typeof lastOption === "object" ? Object.create(lastOption) : {}; // …but max code length… if (typeof context.options[0] === "number") { @@ -118,7 +118,7 @@ module.exports = { options.tabWidth = context.options[1]; } - var maxLength = options.code || 80, + let maxLength = options.code || 80, tabWidth = options.tabWidth || 4, ignorePattern = options.ignorePattern || null, ignoreComments = options.ignoreComments || false, @@ -156,7 +156,7 @@ module.exports = { * @returns {boolean} If the comment covers the entire line */ function isFullLineComment(line, lineNumber, comment) { - var start = comment.loc.start, + let start = comment.loc.start, end = comment.loc.end, isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim(); @@ -188,7 +188,7 @@ module.exports = { function checkProgramForMaxLength(node) { // split (honors line-ending) - var lines = sourceCode.lines, + let lines = sourceCode.lines, // list of comments to ignore comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : [], @@ -199,23 +199,24 @@ module.exports = { lines.forEach(function(line, i) { // i is zero-indexed, line numbers are one-indexed - var lineNumber = i + 1; + let lineNumber = i + 1; /* * if we're checking comment length; we need to know whether this * line is a comment */ - var lineIsComment = false; + let lineIsComment = false; /* * We can short-circuit the comment checks if we're already out of * comments to check. */ if (commentsIndex < comments.length) { + let comment = null; // iterate over comments until we find one past the current line do { - var comment = comments[++commentsIndex]; + comment = comments[++commentsIndex]; } while (comment && comment.loc.start.line <= lineNumber); // and step back by one @@ -234,7 +235,7 @@ module.exports = { return; } - var lineLength = computeLineLength(line, tabWidth); + let lineLength = computeLineLength(line, tabWidth); if (lineIsComment && ignoreComments) { return; diff --git a/tools/eslint/lib/rules/max-lines.js b/tools/eslint/lib/rules/max-lines.js index 751310e81da42a..1e311eaffbc25a 100644 --- a/tools/eslint/lib/rules/max-lines.js +++ b/tools/eslint/lib/rules/max-lines.js @@ -8,8 +8,8 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); -var astUtils = require("../ast-utils"); +let lodash = require("lodash"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -52,7 +52,7 @@ module.exports = { }, create: function(context) { - var option = context.options[0], + let option = context.options[0], max = 300; if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") { @@ -63,10 +63,10 @@ module.exports = { max = option; } - var skipComments = option && option.skipComments; - var skipBlankLines = option && option.skipBlankLines; + let skipComments = option && option.skipComments; + let skipBlankLines = option && option.skipBlankLines; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Returns whether or not a token is a comment node type @@ -83,10 +83,10 @@ module.exports = { * @returns {int[]} The line numbers */ function getLinesWithoutCode(comment) { - var start = comment.loc.start.line; - var end = comment.loc.end.line; + let start = comment.loc.start.line; + let end = comment.loc.end.line; - var token; + let token; token = comment; do { @@ -114,7 +114,7 @@ module.exports = { return { "Program:exit": function() { - var lines = sourceCode.lines.map(function(text, i) { + let lines = sourceCode.lines.map(function(text, i) { return { lineNumber: i + 1, text: text }; }); @@ -125,9 +125,9 @@ module.exports = { } if (skipComments) { - var comments = sourceCode.getAllComments(); + let comments = sourceCode.getAllComments(); - var commentLines = lodash.flatten(comments.map(function(comment) { + let commentLines = lodash.flatten(comments.map(function(comment) { return getLinesWithoutCode(comment); })); @@ -139,7 +139,7 @@ module.exports = { if (lines.length > max) { context.report({ loc: { line: 1, column: 0 }, - message: "File must be at most " + max + " lines long" + message: "File must be at most " + max + " lines long." }); } } diff --git a/tools/eslint/lib/rules/max-nested-callbacks.js b/tools/eslint/lib/rules/max-nested-callbacks.js index 06554127c63242..a1145c1f1a6834 100644 --- a/tools/eslint/lib/rules/max-nested-callbacks.js +++ b/tools/eslint/lib/rules/max-nested-callbacks.js @@ -48,7 +48,7 @@ module.exports = { //-------------------------------------------------------------------------- // Constants //-------------------------------------------------------------------------- - var option = context.options[0], + let option = context.options[0], THRESHOLD = 10; if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { @@ -65,7 +65,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var callbackStack = []; + let callbackStack = []; /** * Checks a given function node for too many callbacks. @@ -74,14 +74,14 @@ module.exports = { * @private */ function checkFunction(node) { - var parent = node.parent; + let parent = node.parent; if (parent.type === "CallExpression") { callbackStack.push(node); } if (callbackStack.length > THRESHOLD) { - var opts = {num: callbackStack.length, max: THRESHOLD}; + let opts = {num: callbackStack.length, max: THRESHOLD}; context.report(node, "Too many nested callbacks ({{num}}). Maximum allowed is {{max}}.", opts); } diff --git a/tools/eslint/lib/rules/max-params.js b/tools/eslint/lib/rules/max-params.js index 5d9d64fac10af9..9fb922392b60a9 100644 --- a/tools/eslint/lib/rules/max-params.js +++ b/tools/eslint/lib/rules/max-params.js @@ -45,7 +45,7 @@ module.exports = { create: function(context) { - var option = context.options[0], + let option = context.options[0], numParams = 3; if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { diff --git a/tools/eslint/lib/rules/max-statements-per-line.js b/tools/eslint/lib/rules/max-statements-per-line.js index 55f09746c30836..165c6dd137556f 100644 --- a/tools/eslint/lib/rules/max-statements-per-line.js +++ b/tools/eslint/lib/rules/max-statements-per-line.js @@ -32,7 +32,7 @@ module.exports = { create: function(context) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), options = context.options[0] || {}, lastStatementLine = 0, numberOfStatementsOnThisLine = 0, @@ -43,7 +43,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/; + let SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/; /** * Gets the actual last token of a given node. @@ -52,7 +52,7 @@ module.exports = { * @returns {Token} The actual last token. */ function getActualLastToken(node) { - var lastToken = sourceCode.getLastToken(node); + let lastToken = sourceCode.getLastToken(node); if (lastToken.value === ";") { lastToken = sourceCode.getTokenBefore(lastToken); @@ -68,7 +68,7 @@ module.exports = { * @returns {void} */ function enterStatement(node) { - var line = node.loc.start.line; + let line = node.loc.start.line; // Skip to allow non-block statements if this is direct child of control statements. // `if (a) foo();` is counted as 1. @@ -100,7 +100,7 @@ module.exports = { * @returns {void} */ function leaveStatement(node) { - var line = getActualLastToken(node).loc.end.line; + let line = getActualLastToken(node).loc.end.line; // Update state. if (line !== lastStatementLine) { diff --git a/tools/eslint/lib/rules/max-statements.js b/tools/eslint/lib/rules/max-statements.js index 72904c64bad0c4..6708be3a12e191 100644 --- a/tools/eslint/lib/rules/max-statements.js +++ b/tools/eslint/lib/rules/max-statements.js @@ -58,7 +58,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var functionStack = [], + let functionStack = [], option = context.options[0], maxStatements = 10, ignoreTopLevelFunctions = context.options[1] && context.options[1].ignoreTopLevelFunctions || false, @@ -107,7 +107,7 @@ module.exports = { * @private */ function endFunction(node) { - var count = functionStack.pop(); + let count = functionStack.pop(); if (ignoreTopLevelFunctions && functionStack.length === 0) { topLevelFunctions.push({ node: node, count: count}); @@ -147,8 +147,8 @@ module.exports = { } topLevelFunctions.forEach(function(element) { - var count = element.count; - var node = element.node; + let count = element.count; + let node = element.node; reportIfTooManyStatements(node, count, maxStatements); }); diff --git a/tools/eslint/lib/rules/multiline-ternary.js b/tools/eslint/lib/rules/multiline-ternary.js new file mode 100644 index 00000000000000..469eb134ded6e8 --- /dev/null +++ b/tools/eslint/lib/rules/multiline-ternary.js @@ -0,0 +1,66 @@ +/** + * @fileoverview Enforce newlines between operands of ternary expressions + * @author Kai Cataldo + */ + +"use strict"; + +let astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "enforce newlines between operands of ternary expressions", + category: "Stylistic Issues", + recommended: false + }, + schema: [] + }, + + create: function(context) { + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Tests whether node is preceded by supplied tokens + * @param {ASTNode} node - node to check + * @param {ASTNode} parentNode - parent of node to report + * @returns {void} + * @private + */ + function reportError(node, parentNode) { + context.report({ + node: node, + message: "Expected newline between {{typeOfError}} of ternary expression.", + data: { + typeOfError: node === parentNode.test ? "test and consequent" : "consequent and alternate" + } + }); + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + ConditionalExpression: function(node) { + let areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(node.test, node.consequent); + let areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(node.consequent, node.alternate); + + if (areTestAndConsequentOnSameLine) { + reportError(node.test, node); + } + + if (areConsequentAndAlternateOnSameLine) { + reportError(node.consequent, node); + } + } + }; + } +}; diff --git a/tools/eslint/lib/rules/new-cap.js b/tools/eslint/lib/rules/new-cap.js index 2dabb30a65511b..5e1baa540cc4e5 100644 --- a/tools/eslint/lib/rules/new-cap.js +++ b/tools/eslint/lib/rules/new-cap.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var CAPS_ALLOWED = [ +let CAPS_ALLOWED = [ "Array", "Boolean", "Date", @@ -61,7 +61,7 @@ function invert(map, key) { * @returns {Object} Object with cap is new exceptions. */ function calculateCapIsNewExceptions(config) { - var capIsNewExceptions = checkArray(config, "capIsNewExceptions", CAPS_ALLOWED); + let capIsNewExceptions = checkArray(config, "capIsNewExceptions", CAPS_ALLOWED); if (capIsNewExceptions !== CAPS_ALLOWED) { capIsNewExceptions = capIsNewExceptions.concat(CAPS_ALLOWED); @@ -115,19 +115,19 @@ module.exports = { create: function(context) { - var config = context.options[0] ? lodash.assign({}, context.options[0]) : {}; + let config = context.options[0] ? lodash.assign({}, context.options[0]) : {}; config.newIsCap = config.newIsCap !== false; config.capIsNew = config.capIsNew !== false; - var skipProperties = config.properties === false; + let skipProperties = config.properties === false; - var newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {}); + let newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {}); - var capIsNewExceptions = calculateCapIsNewExceptions(config); + let capIsNewExceptions = calculateCapIsNewExceptions(config); - var listeners = {}; + let listeners = {}; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -140,7 +140,7 @@ module.exports = { */ function extractNameFromExpression(node) { - var name = "", + let name = "", property; if (node.callee.type === "MemberExpression") { @@ -164,10 +164,10 @@ module.exports = { * @returns {string} capitalization state: "non-alpha", "lower", or "upper" */ function getCap(str) { - var firstChar = str.charAt(0); + let firstChar = str.charAt(0); - var firstCharLower = firstChar.toLowerCase(); - var firstCharUpper = firstChar.toUpperCase(); + let firstCharLower = firstChar.toLowerCase(); + let firstCharUpper = firstChar.toUpperCase(); if (firstCharLower === firstCharUpper) { @@ -185,7 +185,7 @@ module.exports = { * @param {Object} allowedMap Object mapping calleeName to a Boolean * @param {ASTNode} node CallExpression node * @param {string} calleeName Capitalized callee name from a CallExpression - * @returns {Boolean} Returns true if the callee may be capitalized + * @returns {boolean} Returns true if the callee may be capitalized */ function isCapAllowed(allowedMap, node, calleeName) { if (allowedMap[calleeName] || allowedMap[sourceCode.getText(node.callee)]) { @@ -209,7 +209,7 @@ module.exports = { * @returns {void} */ function report(node, message) { - var callee = node.callee; + let callee = node.callee; if (callee.type === "MemberExpression") { callee = callee.property; @@ -225,11 +225,11 @@ module.exports = { if (config.newIsCap) { listeners.NewExpression = function(node) { - var constructorName = extractNameFromExpression(node); + let constructorName = extractNameFromExpression(node); if (constructorName) { - var capitalization = getCap(constructorName); - var isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName); + let capitalization = getCap(constructorName); + let isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName); if (!isAllowed) { report(node, "A constructor name should not start with a lowercase letter."); @@ -241,11 +241,11 @@ module.exports = { if (config.capIsNew) { listeners.CallExpression = function(node) { - var calleeName = extractNameFromExpression(node); + let calleeName = extractNameFromExpression(node); if (calleeName) { - var capitalization = getCap(calleeName); - var isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName); + let capitalization = getCap(calleeName); + let isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName); if (!isAllowed) { report(node, "A function with a name starting with an uppercase letter should only be used as a constructor."); diff --git a/tools/eslint/lib/rules/new-parens.js b/tools/eslint/lib/rules/new-parens.js index ec6106647af25d..7ebd144b7ee766 100644 --- a/tools/eslint/lib/rules/new-parens.js +++ b/tools/eslint/lib/rules/new-parens.js @@ -21,18 +21,18 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { NewExpression: function(node) { - var tokens = sourceCode.getTokens(node); - var prenticesTokens = tokens.filter(function(token) { + let tokens = sourceCode.getTokens(node); + let prenticesTokens = tokens.filter(function(token) { return token.value === "(" || token.value === ")"; }); if (prenticesTokens.length < 2) { - context.report(node, "Missing '()' invoking a constructor"); + context.report(node, "Missing '()' invoking a constructor."); } } }; diff --git a/tools/eslint/lib/rules/newline-after-var.js b/tools/eslint/lib/rules/newline-after-var.js index 8801407c0bf0c2..cb06c6f26145ee 100644 --- a/tools/eslint/lib/rules/newline-after-var.js +++ b/tools/eslint/lib/rules/newline-after-var.js @@ -26,16 +26,16 @@ module.exports = { create: function(context) { - var ALWAYS_MESSAGE = "Expected blank line after variable declarations.", + let ALWAYS_MESSAGE = "Expected blank line after variable declarations.", NEVER_MESSAGE = "Unexpected blank line after variable declarations."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); // Default `mode` to "always". - var mode = context.options[0] === "never" ? "never" : "always"; + let mode = context.options[0] === "never" ? "never" : "always"; // Cache starting and ending line numbers of comments for faster lookup - var commentEndLine = sourceCode.getAllComments().reduce(function(result, token) { + let commentEndLine = sourceCode.getAllComments().reduce(function(result, token) { result[token.loc.start.line] = token.loc.end.line; return result; }, {}); @@ -83,7 +83,7 @@ module.exports = { * @returns {boolean} True if `node` is last of their parent block. */ function isLastNode(node) { - var token = sourceCode.getTokenAfter(node); + let token = sourceCode.getTokenAfter(node); return !token || (token.type === "Punctuator" && token.value === "}"); } @@ -95,7 +95,7 @@ module.exports = { * @returns {boolean} True if `token` does not start immediately after a comment */ function hasBlankLineAfterComment(token, commentStartLine) { - var commentEnd = commentEndLine[commentStartLine]; + let commentEnd = commentEndLine[commentStartLine]; // If there's another comment, repeat check for blank line if (commentEndLine[commentEnd + 1]) { @@ -114,7 +114,7 @@ module.exports = { * @returns {void} */ function checkForBlankLine(node) { - var lastToken = sourceCode.getLastToken(node), + let lastToken = sourceCode.getLastToken(node), nextToken = sourceCode.getTokenAfter(node), nextLineNum = lastToken.loc.end.line + 1, noNextLineToken, diff --git a/tools/eslint/lib/rules/newline-before-return.js b/tools/eslint/lib/rules/newline-before-return.js index 5c8a139358c8b3..966ddb9193b505 100644 --- a/tools/eslint/lib/rules/newline-before-return.js +++ b/tools/eslint/lib/rules/newline-before-return.js @@ -20,7 +20,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -34,7 +34,7 @@ module.exports = { * @private */ function isPrecededByTokens(node, testTokens) { - var tokenBefore = sourceCode.getTokenBefore(node); + let tokenBefore = sourceCode.getTokenBefore(node); return testTokens.some(function(token) { return tokenBefore.value === token; @@ -48,7 +48,7 @@ module.exports = { * @private */ function isFirstNode(node) { - var parentType = node.parent.type; + let parentType = node.parent.type; if (node.parent.body) { return Array.isArray(node.parent.body) @@ -75,7 +75,7 @@ module.exports = { * @private */ function calcCommentLines(node, lineNumTokenBefore) { - var comments = sourceCode.getComments(node).leading, + let comments = sourceCode.getComments(node).leading, numLinesComments = 0; if (!comments.length) { @@ -109,7 +109,7 @@ module.exports = { * @private */ function hasNewlineBefore(node) { - var tokenBefore = sourceCode.getTokenBefore(node), + let tokenBefore = sourceCode.getTokenBefore(node), lineNumNode = node.loc.start.line, lineNumTokenBefore, commentLines; diff --git a/tools/eslint/lib/rules/newline-per-chained-call.js b/tools/eslint/lib/rules/newline-per-chained-call.js index c412d53e994841..068e7b97ae9579 100644 --- a/tools/eslint/lib/rules/newline-per-chained-call.js +++ b/tools/eslint/lib/rules/newline-per-chained-call.js @@ -33,10 +33,10 @@ module.exports = { create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, ignoreChainWithDepth = options.ignoreChainWithDepth || 2; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Gets the property text of a given MemberExpression node. @@ -46,9 +46,9 @@ module.exports = { * @returns {string} The property text of the node. */ function getPropertyText(node) { - var prefix = node.computed ? "[" : "."; - var lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g); - var suffix = node.computed && lines.length === 1 ? "]" : ""; + let prefix = node.computed ? "[" : "."; + let lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g); + let suffix = node.computed && lines.length === 1 ? "]" : ""; return prefix + lines[0] + suffix; } @@ -59,9 +59,9 @@ module.exports = { return; } - var callee = node.callee; - var parent = callee.object; - var depth = 1; + let callee = node.callee; + let parent = callee.object; + let depth = 1; while (parent && parent.callee) { depth += 1; diff --git a/tools/eslint/lib/rules/no-alert.js b/tools/eslint/lib/rules/no-alert.js index e491dfefc5504e..1ff04a3b687c0f 100644 --- a/tools/eslint/lib/rules/no-alert.js +++ b/tools/eslint/lib/rules/no-alert.js @@ -51,7 +51,7 @@ function getPropertyName(memberExpressionNode) { * @returns {Reference|null} Returns the found reference or null if none were found. */ function findReference(scope, node) { - var references = scope.references.filter(function(reference) { + let references = scope.references.filter(function(reference) { return reference.identifier.range[0] === node.range[0] && reference.identifier.range[1] === node.range[1]; }); @@ -70,7 +70,7 @@ function findReference(scope, node) { * @returns {boolean} Whether or not the name is shadowed. */ function isShadowed(scope, globalScope, node) { - var reference = findReference(scope, node); + let reference = findReference(scope, node); return reference && reference.resolved && reference.resolved.defs.length > 0; } @@ -108,7 +108,7 @@ module.exports = { }, create: function(context) { - var globalScope; + let globalScope; return { @@ -117,7 +117,7 @@ module.exports = { }, CallExpression: function(node) { - var callee = node.callee, + let callee = node.callee, identifierName, currentScope = context.getScope(); diff --git a/tools/eslint/lib/rules/no-bitwise.js b/tools/eslint/lib/rules/no-bitwise.js index 0294998ecc1022..bfb6c180da4a12 100644 --- a/tools/eslint/lib/rules/no-bitwise.js +++ b/tools/eslint/lib/rules/no-bitwise.js @@ -8,7 +8,7 @@ // // Set of bitwise operators. // -var BITWISE_OPERATORS = [ +let BITWISE_OPERATORS = [ "^", "|", "&", "<<", ">>", ">>>", "^=", "|=", "&=", "<<=", ">>=", ">>>=", "~" @@ -47,9 +47,9 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var allowed = options.allow || []; - var int32Hint = options.int32Hint === true; + let options = context.options[0] || {}; + let allowed = options.allow || []; + let int32Hint = options.int32Hint === true; /** * Reports an unexpected use of a bitwise operator. diff --git a/tools/eslint/lib/rules/no-caller.js b/tools/eslint/lib/rules/no-caller.js index 0405fdaeb90303..75cfb63f65c114 100644 --- a/tools/eslint/lib/rules/no-caller.js +++ b/tools/eslint/lib/rules/no-caller.js @@ -25,7 +25,7 @@ module.exports = { return { MemberExpression: function(node) { - var objectName = node.object.name, + let objectName = node.object.name, propertyName = node.property.name; if (objectName === "arguments" && !node.computed && propertyName && propertyName.match(/^calle[er]$/)) { diff --git a/tools/eslint/lib/rules/no-case-declarations.js b/tools/eslint/lib/rules/no-case-declarations.js index 8ef202538ec573..6538674d41e92e 100644 --- a/tools/eslint/lib/rules/no-case-declarations.js +++ b/tools/eslint/lib/rules/no-case-declarations.js @@ -40,8 +40,8 @@ module.exports = { return { SwitchCase: function(node) { - for (var i = 0; i < node.consequent.length; i++) { - var statement = node.consequent[i]; + for (let i = 0; i < node.consequent.length; i++) { + let statement = node.consequent[i]; if (isLexicalDeclaration(statement)) { context.report({ diff --git a/tools/eslint/lib/rules/no-catch-shadow.js b/tools/eslint/lib/rules/no-catch-shadow.js index 4a206833c08928..919ad3bc37d884 100644 --- a/tools/eslint/lib/rules/no-catch-shadow.js +++ b/tools/eslint/lib/rules/no-catch-shadow.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -34,7 +34,7 @@ module.exports = { /** * Check if the parameters are been shadowed - * @param {object} scope current scope + * @param {Object} scope current scope * @param {string} name parameter name * @returns {boolean} True is its been shadowed */ @@ -49,7 +49,7 @@ module.exports = { return { CatchClause: function(node) { - var scope = context.getScope(); + let scope = context.getScope(); // When blockBindings is enabled, CatchClause creates its own scope // so start from one upper scope to exclude the current node diff --git a/tools/eslint/lib/rules/no-class-assign.js b/tools/eslint/lib/rules/no-class-assign.js index 1e4d3243d8b918..e12d3a065a6cae 100644 --- a/tools/eslint/lib/rules/no-class-assign.js +++ b/tools/eslint/lib/rules/no-class-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-cond-assign.js b/tools/eslint/lib/rules/no-cond-assign.js index e0979ddaf29be4..5cba25e8c78be5 100644 --- a/tools/eslint/lib/rules/no-cond-assign.js +++ b/tools/eslint/lib/rules/no-cond-assign.js @@ -4,7 +4,7 @@ */ "use strict"; -var NODE_DESCRIPTIONS = { +let NODE_DESCRIPTIONS = { DoWhileStatement: "a 'do...while' statement", ForStatement: "a 'for' statement", IfStatement: "an 'if' statement", @@ -32,9 +32,9 @@ module.exports = { create: function(context) { - var prohibitAssign = (context.options[0] || "except-parens"); + let prohibitAssign = (context.options[0] || "except-parens"); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check whether an AST node is the test expression for a conditional statement. @@ -53,7 +53,7 @@ module.exports = { * @returns {?Object} The closest ancestor node that represents a conditional statement. */ function findConditionalAncestor(node) { - var currentAncestor = node; + let currentAncestor = node; do { if (isConditionalTestExpression(currentAncestor)) { @@ -70,7 +70,7 @@ module.exports = { * @returns {boolean} `true` if the code is enclosed in parentheses; otherwise, `false`. */ function isParenthesised(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return previousToken.value === "(" && previousToken.range[1] <= node.range[0] && @@ -83,7 +83,7 @@ module.exports = { * @returns {boolean} `true` if the code is enclosed in two sets of parentheses; otherwise, `false`. */ function isParenthesisedTwice(node) { - var previousToken = sourceCode.getTokenBefore(node, 1), + let previousToken = sourceCode.getTokenBefore(node, 1), nextToken = sourceCode.getTokenAfter(node, 1); return isParenthesised(node) && @@ -120,7 +120,7 @@ module.exports = { * @returns {void} */ function testForConditionalAncestor(node) { - var ancestor = findConditionalAncestor(node); + let ancestor = findConditionalAncestor(node); if (ancestor) { context.report(ancestor, "Unexpected assignment within {{type}}.", { diff --git a/tools/eslint/lib/rules/no-confusing-arrow.js b/tools/eslint/lib/rules/no-confusing-arrow.js index 1f18aa356778ae..42d1f865e272fe 100644 --- a/tools/eslint/lib/rules/no-confusing-arrow.js +++ b/tools/eslint/lib/rules/no-confusing-arrow.js @@ -6,7 +6,7 @@ "use strict"; -var astUtils = require("../ast-utils.js"); +let astUtils = require("../ast-utils.js"); //------------------------------------------------------------------------------ // Helpers @@ -43,8 +43,8 @@ module.exports = { }, create: function(context) { - var config = context.options[0] || {}; - var sourceCode = context.getSourceCode(); + let config = context.options[0] || {}; + let sourceCode = context.getSourceCode(); /** * Reports if an arrow function contains an ambiguous conditional. @@ -52,7 +52,7 @@ module.exports = { * @returns {void} */ function checkArrowFunc(node) { - var body = node.body; + let body = node.body; if (isConditional(body) && !(config.allowParens && astUtils.isParenthesised(sourceCode, body))) { context.report(node, "Arrow function used ambiguously with a conditional expression."); diff --git a/tools/eslint/lib/rules/no-console.js b/tools/eslint/lib/rules/no-console.js index 18a897409f6586..553fc724607de0 100644 --- a/tools/eslint/lib/rules/no-console.js +++ b/tools/eslint/lib/rules/no-console.js @@ -42,12 +42,12 @@ module.exports = { MemberExpression: function(node) { if (node.object.name === "console") { - var blockConsole = true; + let blockConsole = true; if (context.options.length > 0) { - var allowedProperties = context.options[0].allow; - var passedProperty = node.property.name; - var propertyIsAllowed = (allowedProperties.indexOf(passedProperty) > -1); + let allowedProperties = context.options[0].allow; + let passedProperty = node.property.name; + let propertyIsAllowed = (allowedProperties.indexOf(passedProperty) > -1); if (propertyIsAllowed) { blockConsole = false; diff --git a/tools/eslint/lib/rules/no-const-assign.js b/tools/eslint/lib/rules/no-const-assign.js index 344e05a644ee67..8015225dbd87dc 100644 --- a/tools/eslint/lib/rules/no-const-assign.js +++ b/tools/eslint/lib/rules/no-const-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-constant-condition.js b/tools/eslint/lib/rules/no-constant-condition.js index 7c4ede7f78cf66..b2d3b647386ce8 100644 --- a/tools/eslint/lib/rules/no-constant-condition.js +++ b/tools/eslint/lib/rules/no-constant-condition.js @@ -32,7 +32,7 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, checkLoops = options.checkLoops !== false; //-------------------------------------------------------------------------- @@ -85,13 +85,16 @@ module.exports = { return isConstant(node.left, false) && isConstant(node.right, false) && node.operator !== "in"; - case "LogicalExpression": - var isLeftConstant = isConstant(node.left, inBooleanPosition); - var isRightConstant = isConstant(node.right, inBooleanPosition); - var isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator)); - var isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator)); + + case "LogicalExpression": { + const isLeftConstant = isConstant(node.left, inBooleanPosition); + const isRightConstant = isConstant(node.right, inBooleanPosition); + const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator)); + const isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator)); return (isLeftConstant && isRightConstant) || isLeftShortCircuit || isRightShortCircuit; + } + case "AssignmentExpression": return (node.operator === "=") && isConstant(node.right, inBooleanPosition); diff --git a/tools/eslint/lib/rules/no-continue.js b/tools/eslint/lib/rules/no-continue.js index 246df89ebe4283..5e8c059b0efd02 100644 --- a/tools/eslint/lib/rules/no-continue.js +++ b/tools/eslint/lib/rules/no-continue.js @@ -24,7 +24,7 @@ module.exports = { return { ContinueStatement: function(node) { - context.report(node, "Unexpected use of continue statement"); + context.report(node, "Unexpected use of continue statement."); } }; diff --git a/tools/eslint/lib/rules/no-control-regex.js b/tools/eslint/lib/rules/no-control-regex.js index 74e03f03c56f40..4032fb2af77004 100644 --- a/tools/eslint/lib/rules/no-control-regex.js +++ b/tools/eslint/lib/rules/no-control-regex.js @@ -33,7 +33,7 @@ module.exports = { return node.value; } else if (typeof node.value === "string") { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); if ((parent.type === "NewExpression" || parent.type === "CallExpression") && parent.callee.type === "Identifier" && parent.callee.name === "RegExp" @@ -53,22 +53,22 @@ module.exports = { /** * Check if given regex string has control characters in it - * @param {String} regexStr regex as string to check - * @returns {Boolean} returns true if finds control characters on given string + * @param {string} regexStr regex as string to check + * @returns {boolean} returns true if finds control characters on given string * @private */ function hasControlCharacters(regexStr) { // check control characters, if RegExp object used - var hasControlChars = /[\x00-\x1f]/.test(regexStr); // eslint-disable-line no-control-regex + let hasControlChars = /[\x00-\x1f]/.test(regexStr); // eslint-disable-line no-control-regex // check substr, if regex literal used - var subStrIndex = regexStr.search(/\\x[01][0-9a-f]/i); + let subStrIndex = regexStr.search(/\\x[01][0-9a-f]/i); if (!hasControlChars && subStrIndex > -1) { // is it escaped, check backslash count - var possibleEscapeCharacters = regexStr.substr(0, subStrIndex).match(/\\+$/gi); + let possibleEscapeCharacters = regexStr.substr(0, subStrIndex).match(/\\+$/gi); hasControlChars = possibleEscapeCharacters === null || !(possibleEscapeCharacters[0].length % 2); } @@ -78,7 +78,7 @@ module.exports = { return { Literal: function(node) { - var computedValue, + let computedValue, regex = getRegExp(node); if (regex) { diff --git a/tools/eslint/lib/rules/no-div-regex.js b/tools/eslint/lib/rules/no-div-regex.js index 75a6085595739b..f54a534b2266a2 100644 --- a/tools/eslint/lib/rules/no-div-regex.js +++ b/tools/eslint/lib/rules/no-div-regex.js @@ -21,12 +21,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Literal: function(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); if (token.type === "RegularExpression" && token.value[1] === "=") { context.report(node, "A regular expression literal can be confused with '/='."); diff --git a/tools/eslint/lib/rules/no-dupe-args.js b/tools/eslint/lib/rules/no-dupe-args.js index e927ce2b3a8576..f63fab5bb24b86 100644 --- a/tools/eslint/lib/rules/no-dupe-args.js +++ b/tools/eslint/lib/rules/no-dupe-args.js @@ -42,13 +42,13 @@ module.exports = { * @private */ function checkParams(node) { - var variables = context.getDeclaredVariables(node); + let variables = context.getDeclaredVariables(node); - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; // Checks and reports duplications. - var defs = variable.defs.filter(isParameter); + let defs = variable.defs.filter(isParameter); if (defs.length >= 2) { context.report({ diff --git a/tools/eslint/lib/rules/no-dupe-class-members.js b/tools/eslint/lib/rules/no-dupe-class-members.js index 883020bdfe5e96..102072b8bbeccb 100644 --- a/tools/eslint/lib/rules/no-dupe-class-members.js +++ b/tools/eslint/lib/rules/no-dupe-class-members.js @@ -21,20 +21,20 @@ module.exports = { }, create: function(context) { - var stack = []; + let stack = []; /** * Gets state of a given member name. * @param {string} name - A name of a member. * @param {boolean} isStatic - A flag which specifies that is a static member. - * @returns {object} A state of a given member name. + * @returns {Object} A state of a given member name. * - retv.init {boolean} A flag which shows the name is declared as normal member. * - retv.get {boolean} A flag which shows the name is declared as getter. * - retv.set {boolean} A flag which shows the name is declared as setter. */ function getState(name, isStatic) { - var stateMap = stack[stack.length - 1]; - var key = "$" + name; // to avoid "__proto__". + let stateMap = stack[stack.length - 1]; + let key = "$" + name; // to avoid "__proto__". if (!stateMap[key]) { stateMap[key] = { @@ -85,9 +85,9 @@ module.exports = { return; } - var name = getName(node.key); - var state = getState(name, node.static); - var isDuplicate = false; + let name = getName(node.key); + let state = getState(name, node.static); + let isDuplicate = false; if (node.kind === "get") { isDuplicate = (state.init || state.get); diff --git a/tools/eslint/lib/rules/no-dupe-keys.js b/tools/eslint/lib/rules/no-dupe-keys.js index 26f009b3bfe0ca..d2a3fc67738a49 100644 --- a/tools/eslint/lib/rules/no-dupe-keys.js +++ b/tools/eslint/lib/rules/no-dupe-keys.js @@ -28,7 +28,7 @@ module.exports = { // Object that will be a map of properties--safe because we will // prefix all of the keys. - var nodeProps = Object.create(null); + let nodeProps = Object.create(null); node.properties.forEach(function(property) { @@ -36,7 +36,7 @@ module.exports = { return; } - var keyName = property.key.name || property.key.value, + let keyName = property.key.name || property.key.value, key = property.kind + "-" + keyName, checkProperty = (!property.computed || property.key.type === "Literal"); diff --git a/tools/eslint/lib/rules/no-duplicate-case.js b/tools/eslint/lib/rules/no-duplicate-case.js index 8c877ed4e82c43..9e9b8b5cd8bec2 100644 --- a/tools/eslint/lib/rules/no-duplicate-case.js +++ b/tools/eslint/lib/rules/no-duplicate-case.js @@ -22,14 +22,14 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { SwitchStatement: function(node) { - var mapping = {}; + let mapping = {}; node.cases.forEach(function(switchCase) { - var key = sourceCode.getText(switchCase.test); + let key = sourceCode.getText(switchCase.test); if (mapping[key]) { context.report(switchCase, "Duplicate case label."); diff --git a/tools/eslint/lib/rules/no-duplicate-imports.js b/tools/eslint/lib/rules/no-duplicate-imports.js index 44432f48635982..8594541b14a5d1 100644 --- a/tools/eslint/lib/rules/no-duplicate-imports.js +++ b/tools/eslint/lib/rules/no-duplicate-imports.js @@ -60,7 +60,7 @@ function checkAndReport(context, node, value, array, message) { */ function handleImports(context, includeExports, importsInFile, exportsInFile) { return function(node) { - var value = getValue(node); + let value = getValue(node); if (value) { checkAndReport(context, node, value, importsInFile, "import is duplicated."); @@ -85,7 +85,7 @@ function handleImports(context, includeExports, importsInFile, exportsInFile) { */ function handleExports(context, importsInFile, exportsInFile) { return function(node) { - var value = getValue(node); + let value = getValue(node); if (value) { checkAndReport(context, node, value, exportsInFile, "export is duplicated."); @@ -116,11 +116,11 @@ module.exports = { }, create: function(context) { - var includeExports = (context.options[0] || {}).includeExports, + let includeExports = (context.options[0] || {}).includeExports, importsInFile = [], exportsInFile = []; - var handlers = { + let handlers = { ImportDeclaration: handleImports(context, includeExports, importsInFile, exportsInFile) }; diff --git a/tools/eslint/lib/rules/no-else-return.js b/tools/eslint/lib/rules/no-else-return.js index 528d4ca566de23..05ead21586be4c 100644 --- a/tools/eslint/lib/rules/no-else-return.js +++ b/tools/eslint/lib/rules/no-else-return.js @@ -56,7 +56,7 @@ module.exports = { */ function naiveHasReturn(node) { if (node.type === "BlockStatement") { - var body = node.body, + let body = node.body, lastChildNode = body[body.length - 1]; return lastChildNode && checkForReturn(lastChildNode); @@ -128,7 +128,7 @@ module.exports = { return { IfStatement: function(node) { - var parent = context.getAncestors().pop(), + let parent = context.getAncestors().pop(), consequents, alternate; diff --git a/tools/eslint/lib/rules/no-empty-character-class.js b/tools/eslint/lib/rules/no-empty-character-class.js index 34ef78a396fcba..4a1ae8f92f6ac7 100644 --- a/tools/eslint/lib/rules/no-empty-character-class.js +++ b/tools/eslint/lib/rules/no-empty-character-class.js @@ -21,7 +21,7 @@ plain-English description of the following regexp: 4. `[gimuy]*`: optional regexp flags 5. `$`: fix the match at the end of the string */ -var regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimuy]*$/; +let regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimuy]*$/; //------------------------------------------------------------------------------ // Rule Definition @@ -39,12 +39,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Literal: function(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); if (token.type === "RegularExpression" && !regex.test(token.value)) { context.report(node, "Empty class."); diff --git a/tools/eslint/lib/rules/no-empty-function.js b/tools/eslint/lib/rules/no-empty-function.js index 0102acff5164cb..d7d8c2e886cd59 100644 --- a/tools/eslint/lib/rules/no-empty-function.js +++ b/tools/eslint/lib/rules/no-empty-function.js @@ -9,7 +9,7 @@ // Helpers //------------------------------------------------------------------------------ -var ALLOW_OPTIONS = Object.freeze([ +let ALLOW_OPTIONS = Object.freeze([ "functions", "arrowFunctions", "generatorFunctions", @@ -19,7 +19,7 @@ var ALLOW_OPTIONS = Object.freeze([ "setters", "constructors" ]); -var SHOW_KIND = Object.freeze({ +let SHOW_KIND = Object.freeze({ functions: "function", arrowFunctions: "arrow function", generatorFunctions: "generator function", @@ -44,8 +44,8 @@ var SHOW_KIND = Object.freeze({ * "constructors". */ function getKind(node) { - var parent = node.parent; - var kind = ""; + let parent = node.parent; + let kind = ""; if (node.type === "ArrowFunctionExpression") { return "arrowFunctions"; @@ -78,7 +78,7 @@ function getKind(node) { } // Detects prefix. - var prefix = ""; + let prefix = ""; if (node.generator) { prefix = "generator"; @@ -118,10 +118,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var allowed = options.allow || []; + let options = context.options[0] || {}; + let allowed = options.allow || []; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports a given function node if the node matches the following patterns. @@ -136,7 +136,7 @@ module.exports = { * @returns {void} */ function reportIfEmpty(node) { - var kind = getKind(node); + let kind = getKind(node); if (allowed.indexOf(kind) === -1 && node.body.type === "BlockStatement" && diff --git a/tools/eslint/lib/rules/no-empty.js b/tools/eslint/lib/rules/no-empty.js index 1302a907533986..8897cce02b3490 100644 --- a/tools/eslint/lib/rules/no-empty.js +++ b/tools/eslint/lib/rules/no-empty.js @@ -5,10 +5,14 @@ "use strict"; //------------------------------------------------------------------------------ -// Rule Definition +// Requirements //------------------------------------------------------------------------------ -var FUNCTION_TYPE = /^(?:ArrowFunctionExpression|Function(?:Declaration|Expression))$/; +let astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ module.exports = { meta: { @@ -32,10 +36,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, allowEmptyCatch = options.allowEmptyCatch || false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { BlockStatement: function(node) { @@ -46,7 +50,7 @@ module.exports = { } // a function is generally allowed to be empty - if (FUNCTION_TYPE.test(node.parent.type)) { + if (astUtils.isFunction(node.parent)) { return; } diff --git a/tools/eslint/lib/rules/no-eq-null.js b/tools/eslint/lib/rules/no-eq-null.js index da039bb9d7de4c..743f2908035355 100644 --- a/tools/eslint/lib/rules/no-eq-null.js +++ b/tools/eslint/lib/rules/no-eq-null.js @@ -26,7 +26,7 @@ module.exports = { return { BinaryExpression: function(node) { - var badOperator = node.operator === "==" || node.operator === "!="; + let badOperator = node.operator === "==" || node.operator === "!="; if (node.right.type === "Literal" && node.right.raw === "null" && badOperator || node.left.type === "Literal" && node.left.raw === "null" && badOperator) { diff --git a/tools/eslint/lib/rules/no-eval.js b/tools/eslint/lib/rules/no-eval.js index 04db4b96b477aa..67ac1017cf4323 100644 --- a/tools/eslint/lib/rules/no-eval.js +++ b/tools/eslint/lib/rules/no-eval.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var candidatesOfGlobalObject = Object.freeze([ +let candidatesOfGlobalObject = Object.freeze([ "global", "window" ]); @@ -94,12 +94,12 @@ module.exports = { }, create: function(context) { - var allowIndirect = Boolean( + let allowIndirect = Boolean( context.options[0] && context.options[0].allowIndirect ); - var sourceCode = context.getSourceCode(); - var funcInfo = null; + let sourceCode = context.getSourceCode(); + let funcInfo = null; /** * Pushs a variable scope (Program or Function) information to the stack. @@ -112,7 +112,7 @@ module.exports = { * @returns {void} */ function enterVarScope(node) { - var strict = context.getScope().isStrict; + let strict = context.getScope().isStrict; funcInfo = { upper: funcInfo, @@ -146,8 +146,8 @@ module.exports = { * @returns {void} */ function report(node) { - var locationNode = node; - var parent = node.parent; + let locationNode = node; + let parent = node.parent; if (node.type === "MemberExpression") { locationNode = node.property; @@ -170,19 +170,19 @@ module.exports = { * @returns {void} */ function reportAccessingEvalViaGlobalObject(globalScope) { - for (var i = 0; i < candidatesOfGlobalObject.length; ++i) { - var name = candidatesOfGlobalObject[i]; - var variable = astUtils.getVariableByName(globalScope, name); + for (let i = 0; i < candidatesOfGlobalObject.length; ++i) { + let name = candidatesOfGlobalObject[i]; + let variable = astUtils.getVariableByName(globalScope, name); if (!variable) { continue; } - var references = variable.references; + let references = variable.references; - for (var j = 0; j < references.length; ++j) { - var identifier = references[j].identifier; - var node = identifier.parent; + for (let j = 0; j < references.length; ++j) { + let identifier = references[j].identifier; + let node = identifier.parent; // To detect code like `window.window.eval`. while (isMember(node, name)) { @@ -204,17 +204,17 @@ module.exports = { * @returns {void} */ function reportAccessingEval(globalScope) { - var variable = astUtils.getVariableByName(globalScope, "eval"); + let variable = astUtils.getVariableByName(globalScope, "eval"); if (!variable) { return; } - var references = variable.references; + let references = variable.references; - for (var i = 0; i < references.length; ++i) { - var reference = references[i]; - var id = reference.identifier; + for (let i = 0; i < references.length; ++i) { + let reference = references[i]; + let id = reference.identifier; if (id.name === "eval" && !astUtils.isCallee(id)) { @@ -229,7 +229,7 @@ module.exports = { // Checks only direct calls to eval. It's simple! return { "CallExpression:exit": function(node) { - var callee = node.callee; + let callee = node.callee; if (isIdentifier(callee, "eval")) { report(callee); @@ -240,7 +240,7 @@ module.exports = { return { "CallExpression:exit": function(node) { - var callee = node.callee; + let callee = node.callee; if (isIdentifier(callee, "eval")) { report(callee); @@ -248,7 +248,7 @@ module.exports = { }, Program: function(node) { - var scope = context.getScope(), + let scope = context.getScope(), features = context.parserOptions.ecmaFeatures || {}, strict = scope.isStrict || @@ -265,7 +265,7 @@ module.exports = { }, "Program:exit": function() { - var globalScope = context.getScope(); + let globalScope = context.getScope(); exitVarScope(); reportAccessingEval(globalScope); diff --git a/tools/eslint/lib/rules/no-ex-assign.js b/tools/eslint/lib/rules/no-ex-assign.js index bf3afc6cd3f485..42aea52723cf40 100644 --- a/tools/eslint/lib/rules/no-ex-assign.js +++ b/tools/eslint/lib/rules/no-ex-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-extend-native.js b/tools/eslint/lib/rules/no-extend-native.js index 69d4931ab6e82b..c58e5c355408ba 100644 --- a/tools/eslint/lib/rules/no-extend-native.js +++ b/tools/eslint/lib/rules/no-extend-native.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var globals = require("globals"); +let globals = require("globals"); //------------------------------------------------------------------------------ // Rule Definition @@ -42,9 +42,9 @@ module.exports = { create: function(context) { - var config = context.options[0] || {}; - var exceptions = config.exceptions || []; - var modifiedBuiltins = Object.keys(globals.builtin).filter(function(builtin) { + let config = context.options[0] || {}; + let exceptions = config.exceptions || []; + let modifiedBuiltins = Object.keys(globals.builtin).filter(function(builtin) { return builtin[0].toUpperCase() === builtin[0]; }); @@ -58,7 +58,7 @@ module.exports = { // handle the Array.prototype.extra style case AssignmentExpression: function(node) { - var lhs = node.left, + let lhs = node.left, affectsProto; if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") { @@ -83,7 +83,7 @@ module.exports = { // handle the Object.definePropert[y|ies](Array.prototype) case CallExpression: function(node) { - var callee = node.callee, + let callee = node.callee, subject, object; diff --git a/tools/eslint/lib/rules/no-extra-bind.js b/tools/eslint/lib/rules/no-extra-bind.js index f75e2fcc25782d..bdafaf040f1dbd 100644 --- a/tools/eslint/lib/rules/no-extra-bind.js +++ b/tools/eslint/lib/rules/no-extra-bind.js @@ -20,7 +20,7 @@ module.exports = { }, create: function(context) { - var scopeInfo = null; + let scopeInfo = null; /** * Reports a given function node. @@ -73,8 +73,8 @@ module.exports = { * @returns {boolean} `true` if the node is the callee of `.bind()` method. */ function isCalleeOfBindMethod(node) { - var parent = node.parent; - var grandparent = parent.parent; + let parent = node.parent; + let grandparent = parent.parent; return ( grandparent && diff --git a/tools/eslint/lib/rules/no-extra-boolean-cast.js b/tools/eslint/lib/rules/no-extra-boolean-cast.js index f14da0821dbbed..890f7cb6051265 100644 --- a/tools/eslint/lib/rules/no-extra-boolean-cast.js +++ b/tools/eslint/lib/rules/no-extra-boolean-cast.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { // Node types which have a test which will coerce values to booleans. - var BOOLEAN_NODE_TYPES = [ + let BOOLEAN_NODE_TYPES = [ "IfStatement", "DoWhileStatement", "WhileStatement", @@ -36,7 +36,7 @@ module.exports = { * * @param {Object} node The node * @param {Object} parent Its parent - * @returns {Boolean} If it is in a boolean context + * @returns {boolean} If it is in a boolean context */ function isInBooleanContext(node, parent) { return ( @@ -52,7 +52,7 @@ module.exports = { return { UnaryExpression: function(node) { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), parent = ancestors.pop(), grandparent = ancestors.pop(); @@ -74,7 +74,7 @@ module.exports = { } }, CallExpression: function(node) { - var parent = node.parent; + let parent = node.parent; if (node.callee.type !== "Identifier" || node.callee.name !== "Boolean") { return; diff --git a/tools/eslint/lib/rules/no-extra-label.js b/tools/eslint/lib/rules/no-extra-label.js index f1a48e3688e96d..5b72209bf2de9b 100644 --- a/tools/eslint/lib/rules/no-extra-label.js +++ b/tools/eslint/lib/rules/no-extra-label.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var scopeInfo = null; + let scopeInfo = null; /** * Creates a new scope with a breakable statement. @@ -98,9 +98,9 @@ module.exports = { return; } - var labelNode = node.label; - var label = labelNode.name; - var info = scopeInfo; + let labelNode = node.label; + let label = labelNode.name; + let info = scopeInfo; while (info) { if (info.breakable || info.label === label) { diff --git a/tools/eslint/lib/rules/no-extra-parens.js b/tools/eslint/lib/rules/no-extra-parens.js index c33a64920ff10f..86ef6ddc0f8686 100644 --- a/tools/eslint/lib/rules/no-extra-parens.js +++ b/tools/eslint/lib/rules/no-extra-parens.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils.js"); +let astUtils = require("../ast-utils.js"); module.exports = { meta: { @@ -54,14 +54,14 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode); - var precedence = astUtils.getPrecedence; - var ALL_NODES = context.options[0] !== "functions"; - var EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false; - var NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false; - var EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false; + let isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode); + let precedence = astUtils.getPrecedence; + let ALL_NODES = context.options[0] !== "functions"; + let EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false; + let NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false; + let EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false; /** * Determines if this rule should be enforced for a node given the current configuration. @@ -80,7 +80,7 @@ module.exports = { * @private */ function isParenthesisedTwice(node) { - var previousToken = sourceCode.getTokenBefore(node, 1), + let previousToken = sourceCode.getTokenBefore(node, 1), nextToken = sourceCode.getTokenAfter(node, 1); return isParenthesised(node) && previousToken && nextToken && @@ -199,7 +199,7 @@ module.exports = { * @returns {boolean} `true` if the node is located at the head of ExpressionStatement. */ function isHeadOfExpressionStatement(node) { - var parent = node.parent; + let parent = node.parent; while (parent) { switch (parent.type) { @@ -263,7 +263,7 @@ module.exports = { * @private */ function report(node) { - var previousToken = sourceCode.getTokenBefore(node); + let previousToken = sourceCode.getTokenBefore(node); context.report(node, previousToken.loc.start, "Gratuitous parentheses around expression."); } @@ -317,7 +317,7 @@ module.exports = { */ function dryBinaryLogical(node) { if (!NESTED_BINARY) { - var prec = precedence(node); + let prec = precedence(node); if (hasExcessParens(node.left) && precedence(node.left) >= prec) { report(node.left); @@ -394,7 +394,7 @@ module.exports = { }, ExpressionStatement: function(node) { - var firstToken, secondToken, firstTokens; + let firstToken, secondToken, firstTokens; if (hasExcessParens(node.expression)) { firstTokens = sourceCode.getFirstTokens(node.expression, 2); @@ -484,7 +484,7 @@ module.exports = { ObjectExpression: function(node) { [].forEach.call(node.properties, function(e) { - var v = e.value; + let v = e.value; if (v && hasExcessParens(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) { report(v); @@ -493,7 +493,7 @@ module.exports = { }, ReturnStatement: function(node) { - var returnToken = sourceCode.getFirstToken(node); + let returnToken = sourceCode.getFirstToken(node); if (isReturnAssignException(node)) { return; @@ -529,7 +529,7 @@ module.exports = { }, ThrowStatement: function(node) { - var throwToken = sourceCode.getFirstToken(node); + let throwToken = sourceCode.getFirstToken(node); if (hasExcessParensNoLineTerminator(throwToken, node.argument)) { report(node.argument); @@ -562,7 +562,7 @@ module.exports = { }, YieldExpression: function(node) { - var yieldToken; + let yieldToken; if (node.argument) { yieldToken = sourceCode.getFirstToken(node); diff --git a/tools/eslint/lib/rules/no-extra-semi.js b/tools/eslint/lib/rules/no-extra-semi.js index 679a16641b7132..37f2253c26addc 100644 --- a/tools/eslint/lib/rules/no-extra-semi.js +++ b/tools/eslint/lib/rules/no-extra-semi.js @@ -22,7 +22,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports an unnecessary semicolon error. @@ -47,7 +47,7 @@ module.exports = { * @returns {void} */ function checkForPartOfClassBody(firstToken) { - for (var token = firstToken; + for (let token = firstToken; token.type === "Punctuator" && token.value !== "}"; token = sourceCode.getTokenAfter(token) ) { @@ -65,7 +65,7 @@ module.exports = { * @returns {void} */ EmptyStatement: function(node) { - var parent = node.parent, + let parent = node.parent, allowedParentTypes = [ "ForStatement", "ForInStatement", diff --git a/tools/eslint/lib/rules/no-fallthrough.js b/tools/eslint/lib/rules/no-fallthrough.js index 2edb4972bafd0a..24f3642fa163b9 100644 --- a/tools/eslint/lib/rules/no-fallthrough.js +++ b/tools/eslint/lib/rules/no-fallthrough.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/i; +let DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/i; /** * Checks whether or not a given node has a fallthrough comment. @@ -24,8 +24,8 @@ var DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/i; * @returns {boolean} `true` if the node has a valid fallthrough comment. */ function hasFallthroughComment(node, context, fallthroughCommentPattern) { - var sourceCode = context.getSourceCode(); - var comment = lodash.last(sourceCode.getComments(node).leading); + let sourceCode = context.getSourceCode(); + let comment = lodash.last(sourceCode.getComments(node).leading); return Boolean(comment && fallthroughCommentPattern.test(comment.value)); } @@ -75,16 +75,16 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var currentCodePath = null; - var sourceCode = context.getSourceCode(); + let options = context.options[0] || {}; + let currentCodePath = null; + let sourceCode = context.getSourceCode(); /* * We need to use leading comments of the next SwitchCase node because * trailing comments is wrong if semicolons are omitted. */ - var fallthroughCase = null; - var fallthroughCommentPattern = null; + let fallthroughCase = null; + let fallthroughCommentPattern = null; if (options.commentPattern) { fallthroughCommentPattern = new RegExp(options.commentPattern); @@ -117,7 +117,7 @@ module.exports = { }, "SwitchCase:exit": function(node) { - var nextToken = sourceCode.getTokenAfter(node); + let nextToken = sourceCode.getTokenAfter(node); /* * `reachable` meant fall through because statements preceded by diff --git a/tools/eslint/lib/rules/no-func-assign.js b/tools/eslint/lib/rules/no-func-assign.js index ac3afe55c05533..2266a044fc32a9 100644 --- a/tools/eslint/lib/rules/no-func-assign.js +++ b/tools/eslint/lib/rules/no-func-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-implicit-coercion.js b/tools/eslint/lib/rules/no-implicit-coercion.js index 113c205855eb45..ee11bd008769b8 100644 --- a/tools/eslint/lib/rules/no-implicit-coercion.js +++ b/tools/eslint/lib/rules/no-implicit-coercion.js @@ -9,13 +9,13 @@ // Helpers //------------------------------------------------------------------------------ -var INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/; -var ALLOWABLE_OPERATORS = ["~", "!!", "+", "*"]; +let INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/; +let ALLOWABLE_OPERATORS = ["~", "!!", "+", "*"]; /** * Parses and normalizes an option object. - * @param {object} options - An option object to parse. - * @returns {object} The parsed and normalized option object. + * @param {Object} options - An option object to parse. + * @returns {Object} The parsed and normalized option object. */ function parseOptions(options) { options = options || {}; @@ -91,7 +91,7 @@ function isNumeric(node) { * @returns {ASTNode|null} The first non-numeric item in the BinaryExpression tree or null */ function getNonNumericOperand(node) { - var left = node.left, + let left = node.left, right = node.right; if (right.type !== "BinaryExpression" && !isNumeric(right)) { @@ -176,10 +176,10 @@ module.exports = { }, create: function(context) { - var options = parseOptions(context.options[0]), + let options = parseOptions(context.options[0]), operatorAllowed = false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { UnaryExpression: function(node) { @@ -220,7 +220,7 @@ module.exports = { // 1 * foo operatorAllowed = options.allow.indexOf("*") >= 0; - var nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && getNonNumericOperand(node); + let nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && getNonNumericOperand(node); if (nonNumericOperand) { context.report( diff --git a/tools/eslint/lib/rules/no-implicit-globals.js b/tools/eslint/lib/rules/no-implicit-globals.js index c2768ea1a0951f..9f8180394f1105 100644 --- a/tools/eslint/lib/rules/no-implicit-globals.js +++ b/tools/eslint/lib/rules/no-implicit-globals.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { return { Program: function() { - var scope = context.getScope(); + let scope = context.getScope(); scope.variables.forEach(function(variable) { if (variable.writeable) { @@ -38,7 +38,7 @@ module.exports = { }); scope.implicit.variables.forEach(function(variable) { - var scopeVariable = scope.set.get(variable.name); + let scopeVariable = scope.set.get(variable.name); if (scopeVariable && scopeVariable.writeable) { return; diff --git a/tools/eslint/lib/rules/no-implied-eval.js b/tools/eslint/lib/rules/no-implied-eval.js index 7c1ed2fb6eb989..ec660fa08f3097 100644 --- a/tools/eslint/lib/rules/no-implied-eval.js +++ b/tools/eslint/lib/rules/no-implied-eval.js @@ -21,13 +21,13 @@ module.exports = { }, create: function(context) { - var CALLEE_RE = /set(?:Timeout|Interval)|execScript/; + let CALLEE_RE = /set(?:Timeout|Interval)|execScript/; /* * Figures out if we should inspect a given binary expression. Is a stack * of stacks, where the first element in each substack is a CallExpression. */ - var impliedEvalAncestorsStack = []; + let impliedEvalAncestorsStack = []; //-------------------------------------------------------------------------- // Helpers @@ -50,7 +50,7 @@ module.exports = { * @private */ function isImpliedEvalMemberExpression(node) { - var object = node.object, + let object = node.object, property = node.property, hasImpliedEvalName = CALLEE_RE.test(property.name) || CALLEE_RE.test(property.value); @@ -67,7 +67,7 @@ module.exports = { * @private */ function isImpliedEvalCallExpression(node) { - var isMemberExpression = (node.callee.type === "MemberExpression"), + let isMemberExpression = (node.callee.type === "MemberExpression"), isIdentifier = (node.callee.type === "Identifier"), isImpliedEvalCallee = (isIdentifier && CALLEE_RE.test(node.callee.name)) || @@ -103,7 +103,7 @@ module.exports = { if (hasImpliedEvalParent(node)) { // remove the entire substack, to avoid duplicate reports - var substack = impliedEvalAncestorsStack.pop(); + let substack = impliedEvalAncestorsStack.pop(); context.report(substack[0], "Implied eval. Consider passing a function instead of a string."); } diff --git a/tools/eslint/lib/rules/no-inline-comments.js b/tools/eslint/lib/rules/no-inline-comments.js index e313eac06f01fb..87039d46971826 100644 --- a/tools/eslint/lib/rules/no-inline-comments.js +++ b/tools/eslint/lib/rules/no-inline-comments.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -22,7 +22,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Will check that comments are not on lines starting with or ending with code @@ -33,16 +33,16 @@ module.exports = { function testCodeAroundComment(node) { // Get the whole line and cut it off at the start of the comment - var startLine = String(sourceCode.lines[node.loc.start.line - 1]); - var endLine = String(sourceCode.lines[node.loc.end.line - 1]); + let startLine = String(sourceCode.lines[node.loc.start.line - 1]); + let endLine = String(sourceCode.lines[node.loc.end.line - 1]); - var preamble = startLine.slice(0, node.loc.start.column).trim(); + let preamble = startLine.slice(0, node.loc.start.column).trim(); // Also check after the comment - var postamble = endLine.slice(node.loc.end.column).trim(); + let postamble = endLine.slice(node.loc.end.column).trim(); // Check that this comment isn't an ESLint directive - var isDirective = astUtils.isDirectiveComment(node); + let isDirective = astUtils.isDirectiveComment(node); // Should be empty if there was only whitespace around the comment if (!isDirective && (preamble || postamble)) { diff --git a/tools/eslint/lib/rules/no-inner-declarations.js b/tools/eslint/lib/rules/no-inner-declarations.js index 3471ce8cc735b8..3e21385a59b73e 100644 --- a/tools/eslint/lib/rules/no-inner-declarations.js +++ b/tools/eslint/lib/rules/no-inner-declarations.js @@ -31,7 +31,7 @@ module.exports = { * @returns {Object} Ancestor's type and distance from node. */ function nearestBody() { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), ancestor = ancestors.pop(), generation = 1; @@ -58,7 +58,7 @@ module.exports = { * @returns {void} */ function check(node) { - var body = nearestBody(node), + let body = nearestBody(node), valid = ((body.type === "Program" && body.distance === 1) || body.distance === 2); diff --git a/tools/eslint/lib/rules/no-invalid-regexp.js b/tools/eslint/lib/rules/no-invalid-regexp.js index 6f8b8673786532..eb693c55c6c9c5 100644 --- a/tools/eslint/lib/rules/no-invalid-regexp.js +++ b/tools/eslint/lib/rules/no-invalid-regexp.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var espree = require("espree"); +let espree = require("espree"); //------------------------------------------------------------------------------ // Rule Definition @@ -38,7 +38,7 @@ module.exports = { create: function(context) { - var options = context.options[0], + let options = context.options[0], allowedFlags = ""; if (options && options.allowConstructorFlags) { @@ -63,7 +63,7 @@ module.exports = { */ function check(node) { if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0])) { - var flags = isString(node.arguments[1]) ? node.arguments[1].value : ""; + let flags = isString(node.arguments[1]) ? node.arguments[1].value : ""; if (allowedFlags) { flags = flags.replace(new RegExp("[" + allowedFlags + "]", "gi"), ""); @@ -72,7 +72,7 @@ module.exports = { try { void new RegExp(node.arguments[0].value); } catch (e) { - context.report(node, e.message); + context.report(node, e.message + "."); } if (flags) { @@ -80,7 +80,7 @@ module.exports = { try { espree.parse("/./" + flags, context.parserOptions); } catch (ex) { - context.report(node, "Invalid flags supplied to RegExp constructor '" + flags + "'"); + context.report(node, "Invalid flags supplied to RegExp constructor '" + flags + "'."); } } diff --git a/tools/eslint/lib/rules/no-invalid-this.js b/tools/eslint/lib/rules/no-invalid-this.js index 198bfd706ad49d..e41c47469915ba 100644 --- a/tools/eslint/lib/rules/no-invalid-this.js +++ b/tools/eslint/lib/rules/no-invalid-this.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var stack = [], + let stack = [], sourceCode = context.getSourceCode(); /** @@ -40,7 +40,7 @@ module.exports = { * an object which has a flag that whether or not `this` keyword is valid. */ stack.getCurrent = function() { - var current = this[this.length - 1]; + let current = this[this.length - 1]; if (!current.init) { current.init = true; @@ -86,7 +86,7 @@ module.exports = { * Modules is always strict mode. */ Program: function(node) { - var scope = context.getScope(), + let scope = context.getScope(), features = context.parserOptions.ecmaFeatures || {}; stack.push({ @@ -111,7 +111,7 @@ module.exports = { // Reports if `this` of the current context is invalid. ThisExpression: function(node) { - var current = stack.getCurrent(); + let current = stack.getCurrent(); if (current && !current.valid) { context.report(node, "Unexpected 'this'."); diff --git a/tools/eslint/lib/rules/no-irregular-whitespace.js b/tools/eslint/lib/rules/no-irregular-whitespace.js index 032dd96c113928..0049de3dde91f8 100644 --- a/tools/eslint/lib/rules/no-irregular-whitespace.js +++ b/tools/eslint/lib/rules/no-irregular-whitespace.js @@ -10,10 +10,10 @@ // Constants //------------------------------------------------------------------------------ -var ALL_IRREGULARS = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]/; -var IRREGULAR_WHITESPACE = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg; -var IRREGULAR_LINE_TERMINATORS = /[\u2028\u2029]/mg; -var LINE_BREAK = /\r\n|\r|\n|\u2028|\u2029/g; +let ALL_IRREGULARS = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]/; +let IRREGULAR_WHITESPACE = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg; +let IRREGULAR_LINE_TERMINATORS = /[\u2028\u2029]/mg; +let LINE_BREAK = /\r\n|\r|\n|\u2028|\u2029/g; //------------------------------------------------------------------------------ // Rule Definition @@ -52,19 +52,19 @@ module.exports = { create: function(context) { // Module store of errors that we have found - var errors = []; + let errors = []; // Comment nodes. We accumulate these as we go, so we can be sure to trigger them after the whole `Program` entity is parsed, even for top-of-file comments. - var commentNodes = []; + let commentNodes = []; // Lookup the `skipComments` option, which defaults to `false`. - var options = context.options[0] || {}; - var skipComments = !!options.skipComments; - var skipStrings = options.skipStrings !== false; - var skipRegExps = !!options.skipRegExps; - var skipTemplates = !!options.skipTemplates; + let options = context.options[0] || {}; + let skipComments = !!options.skipComments; + let skipStrings = options.skipStrings !== false; + let skipRegExps = !!options.skipRegExps; + let skipTemplates = !!options.skipTemplates; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Removes errors that occur inside a string node @@ -73,11 +73,11 @@ module.exports = { * @private */ function removeWhitespaceError(node) { - var locStart = node.loc.start; - var locEnd = node.loc.end; + let locStart = node.loc.start; + let locEnd = node.loc.end; errors = errors.filter(function(error) { - var errorLoc = error[1]; + let errorLoc = error[1]; if (errorLoc.line >= locStart.line && errorLoc.line <= locEnd.line) { if (errorLoc.column >= locStart.column && (errorLoc.column <= locEnd.column || errorLoc.line < locEnd.line)) { @@ -95,8 +95,8 @@ module.exports = { * @private */ function removeInvalidNodeErrorsInIdentifierOrLiteral(node) { - var shouldCheckStrings = skipStrings && (typeof node.value === "string"); - var shouldCheckRegExps = skipRegExps && (node.value instanceof RegExp); + let shouldCheckStrings = skipStrings && (typeof node.value === "string"); + let shouldCheckRegExps = skipRegExps && (node.value instanceof RegExp); if (shouldCheckStrings || shouldCheckRegExps) { @@ -140,10 +140,10 @@ module.exports = { * @private */ function checkForIrregularWhitespace(node) { - var sourceLines = sourceCode.lines; + let sourceLines = sourceCode.lines; sourceLines.forEach(function(sourceLine, lineIndex) { - var lineNumber = lineIndex + 1, + let lineNumber = lineIndex + 1, location, match; @@ -153,7 +153,7 @@ module.exports = { column: match.index }; - errors.push([node, location, "Irregular whitespace not allowed"]); + errors.push([node, location, "Irregular whitespace not allowed."]); } }); } @@ -165,7 +165,7 @@ module.exports = { * @private */ function checkForIrregularLineTerminators(node) { - var source = sourceCode.getText(), + let source = sourceCode.getText(), sourceLines = sourceCode.lines, linebreaks = source.match(LINE_BREAK), lastLineIndex = -1, @@ -181,7 +181,7 @@ module.exports = { column: sourceLines[lineIndex].length }; - errors.push([node, location, "Irregular whitespace not allowed"]); + errors.push([node, location, "Irregular whitespace not allowed."]); lastLineIndex = lineIndex; } } @@ -203,7 +203,7 @@ module.exports = { */ function noop() {} - var nodes = {}; + let nodes = {}; if (ALL_IRREGULARS.test(sourceCode.getText())) { nodes.Program = function(node) { diff --git a/tools/eslint/lib/rules/no-label-var.js b/tools/eslint/lib/rules/no-label-var.js index 7c6d56f3552a3a..a203324f147d64 100644 --- a/tools/eslint/lib/rules/no-label-var.js +++ b/tools/eslint/lib/rules/no-label-var.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -34,7 +34,7 @@ module.exports = { /** * Check if the identifier is present inside current scope - * @param {object} scope current scope + * @param {Object} scope current scope * @param {string} name To evaluate * @returns {boolean} True if its present * @private @@ -52,7 +52,7 @@ module.exports = { LabeledStatement: function(node) { // Fetch the innermost scope. - var scope = context.getScope(); + let scope = context.getScope(); // Recursively find the identifier walking up the scope, starting // with the innermost scope. diff --git a/tools/eslint/lib/rules/no-labels.js b/tools/eslint/lib/rules/no-labels.js index da0cd8e7426643..adc5bc0f81be09 100644 --- a/tools/eslint/lib/rules/no-labels.js +++ b/tools/eslint/lib/rules/no-labels.js @@ -5,10 +5,10 @@ "use strict"; //------------------------------------------------------------------------------ -// Constants +// Requirements //------------------------------------------------------------------------------ -var LOOP_TYPES = /^(?:While|DoWhile|For|ForIn|ForOf)Statement$/; +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -39,10 +39,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0]; - var allowLoop = Boolean(options && options.allowLoop); - var allowSwitch = Boolean(options && options.allowSwitch); - var scopeInfo = null; + let options = context.options[0]; + let allowLoop = Boolean(options && options.allowLoop); + let allowSwitch = Boolean(options && options.allowSwitch); + let scopeInfo = null; /** * Gets the kind of a given node. @@ -51,12 +51,10 @@ module.exports = { * @returns {string} The kind of the node. */ function getBodyKind(node) { - var type = node.type; - - if (LOOP_TYPES.test(type)) { + if (astUtils.isLoop(node)) { return "loop"; } - if (type === "SwitchStatement") { + if (node.type === "SwitchStatement") { return "switch"; } return "other"; @@ -83,7 +81,7 @@ module.exports = { * @returns {boolean} `true` if the name is a label of a loop. */ function getKind(label) { - var info = scopeInfo; + let info = scopeInfo; while (info) { if (info.label === label) { diff --git a/tools/eslint/lib/rules/no-lone-blocks.js b/tools/eslint/lib/rules/no-lone-blocks.js index 113cd89b937c66..e93f1d0809b6cd 100644 --- a/tools/eslint/lib/rules/no-lone-blocks.js +++ b/tools/eslint/lib/rules/no-lone-blocks.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { // A stack of lone blocks to be checked for block-level bindings - var loneBlocks = [], + let loneBlocks = [], ruleDef; /** @@ -32,7 +32,7 @@ module.exports = { * @returns {void} */ function report(node) { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); context.report(node, parent.type === "Program" ? "Block is redundant." : @@ -45,7 +45,7 @@ module.exports = { * @returns {boolean} True if the current node is a lone block. */ function isLoneBlock() { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); return parent.type === "BlockStatement" || parent.type === "Program"; } @@ -60,7 +60,7 @@ module.exports = { return; } - var block = context.getAncestors().pop(); + let block = context.getAncestors().pop(); if (loneBlocks[loneBlocks.length - 1] === block) { loneBlocks.pop(); diff --git a/tools/eslint/lib/rules/no-lonely-if.js b/tools/eslint/lib/rules/no-lonely-if.js index 1efd1acc018265..4c99bca8389019 100644 --- a/tools/eslint/lib/rules/no-lonely-if.js +++ b/tools/eslint/lib/rules/no-lonely-if.js @@ -23,7 +23,7 @@ module.exports = { return { IfStatement: function(node) { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), parent = ancestors.pop(), grandparent = ancestors.pop(); diff --git a/tools/eslint/lib/rules/no-loop-func.js b/tools/eslint/lib/rules/no-loop-func.js index 247dc52cd47516..e9409338961f3a 100644 --- a/tools/eslint/lib/rules/no-loop-func.js +++ b/tools/eslint/lib/rules/no-loop-func.js @@ -20,7 +20,7 @@ * `null`. */ function getContainingLoopNode(node) { - var parent = node.parent; + let parent = node.parent; while (parent) { switch (parent.type) { @@ -73,8 +73,8 @@ function getContainingLoopNode(node) { * @returns {ASTNode} The most outer loop node. */ function getTopLoopNode(node, excludedNode) { - var retv = node; - var border = excludedNode ? excludedNode.range[1] : 0; + let retv = node; + let border = excludedNode ? excludedNode.range[1] : 0; while (node && node.range[0] >= border) { retv = node; @@ -94,10 +94,10 @@ function getTopLoopNode(node, excludedNode) { * @returns {boolean} `true` if the reference is safe or not. */ function isSafe(funcNode, loopNode, reference) { - var variable = reference.resolved; - var definition = variable && variable.defs[0]; - var declaration = definition && definition.parent; - var kind = (declaration && declaration.type === "VariableDeclaration") + let variable = reference.resolved; + let definition = variable && variable.defs[0]; + let declaration = definition && definition.parent; + let kind = (declaration && declaration.type === "VariableDeclaration") ? declaration.kind : ""; @@ -117,7 +117,7 @@ function isSafe(funcNode, loopNode, reference) { // WriteReferences which exist after this border are unsafe because those // can modify the variable. - var border = getTopLoopNode( + let border = getTopLoopNode( loopNode, (kind === "let") ? declaration : null ).range[0]; @@ -135,7 +135,7 @@ function isSafe(funcNode, loopNode, reference) { * @returns {boolean} `true` if the reference is safe. */ function isSafeReference(upperRef) { - var id = upperRef.identifier; + let id = upperRef.identifier; return ( !upperRef.isWrite() || @@ -174,18 +174,18 @@ module.exports = { * @returns {boolean} Whether or not the node is within a loop. */ function checkForLoops(node) { - var loopNode = getContainingLoopNode(node); + let loopNode = getContainingLoopNode(node); if (!loopNode) { return; } - var references = context.getScope().through; + let references = context.getScope().through; if (references.length > 0 && !references.every(isSafe.bind(null, node, loopNode)) ) { - context.report(node, "Don't make functions within a loop"); + context.report(node, "Don't make functions within a loop."); } } diff --git a/tools/eslint/lib/rules/no-magic-numbers.js b/tools/eslint/lib/rules/no-magic-numbers.js index 2e7434c1a58f16..76d71c1e6ce526 100644 --- a/tools/eslint/lib/rules/no-magic-numbers.js +++ b/tools/eslint/lib/rules/no-magic-numbers.js @@ -42,7 +42,7 @@ module.exports = { }, create: function(context) { - var config = context.options[0] || {}, + let config = context.options[0] || {}, detectObjects = !!config.detectObjects, enforceConst = !!config.enforceConst, ignore = config.ignore || [], @@ -100,7 +100,7 @@ module.exports = { return { Literal: function(node) { - var parent = node.parent, + let parent = node.parent, value = node.value, raw = node.raw, okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"]; @@ -128,14 +128,14 @@ module.exports = { if (enforceConst && parent.parent.kind !== "const") { context.report({ node: node, - message: "Number constants declarations must use 'const'" + message: "Number constants declarations must use 'const'." }); } } else if (okTypes.indexOf(parent.type) === -1 || (parent.type === "AssignmentExpression" && parent.operator !== "=")) { context.report({ node: node, - message: "No magic number: " + raw + message: "No magic number: " + raw + "." }); } } diff --git a/tools/eslint/lib/rules/no-mixed-operators.js b/tools/eslint/lib/rules/no-mixed-operators.js index 9a8b1c3925198b..f6e686521df85c 100644 --- a/tools/eslint/lib/rules/no-mixed-operators.js +++ b/tools/eslint/lib/rules/no-mixed-operators.js @@ -9,43 +9,43 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils.js"); +let astUtils = require("../ast-utils.js"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var ARITHMETIC_OPERATORS = ["+", "-", "*", "/", "%", "**"]; -var BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"]; -var COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="]; -var LOGICAL_OPERATORS = ["&&", "||"]; -var RELATIONAL_OPERATORS = ["in", "instanceof"]; -var ALL_OPERATORS = [].concat( +let ARITHMETIC_OPERATORS = ["+", "-", "*", "/", "%", "**"]; +let BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"]; +let COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="]; +let LOGICAL_OPERATORS = ["&&", "||"]; +let RELATIONAL_OPERATORS = ["in", "instanceof"]; +let ALL_OPERATORS = [].concat( ARITHMETIC_OPERATORS, BITWISE_OPERATORS, COMPARISON_OPERATORS, LOGICAL_OPERATORS, RELATIONAL_OPERATORS ); -var DEFAULT_GROUPS = [ +let DEFAULT_GROUPS = [ ARITHMETIC_OPERATORS, BITWISE_OPERATORS, COMPARISON_OPERATORS, LOGICAL_OPERATORS, RELATIONAL_OPERATORS ]; -var TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/; +let TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/; /** * Normalizes options. * - * @param {object|undefined} options - A options object to normalize. - * @returns {object} Normalized option object. + * @param {Object|undefined} options - A options object to normalize. + * @returns {Object} Normalized option object. */ function normalizeOptions(options) { - var hasGroups = (options && options.groups && options.groups.length > 0); - var groups = hasGroups ? options.groups : DEFAULT_GROUPS; - var allowSamePrecedence = (options && options.allowSamePrecedence) !== false; + let hasGroups = (options && options.groups && options.groups.length > 0); + let groups = hasGroups ? options.groups : DEFAULT_GROUPS; + let allowSamePrecedence = (options && options.allowSamePrecedence) !== false; return { groups: groups, @@ -102,8 +102,8 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var options = normalizeOptions(context.options[0]); + let sourceCode = context.getSourceCode(); + let options = normalizeOptions(context.options[0]); /** * Checks whether a given node should be ignored by options or not. @@ -114,8 +114,8 @@ module.exports = { * @returns {boolean} `true` if the node should be ignored. */ function shouldIgnore(node) { - var a = node; - var b = node.parent; + let a = node; + let b = node.parent; return ( !includesBothInAGroup(options.groups, a.operator, b.operator) || @@ -150,7 +150,7 @@ module.exports = { * @returns {Token} The operator token of the node. */ function getOperatorToken(node) { - var token = sourceCode.getTokenAfter(node.left); + let token = sourceCode.getTokenAfter(node.left); while (token.value === ")") { token = sourceCode.getTokenAfter(token); @@ -169,10 +169,10 @@ module.exports = { * @returns {void} */ function reportBothOperators(node) { - var parent = node.parent; - var left = (parent.left === node) ? node : parent; - var right = (parent.left !== node) ? node : parent; - var message = + let parent = node.parent; + let left = (parent.left === node) ? node : parent; + let right = (parent.left !== node) ? node : parent; + let message = "Unexpected mix of '" + left.operator + "' and '" + right.operator + "'."; diff --git a/tools/eslint/lib/rules/no-mixed-requires.js b/tools/eslint/lib/rules/no-mixed-requires.js index b6d365a9dbb52d..68ce51f56fcece 100644 --- a/tools/eslint/lib/rules/no-mixed-requires.js +++ b/tools/eslint/lib/rules/no-mixed-requires.js @@ -42,7 +42,7 @@ module.exports = { create: function(context) { - var grouping = false, + let grouping = false, allowCall = false, options = context.options[0]; @@ -74,13 +74,13 @@ module.exports = { ]; } - var BUILTIN_MODULES = getBuiltinModules(); + let BUILTIN_MODULES = getBuiltinModules(); - var DECL_REQUIRE = "require", + let DECL_REQUIRE = "require", DECL_UNINITIALIZED = "uninitialized", DECL_OTHER = "other"; - var REQ_CORE = "core", + let REQ_CORE = "core", REQ_FILE = "file", REQ_MODULE = "module", REQ_COMPUTED = "computed"; @@ -137,7 +137,7 @@ module.exports = { return REQ_COMPUTED; } - var arg = initExpression.arguments[0]; + let arg = initExpression.arguments[0]; if (arg.type !== "Literal" || typeof arg.value !== "string") { @@ -167,10 +167,10 @@ module.exports = { * @returns {boolean} True if the declarations are mixed, false if not. */ function isMixed(declarations) { - var contains = {}; + let contains = {}; declarations.forEach(function(declaration) { - var type = getDeclarationType(declaration.init); + let type = getDeclarationType(declaration.init); contains[type] = true; }); @@ -188,7 +188,7 @@ module.exports = { * @returns {boolean} True if the declarations are grouped, false if not. */ function isGrouped(declarations) { - var found = {}; + let found = {}; declarations.forEach(function(declaration) { if (getDeclarationType(declaration.init) === DECL_REQUIRE) { diff --git a/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js b/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js index 74553f65115cc7..19734b1b5d5d30 100644 --- a/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js +++ b/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js @@ -24,9 +24,9 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var smartTabs, + let smartTabs, ignoredLocs = []; switch (context.options[0]) { @@ -85,7 +85,7 @@ module.exports = { * or the reverse before non-tab/-space * characters begin. */ - var regex = /^(?=[\t ]*(\t | \t))/, + let regex = /^(?=[\t ]*(\t | \t))/, match, lines = sourceCode.lines, comments = sourceCode.getAllComments(); @@ -119,10 +119,10 @@ module.exports = { match = regex.exec(line); if (match) { - var lineNumber = i + 1, + let lineNumber = i + 1, column = match.index + 1; - for (var j = 0; j < ignoredLocs.length; j++) { + for (let j = 0; j < ignoredLocs.length; j++) { if (beforeLoc(ignoredLocs[j], lineNumber, column)) { continue; } diff --git a/tools/eslint/lib/rules/no-multi-spaces.js b/tools/eslint/lib/rules/no-multi-spaces.js index 2fd89ef4dc0d48..78d600c8848931 100644 --- a/tools/eslint/lib/rules/no-multi-spaces.js +++ b/tools/eslint/lib/rules/no-multi-spaces.js @@ -41,7 +41,7 @@ module.exports = { create: function(context) { // the index of the last comment that was checked - var exceptions = { Property: true }, + let exceptions = { Property: true }, hasExceptions = true, options = context.options[0], lastCommentIndex = 0; @@ -69,7 +69,7 @@ module.exports = { */ function isIndexInComment(index, comments) { - var comment; + let comment; while (lastCommentIndex < comments.length) { @@ -95,7 +95,7 @@ module.exports = { return { Program: function() { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), source = sourceCode.getText(), allComments = sourceCode.getAllComments(), pattern = /[^\n\r\u2028\u2029\t ].? {2,}/g, // note: repeating space @@ -108,7 +108,7 @@ module.exports = { * Creates a fix function that removes the multiple spaces between the two tokens * @param {RuleFixer} leftToken left token * @param {RuleFixer} rightToken right token - * @returns {function} fix function + * @returns {Function} fix function * @private */ function createFix(leftToken, rightToken) { diff --git a/tools/eslint/lib/rules/no-multi-str.js b/tools/eslint/lib/rules/no-multi-str.js index fe7fee4a60a38c..1d880104591f44 100644 --- a/tools/eslint/lib/rules/no-multi-str.js +++ b/tools/eslint/lib/rules/no-multi-str.js @@ -39,7 +39,7 @@ module.exports = { return { Literal: function(node) { - var lineBreak = /\n/; + let lineBreak = /\n/; if (lineBreak.test(node.raw) && !isJSXElement(node.parent)) { context.report(node, "Multiline support is limited to browsers supporting ES5 only."); diff --git a/tools/eslint/lib/rules/no-multiple-empty-lines.js b/tools/eslint/lib/rules/no-multiple-empty-lines.js index 7508164d38eb05..cede2d5e78abef 100644 --- a/tools/eslint/lib/rules/no-multiple-empty-lines.js +++ b/tools/eslint/lib/rules/no-multiple-empty-lines.js @@ -45,12 +45,12 @@ module.exports = { create: function(context) { // Use options.max or 2 as default - var max = 2, + let max = 2, maxEOF, maxBOF; // store lines that appear empty but really aren't - var notEmpty = []; + let notEmpty = []; if (context.options.length) { max = context.options[0].max; @@ -58,7 +58,7 @@ module.exports = { maxBOF = typeof context.options[0].maxBOF !== "undefined" ? context.options[0].maxBOF : max; } - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Public @@ -67,8 +67,8 @@ module.exports = { return { TemplateLiteral: function(node) { - var start = node.loc.start.line; - var end = node.loc.end.line; + let start = node.loc.start.line; + let end = node.loc.end.line; while (start <= end) { notEmpty.push(start); @@ -77,7 +77,7 @@ module.exports = { }, "Program:exit": function checkBlankLines(node) { - var lines = sourceCode.lines, + let lines = sourceCode.lines, fullLines = sourceCode.text.match(/.*(\r\n|\r|\n|\u2028|\u2029)/g) || [], firstNonBlankLine = -1, trimmedLines = [], @@ -98,7 +98,7 @@ module.exports = { linesRangeStart.push(0); lines.forEach(function(str, i) { - var length = i < fullLines.length ? fullLines[i].length : 0, + let length = i < fullLines.length ? fullLines[i].length : 0, trimmed = str.trim(); if ((firstNonBlankLine === -1) && (trimmed !== "")) { diff --git a/tools/eslint/lib/rules/no-native-reassign.js b/tools/eslint/lib/rules/no-native-reassign.js index 8b75f022a07163..aa8314dda67b92 100644 --- a/tools/eslint/lib/rules/no-native-reassign.js +++ b/tools/eslint/lib/rules/no-native-reassign.js @@ -33,8 +33,8 @@ module.exports = { }, create: function(context) { - var config = context.options[0]; - var exceptions = (config && config.exceptions) || []; + let config = context.options[0]; + let exceptions = (config && config.exceptions) || []; /** * Reports write references. @@ -44,7 +44,7 @@ module.exports = { * @returns {void} */ function checkReference(reference, index, references) { - var identifier = reference.identifier; + let identifier = reference.identifier; if (reference.init === false && reference.isWrite() && @@ -74,7 +74,7 @@ module.exports = { return { Program: function() { - var globalScope = context.getScope(); + let globalScope = context.getScope(); globalScope.variables.forEach(checkVariable); } diff --git a/tools/eslint/lib/rules/no-negated-in-lhs.js b/tools/eslint/lib/rules/no-negated-in-lhs.js index 891b75dd2f4171..46f6c1cad4321c 100644 --- a/tools/eslint/lib/rules/no-negated-in-lhs.js +++ b/tools/eslint/lib/rules/no-negated-in-lhs.js @@ -26,7 +26,7 @@ module.exports = { BinaryExpression: function(node) { if (node.operator === "in" && node.left.type === "UnaryExpression" && node.left.operator === "!") { - context.report(node, "The 'in' expression's left operand is negated"); + context.report(node, "The 'in' expression's left operand is negated."); } } }; diff --git a/tools/eslint/lib/rules/no-nested-ternary.js b/tools/eslint/lib/rules/no-nested-ternary.js index 34f9eaaa8dbc8a..d28ee693cf0631 100644 --- a/tools/eslint/lib/rules/no-nested-ternary.js +++ b/tools/eslint/lib/rules/no-nested-ternary.js @@ -26,7 +26,7 @@ module.exports = { ConditionalExpression: function(node) { if (node.alternate.type === "ConditionalExpression" || node.consequent.type === "ConditionalExpression") { - context.report(node, "Do not nest ternary expressions"); + context.report(node, "Do not nest ternary expressions."); } } }; diff --git a/tools/eslint/lib/rules/no-new-symbol.js b/tools/eslint/lib/rules/no-new-symbol.js index c7c524641ee6bd..d4c4e67b17b46b 100644 --- a/tools/eslint/lib/rules/no-new-symbol.js +++ b/tools/eslint/lib/rules/no-new-symbol.js @@ -24,12 +24,12 @@ module.exports = { return { "Program:exit": function() { - var globalScope = context.getScope(); - var variable = globalScope.set.get("Symbol"); + let globalScope = context.getScope(); + let variable = globalScope.set.get("Symbol"); if (variable && variable.defs.length === 0) { variable.references.forEach(function(ref) { - var node = ref.identifier; + let node = ref.identifier; if (node.parent && node.parent.type === "NewExpression") { context.report(node, "`Symbol` cannot be called as a constructor."); diff --git a/tools/eslint/lib/rules/no-new-wrappers.js b/tools/eslint/lib/rules/no-new-wrappers.js index eec774fdcad14f..756ee80076f754 100644 --- a/tools/eslint/lib/rules/no-new-wrappers.js +++ b/tools/eslint/lib/rules/no-new-wrappers.js @@ -25,7 +25,7 @@ module.exports = { return { NewExpression: function(node) { - var wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"]; + let wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"]; if (wrapperObjects.indexOf(node.callee.name) > -1) { context.report(node, "Do not use {{fn}} as a constructor.", { fn: node.callee.name }); diff --git a/tools/eslint/lib/rules/no-obj-calls.js b/tools/eslint/lib/rules/no-obj-calls.js index 0f58ab93dbd6d6..ba1c45a31fe75d 100644 --- a/tools/eslint/lib/rules/no-obj-calls.js +++ b/tools/eslint/lib/rules/no-obj-calls.js @@ -26,7 +26,7 @@ module.exports = { CallExpression: function(node) { if (node.callee.type === "Identifier") { - var name = node.callee.name; + let name = node.callee.name; if (name === "Math" || name === "JSON") { context.report(node, "'{{name}}' is not a function.", { name: name }); diff --git a/tools/eslint/lib/rules/no-octal-escape.js b/tools/eslint/lib/rules/no-octal-escape.js index 3ca01324b5ea2d..cf5953a986f914 100644 --- a/tools/eslint/lib/rules/no-octal-escape.js +++ b/tools/eslint/lib/rules/no-octal-escape.js @@ -29,7 +29,7 @@ module.exports = { return; } - var match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/), + let match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/), octalDigit; if (match) { diff --git a/tools/eslint/lib/rules/no-param-reassign.js b/tools/eslint/lib/rules/no-param-reassign.js index fad61fc0c1eb9b..3a59106a2d537e 100644 --- a/tools/eslint/lib/rules/no-param-reassign.js +++ b/tools/eslint/lib/rules/no-param-reassign.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/; +let stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/; module.exports = { meta: { @@ -30,7 +30,7 @@ module.exports = { }, create: function(context) { - var props = context.options[0] && Boolean(context.options[0].props); + let props = context.options[0] && Boolean(context.options[0].props); /** * Checks whether or not the reference modifies properties of its variable. @@ -38,8 +38,8 @@ module.exports = { * @returns {boolean} Whether or not the reference modifies properties of its variable. */ function isModifyingProp(reference) { - var node = reference.identifier; - var parent = node.parent; + let node = reference.identifier; + let parent = node.parent; while (parent && !stopNodePattern.test(parent.type)) { switch (parent.type) { @@ -92,7 +92,7 @@ module.exports = { * @returns {void} */ function checkReference(reference, index, references) { - var identifier = reference.identifier; + let identifier = reference.identifier; if (identifier && !reference.init && diff --git a/tools/eslint/lib/rules/no-path-concat.js b/tools/eslint/lib/rules/no-path-concat.js index 1412c6c32e3546..f13d94267455a0 100644 --- a/tools/eslint/lib/rules/no-path-concat.js +++ b/tools/eslint/lib/rules/no-path-concat.js @@ -21,7 +21,7 @@ module.exports = { create: function(context) { - var MATCHER = /^__(?:dir|file)name$/; + let MATCHER = /^__(?:dir|file)name$/; //-------------------------------------------------------------------------- // Public @@ -31,7 +31,7 @@ module.exports = { BinaryExpression: function(node) { - var left = node.left, + let left = node.left, right = node.right; if (node.operator === "+" && diff --git a/tools/eslint/lib/rules/no-plusplus.js b/tools/eslint/lib/rules/no-plusplus.js index 159a42be2c13d1..34e54001ae5885 100644 --- a/tools/eslint/lib/rules/no-plusplus.js +++ b/tools/eslint/lib/rules/no-plusplus.js @@ -33,7 +33,7 @@ module.exports = { create: function(context) { - var config = context.options[0], + let config = context.options[0], allowInForAfterthought = false; if (typeof config === "object") { diff --git a/tools/eslint/lib/rules/no-process-env.js b/tools/eslint/lib/rules/no-process-env.js index af48c78029880e..d1bf15a245db13 100644 --- a/tools/eslint/lib/rules/no-process-env.js +++ b/tools/eslint/lib/rules/no-process-env.js @@ -24,7 +24,7 @@ module.exports = { return { MemberExpression: function(node) { - var objectName = node.object.name, + let objectName = node.object.name, propertyName = node.property.name; if (objectName === "process" && !node.computed && propertyName && propertyName === "env") { diff --git a/tools/eslint/lib/rules/no-process-exit.js b/tools/eslint/lib/rules/no-process-exit.js index 6d8674418bb590..045214e7e74bc0 100644 --- a/tools/eslint/lib/rules/no-process-exit.js +++ b/tools/eslint/lib/rules/no-process-exit.js @@ -28,7 +28,7 @@ module.exports = { return { CallExpression: function(node) { - var callee = node.callee; + let callee = node.callee; if (callee.type === "MemberExpression" && callee.object.name === "process" && callee.property.name === "exit" diff --git a/tools/eslint/lib/rules/no-prototype-builtins.js b/tools/eslint/lib/rules/no-prototype-builtins.js index febb1459be67e9..08b0b6dcf9a68d 100644 --- a/tools/eslint/lib/rules/no-prototype-builtins.js +++ b/tools/eslint/lib/rules/no-prototype-builtins.js @@ -14,11 +14,13 @@ module.exports = { description: "disallow calling some `Object.prototype` methods directly on objects", category: "Possible Errors", recommended: false - } + }, + + schema: [] }, create: function(context) { - var DISALLOWED_PROPS = [ + let DISALLOWED_PROPS = [ "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable" @@ -33,7 +35,7 @@ module.exports = { if (node.callee.type !== "MemberExpression" || node.callee.computed) { return; } - var propName = node.callee.property.name; + let propName = node.callee.property.name; if (DISALLOWED_PROPS.indexOf(propName) > -1) { context.report({ diff --git a/tools/eslint/lib/rules/no-redeclare.js b/tools/eslint/lib/rules/no-redeclare.js index 4253cc85334658..8a1540ff79f575 100644 --- a/tools/eslint/lib/rules/no-redeclare.js +++ b/tools/eslint/lib/rules/no-redeclare.js @@ -29,7 +29,7 @@ module.exports = { }, create: function(context) { - var options = { + let options = { builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals) }; @@ -41,18 +41,18 @@ module.exports = { */ function findVariablesInScope(scope) { scope.variables.forEach(function(variable) { - var hasBuiltin = options.builtinGlobals && "writeable" in variable; - var count = (hasBuiltin ? 1 : 0) + variable.identifiers.length; + let hasBuiltin = options.builtinGlobals && "writeable" in variable; + let count = (hasBuiltin ? 1 : 0) + variable.identifiers.length; if (count >= 2) { variable.identifiers.sort(function(a, b) { return a.range[1] - b.range[1]; }); - for (var i = (hasBuiltin ? 0 : 1), l = variable.identifiers.length; i < l; i++) { + for (let i = (hasBuiltin ? 0 : 1), l = variable.identifiers.length; i < l; i++) { context.report( variable.identifiers[i], - "'{{a}}' is already defined", + "'{{a}}' is already defined.", {a: variable.name}); } } @@ -67,7 +67,7 @@ module.exports = { * @private */ function checkForGlobal(node) { - var scope = context.getScope(), + let scope = context.getScope(), parserOptions = context.parserOptions, ecmaFeatures = parserOptions.ecmaFeatures || {}; diff --git a/tools/eslint/lib/rules/no-regex-spaces.js b/tools/eslint/lib/rules/no-regex-spaces.js index a2f1d48f716e13..de179894b36c34 100644 --- a/tools/eslint/lib/rules/no-regex-spaces.js +++ b/tools/eslint/lib/rules/no-regex-spaces.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Validate regular expressions @@ -31,7 +31,7 @@ module.exports = { * @private */ function checkRegex(node, value) { - var multipleSpacesRegex = /( {2,})+?/, + let multipleSpacesRegex = /( {2,})+?/, regexResults = multipleSpacesRegex.exec(value); if (regexResults !== null) { @@ -46,7 +46,7 @@ module.exports = { * @private */ function checkLiteral(node) { - var token = sourceCode.getFirstToken(node), + let token = sourceCode.getFirstToken(node), nodeType = token.type, nodeValue = token.value; diff --git a/tools/eslint/lib/rules/no-restricted-globals.js b/tools/eslint/lib/rules/no-restricted-globals.js index 3292705b13b31d..19bd6a94aeca67 100644 --- a/tools/eslint/lib/rules/no-restricted-globals.js +++ b/tools/eslint/lib/rules/no-restricted-globals.js @@ -26,7 +26,7 @@ module.exports = { }, create: function(context) { - var restrictedGlobals = context.options; + let restrictedGlobals = context.options; // if no globals are restricted we don't need to check if (restrictedGlobals.length === 0) { @@ -40,7 +40,7 @@ module.exports = { * @private */ function reportReference(reference) { - context.report(reference.identifier, "Unexpected use of '{{name}}'", { + context.report(reference.identifier, "Unexpected use of '{{name}}'.", { name: reference.identifier.name }); } @@ -57,7 +57,7 @@ module.exports = { return { Program: function() { - var scope = context.getScope(); + let scope = context.getScope(); // Report variables declared elsewhere (ex: variables defined as "global" by eslint) scope.variables.forEach(function(variable) { @@ -77,4 +77,3 @@ module.exports = { }; } }; - diff --git a/tools/eslint/lib/rules/no-restricted-imports.js b/tools/eslint/lib/rules/no-restricted-imports.js index 3129ce72784b2a..da768c135c7b43 100644 --- a/tools/eslint/lib/rules/no-restricted-imports.js +++ b/tools/eslint/lib/rules/no-restricted-imports.js @@ -26,7 +26,7 @@ module.exports = { }, create: function(context) { - var restrictedImports = context.options; + let restrictedImports = context.options; // if no imports are restricted we don"t need to check if (restrictedImports.length === 0) { @@ -37,7 +37,7 @@ module.exports = { ImportDeclaration: function(node) { if (node && node.source && node.source.value) { - var value = node.source.value.trim(); + let value = node.source.value.trim(); if (restrictedImports.indexOf(value) !== -1) { context.report(node, "'{{importName}}' import is restricted from being used.", { diff --git a/tools/eslint/lib/rules/no-restricted-modules.js b/tools/eslint/lib/rules/no-restricted-modules.js index 43e53915628a77..eeb6bf270d36b4 100644 --- a/tools/eslint/lib/rules/no-restricted-modules.js +++ b/tools/eslint/lib/rules/no-restricted-modules.js @@ -28,7 +28,7 @@ module.exports = { create: function(context) { // trim restricted module names - var restrictedModules = context.options; + let restrictedModules = context.options; // if no modules are restricted we don't need to check the CallExpressions if (restrictedModules.length === 0) { @@ -56,14 +56,14 @@ module.exports = { /** * Function to check if a node has an argument that is an restricted module and return its name. * @param {ASTNode} node The node to check - * @returns {undefined|String} restricted module name or undefined if node argument isn't restricted. + * @returns {undefined|string} restricted module name or undefined if node argument isn't restricted. */ function getRestrictedModuleName(node) { - var moduleName; + let moduleName; // node has arguments and first argument is string if (node.arguments.length && isString(node.arguments[0])) { - var argumentValue = node.arguments[0].value.trim(); + let argumentValue = node.arguments[0].value.trim(); // check if argument value is in restricted modules array if (restrictedModules.indexOf(argumentValue) !== -1) { @@ -77,7 +77,7 @@ module.exports = { return { CallExpression: function(node) { if (isRequireCall(node)) { - var restrictedModuleName = getRestrictedModuleName(node); + let restrictedModuleName = getRestrictedModuleName(node); if (restrictedModuleName) { context.report(node, "'{{moduleName}}' module is restricted from being used.", { diff --git a/tools/eslint/lib/rules/no-restricted-syntax.js b/tools/eslint/lib/rules/no-restricted-syntax.js index cd9eb603f9870b..84c62d63ac0d1f 100644 --- a/tools/eslint/lib/rules/no-restricted-syntax.js +++ b/tools/eslint/lib/rules/no-restricted-syntax.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var nodeTypes = require("espree").Syntax; +let nodeTypes = require("espree").Syntax; module.exports = { meta: { diff --git a/tools/eslint/lib/rules/no-return-assign.js b/tools/eslint/lib/rules/no-return-assign.js index 38fc1cb0ebbab5..54935060710e72 100644 --- a/tools/eslint/lib/rules/no-return-assign.js +++ b/tools/eslint/lib/rules/no-return-assign.js @@ -8,7 +8,7 @@ // Helpers //------------------------------------------------------------------------------ -var SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/; +let SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/; /** * Checks whether or not a node is enclosed in parentheses. @@ -17,8 +17,8 @@ var SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExp * @returns {boolean} Whether or not the node is enclosed in parentheses. */ function isEnclosedInParens(node, sourceCode) { - var prevToken = sourceCode.getTokenBefore(node); - var nextToken = sourceCode.getTokenAfter(node); + let prevToken = sourceCode.getTokenBefore(node); + let nextToken = sourceCode.getTokenAfter(node); return prevToken && prevToken.value === "(" && nextToken && nextToken.value === ")"; } @@ -43,8 +43,8 @@ module.exports = { }, create: function(context) { - var always = (context.options[0] || "except-parens") !== "except-parens"; - var sourceCode = context.getSourceCode(); + let always = (context.options[0] || "except-parens") !== "except-parens"; + let sourceCode = context.getSourceCode(); return { AssignmentExpression: function(node) { @@ -52,7 +52,7 @@ module.exports = { return; } - var parent = node.parent; + let parent = node.parent; // Find ReturnStatement or ArrowFunctionExpression in ancestors. while (parent && !SENTINEL_TYPE.test(parent.type)) { diff --git a/tools/eslint/lib/rules/no-script-url.js b/tools/eslint/lib/rules/no-script-url.js index 1985cf3b95f51c..1c12490b4330f9 100644 --- a/tools/eslint/lib/rules/no-script-url.js +++ b/tools/eslint/lib/rules/no-script-url.js @@ -28,7 +28,7 @@ module.exports = { Literal: function(node) { - var value; + let value; if (node.value && typeof node.value === "string") { value = node.value.toLowerCase(); diff --git a/tools/eslint/lib/rules/no-self-assign.js b/tools/eslint/lib/rules/no-self-assign.js index bcccc3d8380a09..e3dc35e81e7cf4 100644 --- a/tools/eslint/lib/rules/no-self-assign.js +++ b/tools/eslint/lib/rules/no-self-assign.js @@ -16,11 +16,11 @@ * a Property. * @param {ASTNode|null} right - A right node to traverse. This is a Pattern or * a Property. - * @param {function} report - A callback function to report. + * @param {Function} report - A callback function to report. * @returns {void} */ function eachSelfAssignment(left, right, report) { - var i, j; + let i, j; if (!left || !right) { @@ -35,10 +35,10 @@ function eachSelfAssignment(left, right, report) { left.type === "ArrayPattern" && right.type === "ArrayExpression" ) { - var end = Math.min(left.elements.length, right.elements.length); + let end = Math.min(left.elements.length, right.elements.length); for (i = 0; i < end; ++i) { - var rightElement = right.elements[i]; + let rightElement = right.elements[i]; eachSelfAssignment(left.elements[i], rightElement, report); @@ -60,7 +60,7 @@ function eachSelfAssignment(left, right, report) { // Gets the index of the last spread property. // It's possible to overwrite properties followed by it. - var startJ = 0; + let startJ = 0; for (i = right.properties.length - 1; i >= 0; --i) { if (right.properties[i].type === "ExperimentalSpreadProperty") { diff --git a/tools/eslint/lib/rules/no-self-compare.js b/tools/eslint/lib/rules/no-self-compare.js index eef05080b75a15..c677e56ffdbd12 100644 --- a/tools/eslint/lib/rules/no-self-compare.js +++ b/tools/eslint/lib/rules/no-self-compare.js @@ -26,7 +26,7 @@ module.exports = { return { BinaryExpression: function(node) { - var operators = ["===", "==", "!==", "!=", ">", "<", ">=", "<="]; + let operators = ["===", "==", "!==", "!=", ">", "<", ">=", "<="]; if (operators.indexOf(node.operator) > -1 && (node.left.type === "Identifier" && node.right.type === "Identifier" && node.left.name === node.right.name || diff --git a/tools/eslint/lib/rules/no-sequences.js b/tools/eslint/lib/rules/no-sequences.js index b0d318c7d08ab6..51c3b8e8080b89 100644 --- a/tools/eslint/lib/rules/no-sequences.js +++ b/tools/eslint/lib/rules/no-sequences.js @@ -21,12 +21,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Parts of the grammar that are required to have parens. */ - var parenthesized = { + let parenthesized = { DoWhileStatement: "test", IfStatement: "test", SwitchStatement: "discriminant", @@ -57,7 +57,7 @@ module.exports = { * @returns {boolean} True if the node has a paren on each side. */ function isParenthesised(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return previousToken && nextToken && @@ -71,7 +71,7 @@ module.exports = { * @returns {boolean} True if two parens surround the node on each side. */ function isParenthesisedTwice(node) { - var previousToken = sourceCode.getTokenBefore(node, 1), + let previousToken = sourceCode.getTokenBefore(node, 1), nextToken = sourceCode.getTokenAfter(node, 1); return isParenthesised(node) && previousToken && nextToken && @@ -99,7 +99,7 @@ module.exports = { } } - var child = sourceCode.getTokenAfter(node.expressions[0]); + let child = sourceCode.getTokenAfter(node.expressions[0]); context.report(node, child.loc.start, "Unexpected use of comma operator."); } diff --git a/tools/eslint/lib/rules/no-shadow-restricted-names.js b/tools/eslint/lib/rules/no-shadow-restricted-names.js index b7731d9d6767bb..d932363d6f7131 100644 --- a/tools/eslint/lib/rules/no-shadow-restricted-names.js +++ b/tools/eslint/lib/rules/no-shadow-restricted-names.js @@ -21,7 +21,7 @@ module.exports = { create: function(context) { - var RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"]; + let RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"]; /** * Check if the node name is present inside the restricted list diff --git a/tools/eslint/lib/rules/no-shadow.js b/tools/eslint/lib/rules/no-shadow.js index ee0dd69f3a571f..62f75047807b4b 100644 --- a/tools/eslint/lib/rules/no-shadow.js +++ b/tools/eslint/lib/rules/no-shadow.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -43,7 +43,7 @@ module.exports = { create: function(context) { - var options = { + let options = { builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals), hoist: (context.options[0] && context.options[0].hoist) || "functions", allow: (context.options[0] && context.options[0].allow) || [] @@ -69,7 +69,7 @@ module.exports = { * @returns {boolean} Whether or not the variable of the class name in the class scope of ClassDeclaration. */ function isDuplicatedClassNameVariable(variable) { - var block = variable.scope.block; + let block = variable.scope.block; return block.type === "ClassDeclaration" && block.id === variable.identifiers[0]; } @@ -85,12 +85,12 @@ module.exports = { * @returns {boolean} Whether or not the variable is inside initializer of scopeVar. */ function isOnInitializer(variable, scopeVar) { - var outerScope = scopeVar.scope; - var outerDef = scopeVar.defs[0]; - var outer = outerDef && outerDef.parent && outerDef.parent.range; - var innerScope = variable.scope; - var innerDef = variable.defs[0]; - var inner = innerDef && innerDef.name.range; + let outerScope = scopeVar.scope; + let outerDef = scopeVar.defs[0]; + let outer = outerDef && outerDef.parent && outerDef.parent.range; + let innerScope = variable.scope; + let innerDef = variable.defs[0]; + let inner = innerDef && innerDef.name.range; return ( outer && @@ -108,7 +108,7 @@ module.exports = { * @returns {Array|undefined} The range of the variable's identifier node. */ function getNameRange(variable) { - var def = variable.defs[0]; + let def = variable.defs[0]; return def && def.name.range; } @@ -120,9 +120,9 @@ module.exports = { * @returns {boolean} Whether or not the variable is in TDZ of scopeVar. */ function isInTdz(variable, scopeVar) { - var outerDef = scopeVar.defs[0]; - var inner = getNameRange(variable); - var outer = getNameRange(scopeVar); + let outerDef = scopeVar.defs[0]; + let inner = getNameRange(variable); + let outer = getNameRange(scopeVar); return ( inner && @@ -140,10 +140,10 @@ module.exports = { * @returns {void} */ function checkForShadows(scope) { - var variables = scope.variables; + let variables = scope.variables; - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; // Skips "arguments" or variables of a class name in the class scope of ClassDeclaration. if (variable.identifiers.length === 0 || @@ -154,7 +154,7 @@ module.exports = { } // Gets shadowed variable. - var shadowed = astUtils.getVariableByName(scope.upper, variable.name); + let shadowed = astUtils.getVariableByName(scope.upper, variable.name); if (shadowed && (shadowed.identifiers.length > 0 || (options.builtinGlobals && "writeable" in shadowed)) && @@ -172,9 +172,9 @@ module.exports = { return { "Program:exit": function() { - var globalScope = context.getScope(); - var stack = globalScope.childScopes.slice(); - var scope; + let globalScope = context.getScope(); + let stack = globalScope.childScopes.slice(); + let scope; while (stack.length) { scope = stack.pop(); diff --git a/tools/eslint/lib/rules/no-spaced-func.js b/tools/eslint/lib/rules/no-spaced-func.js index f0a16121136cf6..90765645e87ad8 100644 --- a/tools/eslint/lib/rules/no-spaced-func.js +++ b/tools/eslint/lib/rules/no-spaced-func.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check if open space is present in a function name @@ -32,7 +32,7 @@ module.exports = { * @private */ function detectOpenSpaces(node) { - var lastCalleeToken = sourceCode.getLastToken(node.callee), + let lastCalleeToken = sourceCode.getLastToken(node.callee), prevToken = lastCalleeToken, parenToken = sourceCode.getTokenAfter(lastCalleeToken); diff --git a/tools/eslint/lib/rules/no-sparse-arrays.js b/tools/eslint/lib/rules/no-sparse-arrays.js index b1ae0ba74036b4..4d4bfd9944c860 100644 --- a/tools/eslint/lib/rules/no-sparse-arrays.js +++ b/tools/eslint/lib/rules/no-sparse-arrays.js @@ -30,7 +30,7 @@ module.exports = { ArrayExpression: function(node) { - var emptySpot = node.elements.indexOf(null) > -1; + let emptySpot = node.elements.indexOf(null) > -1; if (emptySpot) { context.report(node, "Unexpected comma in middle of array."); diff --git a/tools/eslint/lib/rules/no-sync.js b/tools/eslint/lib/rules/no-sync.js index be6860e75af4ac..ddd1f9484b9103 100644 --- a/tools/eslint/lib/rules/no-sync.js +++ b/tools/eslint/lib/rules/no-sync.js @@ -27,7 +27,7 @@ module.exports = { return { MemberExpression: function(node) { - var propertyName = node.property.name, + let propertyName = node.property.name, syncRegex = /.*Sync$/; if (syncRegex.exec(propertyName) !== null) { diff --git a/tools/eslint/lib/rules/no-tabs.js b/tools/eslint/lib/rules/no-tabs.js new file mode 100644 index 00000000000000..ef873db2bdb0b8 --- /dev/null +++ b/tools/eslint/lib/rules/no-tabs.js @@ -0,0 +1,47 @@ +/** + * @fileoverview Rule to check for tabs inside a file + * @author Gyandeep Singh + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ +const regex = /\t/; + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "Disallow tabs in file", + category: "Stylistic Issues", + recommended: false + }, + schema: [] + }, + + create(context) { + return { + Program(node) { + context.getSourceLines().forEach((line, index) => { + const match = regex.exec(line); + + if (match) { + context.report( + node, + { + line: index + 1, + column: match.index + 1 + }, + "Unexpected tab character." + ); + } + }); + } + }; + } +}; diff --git a/tools/eslint/lib/rules/no-this-before-super.js b/tools/eslint/lib/rules/no-this-before-super.js index fb172f47f3a6fa..82eda02160abfb 100644 --- a/tools/eslint/lib/rules/no-this-before-super.js +++ b/tools/eslint/lib/rules/no-this-before-super.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -55,7 +55,7 @@ module.exports = { * - scope: The scope of the owner class. * - codePath: The code path of this constructor. */ - var funcInfo = null; + let funcInfo = null; /* * Information for each code path segment. @@ -64,7 +64,7 @@ module.exports = { * - superCalled: The flag which shows `super()` called in all code paths. * - invalidNodes: The array of invalid ThisExpression and Super nodes. */ - var segInfoMap = Object.create(null); + let segInfoMap = Object.create(null); /** * Gets whether or not `super()` is called in a given code path segment. @@ -101,10 +101,10 @@ module.exports = { * @returns {void} */ function setInvalid(node) { - var segments = funcInfo.codePath.currentSegments; + let segments = funcInfo.codePath.currentSegments; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { segInfoMap[segment.id].invalidNodes.push(node); @@ -117,10 +117,10 @@ module.exports = { * @returns {void} */ function setSuperCalled() { - var segments = funcInfo.codePath.currentSegments; + let segments = funcInfo.codePath.currentSegments; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { segInfoMap[segment.id].superCalled = true; @@ -140,7 +140,7 @@ module.exports = { if (isConstructorFunction(node)) { // Class > ClassBody > MethodDefinition > FunctionExpression - var classNode = node.parent.parent.parent; + let classNode = node.parent.parent.parent; funcInfo = { upper: funcInfo, @@ -172,7 +172,7 @@ module.exports = { * @returns {void} */ onCodePathEnd: function(codePath) { - var isDerivedClass = funcInfo.hasExtends; + let isDerivedClass = funcInfo.hasExtends; funcInfo = funcInfo.upper; if (!isDerivedClass) { @@ -180,10 +180,10 @@ module.exports = { } codePath.traverseSegments(function(segment, controller) { - var info = segInfoMap[segment.id]; + let info = segInfoMap[segment.id]; - for (var i = 0; i < info.invalidNodes.length; ++i) { - var invalidNode = info.invalidNodes[i]; + for (let i = 0; i < info.invalidNodes.length; ++i) { + let invalidNode = info.invalidNodes[i]; context.report({ message: "'{{kind}}' is not allowed before 'super()'.", @@ -238,7 +238,7 @@ module.exports = { funcInfo.codePath.traverseSegments( {first: toSegment, last: fromSegment}, function(segment, controller) { - var info = segInfoMap[segment.id]; + let info = segInfoMap[segment.id]; if (info.superCalled) { info.invalidNodes = []; diff --git a/tools/eslint/lib/rules/no-throw-literal.js b/tools/eslint/lib/rules/no-throw-literal.js index bedf94379e81f3..69eda1c76545e8 100644 --- a/tools/eslint/lib/rules/no-throw-literal.js +++ b/tools/eslint/lib/rules/no-throw-literal.js @@ -27,10 +27,11 @@ function couldBeError(node) { case "AssignmentExpression": return couldBeError(node.right); - case "SequenceExpression": - var exprs = node.expressions; + case "SequenceExpression": { + const exprs = node.expressions; return exprs.length !== 0 && couldBeError(exprs[exprs.length - 1]); + } case "LogicalExpression": return couldBeError(node.left) || couldBeError(node.right); diff --git a/tools/eslint/lib/rules/no-trailing-spaces.js b/tools/eslint/lib/rules/no-trailing-spaces.js index a08907fc95f343..6b82cfc38cd5fd 100644 --- a/tools/eslint/lib/rules/no-trailing-spaces.js +++ b/tools/eslint/lib/rules/no-trailing-spaces.js @@ -32,13 +32,13 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]", + let BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]", SKIP_BLANK = "^" + BLANK_CLASS + "*$", NONBLANK = BLANK_CLASS + "+$"; - var options = context.options[0] || {}, + let options = context.options[0] || {}, skipBlankLines = options.skipBlankLines || false; /** @@ -78,7 +78,7 @@ module.exports = { // Let's hack. Since Espree does not return whitespace nodes, // fetch the source code and do matching via regexps. - var re = new RegExp(NONBLANK), + let re = new RegExp(NONBLANK), skipMatch = new RegExp(SKIP_BLANK), matches, lines = sourceCode.lines, @@ -90,14 +90,14 @@ module.exports = { fixRange = [], containingNode; - for (var i = 0, ii = lines.length; i < ii; i++) { + for (let i = 0, ii = lines.length; i < ii; i++) { matches = re.exec(lines[i]); // Always add linebreak length to line length to accommodate for line break (\n or \r\n) // Because during the fix time they also reserve one spot in the array. // Usually linebreak length is 2 for \r\n (CRLF) and 1 for \n (LF) - var linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1; - var lineLength = lines[i].length + linebreakLength; + let linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1; + let lineLength = lines[i].length + linebreakLength; if (matches) { location = { diff --git a/tools/eslint/lib/rules/no-undef-init.js b/tools/eslint/lib/rules/no-undef-init.js index 8622e45701f0a1..2683f61e8aa0e4 100644 --- a/tools/eslint/lib/rules/no-undef-init.js +++ b/tools/eslint/lib/rules/no-undef-init.js @@ -25,7 +25,7 @@ module.exports = { return { VariableDeclarator: function(node) { - var name = node.id.name, + let name = node.id.name, init = node.init && node.init.name; if (init === "undefined" && node.parent.kind !== "const") { diff --git a/tools/eslint/lib/rules/no-undef.js b/tools/eslint/lib/rules/no-undef.js index b76ce4bb5bfefc..da9437157ceda3 100644 --- a/tools/eslint/lib/rules/no-undef.js +++ b/tools/eslint/lib/rules/no-undef.js @@ -14,7 +14,7 @@ * @returns {boolean} Whether or not the node is the argument of a typeof operator. */ function hasTypeOfOperator(node) { - var parent = node.parent; + let parent = node.parent; return parent.type === "UnaryExpression" && parent.operator === "typeof"; } @@ -45,15 +45,15 @@ module.exports = { }, create: function(context) { - var options = context.options[0]; - var considerTypeOf = options && options.typeof === true || false; + let options = context.options[0]; + let considerTypeOf = options && options.typeof === true || false; return { "Program:exit": function(/* node */) { - var globalScope = context.getScope(); + let globalScope = context.getScope(); globalScope.through.forEach(function(ref) { - var identifier = ref.identifier; + let identifier = ref.identifier; if (!considerTypeOf && hasTypeOfOperator(identifier)) { return; diff --git a/tools/eslint/lib/rules/no-undefined.js b/tools/eslint/lib/rules/no-undefined.js index 3ad2128b4efb0c..a34d665203f48a 100644 --- a/tools/eslint/lib/rules/no-undefined.js +++ b/tools/eslint/lib/rules/no-undefined.js @@ -25,7 +25,7 @@ module.exports = { Identifier: function(node) { if (node.name === "undefined") { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); if (!parent || parent.type !== "MemberExpression" || node !== parent.property || parent.computed) { context.report(node, "Unexpected use of undefined."); diff --git a/tools/eslint/lib/rules/no-underscore-dangle.js b/tools/eslint/lib/rules/no-underscore-dangle.js index 4217f8adc53b96..a6a3b174fc2bd4 100644 --- a/tools/eslint/lib/rules/no-underscore-dangle.js +++ b/tools/eslint/lib/rules/no-underscore-dangle.js @@ -29,6 +29,9 @@ module.exports = { }, allowAfterThis: { type: "boolean" + }, + allowAfterSuper: { + type: "boolean" } }, additionalProperties: false @@ -38,9 +41,10 @@ module.exports = { create: function(context) { - var options = context.options[0] || {}; - var ALLOWED_VARIABLES = options.allow ? options.allow : []; - var allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false; + let options = context.options[0] || {}; + let ALLOWED_VARIABLES = options.allow ? options.allow : []; + let allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false; + let allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false; //------------------------------------------------------------------------- // Helpers @@ -65,7 +69,7 @@ module.exports = { * @private */ function hasTrailingUnderscore(identifier) { - var len = identifier.length; + let len = identifier.length; return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_"); } @@ -100,7 +104,7 @@ module.exports = { */ function checkForTrailingUnderscoreInFunctionDeclaration(node) { if (node.id) { - var identifier = node.id.name; + let identifier = node.id.name; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) { context.report(node, "Unexpected dangling '_' in '" + identifier + "'."); @@ -115,7 +119,7 @@ module.exports = { * @private */ function checkForTrailingUnderscoreInVariableExpression(node) { - var identifier = node.id.name; + let identifier = node.id.name; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) { @@ -130,11 +134,13 @@ module.exports = { * @private */ function checkForTrailingUnderscoreInMemberExpression(node) { - var identifier = node.property.name, - isMemberOfThis = node.object.type === "ThisExpression"; + let identifier = node.property.name, + isMemberOfThis = node.object.type === "ThisExpression", + isMemberOfSuper = node.object.type === "Super"; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !(isMemberOfThis && allowAfterThis) && + !(isMemberOfSuper && allowAfterSuper) && !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) { context.report(node, "Unexpected dangling '_' in '" + identifier + "'."); } diff --git a/tools/eslint/lib/rules/no-unexpected-multiline.js b/tools/eslint/lib/rules/no-unexpected-multiline.js index af0beb2c4dd697..6fcb8c681a9857 100644 --- a/tools/eslint/lib/rules/no-unexpected-multiline.js +++ b/tools/eslint/lib/rules/no-unexpected-multiline.js @@ -20,11 +20,11 @@ module.exports = { create: function(context) { - var FUNCTION_MESSAGE = "Unexpected newline between function and ( of function call."; - var PROPERTY_MESSAGE = "Unexpected newline between object and [ of property access."; - var TAGGED_TEMPLATE_MESSAGE = "Unexpected newline between template tag and template literal."; + let FUNCTION_MESSAGE = "Unexpected newline between function and ( of function call."; + let PROPERTY_MESSAGE = "Unexpected newline between object and [ of property access."; + let TAGGED_TEMPLATE_MESSAGE = "Unexpected newline between template tag and template literal."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check to see if there is a newline between the node and the following open bracket @@ -35,8 +35,8 @@ module.exports = { * @private */ function checkForBreakAfter(node, msg) { - var nodeExpressionEnd = node; - var openParen = sourceCode.getTokenAfter(node); + let nodeExpressionEnd = node; + let openParen = sourceCode.getTokenAfter(node); // Move along until the end of the wrapped expression while (openParen.value === ")") { diff --git a/tools/eslint/lib/rules/no-unmodified-loop-condition.js b/tools/eslint/lib/rules/no-unmodified-loop-condition.js index ed49b5996ef641..099dd5f955e999 100644 --- a/tools/eslint/lib/rules/no-unmodified-loop-condition.js +++ b/tools/eslint/lib/rules/no-unmodified-loop-condition.js @@ -9,27 +9,26 @@ // Requirements //------------------------------------------------------------------------------ -var Map = require("es6-map"), - Traverser = require("../util/traverser"), +let Traverser = require("../util/traverser"), astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var pushAll = Function.apply.bind(Array.prototype.push); -var SENTINEL_PATTERN = /(?:(?:Call|Class|Function|Member|New|Yield)Expression|Statement|Declaration)$/; -var LOOP_PATTERN = /^(?:DoWhile|For|While)Statement$/; -var GROUP_PATTERN = /^(?:BinaryExpression|ConditionalExpression)$/; -var SKIP_PATTERN = /^(?:ArrowFunction|Class|Function)Expression$/; -var DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/; +let pushAll = Function.apply.bind(Array.prototype.push); +let SENTINEL_PATTERN = /(?:(?:Call|Class|Function|Member|New|Yield)Expression|Statement|Declaration)$/; +let LOOP_PATTERN = /^(?:DoWhile|For|While)Statement$/; // for-in/of statements don't have `test` property. +let GROUP_PATTERN = /^(?:BinaryExpression|ConditionalExpression)$/; +let SKIP_PATTERN = /^(?:ArrowFunction|Class|Function)Expression$/; +let DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/; /** - * @typedef {object} LoopConditionInfo + * @typedef {Object} LoopConditionInfo * @property {escope.Reference} reference - The reference. * @property {ASTNode} group - BinaryExpression or ConditionalExpression nodes * that the reference is belonging to. - * @property {function} isInLoop - The predicate which checks a given reference + * @property {Function} isInLoop - The predicate which checks a given reference * is in this loop. * @property {boolean} modified - The flag that the reference is modified in * this loop. @@ -43,7 +42,7 @@ var DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/; */ function isWriteReference(reference) { if (reference.init) { - var def = reference.resolved && reference.resolved.defs[0]; + let def = reference.resolved && reference.resolved.defs[0]; if (!def || def.type !== "Variable" || def.parent.kind !== "var") { return false; @@ -82,8 +81,8 @@ function isUnmodifiedAndNotBelongToGroup(condition) { * @returns {boolean} `true` if the reference is inside of the node. */ function isInRange(node, reference) { - var or = node.range; - var ir = reference.identifier.range; + let or = node.range; + let ir = reference.identifier.range; return or[0] <= ir[0] && ir[1] <= or[1]; } @@ -96,7 +95,7 @@ function isInRange(node, reference) { * @returns {boolean} `true` if the reference is inside of the loop node's * condition. */ -var isInLoop = { +let isInLoop = { WhileStatement: isInRange, DoWhileStatement: isInRange, ForStatement: function(node, reference) { @@ -115,7 +114,7 @@ var isInLoop = { * @returns {boolean} `true` if the node is dynamic. */ function hasDynamicExpressions(root) { - var retv = false, + let retv = false, traverser = new Traverser(); traverser.traverse(root, { @@ -143,9 +142,9 @@ function toLoopCondition(reference) { return null; } - var group = null; - var child = reference.identifier; - var node = child.parent; + let group = null; + let child = reference.identifier; + let node = child.parent; while (node) { if (SENTINEL_PATTERN.test(node.type)) { @@ -193,7 +192,7 @@ function toLoopCondition(reference) { * @returns {ASTNode|null} The function node or null. */ function getEncloseFunctionDeclaration(reference) { - var node = reference.identifier; + let node = reference.identifier; while (node) { if (node.type === "FunctionDeclaration") { @@ -214,13 +213,13 @@ function getEncloseFunctionDeclaration(reference) { * @returns {void} */ function updateModifiedFlag(conditions, modifiers) { - var funcNode, funcVar; + let funcNode, funcVar; - for (var i = 0; i < conditions.length; ++i) { - var condition = conditions[i]; + for (let i = 0; i < conditions.length; ++i) { + let condition = conditions[i]; - for (var j = 0; !condition.modified && j < modifiers.length; ++j) { - var modifier = modifiers[j], + for (let j = 0; !condition.modified && j < modifiers.length; ++j) { + let modifier = modifiers[j], inLoop; /* @@ -255,7 +254,7 @@ module.exports = { }, create: function(context) { - var groupMap = null; + let groupMap = null; /** * Reports a given condition info. @@ -264,7 +263,7 @@ module.exports = { * @returns {void} */ function report(condition) { - var node = condition.reference.identifier; + let node = condition.reference.identifier; context.report({ node: node, @@ -281,11 +280,11 @@ module.exports = { * @returns {void} */ function registerConditionsToGroup(conditions) { - for (var i = 0; i < conditions.length; ++i) { - var condition = conditions[i]; + for (let i = 0; i < conditions.length; ++i) { + let condition = conditions[i]; if (condition.group) { - var group = groupMap.get(condition.group); + let group = groupMap.get(condition.group); if (!group) { group = []; @@ -318,7 +317,7 @@ module.exports = { function checkReferences(variable) { // Gets references that exist in loop conditions. - var conditions = variable + let conditions = variable .references .map(toLoopCondition) .filter(Boolean); @@ -331,7 +330,7 @@ module.exports = { registerConditionsToGroup(conditions); // Check the conditions are modified. - var modifiers = variable.references.filter(isWriteReference); + let modifiers = variable.references.filter(isWriteReference); if (modifiers.length > 0) { updateModifiedFlag(conditions, modifiers); @@ -348,11 +347,11 @@ module.exports = { return { "Program:exit": function() { - var queue = [context.getScope()]; + let queue = [context.getScope()]; groupMap = new Map(); - var scope; + let scope; while ((scope = queue.pop())) { pushAll(queue, scope.childScopes); diff --git a/tools/eslint/lib/rules/no-unneeded-ternary.js b/tools/eslint/lib/rules/no-unneeded-ternary.js index 1c344a42e615ea..64c767ed0eb2de 100644 --- a/tools/eslint/lib/rules/no-unneeded-ternary.js +++ b/tools/eslint/lib/rules/no-unneeded-ternary.js @@ -31,8 +31,8 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var defaultAssignment = options.defaultAssignment !== false; + let options = context.options[0] || {}; + let defaultAssignment = options.defaultAssignment !== false; /** * Test if the node is a boolean literal @@ -60,9 +60,9 @@ module.exports = { ConditionalExpression: function(node) { if (isBooleanLiteral(node.alternate) && isBooleanLiteral(node.consequent)) { - context.report(node, node.consequent.loc.start, "Unnecessary use of boolean literals in conditional expression"); + context.report(node, node.consequent.loc.start, "Unnecessary use of boolean literals in conditional expression."); } else if (!defaultAssignment && matchesDefaultAssignment(node)) { - context.report(node, node.consequent.loc.start, "Unnecessary use of conditional expression for default assignment"); + context.report(node, node.consequent.loc.start, "Unnecessary use of conditional expression for default assignment."); } } }; diff --git a/tools/eslint/lib/rules/no-unreachable.js b/tools/eslint/lib/rules/no-unreachable.js index c28a6d2f2fa787..d52b9f3517bc22 100644 --- a/tools/eslint/lib/rules/no-unreachable.js +++ b/tools/eslint/lib/rules/no-unreachable.js @@ -26,6 +26,75 @@ function isUnreachable(segment) { return !segment.reachable; } +/** + * The class to distinguish consecutive unreachable statements. + */ +class ConsecutiveRange { + constructor(sourceCode) { + this.sourceCode = sourceCode; + this.startNode = null; + this.endNode = null; + } + + /** + * The location object of this range. + * @type {Object} + */ + get location() { + return { + start: this.startNode.loc.start, + end: this.endNode.loc.end + }; + } + + /** + * `true` if this range is empty. + * @type {boolean} + */ + get isEmpty() { + return !(this.startNode && this.endNode); + } + + /** + * Checks whether the given node is inside of this range. + * @param {ASTNode|Token} node - The node to check. + * @returns {boolean} `true` if the node is inside of this range. + */ + contains(node) { + return ( + node.range[0] >= this.startNode.range[0] && + node.range[1] <= this.endNode.range[1] + ); + } + + /** + * Checks whether the given node is consecutive to this range. + * @param {ASTNode} node - The node to check. + * @returns {boolean} `true` if the node is consecutive to this range. + */ + isConsecutive(node) { + return this.contains(this.sourceCode.getTokenBefore(node)); + } + + /** + * Merges the given node to this range. + * @param {ASTNode} node - The node to merge. + * @returns {void} + */ + merge(node) { + this.endNode = node; + } + + /** + * Resets this range by the given node or null. + * @param {ASTNode|null} node - The node to reset, or null. + * @returns {void} + */ + reset(node) { + this.startNode = this.endNode = node; + } +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -42,7 +111,9 @@ module.exports = { }, create: function(context) { - var currentCodePath = null; + let currentCodePath = null; + + const range = new ConsecutiveRange(context.getSourceCode()); /** * Reports a given node if it's unreachable. @@ -50,9 +121,42 @@ module.exports = { * @returns {void} */ function reportIfUnreachable(node) { - if (currentCodePath.currentSegments.every(isUnreachable)) { - context.report({message: "Unreachable code.", node: node}); + let nextNode = null; + + if (node && currentCodePath.currentSegments.every(isUnreachable)) { + + // Store this statement to distinguish consecutive statements. + if (range.isEmpty) { + range.reset(node); + return; + } + + // Skip if this statement is inside of the current range. + if (range.contains(node)) { + return; + } + + // Merge if this statement is consecutive to the current range. + if (range.isConsecutive(node)) { + range.merge(node); + return; + } + + nextNode = node; + } + + // Report the current range since this statement is reachable or is + // not consecutive to the current range. + if (!range.isEmpty) { + context.report({ + message: "Unreachable code.", + loc: range.location, + node: range.startNode + }); } + + // Update the current range. + range.reset(nextNode); } return { @@ -96,7 +200,11 @@ module.exports = { WithStatement: reportIfUnreachable, ExportNamedDeclaration: reportIfUnreachable, ExportDefaultDeclaration: reportIfUnreachable, - ExportAllDeclaration: reportIfUnreachable + ExportAllDeclaration: reportIfUnreachable, + + "Program:exit": function() { + reportIfUnreachable(); + } }; } }; diff --git a/tools/eslint/lib/rules/no-unsafe-finally.js b/tools/eslint/lib/rules/no-unsafe-finally.js index 8c3815459c1aec..305cce28ad1d03 100644 --- a/tools/eslint/lib/rules/no-unsafe-finally.js +++ b/tools/eslint/lib/rules/no-unsafe-finally.js @@ -9,9 +9,9 @@ // Helpers //------------------------------------------------------------------------------ -var SENTINEL_NODE_TYPE_RETURN_THROW = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression)$/; -var SENTINEL_NODE_TYPE_BREAK = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement|SwitchStatement)$/; -var SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement)$/; +let SENTINEL_NODE_TYPE_RETURN_THROW = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression)$/; +let SENTINEL_NODE_TYPE_BREAK = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement|SwitchStatement)$/; +let SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement)$/; //------------------------------------------------------------------------------ @@ -24,7 +24,9 @@ module.exports = { description: "disallow control flow statements in `finally` blocks", category: "Possible Errors", recommended: true - } + }, + + schema: [] }, create: function(context) { @@ -32,7 +34,7 @@ module.exports = { * Checks if the node is the finalizer of a TryStatement * * @param {ASTNode} node - node to check. - * @returns {Boolean} - true if the node is the finalizer of a TryStatement + * @returns {boolean} - true if the node is the finalizer of a TryStatement */ function isFinallyBlock(node) { return node.parent.type === "TryStatement" && node.parent.finalizer === node; @@ -42,12 +44,12 @@ module.exports = { * Climbs up the tree if the node is not a sentinel node * * @param {ASTNode} node - node to check. - * @param {String} label - label of the break or continue statement - * @returns {Boolean} - return whether the node is a finally block or a sentinel node + * @param {string} label - label of the break or continue statement + * @returns {boolean} - return whether the node is a finally block or a sentinel node */ function isInFinallyBlock(node, label) { - var labelInside = false; - var sentinelNodeType; + let labelInside = false; + let sentinelNodeType; if (node.type === "BreakStatement" && !node.label) { sentinelNodeType = SENTINEL_NODE_TYPE_BREAK; @@ -81,7 +83,7 @@ module.exports = { function check(node) { if (isInFinallyBlock(node, node.label)) { context.report({ - message: "Unsafe usage of " + node.type, + message: "Unsafe usage of " + node.type + ".", node: node, line: node.loc.line, column: node.loc.column diff --git a/tools/eslint/lib/rules/no-unused-expressions.js b/tools/eslint/lib/rules/no-unused-expressions.js index 9438268ab24c33..d2bdda70f21ee6 100644 --- a/tools/eslint/lib/rules/no-unused-expressions.js +++ b/tools/eslint/lib/rules/no-unused-expressions.js @@ -33,7 +33,7 @@ module.exports = { }, create: function(context) { - var config = context.options[0] || {}, + let config = context.options[0] || {}, allowShortCircuit = config.allowShortCircuit || false, allowTernary = config.allowTernary || false; @@ -52,12 +52,12 @@ module.exports = { * @returns {a[]} the leading sequence of members in the given list that pass the given predicate */ function takeWhile(predicate, list) { - for (var i = 0, l = list.length; i < l; ++i) { + for (let i = 0; i < list.length; ++i) { if (!predicate(list[i])) { - break; + return list.slice(0, i); } } - return [].slice.call(list, 0, i); + return list.slice(); } /** @@ -74,7 +74,7 @@ module.exports = { * @returns {boolean} whether the given node is considered a directive in its current position */ function isDirective(node, ancestors) { - var parent = ancestors[ancestors.length - 1], + let parent = ancestors[ancestors.length - 1], grandparent = ancestors[ancestors.length - 2]; return (parent.type === "Program" || parent.type === "BlockStatement" && diff --git a/tools/eslint/lib/rules/no-unused-labels.js b/tools/eslint/lib/rules/no-unused-labels.js index 77713fc408bca4..ec13c6168e7896 100644 --- a/tools/eslint/lib/rules/no-unused-labels.js +++ b/tools/eslint/lib/rules/no-unused-labels.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var scopeInfo = null; + let scopeInfo = null; /** * Adds a scope info to the stack. @@ -68,8 +68,8 @@ module.exports = { return; } - var label = node.label.name; - var info = scopeInfo; + let label = node.label.name; + let info = scopeInfo; while (info) { if (info.label === label) { diff --git a/tools/eslint/lib/rules/no-unused-vars.js b/tools/eslint/lib/rules/no-unused-vars.js index 39b7703c3c189a..951330de9bb1b4 100644 --- a/tools/eslint/lib/rules/no-unused-vars.js +++ b/tools/eslint/lib/rules/no-unused-vars.js @@ -9,8 +9,8 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); -var astUtils = require("../ast-utils"); +let lodash = require("lodash"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -60,15 +60,15 @@ module.exports = { create: function(context) { - var MESSAGE = "'{{name}}' is defined but never used"; + let MESSAGE = "'{{name}}' is defined but never used."; - var config = { + let config = { vars: "all", args: "after-used", caughtErrors: "none" }; - var firstOption = context.options[0]; + let firstOption = context.options[0]; if (firstOption) { if (typeof firstOption === "string") { @@ -96,7 +96,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var STATEMENT_TYPE = /(?:Statement|Declaration)$/; + let STATEMENT_TYPE = /(?:Statement|Declaration)$/; /** * Determines if a given variable is being exported from a module. @@ -106,11 +106,11 @@ module.exports = { */ function isExported(variable) { - var definition = variable.defs[0]; + let definition = variable.defs[0]; if (definition) { - var node = definition.node; + let node = definition.node; if (node.type === "VariableDeclarator") { node = node.parent; @@ -142,7 +142,7 @@ module.exports = { * @private */ function isSelfReference(ref, nodes) { - var scope = ref.from; + let scope = ref.from; while (scope) { if (nodes.indexOf(scope.block) >= 0) { @@ -155,12 +155,35 @@ module.exports = { return false; } + /** + * Checks whether a given node is inside of a loop or not. + * + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is inside of a loop. + * @private + */ + function isInsideOfLoop(node) { + while (node) { + if (astUtils.isLoop(node)) { + return true; + } + if (astUtils.isFunction(node)) { + return false; + } + + node = node.parent; + } + + return false; + } + /** * Checks the position of given nodes. * * @param {ASTNode} inner - A node which is expected as inside. * @param {ASTNode} outer - A node which is expected as outside. * @returns {boolean} `true` if the `inner` node exists in the `outer` node. + * @private */ function isInside(inner, outer) { return ( @@ -173,17 +196,25 @@ module.exports = { * If a given reference is left-hand side of an assignment, this gets * the right-hand side node of the assignment. * + * In the following cases, this returns null. + * + * - The reference is not the LHS of an assignment expression. + * - The reference is inside of a loop. + * - The reference is inside of a function scope which is different from + * the declaration. + * * @param {escope.Reference} ref - A reference to check. * @param {ASTNode} prevRhsNode - The previous RHS node. - * @returns {ASTNode} The RHS node. + * @returns {ASTNode|null} The RHS node or null. + * @private */ function getRhsNode(ref, prevRhsNode) { - var id = ref.identifier; - var parent = id.parent; - var granpa = parent.parent; - var refScope = ref.from.variableScope; - var varScope = ref.resolved.scope.variableScope; - var canBeUsedLater = refScope !== varScope; + let id = ref.identifier; + let parent = id.parent; + let granpa = parent.parent; + let refScope = ref.from.variableScope; + let varScope = ref.resolved.scope.variableScope; + let canBeUsedLater = refScope !== varScope || isInsideOfLoop(id); /* * Inherits the previous node if this reference is in the node. @@ -213,10 +244,11 @@ module.exports = { * - the funcNode is assigned to a variable. * - the funcNode is bound as an argument of a function call. * - the function is bound to a property and the object satisfies above conditions. + * @private */ function isStorableFunction(funcNode, rhsNode) { - var node = funcNode; - var parent = funcNode.parent; + let node = funcNode; + let parent = funcNode.parent; while (parent && isInside(parent, rhsNode)) { switch (parent.type) { @@ -266,9 +298,10 @@ module.exports = { * @param {ASTNode} id - An Identifier node to check. * @param {ASTNode} rhsNode - The RHS node of the previous assignment. * @returns {boolean} `true` if the `id` node exists inside of a function node which can be used later. + * @private */ function isInsideOfStorableFunction(id, rhsNode) { - var funcNode = astUtils.getUpperFunction(id); + let funcNode = astUtils.getUpperFunction(id); return ( funcNode && @@ -283,11 +316,12 @@ module.exports = { * @param {escope.Reference} ref - A reference to check. * @param {ASTNode} rhsNode - The RHS node of the previous assignment. * @returns {boolean} The reference is a read to update itself. + * @private */ function isReadForItself(ref, rhsNode) { - var id = ref.identifier; - var parent = id.parent; - var granpa = parent.parent; + let id = ref.identifier; + let parent = id.parent; + let granpa = parent.parent; return ref.isRead() && ( @@ -319,7 +353,7 @@ module.exports = { * @private */ function isForInRef(ref) { - var target = ref.identifier.parent; + let target = ref.identifier.parent; // "for (var ...) { return; }" @@ -355,7 +389,7 @@ module.exports = { * @private */ function isUsedVariable(variable) { - var functionNodes = variable.defs.filter(function(def) { + let functionNodes = variable.defs.filter(function(def) { return def.type === "FunctionName"; }).map(function(def) { return def.node; @@ -368,7 +402,7 @@ module.exports = { return true; } - var forItself = isReadForItself(ref, rhsNode); + let forItself = isReadForItself(ref, rhsNode); rhsNode = getRhsNode(ref, rhsNode); @@ -388,13 +422,13 @@ module.exports = { * @private */ function collectUnusedVariables(scope, unusedVars) { - var variables = scope.variables; - var childScopes = scope.childScopes; - var i, l; + let variables = scope.variables; + let childScopes = scope.childScopes; + let i, l; if (scope.type !== "TDZ" && (scope.type !== "global" || config.vars === "all")) { for (i = 0, l = variables.length; i < l; ++i) { - var variable = variables[i]; + let variable = variables[i]; // skip a variable of class itself name in the class scope if (scope.type === "class" && scope.block.id === variable.identifiers[0]) { @@ -412,10 +446,10 @@ module.exports = { } // explicit global variables don't have definitions. - var def = variable.defs[0]; + let def = variable.defs[0]; if (def) { - var type = def.type; + let type = def.type; // skip catch variables if (type === "CatchClause") { @@ -480,13 +514,13 @@ module.exports = { * @private */ function getColumnInComment(variable, comment) { - var namePattern = new RegExp("[\\s,]" + lodash.escapeRegExp(variable.name) + "(?:$|[\\s,:])", "g"); + let namePattern = new RegExp("[\\s,]" + lodash.escapeRegExp(variable.name) + "(?:$|[\\s,:])", "g"); // To ignore the first text "global". namePattern.lastIndex = comment.value.indexOf("global") + 6; // Search a given variable name. - var match = namePattern.exec(comment.value); + let match = namePattern.exec(comment.value); return match ? match.index + 1 : 0; } @@ -500,11 +534,11 @@ module.exports = { * @private */ function getLocation(variable) { - var comment = variable.eslintExplicitGlobalComment; - var baseLoc = comment.loc.start; - var column = getColumnInComment(variable, comment); - var prefix = comment.value.slice(0, column); - var lineInComment = (prefix.match(/\n/g) || []).length; + let comment = variable.eslintExplicitGlobalComment; + let baseLoc = comment.loc.start; + let column = getColumnInComment(variable, comment); + let prefix = comment.value.slice(0, column); + let lineInComment = (prefix.match(/\n/g) || []).length; if (lineInComment > 0) { column -= 1 + prefix.lastIndexOf("\n"); @@ -526,10 +560,10 @@ module.exports = { return { "Program:exit": function(programNode) { - var unusedVars = collectUnusedVariables(context.getScope(), []); + let unusedVars = collectUnusedVariables(context.getScope(), []); - for (var i = 0, l = unusedVars.length; i < l; ++i) { - var unusedVar = unusedVars[i]; + for (let i = 0, l = unusedVars.length; i < l; ++i) { + let unusedVar = unusedVars[i]; if (unusedVar.eslintExplicitGlobal) { context.report({ diff --git a/tools/eslint/lib/rules/no-use-before-define.js b/tools/eslint/lib/rules/no-use-before-define.js index 889e709948259c..90dd05c8b1bbf6 100644 --- a/tools/eslint/lib/rules/no-use-before-define.js +++ b/tools/eslint/lib/rules/no-use-before-define.js @@ -9,17 +9,18 @@ // Helpers //------------------------------------------------------------------------------ -var SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/; +let SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/; +let FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/; /** * Parses a given value as options. * * @param {any} options - A value to parse. - * @returns {object} The parsed options. + * @returns {Object} The parsed options. */ function parseOptions(options) { - var functions = true; - var classes = true; + let functions = true; + let classes = true; if (typeof options === "string") { functions = (options !== "nofunc"); @@ -87,6 +88,14 @@ function isInRange(node, location) { /** * Checks whether or not a given reference is inside of the initializers of a given variable. * + * This returns `true` in the following cases: + * + * var a = a + * var [a = a] = list + * var {a = a} = obj + * for (var a in a) {} + * for (var a of a) {} + * * @param {Variable} variable - A variable to check. * @param {Reference} reference - A reference to check. * @returns {boolean} `true` if the reference is inside of the initializers. @@ -96,14 +105,19 @@ function isInInitializer(variable, reference) { return false; } - var node = variable.identifiers[0].parent; - var location = reference.identifier.range[1]; + let node = variable.identifiers[0].parent; + let location = reference.identifier.range[1]; while (node) { if (node.type === "VariableDeclarator") { if (isInRange(node.init, location)) { return true; } + if (FOR_IN_OF_TYPE.test(node.parent.parent.type) && + isInRange(node.parent.parent.right, location) + ) { + return true; + } break; } else if (node.type === "AssignmentPattern") { if (isInRange(node.right, location)) { @@ -151,10 +165,10 @@ module.exports = { }, create: function(context) { - var options = parseOptions(context.options[0]); + let options = parseOptions(context.options[0]); // Defines a function which checks whether or not a reference is allowed according to the option. - var isAllowed; + let isAllowed; if (options.functions && options.classes) { isAllowed = alwaysFalse; @@ -174,7 +188,7 @@ module.exports = { */ function findVariablesInScope(scope) { scope.references.forEach(function(reference) { - var variable = reference.resolved; + let variable = reference.resolved; // Skips when the reference is: // - initialization's. @@ -194,7 +208,7 @@ module.exports = { // Reports. context.report({ node: reference.identifier, - message: "'{{name}}' was used before it was defined", + message: "'{{name}}' was used before it was defined.", data: reference.identifier }); }); @@ -207,14 +221,14 @@ module.exports = { * @private */ function findVariables() { - var scope = context.getScope(); + let scope = context.getScope(); findVariablesInScope(scope); } - var ruleDefinition = { + let ruleDefinition = { "Program:exit": function(node) { - var scope = context.getScope(), + let scope = context.getScope(), ecmaFeatures = context.parserOptions.ecmaFeatures || {}; findVariablesInScope(scope); diff --git a/tools/eslint/lib/rules/no-useless-call.js b/tools/eslint/lib/rules/no-useless-call.js index 49cbbc5401c7f5..b05292ff79ee71 100644 --- a/tools/eslint/lib/rules/no-useless-call.js +++ b/tools/eslint/lib/rules/no-useless-call.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -36,13 +36,13 @@ function isCallOrNonVariadicApply(node) { * @returns {boolean} the source code for the given node. */ function equalTokens(left, right, sourceCode) { - var tokensL = sourceCode.getTokens(left); - var tokensR = sourceCode.getTokens(right); + let tokensL = sourceCode.getTokens(left); + let tokensR = sourceCode.getTokens(right); if (tokensL.length !== tokensR.length) { return false; } - for (var i = 0; i < tokensL.length; ++i) { + for (let i = 0; i < tokensL.length; ++i) { if (tokensL[i].type !== tokensR[i].type || tokensL[i].value !== tokensR[i].value ) { @@ -83,7 +83,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { CallExpression: function(node) { @@ -91,9 +91,9 @@ module.exports = { return; } - var applied = node.callee.object; - var expectedThis = (applied.type === "MemberExpression") ? applied.object : null; - var thisArg = node.arguments[0]; + let applied = node.callee.object; + let expectedThis = (applied.type === "MemberExpression") ? applied.object : null; + let thisArg = node.arguments[0]; if (isValidThisArg(expectedThis, thisArg, sourceCode)) { context.report( diff --git a/tools/eslint/lib/rules/no-useless-computed-key.js b/tools/eslint/lib/rules/no-useless-computed-key.js index 2e0ac18019a70e..f25b9e547433ed 100644 --- a/tools/eslint/lib/rules/no-useless-computed-key.js +++ b/tools/eslint/lib/rules/no-useless-computed-key.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{property}}] found."; +let MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{property}}] found."; module.exports = { meta: { @@ -16,10 +16,12 @@ module.exports = { description: "disallow unnecessary computed property keys in object literals", category: "ECMAScript 6", recommended: false - } + }, + + schema: [] }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Property: function(node) { @@ -27,7 +29,7 @@ module.exports = { return; } - var key = node.key, + let key = node.key, nodeType = typeof key.value; if (key.type === "Literal" && (nodeType === "string" || nodeType === "number")) { diff --git a/tools/eslint/lib/rules/no-useless-concat.js b/tools/eslint/lib/rules/no-useless-concat.js index 8569d4276a4454..6c4cecd7b67139 100644 --- a/tools/eslint/lib/rules/no-useless-concat.js +++ b/tools/eslint/lib/rules/no-useless-concat.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -29,7 +29,7 @@ function isConcatenation(node) { * @returns {ASTNode} node */ function getLeft(node) { - var left = node.left; + let left = node.left; while (isConcatenation(left)) { left = left.right; @@ -43,7 +43,7 @@ function getLeft(node) { * @returns {ASTNode} node */ function getRight(node) { - var right = node.right; + let right = node.right; while (isConcatenation(right)) { right = right.left; @@ -67,7 +67,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { BinaryExpression: function(node) { @@ -78,8 +78,8 @@ module.exports = { } // account for the `foo + "a" + "b"` case - var left = getLeft(node); - var right = getRight(node); + let left = getLeft(node); + let right = getRight(node); if (astUtils.isStringLiteral(left) && astUtils.isStringLiteral(right) && @@ -87,7 +87,7 @@ module.exports = { ) { // move warning location to operator - var operatorToken = sourceCode.getTokenAfter(left); + let operatorToken = sourceCode.getTokenAfter(left); while (operatorToken.value !== "+") { operatorToken = sourceCode.getTokenAfter(operatorToken); diff --git a/tools/eslint/lib/rules/no-useless-constructor.js b/tools/eslint/lib/rules/no-useless-constructor.js index b91ab4bcae5866..f6be08f69da43d 100644 --- a/tools/eslint/lib/rules/no-useless-constructor.js +++ b/tools/eslint/lib/rules/no-useless-constructor.js @@ -109,7 +109,7 @@ function isPassingThrough(ctorParams, superArgs) { return false; } - for (var i = 0; i < ctorParams.length; ++i) { + for (let i = 0; i < ctorParams.length; ++i) { if (!isValidPair(ctorParams[i], superArgs[i])) { return false; } @@ -163,9 +163,9 @@ module.exports = { return; } - var body = node.value.body.body; - var ctorParams = node.value.params; - var superClass = node.parent.parent.superClass; + let body = node.value.body.body; + let ctorParams = node.value.params; + let superClass = node.parent.parent.superClass; if (superClass ? isRedundantSuperCall(body, ctorParams) : (body.length === 0)) { context.report({ diff --git a/tools/eslint/lib/rules/no-useless-escape.js b/tools/eslint/lib/rules/no-useless-escape.js index 036831fc394f4f..226a9da16590d2 100644 --- a/tools/eslint/lib/rules/no-useless-escape.js +++ b/tools/eslint/lib/rules/no-useless-escape.js @@ -9,7 +9,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var VALID_STRING_ESCAPES = [ +let VALID_STRING_ESCAPES = [ "\\", "n", "r", @@ -23,7 +23,7 @@ var VALID_STRING_ESCAPES = [ "\r" ]; -var VALID_REGEX_ESCAPES = [ +let VALID_REGEX_ESCAPES = [ "\\", ".", "-", @@ -80,8 +80,8 @@ module.exports = { * @returns {void} */ function validate(escapes, node, elm) { - var escapeNotFound = escapes.indexOf(elm[0][1]) === -1; - var isQuoteEscape = elm[0][1] === node.raw[0]; + let escapeNotFound = escapes.indexOf(elm[0][1]) === -1; + let isQuoteEscape = elm[0][1] === node.raw[0]; if (escapeNotFound && !isQuoteEscape) { context.report({ @@ -90,7 +90,7 @@ module.exports = { line: node.loc.start.line, column: node.loc.start.column + elm.index }, - message: "Unnecessary escape character: " + elm[0] + message: "Unnecessary escape character: " + elm[0] + "." }); } } @@ -102,8 +102,8 @@ module.exports = { * @returns {void} */ function check(node) { - var nodeEscapes, match; - var pattern = /\\[^\d]/g; + let nodeEscapes, match; + let pattern = /\\[^\d]/g; if (typeof node.value === "string") { diff --git a/tools/eslint/lib/rules/no-useless-rename.js b/tools/eslint/lib/rules/no-useless-rename.js index ec2282784b572c..80539e57723ad3 100644 --- a/tools/eslint/lib/rules/no-useless-rename.js +++ b/tools/eslint/lib/rules/no-useless-rename.js @@ -31,7 +31,7 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, ignoreDestructuring = options.ignoreDestructuring === true, ignoreImport = options.ignoreImport === true, ignoreExport = options.ignoreExport === true; @@ -49,7 +49,7 @@ module.exports = { * @returns {void} */ function reportError(node, initial, result, type) { - var name = initial.type === "Identifier" ? initial.name : initial.value; + let name = initial.type === "Identifier" ? initial.name : initial.value; return context.report({ node: node, @@ -73,7 +73,7 @@ module.exports = { * @returns {void} */ function checkDestructured(node) { - var properties, + let properties, i; if (ignoreDestructuring) { diff --git a/tools/eslint/lib/rules/no-var.js b/tools/eslint/lib/rules/no-var.js index 2e9948a330e190..fc7783d7160e40 100644 --- a/tools/eslint/lib/rules/no-var.js +++ b/tools/eslint/lib/rules/no-var.js @@ -5,6 +5,72 @@ "use strict"; +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +let SCOPE_NODE_TYPE = /^(?:Program|BlockStatement|SwitchStatement|ForStatement|ForInStatement|ForOfStatement)$/; + +/** + * Gets the scope node which directly contains a given node. + * + * @param {ASTNode} node - A node to get. This is a `VariableDeclaration` or + * an `Identifier`. + * @returns {ASTNode} A scope node. This is one of `Program`, `BlockStatement`, + * `SwitchStatement`, `ForStatement`, `ForInStatement`, and + * `ForOfStatement`. + */ +function getScopeNode(node) { + while (node) { + if (SCOPE_NODE_TYPE.test(node.type)) { + return node; + } + + node = node.parent; + } + + /* istanbul ignore next : unreachable */ + return null; +} + +/** + * Checks whether a given variable is redeclared or not. + * + * @param {escope.Variable} variable - A variable to check. + * @returns {boolean} `true` if the variable is redeclared. + */ +function isRedeclared(variable) { + return variable.defs.length >= 2; +} + +/** + * Checks whether a given variable is used from outside of the specified scope. + * + * @param {ASTNode} scopeNode - A scope node to check. + * @returns {Function} The predicate function which checks whether a given + * variable is used from outside of the specified scope. + */ +function isUsedFromOutsideOf(scopeNode) { + + /** + * Checks whether a given reference is inside of the specified scope or not. + * + * @param {escope.Reference} reference - A reference to check. + * @returns {boolean} `true` if the reference is inside of the specified + * scope. + */ + function isOutsideOfScope(reference) { + let scope = scopeNode.range; + let id = reference.identifier.range; + + return id[0] < scope[0] || id[1] > scope[1]; + } + + return function(variable) { + return variable.references.some(isOutsideOfScope); + }; +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -17,19 +83,80 @@ module.exports = { recommended: false }, - schema: [] + schema: [], + fixable: "code" }, create: function(context) { + let sourceCode = context.getSourceCode(); + + /** + * Checks whether it can fix a given variable declaration or not. + * It cannot fix if the following cases: + * + * - A variable is declared on a SwitchCase node. + * - A variable is redeclared. + * - A variable is used from outside the scope. + * + * ## A variable is declared on a SwitchCase node. + * + * If this rule modifies 'var' declarations on a SwitchCase node, it + * would generate the warnings of 'no-case-declarations' rule. And the + * 'eslint:recommended' preset includes 'no-case-declarations' rule, so + * this rule doesn't modify those declarations. + * + * ## A variable is redeclared. + * + * The language spec disallows redeclarations of `let` declarations. + * Those variables would cause syntax errors. + * + * ## A variable is used from outside the scope. + * + * The language spec disallows accesses from outside of the scope for + * `let` declarations. Those variables would cause reference errors. + * + * @param {ASTNode} node - A variable declaration node to check. + * @returns {boolean} `true` if it can fix the node. + */ + function canFix(node) { + let variables = context.getDeclaredVariables(node); + let scopeNode = getScopeNode(node); + + return !( + node.parent.type === "SwitchCase" || + variables.some(isRedeclared) || + variables.some(isUsedFromOutsideOf(scopeNode)) + ); + } + + /** + * Reports a given variable declaration node. + * + * @param {ASTNode} node - A variable declaration node to report. + * @returns {void} + */ + function report(node) { + let varToken = sourceCode.getFirstToken(node); + + context.report({ + node: node, + message: "Unexpected var, use let or const instead.", + + fix: function(fixer) { + if (canFix(node)) { + return fixer.replaceText(varToken, "let"); + } + return null; + } + }); + } return { VariableDeclaration: function(node) { if (node.kind === "var") { - context.report(node, "Unexpected var, use let or const instead."); + report(node); } } - }; - } }; diff --git a/tools/eslint/lib/rules/no-warning-comments.js b/tools/eslint/lib/rules/no-warning-comments.js index dadf231f5c39f0..7db6ed1234b830 100644 --- a/tools/eslint/lib/rules/no-warning-comments.js +++ b/tools/eslint/lib/rules/no-warning-comments.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -40,7 +40,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0] || {}, + let configuration = context.options[0] || {}, warningTerms = configuration.terms || ["todo", "fixme", "xxx"], location = configuration.location || "start", selfConfigRegEx = /\bno-warning-comments\b/, @@ -51,11 +51,11 @@ module.exports = { * location ("start" or "anywhere"). If the term starts or ends with non word characters, then the match will not * require word boundaries on that side. * - * @param {String} term A term to convert to a RegExp + * @param {string} term A term to convert to a RegExp * @returns {RegExp} The term converted to a RegExp */ function convertToRegExp(term) { - var escaped = term.replace(/[-\/\\$\^*+?.()|\[\]{}]/g, "\\$&"), + let escaped = term.replace(/[-\/\\$\^*+?.()|\[\]{}]/g, "\\$&"), suffix, prefix; @@ -89,11 +89,11 @@ module.exports = { /** * Checks the specified comment for matches of the configured warning terms and returns the matches. - * @param {String} comment The comment which is checked. + * @param {string} comment The comment which is checked. * @returns {Array} All matched warning terms for this comment. */ function commentContainsWarningTerm(comment) { - var matches = []; + let matches = []; warningRegExps.forEach(function(regex, index) { if (regex.test(comment)) { @@ -114,7 +114,7 @@ module.exports = { return; } - var matches = commentContainsWarningTerm(node.value); + let matches = commentContainsWarningTerm(node.value); matches.forEach(function(matchedTerm) { context.report(node, "Unexpected '" + matchedTerm + "' comment."); diff --git a/tools/eslint/lib/rules/no-whitespace-before-property.js b/tools/eslint/lib/rules/no-whitespace-before-property.js index 347c63d934f166..fd13ba9d5d530c 100644 --- a/tools/eslint/lib/rules/no-whitespace-before-property.js +++ b/tools/eslint/lib/rules/no-whitespace-before-property.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -23,7 +23,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -36,7 +36,7 @@ module.exports = { * @private */ function findOpeningBracket(node) { - var token = sourceCode.getTokenBefore(node.property); + let token = sourceCode.getTokenBefore(node.property); while (token.value !== "[") { token = sourceCode.getTokenBefore(token); @@ -53,7 +53,7 @@ module.exports = { * @private */ function reportError(node, leftToken, rightToken) { - var replacementText = node.computed ? "" : "."; + let replacementText = node.computed ? "" : "."; context.report({ node: node, @@ -73,8 +73,8 @@ module.exports = { return { MemberExpression: function(node) { - var rightToken; - var leftToken; + let rightToken; + let leftToken; if (!astUtils.isTokenOnSameLine(node.object, node.property)) { return; diff --git a/tools/eslint/lib/rules/object-curly-newline.js b/tools/eslint/lib/rules/object-curly-newline.js index aaa4af02a28f55..b69bd190447af0 100644 --- a/tools/eslint/lib/rules/object-curly-newline.js +++ b/tools/eslint/lib/rules/object-curly-newline.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ // Schema objects. -var OPTION_VALUE = { +let OPTION_VALUE = { oneOf: [ { enum: ["always", "never"] @@ -41,12 +41,12 @@ var OPTION_VALUE = { /** * Normalizes a given option value. * - * @param {string|object|undefined} value - An option value to parse. + * @param {string|Object|undefined} value - An option value to parse. * @returns {{multiline: boolean, minProperties: number}} Normalized option object. */ function normalizeOptionValue(value) { - var multiline = false; - var minProperties = Number.POSITIVE_INFINITY; + let multiline = false; + let minProperties = Number.POSITIVE_INFINITY; if (value) { if (value === "always") { @@ -67,7 +67,7 @@ function normalizeOptionValue(value) { /** * Normalizes a given option value. * - * @param {string|object|undefined} options - An option value to parse. + * @param {string|Object|undefined} options - An option value to parse. * @returns {{ObjectExpression: {multiline: boolean, minProperties: number}, ObjectPattern: {multiline: boolean, minProperties: number}}} Normalized option object. */ function normalizeOptions(options) { @@ -78,7 +78,7 @@ function normalizeOptions(options) { }; } - var value = normalizeOptionValue(options); + let value = normalizeOptionValue(options); return {ObjectExpression: value, ObjectPattern: value}; } @@ -114,8 +114,8 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var normalizedOptions = normalizeOptions(context.options[0]); + let sourceCode = context.getSourceCode(); + let normalizedOptions = normalizeOptions(context.options[0]); /** * Reports a given node if it violated this rule. @@ -125,12 +125,12 @@ module.exports = { * @returns {void} */ function check(node) { - var options = normalizedOptions[node.type]; - var openBrace = sourceCode.getFirstToken(node); - var closeBrace = sourceCode.getLastToken(node); - var first = sourceCode.getTokenOrCommentAfter(openBrace); - var last = sourceCode.getTokenOrCommentBefore(closeBrace); - var needsLinebreaks = ( + let options = normalizedOptions[node.type]; + let openBrace = sourceCode.getFirstToken(node); + let closeBrace = sourceCode.getLastToken(node); + let first = sourceCode.getTokenOrCommentAfter(openBrace); + let last = sourceCode.getTokenOrCommentBefore(closeBrace); + let needsLinebreaks = ( node.properties.length >= options.minProperties || ( options.multiline && @@ -153,7 +153,7 @@ module.exports = { if (needsLinebreaks) { if (astUtils.isTokenOnSameLine(openBrace, first)) { context.report({ - message: "Expected a line break after this open brace.", + message: "Expected a line break after this opening brace.", node: node, loc: openBrace.loc.start, fix: function(fixer) { @@ -163,7 +163,7 @@ module.exports = { } if (astUtils.isTokenOnSameLine(last, closeBrace)) { context.report({ - message: "Expected a line break before this close brace.", + message: "Expected a line break before this closing brace.", node: node, loc: closeBrace.loc.start, fix: function(fixer) { @@ -174,7 +174,7 @@ module.exports = { } else { if (!astUtils.isTokenOnSameLine(openBrace, first)) { context.report({ - message: "Unexpected a line break after this open brace.", + message: "Unexpected line break after this opening brace.", node: node, loc: openBrace.loc.start, fix: function(fixer) { @@ -187,7 +187,7 @@ module.exports = { } if (!astUtils.isTokenOnSameLine(last, closeBrace)) { context.report({ - message: "Unexpected a line break before this close brace.", + message: "Unexpected line break before this closing brace.", node: node, loc: closeBrace.loc.start, fix: function(fixer) { diff --git a/tools/eslint/lib/rules/object-curly-spacing.js b/tools/eslint/lib/rules/object-curly-spacing.js index e5dfb8d036cb04..4fe1f85758be67 100644 --- a/tools/eslint/lib/rules/object-curly-spacing.js +++ b/tools/eslint/lib/rules/object-curly-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -40,7 +40,7 @@ module.exports = { }, create: function(context) { - var spaced = context.options[0] === "always", + let spaced = context.options[0] === "always", sourceCode = context.getSourceCode(); /** @@ -54,7 +54,7 @@ module.exports = { return context.options[1] ? context.options[1][option] === !spaced : false; } - var options = { + let options = { spaced: spaced, arraysInObjectsException: isOptionSet("arraysInObjects"), objectsInObjectsException: isOptionSet("objectsInObjects") @@ -74,9 +74,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space after '" + token.value + "'", + message: "There should be no space after '" + token.value + "'.", fix: function(fixer) { - var nextToken = context.getSourceCode().getTokenAfter(token); + let nextToken = context.getSourceCode().getTokenAfter(token); return fixer.removeRange([token.range[1], nextToken.range[0]]); } @@ -93,9 +93,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space before '" + token.value + "'", + message: "There should be no space before '" + token.value + "'.", fix: function(fixer) { - var previousToken = context.getSourceCode().getTokenBefore(token); + let previousToken = context.getSourceCode().getTokenBefore(token); return fixer.removeRange([previousToken.range[1], token.range[0]]); } @@ -112,7 +112,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required after '" + token.value + "'", + message: "A space is required after '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextAfter(token, " "); } @@ -129,7 +129,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required before '" + token.value + "'", + message: "A space is required before '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextBefore(token, " "); } @@ -146,7 +146,7 @@ module.exports = { * @returns {void} */ function validateBraceSpacing(node, first, second, penultimate, last) { - var shouldCheckPenultimate, + let shouldCheckPenultimate, penultimateType, closingCurlyBraceMustBeSpaced, firstSpaced, @@ -195,7 +195,7 @@ module.exports = { return; } - var first = sourceCode.getFirstToken(node), + let first = sourceCode.getFirstToken(node), last = sourceCode.getLastToken(node), second = sourceCode.getTokenAfter(first), penultimate = sourceCode.getTokenBefore(last); @@ -213,7 +213,7 @@ module.exports = { return; } - var firstSpecifier = node.specifiers[0], + let firstSpecifier = node.specifiers[0], lastSpecifier = node.specifiers[node.specifiers.length - 1]; if (lastSpecifier.type !== "ImportSpecifier") { @@ -223,7 +223,7 @@ module.exports = { firstSpecifier = node.specifiers[1]; } - var first = sourceCode.getTokenBefore(firstSpecifier), + let first = sourceCode.getTokenBefore(firstSpecifier), last = sourceCode.getTokenAfter(lastSpecifier); // to support a trailing comma. @@ -231,7 +231,7 @@ module.exports = { last = sourceCode.getTokenAfter(last); } - var second = sourceCode.getTokenAfter(first), + let second = sourceCode.getTokenAfter(first), penultimate = sourceCode.getTokenBefore(last); validateBraceSpacing(node, first, second, penultimate, last); @@ -247,7 +247,7 @@ module.exports = { return; } - var firstSpecifier = node.specifiers[0], + let firstSpecifier = node.specifiers[0], lastSpecifier = node.specifiers[node.specifiers.length - 1], first = sourceCode.getTokenBefore(firstSpecifier), last = sourceCode.getTokenAfter(lastSpecifier); @@ -257,7 +257,7 @@ module.exports = { last = sourceCode.getTokenAfter(last); } - var second = sourceCode.getTokenAfter(first), + let second = sourceCode.getTokenAfter(first), penultimate = sourceCode.getTokenBefore(last); validateBraceSpacing(node, first, second, penultimate, last); diff --git a/tools/eslint/lib/rules/object-property-newline.js b/tools/eslint/lib/rules/object-property-newline.js index eb96152bb167cb..fef7b871b442e1 100644 --- a/tools/eslint/lib/rules/object-property-newline.js +++ b/tools/eslint/lib/rules/object-property-newline.js @@ -31,21 +31,21 @@ module.exports = { }, create: function(context) { - var allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine); - var errorMessage = allowSameLine ? - "Object properties must go on a new line if they aren't all on the same line" : - "Object properties must go on a new line"; + let allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine); + let errorMessage = allowSameLine ? + "Object properties must go on a new line if they aren't all on the same line." : + "Object properties must go on a new line."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { ObjectExpression: function(node) { - var lastTokenOfPreviousProperty, firstTokenOfCurrentProperty; + let lastTokenOfPreviousProperty, firstTokenOfCurrentProperty; if (allowSameLine) { if (node.properties.length > 1) { - var firstTokenOfFirstProperty = sourceCode.getFirstToken(node.properties[0]); - var lastTokenOfLastProperty = sourceCode.getLastToken(node.properties[node.properties.length - 1]); + let firstTokenOfFirstProperty = sourceCode.getFirstToken(node.properties[0]); + let lastTokenOfLastProperty = sourceCode.getLastToken(node.properties[node.properties.length - 1]); if (firstTokenOfFirstProperty.loc.end.line === lastTokenOfLastProperty.loc.start.line) { @@ -55,7 +55,7 @@ module.exports = { } } - for (var i = 1; i < node.properties.length; i++) { + for (let i = 1; i < node.properties.length; i++) { lastTokenOfPreviousProperty = sourceCode.getLastToken(node.properties[i - 1]); firstTokenOfCurrentProperty = sourceCode.getFirstToken(node.properties[i]); diff --git a/tools/eslint/lib/rules/object-shorthand.js b/tools/eslint/lib/rules/object-shorthand.js index a528c00d38f0a8..1d08178d57e58f 100644 --- a/tools/eslint/lib/rules/object-shorthand.js +++ b/tools/eslint/lib/rules/object-shorthand.js @@ -5,7 +5,7 @@ "use strict"; -var OPTIONS = { +let OPTIONS = { always: "always", never: "never", methods: "methods", @@ -83,14 +83,14 @@ module.exports = { }, create: function(context) { - var APPLY = context.options[0] || OPTIONS.always; - var APPLY_TO_METHODS = APPLY === OPTIONS.methods || APPLY === OPTIONS.always; - var APPLY_TO_PROPS = APPLY === OPTIONS.properties || APPLY === OPTIONS.always; - var APPLY_NEVER = APPLY === OPTIONS.never; + let APPLY = context.options[0] || OPTIONS.always; + let APPLY_TO_METHODS = APPLY === OPTIONS.methods || APPLY === OPTIONS.always; + let APPLY_TO_PROPS = APPLY === OPTIONS.properties || APPLY === OPTIONS.always; + let APPLY_NEVER = APPLY === OPTIONS.never; - var PARAMS = context.options[1] || {}; - var IGNORE_CONSTRUCTORS = PARAMS.ignoreConstructors; - var AVOID_QUOTES = PARAMS.avoidQuotes; + let PARAMS = context.options[1] || {}; + let IGNORE_CONSTRUCTORS = PARAMS.ignoreConstructors; + let AVOID_QUOTES = PARAMS.avoidQuotes; //-------------------------------------------------------------------------- // Helpers @@ -103,7 +103,7 @@ module.exports = { * @private */ function isConstructor(name) { - var firstChar = name.charAt(0); + let firstChar = name.charAt(0); return firstChar === firstChar.toUpperCase(); } @@ -123,7 +123,7 @@ module.exports = { return { Property: function(node) { - var isConciseProperty = node.method || node.shorthand, + let isConciseProperty = node.method || node.shorthand, type; // Ignore destructuring assignment diff --git a/tools/eslint/lib/rules/one-var-declaration-per-line.js b/tools/eslint/lib/rules/one-var-declaration-per-line.js index f4cdb84b187fa2..e7a29fb115dc5c 100644 --- a/tools/eslint/lib/rules/one-var-declaration-per-line.js +++ b/tools/eslint/lib/rules/one-var-declaration-per-line.js @@ -25,8 +25,8 @@ module.exports = { create: function(context) { - var ERROR_MESSAGE = "Expected variable declaration to be on a new line."; - var always = context.options[0] === "always"; + let ERROR_MESSAGE = "Expected variable declaration to be on a new line."; + let always = context.options[0] === "always"; //-------------------------------------------------------------------------- // Helpers @@ -54,8 +54,8 @@ module.exports = { return; } - var declarations = node.declarations; - var prev; + let declarations = node.declarations; + let prev; declarations.forEach(function(current) { if (prev && prev.loc.end.line === current.loc.start.line) { diff --git a/tools/eslint/lib/rules/one-var.js b/tools/eslint/lib/rules/one-var.js index 2bd49f511f4f15..10cdb626e57dd0 100644 --- a/tools/eslint/lib/rules/one-var.js +++ b/tools/eslint/lib/rules/one-var.js @@ -57,12 +57,12 @@ module.exports = { create: function(context) { - var MODE_ALWAYS = "always", + let MODE_ALWAYS = "always", MODE_NEVER = "never"; - var mode = context.options[0] || MODE_ALWAYS; + let mode = context.options[0] || MODE_ALWAYS; - var options = { + let options = { }; if (typeof mode === "string") { // simple options configuration with just a string @@ -113,8 +113,8 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var functionStack = []; - var blockStack = []; + let functionStack = []; + let blockStack = []; /** * Increments the blockStack counter. @@ -166,7 +166,7 @@ module.exports = { * @private */ function recordTypes(statementType, declarations, currentScope) { - for (var i = 0; i < declarations.length; i++) { + for (let i = 0; i < declarations.length; i++) { if (declarations[i].init === null) { if (options[statementType] && options[statementType].uninitialized === MODE_ALWAYS) { currentScope.uninitialized = true; @@ -185,7 +185,7 @@ module.exports = { * @returns {Object} The scope associated with statementType */ function getCurrentScope(statementType) { - var currentScope; + let currentScope; if (statementType === "var") { currentScope = functionStack[functionStack.length - 1]; @@ -204,9 +204,9 @@ module.exports = { * @private */ function countDeclarations(declarations) { - var counts = { uninitialized: 0, initialized: 0 }; + let counts = { uninitialized: 0, initialized: 0 }; - for (var i = 0; i < declarations.length; i++) { + for (let i = 0; i < declarations.length; i++) { if (declarations[i].init === null) { counts.uninitialized++; } else { @@ -225,9 +225,9 @@ module.exports = { */ function hasOnlyOneStatement(statementType, declarations) { - var declarationCounts = countDeclarations(declarations); - var currentOptions = options[statementType] || {}; - var currentScope = getCurrentScope(statementType); + let declarationCounts = countDeclarations(declarations); + let currentOptions = options[statementType] || {}; + let currentScope = getCurrentScope(statementType); if (currentOptions.uninitialized === MODE_ALWAYS && currentOptions.initialized === MODE_ALWAYS) { if (currentScope.uninitialized || currentScope.initialized) { @@ -266,7 +266,7 @@ module.exports = { SwitchStatement: startBlock, VariableDeclaration: function(node) { - var parent = node.parent, + let parent = node.parent, type, declarations, declarationCounts; type = node.kind; @@ -296,7 +296,7 @@ module.exports = { // never if (parent.type !== "ForStatement" || parent.init !== node) { - var totalDeclarations = declarationCounts.uninitialized + declarationCounts.initialized; + let totalDeclarations = declarationCounts.uninitialized + declarationCounts.initialized; if (totalDeclarations > 1) { diff --git a/tools/eslint/lib/rules/operator-assignment.js b/tools/eslint/lib/rules/operator-assignment.js index 7e60c9efd40801..3088ff174f52aa 100644 --- a/tools/eslint/lib/rules/operator-assignment.js +++ b/tools/eslint/lib/rules/operator-assignment.js @@ -93,7 +93,7 @@ module.exports = { * @returns {void} */ function verify(node) { - var expr, left, operator; + let expr, left, operator; if (node.operator !== "=" || node.right.type !== "BinaryExpression") { return; diff --git a/tools/eslint/lib/rules/operator-linebreak.js b/tools/eslint/lib/rules/operator-linebreak.js index 8f17155b862711..2b2f1274aa11b8 100644 --- a/tools/eslint/lib/rules/operator-linebreak.js +++ b/tools/eslint/lib/rules/operator-linebreak.js @@ -5,7 +5,7 @@ "use strict"; -var lodash = require("lodash"), +let lodash = require("lodash"), astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ @@ -44,10 +44,10 @@ module.exports = { create: function(context) { - var usedDefaultGlobal = !context.options[0]; - var globalStyle = context.options[0] || "after"; - var options = context.options[1] || {}; - var styleOverrides = options.overrides ? lodash.assign({}, options.overrides) : {}; + let usedDefaultGlobal = !context.options[0]; + let globalStyle = context.options[0] || "after"; + let options = context.options[1] || {}; + let styleOverrides = options.overrides ? lodash.assign({}, options.overrides) : {}; if (usedDefaultGlobal && !styleOverrides["?"]) { styleOverrides["?"] = "before"; @@ -57,7 +57,7 @@ module.exports = { styleOverrides[":"] = "before"; } - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -71,8 +71,8 @@ module.exports = { * @returns {void} */ function validateNode(node, leftSide) { - var leftToken = sourceCode.getLastToken(leftSide); - var operatorToken = sourceCode.getTokenAfter(leftToken); + let leftToken = sourceCode.getLastToken(leftSide); + let operatorToken = sourceCode.getTokenAfter(leftToken); // When the left part of a binary expression is a single expression wrapped in // parentheses (ex: `(a) + b`), leftToken will be the last token of the expression @@ -84,10 +84,10 @@ module.exports = { operatorToken = sourceCode.getTokenAfter(operatorToken); } - var rightToken = sourceCode.getTokenAfter(operatorToken); - var operator = operatorToken.value; - var operatorStyleOverride = styleOverrides[operator]; - var style = operatorStyleOverride || globalStyle; + let rightToken = sourceCode.getTokenAfter(operatorToken); + let operator = operatorToken.value; + let operatorStyleOverride = styleOverrides[operator]; + let style = operatorStyleOverride || globalStyle; // if single line if (astUtils.isTokenOnSameLine(leftToken, operatorToken) && @@ -123,7 +123,7 @@ module.exports = { context.report(node, { line: operatorToken.loc.end.line, column: operatorToken.loc.end.column - }, "There should be no line break before or after '" + operator + "'"); + }, "There should be no line break before or after '" + operator + "'."); } } diff --git a/tools/eslint/lib/rules/padded-blocks.js b/tools/eslint/lib/rules/padded-blocks.js index 7ec24c65d7dba6..2754cda4de689c 100644 --- a/tools/eslint/lib/rules/padded-blocks.js +++ b/tools/eslint/lib/rules/padded-blocks.js @@ -47,8 +47,8 @@ module.exports = { }, create: function(context) { - var options = {}; - var config = context.options[0] || "always"; + let options = {}; + let config = context.options[0] || "always"; if (typeof config === "string") { options.blocks = config === "always"; @@ -64,10 +64,10 @@ module.exports = { } } - var ALWAYS_MESSAGE = "Block must be padded by blank lines.", + let ALWAYS_MESSAGE = "Block must be padded by blank lines.", NEVER_MESSAGE = "Block must not be padded by blank lines."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Gets the open brace token from a given node. @@ -96,7 +96,7 @@ module.exports = { * @returns {boolean} Whether or not the token is followed by a blank line. */ function isTokenTopPadded(token) { - var tokenStartLine = token.loc.start.line, + let tokenStartLine = token.loc.start.line, expectedFirstLine = tokenStartLine + 2, first, firstLine; @@ -116,7 +116,7 @@ module.exports = { * @returns {boolean} Whether or not the token is preceeded by a blank line */ function isTokenBottomPadded(token) { - var blockEnd = token.loc.end.line, + let blockEnd = token.loc.end.line, expectedLastLine = blockEnd - 2, last, lastLine; @@ -156,7 +156,7 @@ module.exports = { * @returns {void} undefined. */ function checkPadding(node) { - var openBrace = getOpenBrace(node), + let openBrace = getOpenBrace(node), closeBrace = sourceCode.getLastToken(node), blockHasTopPadding = isTokenTopPadded(openBrace), blockHasBottomPadding = isTokenBottomPadded(closeBrace); @@ -184,7 +184,7 @@ module.exports = { } } else { if (blockHasTopPadding) { - var nextToken = sourceCode.getTokenOrCommentAfter(openBrace); + let nextToken = sourceCode.getTokenOrCommentAfter(openBrace); context.report({ node: node, @@ -197,7 +197,7 @@ module.exports = { } if (blockHasBottomPadding) { - var previousToken = sourceCode.getTokenOrCommentBefore(closeBrace); + let previousToken = sourceCode.getTokenOrCommentBefore(closeBrace); context.report({ node: node, @@ -211,7 +211,7 @@ module.exports = { } } - var rule = {}; + let rule = {}; if (options.hasOwnProperty("switches")) { rule.SwitchStatement = function(node) { diff --git a/tools/eslint/lib/rules/prefer-arrow-callback.js b/tools/eslint/lib/rules/prefer-arrow-callback.js index 4c4c2e6f2b10b6..185bf160576ad3 100644 --- a/tools/eslint/lib/rules/prefer-arrow-callback.js +++ b/tools/eslint/lib/rules/prefer-arrow-callback.js @@ -35,10 +35,10 @@ function checkMetaProperty(node, metaName, propertyName) { * @returns {escope.Variable} The found variable object. */ function getVariableOfArguments(scope) { - var variables = scope.variables; + let variables = scope.variables; - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; if (variable.name === "arguments") { @@ -58,13 +58,13 @@ function getVariableOfArguments(scope) { /** * Checkes whether or not a given node is a callback. * @param {ASTNode} node - A node to check. - * @returns {object} + * @returns {Object} * {boolean} retv.isCallback - `true` if the node is a callback. * {boolean} retv.isLexicalThis - `true` if the node is with `.bind(this)`. */ function getCallbackInfo(node) { - var retv = {isCallback: false, isLexicalThis: false}; - var parent = node.parent; + let retv = {isCallback: false, isLexicalThis: false}; + let parent = node.parent; while (node) { switch (parent.type) { @@ -144,10 +144,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; + let options = context.options[0] || {}; - var allowUnboundThis = options.allowUnboundThis !== false; // default to true - var allowNamedFunctions = options.allowNamedFunctions; + let allowUnboundThis = options.allowUnboundThis !== false; // default to true + let allowNamedFunctions = options.allowNamedFunctions; /* * {Array<{this: boolean, super: boolean, meta: boolean}>} @@ -155,7 +155,7 @@ module.exports = { * - super - A flag which shows there are one or more Super. * - meta - A flag which shows there are one or more MethProperty. */ - var stack = []; + let stack = []; /** * Pushes new function scope with all `false` flags. @@ -182,7 +182,7 @@ module.exports = { // If there are below, it cannot replace with arrow functions merely. ThisExpression: function() { - var info = stack[stack.length - 1]; + let info = stack[stack.length - 1]; if (info) { info.this = true; @@ -190,7 +190,7 @@ module.exports = { }, Super: function() { - var info = stack[stack.length - 1]; + let info = stack[stack.length - 1]; if (info) { info.super = true; @@ -198,7 +198,7 @@ module.exports = { }, MetaProperty: function(node) { - var info = stack[stack.length - 1]; + let info = stack[stack.length - 1]; if (info && checkMetaProperty(node, "new", "target")) { info.meta = true; @@ -212,7 +212,7 @@ module.exports = { // Main. FunctionExpression: enterScope, "FunctionExpression:exit": function(node) { - var scopeInfo = exitScope(); + let scopeInfo = exitScope(); // Skip named function expressions if (allowNamedFunctions && node.id && node.id.name) { @@ -225,21 +225,21 @@ module.exports = { } // Skip recursive functions. - var nameVar = context.getDeclaredVariables(node)[0]; + let nameVar = context.getDeclaredVariables(node)[0]; if (isFunctionName(nameVar) && nameVar.references.length > 0) { return; } // Skip if it's using arguments. - var variable = getVariableOfArguments(context.getScope()); + let variable = getVariableOfArguments(context.getScope()); if (variable && variable.references.length > 0) { return; } // Reports if it's a callback which can replace with arrows. - var callbackInfo = getCallbackInfo(node); + let callbackInfo = getCallbackInfo(node); if (callbackInfo.isCallback && (!allowUnboundThis || !scopeInfo.this || callbackInfo.isLexicalThis) && diff --git a/tools/eslint/lib/rules/prefer-const.js b/tools/eslint/lib/rules/prefer-const.js index 7b8ac425193b85..5935e02b2c3b28 100644 --- a/tools/eslint/lib/rules/prefer-const.js +++ b/tools/eslint/lib/rules/prefer-const.js @@ -9,16 +9,15 @@ // Requirements //------------------------------------------------------------------------------ -var Map = require("es6-map"); -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var PATTERN_TYPE = /^(?:.+?Pattern|RestElement|Property)$/; -var DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/; -var DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/; +let PATTERN_TYPE = /^(?:.+?Pattern|RestElement|Property)$/; +let DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/; +let DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/; /** * Adds multiple items to the tail of an array. @@ -27,7 +26,7 @@ var DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/; * @param {any[]} values - Items to be added. * @returns {void} */ -var pushAll = Function.apply.bind(Array.prototype.push); +let pushAll = Function.apply.bind(Array.prototype.push); /** * Checks whether a given node is located at `ForStatement.init` or not. @@ -46,7 +45,7 @@ function isInitOfForStatement(node) { * @returns {boolean} `true` if the node can become a VariableDeclaration. */ function canBecomeVariableDeclaration(identifier) { - var node = identifier.parent; + let node = identifier.parent; while (PATTERN_TYPE.test(node.type)) { node = node.parent; @@ -88,15 +87,15 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) { } // Finds the unique WriteReference. - var writer = null; - var isReadBeforeInit = false; - var references = variable.references; + let writer = null; + let isReadBeforeInit = false; + let references = variable.references; - for (var i = 0; i < references.length; ++i) { - var reference = references[i]; + for (let i = 0; i < references.length; ++i) { + let reference = references[i]; if (reference.isWrite()) { - var isReassigned = ( + let isReassigned = ( writer !== null && writer.identifier !== reference.identifier ); @@ -116,7 +115,7 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) { // If the assignment is from a different scope, ignore it. // If the assignment cannot change to a declaration, ignore it. - var shouldBeConst = ( + let shouldBeConst = ( writer !== null && writer.from === variable.scope && canBecomeVariableDeclaration(writer.identifier) @@ -145,7 +144,7 @@ function getDestructuringHost(reference) { if (!reference.isWrite()) { return null; } - var node = reference.identifier.parent; + let node = reference.identifier.parent; while (PATTERN_TYPE.test(node.type)) { node = node.parent; @@ -169,17 +168,17 @@ function getDestructuringHost(reference) { * @returns {Map} Grouped identifier nodes. */ function groupByDestructuring(variables, ignoreReadBeforeAssign) { - var identifierMap = new Map(); + let identifierMap = new Map(); - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; - var references = variable.references; - var identifier = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); - var prevId = null; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; + let references = variable.references; + let identifier = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); + let prevId = null; - for (var j = 0; j < references.length; ++j) { - var reference = references[j]; - var id = reference.identifier; + for (let j = 0; j < references.length; ++j) { + let reference = references[j]; + let id = reference.identifier; // Avoid counting a reference twice or more for default values of // destructuring. @@ -189,7 +188,7 @@ function groupByDestructuring(variables, ignoreReadBeforeAssign) { prevId = id; // Add the identifier node into the destructuring group. - var group = getDestructuringHost(reference); + let group = getDestructuringHost(reference); if (group) { if (identifierMap.has(group)) { @@ -209,7 +208,7 @@ function groupByDestructuring(variables, ignoreReadBeforeAssign) { * * @param {ASTNode} node – The node to search from. * @param {string} type – The type field of the parent node. - * @param {function} shouldStop – a predicate that returns true if the traversal should stop, and false otherwise. + * @param {Function} shouldStop – a predicate that returns true if the traversal should stop, and false otherwise. * @returns {ASTNode} The closest ancestor with the specified type; null if no such ancestor exists. */ function findUp(node, type, shouldStop) { @@ -249,10 +248,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var checkingMixedDestructuring = options.destructuring !== "all"; - var ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true; - var variables = null; + let options = context.options[0] || {}; + let checkingMixedDestructuring = options.destructuring !== "all"; + let ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true; + let variables = null; /** * Reports a given Identifier node. @@ -261,7 +260,7 @@ module.exports = { * @returns {void} */ function report(node) { - var reportArgs = { + let reportArgs = { node: node, message: "'{{name}}' is never reassigned. Use 'const' instead.", data: node @@ -318,7 +317,7 @@ module.exports = { * @returns {void} */ function checkVariable(variable) { - var node = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); + let node = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); if (node) { report(node); diff --git a/tools/eslint/lib/rules/prefer-reflect.js b/tools/eslint/lib/rules/prefer-reflect.js index 38bb093ba6f509..b2b0b9abda821d 100644 --- a/tools/eslint/lib/rules/prefer-reflect.js +++ b/tools/eslint/lib/rules/prefer-reflect.js @@ -45,7 +45,7 @@ module.exports = { }, create: function(context) { - var existingNames = { + let existingNames = { apply: "Function.prototype.apply", call: "Function.prototype.call", defineProperty: "Object.defineProperty", @@ -57,7 +57,7 @@ module.exports = { preventExtensions: "Object.preventExtensions" }; - var reflectSubsitutes = { + let reflectSubsitutes = { apply: "Reflect.apply", call: "Reflect.apply", defineProperty: "Reflect.defineProperty", @@ -69,7 +69,7 @@ module.exports = { preventExtensions: "Reflect.preventExtensions" }; - var exceptions = (context.options[0] || {}).exceptions || []; + let exceptions = (context.options[0] || {}).exceptions || []; /** * Reports the Reflect violation based on the `existing` and `substitute` @@ -79,7 +79,7 @@ module.exports = { * @returns {void} */ function report(node, existing, substitute) { - context.report(node, "Avoid using {{existing}}, instead use {{substitute}}", { + context.report(node, "Avoid using {{existing}}, instead use {{substitute}}.", { existing: existing, substitute: substitute }); @@ -87,19 +87,19 @@ module.exports = { return { CallExpression: function(node) { - var methodName = (node.callee.property || {}).name; - var isReflectCall = (node.callee.object || {}).name === "Reflect"; - var hasReflectSubsitute = reflectSubsitutes.hasOwnProperty(methodName); - var userConfiguredException = exceptions.indexOf(methodName) !== -1; + let methodName = (node.callee.property || {}).name; + let isReflectCall = (node.callee.object || {}).name === "Reflect"; + let hasReflectSubsitute = reflectSubsitutes.hasOwnProperty(methodName); + let userConfiguredException = exceptions.indexOf(methodName) !== -1; if (hasReflectSubsitute && !isReflectCall && !userConfiguredException) { report(node, existingNames[methodName], reflectSubsitutes[methodName]); } }, UnaryExpression: function(node) { - var isDeleteOperator = node.operator === "delete"; - var targetsIdentifier = node.argument.type === "Identifier"; - var userConfiguredException = exceptions.indexOf("delete") !== -1; + let isDeleteOperator = node.operator === "delete"; + let targetsIdentifier = node.argument.type === "Identifier"; + let userConfiguredException = exceptions.indexOf("delete") !== -1; if (isDeleteOperator && !targetsIdentifier && !userConfiguredException) { report(node, "the delete keyword", "Reflect.deleteProperty"); diff --git a/tools/eslint/lib/rules/prefer-rest-params.js b/tools/eslint/lib/rules/prefer-rest-params.js index 0ce1d8a1220b28..5a9164ed7f4e47 100644 --- a/tools/eslint/lib/rules/prefer-rest-params.js +++ b/tools/eslint/lib/rules/prefer-rest-params.js @@ -15,10 +15,10 @@ * @returns {escope.Variable} The found variable object. */ function getVariableOfArguments(scope) { - var variables = scope.variables; + let variables = scope.variables; - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; if (variable.name === "arguments") { @@ -68,7 +68,7 @@ module.exports = { * @returns {void} */ function checkForArguments() { - var argumentsVar = getVariableOfArguments(context.getScope()); + let argumentsVar = getVariableOfArguments(context.getScope()); if (argumentsVar) { argumentsVar.references.forEach(report); diff --git a/tools/eslint/lib/rules/prefer-spread.js b/tools/eslint/lib/rules/prefer-spread.js index 67f1e855b00644..58fc85ca907355 100644 --- a/tools/eslint/lib/rules/prefer-spread.js +++ b/tools/eslint/lib/rules/prefer-spread.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -35,13 +35,13 @@ function isVariadicApplyCalling(node) { * @returns {boolean} the source code for the given node. */ function equalTokens(left, right, sourceCode) { - var tokensL = sourceCode.getTokens(left); - var tokensR = sourceCode.getTokens(right); + let tokensL = sourceCode.getTokens(left); + let tokensR = sourceCode.getTokens(right); if (tokensL.length !== tokensR.length) { return false; } - for (var i = 0; i < tokensL.length; ++i) { + for (let i = 0; i < tokensL.length; ++i) { if (tokensL[i].type !== tokensR[i].type || tokensL[i].value !== tokensR[i].value ) { @@ -82,7 +82,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { CallExpression: function(node) { @@ -90,9 +90,9 @@ module.exports = { return; } - var applied = node.callee.object; - var expectedThis = (applied.type === "MemberExpression") ? applied.object : null; - var thisArg = node.arguments[0]; + let applied = node.callee.object; + let expectedThis = (applied.type === "MemberExpression") ? applied.object : null; + let thisArg = node.arguments[0]; if (isValidThisArg(expectedThis, thisArg, sourceCode)) { context.report(node, "use the spread operator instead of the '.apply()'."); diff --git a/tools/eslint/lib/rules/prefer-template.js b/tools/eslint/lib/rules/prefer-template.js index 0165aaecd65d8c..4a0da8e197d5d0 100644 --- a/tools/eslint/lib/rules/prefer-template.js +++ b/tools/eslint/lib/rules/prefer-template.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -66,7 +66,7 @@ module.exports = { }, create: function(context) { - var done = Object.create(null); + let done = Object.create(null); /** * Reports if a given node is string concatenation with non string literals. @@ -79,7 +79,7 @@ module.exports = { return; } - var topBinaryExpr = getTopConcatBinaryExpression(node.parent); + let topBinaryExpr = getTopConcatBinaryExpression(node.parent); // Checks whether or not this node had been checked already. if (done[topBinaryExpr.range[0]]) { diff --git a/tools/eslint/lib/rules/quote-props.js b/tools/eslint/lib/rules/quote-props.js index 1fd2e74a5a34c4..ec65647450cfe5 100644 --- a/tools/eslint/lib/rules/quote-props.js +++ b/tools/eslint/lib/rules/quote-props.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var espree = require("espree"), +let espree = require("espree"), keywords = require("../util/keywords"); //------------------------------------------------------------------------------ @@ -66,7 +66,7 @@ module.exports = { create: function(context) { - var MODE = context.options[0], + let MODE = context.options[0], KEYWORDS = context.options[1] && context.options[1].keywords, CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false, NUMBERS = context.options[1] && context.options[1].numbers, @@ -106,7 +106,7 @@ module.exports = { * @returns {void} */ function checkUnnecessaryQuotes(node) { - var key = node.key, + let key = node.key, isKeywordToken, tokens; @@ -147,7 +147,7 @@ module.exports = { * @returns {void} */ function checkOmittedQuotes(node) { - var key = node.key; + let key = node.key; if (!node.method && !node.computed && !node.shorthand && !(key.type === "Literal" && typeof key.value === "string")) { context.report(node, MESSAGE_UNQUOTED, { @@ -163,12 +163,12 @@ module.exports = { * @returns {void} */ function checkConsistency(node, checkQuotesRedundancy) { - var quotes = false, + let quotes = false, lackOfQuotes = false, necessaryQuotes = false; node.properties.forEach(function(property) { - var key = property.key, + let key = property.key, tokens; if (!key || property.method || property.computed || property.shorthand) { diff --git a/tools/eslint/lib/rules/quotes.js b/tools/eslint/lib/rules/quotes.js index d4e9203811cf7f..18635da537fa53 100644 --- a/tools/eslint/lib/rules/quotes.js +++ b/tools/eslint/lib/rules/quotes.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var QUOTE_SETTINGS = { +let QUOTE_SETTINGS = { double: { quote: "\"", alternateQuote: "'", @@ -45,8 +45,8 @@ var QUOTE_SETTINGS = { QUOTE_SETTINGS.double.convert = QUOTE_SETTINGS.single.convert = QUOTE_SETTINGS.backtick.convert = function(str) { - var newQuote = this.quote; - var oldQuote = str[0]; + let newQuote = this.quote; + let oldQuote = str[0]; if (newQuote === oldQuote) { return str; @@ -65,8 +65,7 @@ QUOTE_SETTINGS.backtick.convert = function(str) { }) + newQuote; }; -var AVOID_ESCAPE = "avoid-escape", - FUNCTION_TYPE = /^(?:Arrow)?Function(?:Declaration|Expression)$/; +let AVOID_ESCAPE = "avoid-escape"; //------------------------------------------------------------------------------ // Rule Definition @@ -110,7 +109,7 @@ module.exports = { create: function(context) { - var quoteOption = context.options[0], + let quoteOption = context.options[0], settings = QUOTE_SETTINGS[quoteOption || "double"], options = context.options[1], avoidEscape = options && options.avoidEscape === true, @@ -155,15 +154,15 @@ module.exports = { * @private */ function isPartOfDirectivePrologue(node) { - var block = node.parent.parent; + let block = node.parent.parent; - if (block.type !== "Program" && (block.type !== "BlockStatement" || !FUNCTION_TYPE.test(block.parent.type))) { + if (block.type !== "Program" && (block.type !== "BlockStatement" || !astUtils.isFunction(block.parent))) { return false; } // Check the node is at a prologue. - for (var i = 0; i < block.body.length; ++i) { - var statement = block.body[i]; + for (let i = 0; i < block.body.length; ++i) { + let statement = block.body[i]; if (statement === node.parent) { return true; @@ -183,7 +182,7 @@ module.exports = { * @private */ function isAllowedAsNonBacktick(node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { @@ -210,7 +209,7 @@ module.exports = { return { Literal: function(node) { - var val = node.value, + let val = node.value, rawVal = node.raw, isValid; @@ -242,7 +241,7 @@ module.exports = { return; } - var shouldWarn = node.quasis.length === 1 && (node.quasis[0].value.cooked.indexOf("\n") === -1); + let shouldWarn = node.quasis.length === 1 && (node.quasis[0].value.cooked.indexOf("\n") === -1); if (shouldWarn) { context.report({ diff --git a/tools/eslint/lib/rules/radix.js b/tools/eslint/lib/rules/radix.js index 05a1c130a9f4df..4c9cb73bebc569 100644 --- a/tools/eslint/lib/rules/radix.js +++ b/tools/eslint/lib/rules/radix.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var MODE_ALWAYS = "always", +let MODE_ALWAYS = "always", MODE_AS_NEEDED = "as-needed"; /** @@ -92,7 +92,7 @@ module.exports = { }, create: function(context) { - var mode = context.options[0] || MODE_ALWAYS; + let mode = context.options[0] || MODE_ALWAYS; /** * Checks the arguments of a given CallExpression node and reports it if it @@ -102,7 +102,7 @@ module.exports = { * @returns {void} */ function checkArguments(node) { - var args = node.arguments; + let args = node.arguments; switch (args.length) { case 0: @@ -139,14 +139,14 @@ module.exports = { return { "Program:exit": function() { - var scope = context.getScope(); - var variable; + let scope = context.getScope(); + let variable; // Check `parseInt()` variable = astUtils.getVariableByName(scope, "parseInt"); if (!isShadowed(variable)) { variable.references.forEach(function(reference) { - var node = reference.identifier; + let node = reference.identifier; if (astUtils.isCallee(node)) { checkArguments(node.parent); @@ -158,7 +158,7 @@ module.exports = { variable = astUtils.getVariableByName(scope, "Number"); if (!isShadowed(variable)) { variable.references.forEach(function(reference) { - var node = reference.identifier.parent; + let node = reference.identifier.parent; if (isParseIntMethod(node) && astUtils.isCallee(node)) { checkArguments(node.parent); diff --git a/tools/eslint/lib/rules/require-jsdoc.js b/tools/eslint/lib/rules/require-jsdoc.js index 083e79b1f55ccb..1503c0ff886b60 100644 --- a/tools/eslint/lib/rules/require-jsdoc.js +++ b/tools/eslint/lib/rules/require-jsdoc.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let lodash = require("lodash"); module.exports = { meta: { @@ -40,13 +40,13 @@ module.exports = { }, create: function(context) { - var source = context.getSourceCode(); - var DEFAULT_OPTIONS = { + let source = context.getSourceCode(); + let DEFAULT_OPTIONS = { FunctionDeclaration: true, MethodDefinition: false, ClassDeclaration: false }; - var options = lodash.assign(DEFAULT_OPTIONS, context.options[0] && context.options[0].require || {}); + let options = lodash.assign(DEFAULT_OPTIONS, context.options[0] && context.options[0].require || {}); /** * Report the error message @@ -64,7 +64,7 @@ module.exports = { */ function checkClassMethodJsDoc(node) { if (node.parent.type === "MethodDefinition") { - var jsdocComment = source.getJSDocComment(node); + let jsdocComment = source.getJSDocComment(node); if (!jsdocComment) { report(node); @@ -78,7 +78,7 @@ module.exports = { * @returns {void} */ function checkJsDoc(node) { - var jsdocComment = source.getJSDocComment(node); + let jsdocComment = source.getJSDocComment(node); if (!jsdocComment) { report(node); diff --git a/tools/eslint/lib/rules/require-yield.js b/tools/eslint/lib/rules/require-yield.js index cde7d8c2c48e00..a4bb292b7a981b 100644 --- a/tools/eslint/lib/rules/require-yield.js +++ b/tools/eslint/lib/rules/require-yield.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var stack = []; + let stack = []; /** * If the node is a generator function, start counting `yield` keywords. @@ -45,7 +45,7 @@ module.exports = { return; } - var countYield = stack.pop(); + let countYield = stack.pop(); if (countYield === 0 && node.body.body.length > 0) { context.report( diff --git a/tools/eslint/lib/rules/rest-spread-spacing.js b/tools/eslint/lib/rules/rest-spread-spacing.js index 7ffafa53199b46..3be2a434210a72 100644 --- a/tools/eslint/lib/rules/rest-spread-spacing.js +++ b/tools/eslint/lib/rules/rest-spread-spacing.js @@ -25,7 +25,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), alwaysSpace = context.options[0] === "always"; //-------------------------------------------------------------------------- @@ -38,7 +38,7 @@ module.exports = { * @returns {void} */ function checkWhiteSpace(node) { - var operator = sourceCode.getFirstToken(node), + let operator = sourceCode.getFirstToken(node), nextToken = sourceCode.getTokenAfter(operator), hasWhitespace = sourceCode.isSpaceBetweenTokens(operator, nextToken), type; @@ -67,7 +67,7 @@ module.exports = { line: operator.loc.end.line, column: operator.loc.end.column }, - message: "Expected whitespace after {{type}} operator", + message: "Expected whitespace after {{type}} operator.", data: { type: type }, @@ -82,7 +82,7 @@ module.exports = { line: operator.loc.end.line, column: operator.loc.end.column }, - message: "Unexpected whitespace after {{type}} operator", + message: "Unexpected whitespace after {{type}} operator.", data: { type: type }, diff --git a/tools/eslint/lib/rules/semi-spacing.js b/tools/eslint/lib/rules/semi-spacing.js index 830044d2f3f960..261905f96fa75f 100644 --- a/tools/eslint/lib/rules/semi-spacing.js +++ b/tools/eslint/lib/rules/semi-spacing.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -39,7 +39,7 @@ module.exports = { create: function(context) { - var config = context.options[0], + let config = context.options[0], requireSpaceBefore = false, requireSpaceAfter = true, sourceCode = context.getSourceCode(); @@ -59,7 +59,7 @@ module.exports = { * @returns {boolean} True if the given token has leading space, false if not. */ function hasLeadingSpace(token) { - var tokenBefore = sourceCode.getTokenBefore(token); + let tokenBefore = sourceCode.getTokenBefore(token); return tokenBefore && astUtils.isTokenOnSameLine(tokenBefore, token) && sourceCode.isSpaceBetweenTokens(tokenBefore, token); } @@ -70,7 +70,7 @@ module.exports = { * @returns {boolean} True if the given token has trailing space, false if not. */ function hasTrailingSpace(token) { - var tokenAfter = sourceCode.getTokenAfter(token); + let tokenAfter = sourceCode.getTokenAfter(token); return tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter) && sourceCode.isSpaceBetweenTokens(token, tokenAfter); } @@ -81,7 +81,7 @@ module.exports = { * @returns {boolean} Whether or not the token is the last in its line. */ function isLastTokenInCurrentLine(token) { - var tokenAfter = sourceCode.getTokenAfter(token); + let tokenAfter = sourceCode.getTokenAfter(token); return !(tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter)); } @@ -92,7 +92,7 @@ module.exports = { * @returns {boolean} Whether or not the token is the first in its line. */ function isFirstTokenInCurrentLine(token) { - var tokenBefore = sourceCode.getTokenBefore(token); + let tokenBefore = sourceCode.getTokenBefore(token); return !(tokenBefore && astUtils.isTokenOnSameLine(token, tokenBefore)); } @@ -103,7 +103,7 @@ module.exports = { * @returns {boolean} Whether or not the next token of a given token is a closing parenthesis. */ function isBeforeClosingParen(token) { - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); return ( nextToken && @@ -128,7 +128,7 @@ module.exports = { * @returns {void} */ function checkSemicolonSpacing(token, node) { - var location; + let location; if (isSemicolon(token)) { location = token.loc.start; @@ -140,7 +140,7 @@ module.exports = { loc: location, message: "Unexpected whitespace before semicolon.", fix: function(fixer) { - var tokenBefore = sourceCode.getTokenBefore(token); + let tokenBefore = sourceCode.getTokenBefore(token); return fixer.removeRange([tokenBefore.range[1], token.range[0]]); } @@ -167,7 +167,7 @@ module.exports = { loc: location, message: "Unexpected whitespace after semicolon.", fix: function(fixer) { - var tokenAfter = sourceCode.getTokenAfter(token); + let tokenAfter = sourceCode.getTokenAfter(token); return fixer.removeRange([token.range[1], tokenAfter.range[0]]); } @@ -195,7 +195,7 @@ module.exports = { * @returns {void} */ function checkNode(node) { - var token = sourceCode.getLastToken(node); + let token = sourceCode.getLastToken(node); checkSemicolonSpacing(token, node); } diff --git a/tools/eslint/lib/rules/semi.js b/tools/eslint/lib/rules/semi.js index d530725040ba83..80b1e9d00256dc 100644 --- a/tools/eslint/lib/rules/semi.js +++ b/tools/eslint/lib/rules/semi.js @@ -53,9 +53,9 @@ module.exports = { create: function(context) { - var OPT_OUT_PATTERN = /[\[\(\/\+\-]/; // One of [(/+- - var options = context.options[1]; - var never = context.options[0] === "never", + let OPT_OUT_PATTERN = /[\[\(\/\+\-]/; // One of [(/+- + let options = context.options[1]; + let never = context.options[0] === "never", exceptOneLine = options && options.omitLastInOneLineBlock === true, sourceCode = context.getSourceCode(); @@ -70,7 +70,7 @@ module.exports = { * @returns {void} */ function report(node, missing) { - var message, + let message, fix, lastToken = sourceCode.getLastToken(node), loc = lastToken.loc; @@ -115,7 +115,7 @@ module.exports = { * @returns {boolean} whether the semicolon is unnecessary. */ function isUnnecessarySemicolon(lastToken) { - var isDivider, isOptOutToken, lastTokenLine, nextToken, nextTokenLine; + let isDivider, isOptOutToken, lastTokenLine, nextToken, nextTokenLine; if (!isSemicolon(lastToken)) { return false; @@ -141,13 +141,13 @@ module.exports = { * @returns {boolean} whether the node is in a one-liner block statement. */ function isOneLinerBlock(node) { - var nextToken = sourceCode.getTokenAfter(node); + let nextToken = sourceCode.getTokenAfter(node); if (!nextToken || nextToken.value !== "}") { return false; } - var parent = node.parent; + let parent = node.parent; return parent && parent.type === "BlockStatement" && parent.loc.start.line === parent.loc.end.line; @@ -159,7 +159,7 @@ module.exports = { * @returns {void} */ function checkForSemicolon(node) { - var lastToken = sourceCode.getLastToken(node); + let lastToken = sourceCode.getLastToken(node); if (never) { if (isUnnecessarySemicolon(lastToken)) { @@ -184,7 +184,7 @@ module.exports = { * @returns {void} */ function checkForSemicolonForVariableDeclaration(node) { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), parentIndex = ancestors.length - 1, parent = ancestors[parentIndex]; diff --git a/tools/eslint/lib/rules/sort-imports.js b/tools/eslint/lib/rules/sort-imports.js index 18b34f86a09659..c8d3340b0cd198 100644 --- a/tools/eslint/lib/rules/sort-imports.js +++ b/tools/eslint/lib/rules/sort-imports.js @@ -44,7 +44,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0] || {}, + let configuration = context.options[0] || {}, ignoreCase = configuration.ignoreCase || false, ignoreMemberSort = configuration.ignoreMemberSort || false, memberSyntaxSortOrder = configuration.memberSyntaxSortOrder || ["none", "all", "multiple", "single"], @@ -98,7 +98,7 @@ module.exports = { return { ImportDeclaration: function(node) { if (previousDeclaration) { - var currentLocalMemberName = getFirstLocalMemberName(node), + let currentLocalMemberName = getFirstLocalMemberName(node), currentMemberSyntaxGroupIndex = getMemberParameterGroupIndex(node), previousLocalMemberName = getFirstLocalMemberName(previousDeclaration), previousMemberSyntaxGroupIndex = getMemberParameterGroupIndex(previousDeclaration); @@ -137,17 +137,17 @@ module.exports = { // Multiple members of an import declaration should also be sorted alphabetically. if (!ignoreMemberSort && node.specifiers.length > 1) { - var previousSpecifier = null; - var previousSpecifierName = null; + let previousSpecifier = null; + let previousSpecifierName = null; - for (var i = 0; i < node.specifiers.length; ++i) { - var currentSpecifier = node.specifiers[i]; + for (let i = 0; i < node.specifiers.length; ++i) { + let currentSpecifier = node.specifiers[i]; if (currentSpecifier.type !== "ImportSpecifier") { continue; } - var currentSpecifierName = currentSpecifier.local.name; + let currentSpecifierName = currentSpecifier.local.name; if (ignoreCase) { currentSpecifierName = currentSpecifierName.toLowerCase(); diff --git a/tools/eslint/lib/rules/sort-vars.js b/tools/eslint/lib/rules/sort-vars.js index 8a7b0e710a7524..4b8187f36a9c98 100644 --- a/tools/eslint/lib/rules/sort-vars.js +++ b/tools/eslint/lib/rules/sort-vars.js @@ -32,7 +32,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0] || {}, + let configuration = context.options[0] || {}, ignoreCase = configuration.ignoreCase || false; return { @@ -42,7 +42,7 @@ module.exports = { return memo; } - var lastVariableName = memo.id.name, + let lastVariableName = memo.id.name, currenVariableName = decl.id.name; if (ignoreCase) { @@ -51,7 +51,7 @@ module.exports = { } if (currenVariableName < lastVariableName) { - context.report(decl, "Variables within the same declaration block should be sorted alphabetically"); + context.report(decl, "Variables within the same declaration block should be sorted alphabetically."); return memo; } else { return decl; diff --git a/tools/eslint/lib/rules/space-before-blocks.js b/tools/eslint/lib/rules/space-before-blocks.js index 468b320447043c..b695e7ac12e62a 100644 --- a/tools/eslint/lib/rules/space-before-blocks.js +++ b/tools/eslint/lib/rules/space-before-blocks.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -48,7 +48,7 @@ module.exports = { }, create: function(context) { - var config = context.options[0], + let config = context.options[0], sourceCode = context.getSourceCode(), checkFunctions = true, checkKeywords = true, @@ -81,7 +81,7 @@ module.exports = { * @returns {void} undefined. */ function checkPrecedingSpace(node) { - var precedingToken = sourceCode.getTokenBefore(node), + let precedingToken = sourceCode.getTokenBefore(node), hasSpace, parent, requireSpace; @@ -127,7 +127,7 @@ module.exports = { * @returns {void} undefined. */ function checkSpaceBeforeCaseBlock(node) { - var cases = node.cases, + let cases = node.cases, firstCase, openingBrace; diff --git a/tools/eslint/lib/rules/space-before-function-paren.js b/tools/eslint/lib/rules/space-before-function-paren.js index 2d26e41e4a9a14..b43d11ed13f776 100644 --- a/tools/eslint/lib/rules/space-before-function-paren.js +++ b/tools/eslint/lib/rules/space-before-function-paren.js @@ -43,7 +43,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0], + let configuration = context.options[0], sourceCode = context.getSourceCode(), requireAnonymousFunctionSpacing = true, forbidAnonymousFunctionSpacing = false, @@ -70,7 +70,7 @@ module.exports = { * @returns {boolean} Whether the function has a name. */ function isNamedFunction(node) { - var parent; + let parent; if (node.id) { return true; @@ -93,7 +93,7 @@ module.exports = { * @returns {void} */ function validateSpacingBeforeParentheses(node) { - var isNamed = isNamedFunction(node), + let isNamed = isNamedFunction(node), leftToken, rightToken, location; diff --git a/tools/eslint/lib/rules/space-in-parens.js b/tools/eslint/lib/rules/space-in-parens.js index 11361aec1202f3..bd8c6eb3af847f 100644 --- a/tools/eslint/lib/rules/space-in-parens.js +++ b/tools/eslint/lib/rules/space-in-parens.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -42,7 +42,7 @@ module.exports = { create: function(context) { - var MISSING_SPACE_MESSAGE = "There must be a space inside this paren.", + let MISSING_SPACE_MESSAGE = "There must be a space inside this paren.", REJECTED_SPACE_MESSAGE = "There should be no spaces inside this paren.", ALWAYS = context.options[0] === "always", @@ -64,7 +64,7 @@ module.exports = { * @private */ function getExceptions() { - var openers = [], + let openers = [], closers = []; if (options.braceException) { @@ -96,7 +96,7 @@ module.exports = { //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines if a token is one of the exceptions for the opener paren @@ -217,7 +217,7 @@ module.exports = { return { Program: function checkParenSpaces(node) { - var tokens, prevToken, nextToken; + let tokens, prevToken, nextToken; exceptions = getExceptions(); tokens = sourceCode.tokensAndComments; diff --git a/tools/eslint/lib/rules/space-infix-ops.js b/tools/eslint/lib/rules/space-infix-ops.js index bea82ba0b65439..9f5b08773a480c 100644 --- a/tools/eslint/lib/rules/space-infix-ops.js +++ b/tools/eslint/lib/rules/space-infix-ops.js @@ -32,29 +32,29 @@ module.exports = { }, create: function(context) { - var int32Hint = context.options[0] ? context.options[0].int32Hint === true : false; + let int32Hint = context.options[0] ? context.options[0].int32Hint === true : false; - var OPERATORS = [ + let OPERATORS = [ "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in", "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=", "?", ":", ",", "**" ]; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Returns the first token which violates the rule * @param {ASTNode} left - The left node of the main node * @param {ASTNode} right - The right node of the main node - * @returns {object} The violator token or null + * @returns {Object} The violator token or null * @private */ function getFirstNonSpacedToken(left, right) { - var op, + let op, tokens = sourceCode.getTokensBetween(left, right, 1); - for (var i = 1, l = tokens.length - 1; i < l; ++i) { + for (let i = 1, l = tokens.length - 1; i < l; ++i) { op = tokens[i]; if ( op.type === "Punctuator" && @@ -70,7 +70,7 @@ module.exports = { /** * Reports an AST node as a rule violation * @param {ASTNode} mainNode - The node to report - * @param {object} culpritToken - The token which has a problem + * @param {Object} culpritToken - The token which has a problem * @returns {void} * @private */ @@ -80,9 +80,9 @@ module.exports = { loc: culpritToken.loc.start, message: "Infix operators must be spaced.", fix: function(fixer) { - var previousToken = sourceCode.getTokenBefore(culpritToken); - var afterToken = sourceCode.getTokenAfter(culpritToken); - var fixString = ""; + let previousToken = sourceCode.getTokenBefore(culpritToken); + let afterToken = sourceCode.getTokenAfter(culpritToken); + let fixString = ""; if (culpritToken.range[0] - previousToken.range[1] === 0) { fixString = " "; @@ -106,7 +106,11 @@ module.exports = { * @private */ function checkBinary(node) { - var nonSpacedNode = getFirstNonSpacedToken(node.left, node.right); + if (node.left.typeAnnotation) { + return; + } + + let nonSpacedNode = getFirstNonSpacedToken(node.left, node.right); if (nonSpacedNode) { if (!(int32Hint && sourceCode.getText(node).substr(-2) === "|0")) { @@ -122,8 +126,8 @@ module.exports = { * @private */ function checkConditional(node) { - var nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent); - var nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate); + let nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent); + let nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate); if (nonSpacedConsequesntNode) { report(node, nonSpacedConsequesntNode); @@ -139,7 +143,7 @@ module.exports = { * @private */ function checkVar(node) { - var nonSpacedNode; + let nonSpacedNode; if (node.init) { nonSpacedNode = getFirstNonSpacedToken(node.id, node.init); diff --git a/tools/eslint/lib/rules/space-unary-ops.js b/tools/eslint/lib/rules/space-unary-ops.js index fdb1c03e9876b3..77a98150b86542 100644 --- a/tools/eslint/lib/rules/space-unary-ops.js +++ b/tools/eslint/lib/rules/space-unary-ops.js @@ -41,9 +41,9 @@ module.exports = { }, create: function(context) { - var options = context.options && Array.isArray(context.options) && context.options[0] || { words: true, nonwords: false }; + let options = context.options && Array.isArray(context.options) && context.options[0] || { words: true, nonwords: false }; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -91,8 +91,8 @@ module.exports = { /** * Verify Unary Word Operator has spaces after the word operator * @param {ASTnode} node AST node - * @param {object} firstToken first token from the AST node - * @param {object} secondToken second token from the AST node + * @param {Object} firstToken first token from the AST node + * @param {Object} secondToken second token from the AST node * @param {string} word The word to be used for reporting * @returns {void} */ @@ -111,8 +111,8 @@ module.exports = { /** * Verify Unary Word Operator doesn't have spaces after the word operator * @param {ASTnode} node AST node - * @param {object} firstToken first token from the AST node - * @param {object} secondToken second token from the AST node + * @param {Object} firstToken first token from the AST node + * @param {Object} secondToken second token from the AST node * @param {string} word The word to be used for reporting * @returns {void} */ @@ -133,8 +133,8 @@ module.exports = { /** * Check Unary Word Operators for spaces after the word operator * @param {ASTnode} node AST node - * @param {object} firstToken first token from the AST node - * @param {object} secondToken second token from the AST node + * @param {Object} firstToken first token from the AST node + * @param {Object} secondToken second token from the AST node * @param {string} word The word to be used for reporting * @returns {void} */ @@ -160,7 +160,7 @@ module.exports = { * @returns {void} */ function checkForSpacesAfterYield(node) { - var tokens = sourceCode.getFirstTokens(node, 3), + let tokens = sourceCode.getFirstTokens(node, 3), word = "yield"; if (!node.argument || node.delegate) { @@ -173,8 +173,8 @@ module.exports = { /** * Verifies UnaryExpression, UpdateExpression and NewExpression have spaces before or after the operator * @param {ASTnode} node AST node - * @param {object} firstToken First token in the expression - * @param {object} secondToken Second token in the expression + * @param {Object} firstToken First token in the expression + * @param {Object} secondToken Second token in the expression * @returns {void} */ function verifyNonWordsHaveSpaces(node, firstToken, secondToken) { @@ -207,8 +207,8 @@ module.exports = { /** * Verifies UnaryExpression, UpdateExpression and NewExpression don't have spaces before or after the operator * @param {ASTnode} node AST node - * @param {object} firstToken First token in the expression - * @param {object} secondToken Second token in the expression + * @param {Object} firstToken First token in the expression + * @param {Object} secondToken Second token in the expression * @returns {void} */ function verifyNonWordsDontHaveSpaces(node, firstToken, secondToken) { @@ -241,7 +241,7 @@ module.exports = { * @returns {void} */ function checkForSpaces(node) { - var tokens = sourceCode.getFirstTokens(node, 2), + let tokens = sourceCode.getFirstTokens(node, 2), firstToken = tokens[0], secondToken = tokens[1]; @@ -250,7 +250,7 @@ module.exports = { return; } - var operator = node.prefix ? tokens[0].value : tokens[1].value; + let operator = node.prefix ? tokens[0].value : tokens[1].value; if (overrideExistsForOperator(node, operator)) { if (overrideEnforcesSpaces(node, operator)) { diff --git a/tools/eslint/lib/rules/spaced-comment.js b/tools/eslint/lib/rules/spaced-comment.js index 149862024c2b3c..7141ba1f423c86 100644 --- a/tools/eslint/lib/rules/spaced-comment.js +++ b/tools/eslint/lib/rules/spaced-comment.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers @@ -16,7 +16,7 @@ var lodash = require("lodash"); * @returns {string} An escaped string. */ function escape(s) { - var isOneChar = s.length === 1; + let isOneChar = s.length === 1; s = lodash.escapeRegExp(s); return isOneChar ? s : "(?:" + s + ")"; @@ -50,38 +50,16 @@ function parseMarkersOption(markers) { } /** - * Creates RegExp object for `always` mode. - * Generated pattern is below: + * Creates string pattern for exceptions. + * Generated pattern: * - * 1. First, a marker or nothing. - * 2. Next, a space or an exception pattern sequence. + * 1. A space or an exception pattern sequence. * - * @param {string[]} markers - A marker list. - * @param {string[]} exceptions - A exception pattern list. - * @returns {RegExp} A RegExp object for `always` mode. + * @param {string[]} exceptions - An exception pattern list. + * @returns {string} A regular expression string for exceptions. */ -function createAlwaysStylePattern(markers, exceptions) { - var pattern = "^"; - - /* - * A marker or nothing. - * ["*"] ==> "\*?" - * ["*", "!"] ==> "(?:\*|!)?" - * ["*", "/", "!<"] ==> "(?:\*|\/|(?:!<))?" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5C*%7C%5C%2F%7C(%3F%3A!%3C))%3F - */ - if (markers.length === 1) { - - // the marker. - pattern += escape(markers[0]); - } else { - - // one of markers. - pattern += "(?:"; - pattern += markers.map(escape).join("|"); - pattern += ")"; - } - - pattern += "?"; // or nothing. +function createExceptionsPattern(exceptions) { + let pattern = ""; /* * A space or an exception pattern sequence. @@ -105,21 +83,59 @@ function createAlwaysStylePattern(markers, exceptions) { pattern += escapeAndRepeat(exceptions[0]); } else { - // a sequence of one of exception patterns. + // a sequence of one of the exception patterns. pattern += "(?:"; pattern += exceptions.map(escapeAndRepeat).join("|"); pattern += ")"; } - pattern += "(?:$|[\n\r]))"; // the sequence continues until the end. + pattern += "(?:$|[\n\r]))"; } + return pattern; +} + +/** + * Creates RegExp object for `always` mode. + * Generated pattern for beginning of comment: + * + * 1. First, a marker or nothing. + * 2. Next, a space or an exception pattern sequence. + * + * @param {string[]} markers - A marker list. + * @param {string[]} exceptions - An exception pattern list. + * @returns {RegExp} A RegExp object for the beginning of a comment in `always` mode. + */ +function createAlwaysStylePattern(markers, exceptions) { + let pattern = "^"; + + /* + * A marker or nothing. + * ["*"] ==> "\*?" + * ["*", "!"] ==> "(?:\*|!)?" + * ["*", "/", "!<"] ==> "(?:\*|\/|(?:!<))?" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5C*%7C%5C%2F%7C(%3F%3A!%3C))%3F + */ + if (markers.length === 1) { + + // the marker. + pattern += escape(markers[0]); + } else { + + // one of markers. + pattern += "(?:"; + pattern += markers.map(escape).join("|"); + pattern += ")"; + } + + pattern += "?"; // or nothing. + pattern += createExceptionsPattern(exceptions); + return new RegExp(pattern); } /** * Creates RegExp object for `never` mode. - * Generated pattern is below: + * Generated pattern for beginning of comment: * * 1. First, a marker or nothing (captured). * 2. Next, a space or a tab. @@ -128,7 +144,7 @@ function createAlwaysStylePattern(markers, exceptions) { * @returns {RegExp} A RegExp object for `never` mode. */ function createNeverStylePattern(markers) { - var pattern = "^(" + markers.map(escape).join("|") + ")?[ \t]+"; + let pattern = "^(" + markers.map(escape).join("|") + ")?[ \t]+"; return new RegExp(pattern); } @@ -198,6 +214,9 @@ module.exports = { items: { type: "string" } + }, + balanced: { + type: "boolean" } }, additionalProperties: false @@ -211,21 +230,25 @@ module.exports = { create: function(context) { // Unless the first option is never, require a space - var requireSpace = context.options[0] !== "never"; + let requireSpace = context.options[0] !== "never"; /* * Parse the second options. * If markers don't include `"*"`, it's added automatically for JSDoc * comments. */ - var config = context.options[1] || {}; - var styleRules = ["block", "line"].reduce(function(rule, type) { - var markers = parseMarkersOption(config[type] && config[type].markers || config.markers); - var exceptions = config[type] && config[type].exceptions || config.exceptions || []; + let config = context.options[1] || {}; + let balanced = config.block && config.block.balanced; + + let styleRules = ["block", "line"].reduce(function(rule, type) { + let markers = parseMarkersOption(config[type] && config[type].markers || config.markers); + let exceptions = config[type] && config[type].exceptions || config.exceptions || []; + let endNeverPattern = "[ \t]+$"; // Create RegExp object for valid patterns. rule[type] = { - regex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers), + beginRegex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers), + endRegex: balanced && requireSpace ? new RegExp(createExceptionsPattern(exceptions) + "$") : new RegExp(endNeverPattern), hasExceptions: exceptions.length > 0, markers: new RegExp("^(" + markers.map(escape).join("|") + ")") }; @@ -234,20 +257,20 @@ module.exports = { }, {}); /** - * Reports a spacing error with an appropriate message. + * Reports a beginning spacing error with an appropriate message. * @param {ASTNode} node - A comment node to check. - * @param {string} message - An error message to report + * @param {string} message - An error message to report. * @param {Array} match - An array of match results for markers. * @returns {void} */ - function report(node, message, match) { - var type = node.type.toLowerCase(), + function reportBegin(node, message, match) { + let type = node.type.toLowerCase(), commentIdentifier = type === "block" ? "/*" : "//"; context.report({ node: node, fix: function(fixer) { - var start = node.range[0], + let start = node.range[0], end = start + 2; if (requireSpace) { @@ -264,13 +287,37 @@ module.exports = { }); } + /** + * Reports an ending spacing error with an appropriate message. + * @param {ASTNode} node - A comment node to check. + * @param {string} message - An error message to report. + * @param {string} match - An array of the matched whitespace characters. + * @returns {void} + */ + function reportEnd(node, message, match) { + context.report({ + node: node, + fix: function(fixer) { + if (requireSpace) { + return fixer.insertTextAfterRange([node.start, node.end - 2], " "); + } else { + let end = node.end - 2, + start = end - match[0].length; + + return fixer.replaceTextRange([start, end], ""); + } + }, + message: message + }); + } + /** * Reports a given comment if it's invalid. * @param {ASTNode} node - a comment node to check. * @returns {void} */ function checkCommentForSpace(node) { - var type = node.type.toLowerCase(), + let type = node.type.toLowerCase(), rule = styleRules[type], commentIdentifier = type === "block" ? "/*" : "//"; @@ -279,28 +326,37 @@ module.exports = { return; } + let beginMatch = rule.beginRegex.exec(node.value); + let endMatch = rule.endRegex.exec(node.value); + // Checks. if (requireSpace) { - if (!rule.regex.test(node.value)) { - var hasMarker = rule.markers.exec(node.value); - var marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier; + if (!beginMatch) { + let hasMarker = rule.markers.exec(node.value); + let marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier; if (rule.hasExceptions) { - report(node, "Expected exception block, space or tab after '" + marker + "' in comment.", hasMarker); + reportBegin(node, "Expected exception block, space or tab after '" + marker + "' in comment.", hasMarker); } else { - report(node, "Expected space or tab after '" + marker + "' in comment.", hasMarker); + reportBegin(node, "Expected space or tab after '" + marker + "' in comment.", hasMarker); } } - } else { - var matched = rule.regex.exec(node.value); - if (matched) { - if (!matched[1]) { - report(node, "Unexpected space or tab after '" + commentIdentifier + "' in comment.", matched); + if (balanced && type === "block" && !endMatch) { + reportEnd(node, "Expected space or tab before '*/' in comment."); + } + } else { + if (beginMatch) { + if (!beginMatch[1]) { + reportBegin(node, "Unexpected space or tab after '" + commentIdentifier + "' in comment.", beginMatch); } else { - report(node, "Unexpected space or tab after marker (" + matched[1] + ") in comment.", matched); + reportBegin(node, "Unexpected space or tab after marker (" + beginMatch[1] + ") in comment.", beginMatch); } } + + if (balanced && type === "block" && endMatch) { + reportEnd(node, "Unexpected space or tab before '*/' in comment.", endMatch); + } } } diff --git a/tools/eslint/lib/rules/strict.js b/tools/eslint/lib/rules/strict.js index 45021517c70251..5f54b15e799150 100644 --- a/tools/eslint/lib/rules/strict.js +++ b/tools/eslint/lib/rules/strict.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var messages = { +let messages = { function: "Use the function form of 'use strict'.", global: "Use the global form of 'use strict'.", multiple: "Multiple 'use strict' directives.", @@ -35,7 +35,7 @@ var messages = { * @returns {ASTNode[]} All of the Use Strict Directives. */ function getUseStrictDirectives(statements) { - var directives = [], + let directives = [], i, statement; for (i = 0; i < statements.length; i++) { @@ -96,7 +96,7 @@ module.exports = { create: function(context) { - var mode = context.options[0] || "safe", + let mode = context.options[0] || "safe", ecmaFeatures = context.parserOptions.ecmaFeatures || {}, scopes = [], classScopes = [], @@ -117,7 +117,7 @@ module.exports = { * @returns {void} */ function reportSlice(nodes, start, end, message) { - var i; + let i; for (i = start; i < end; i++) { context.report(nodes[i], message); @@ -152,7 +152,7 @@ module.exports = { * @returns {void} */ function enterFunctionInFunctionMode(node, useStrictDirectives) { - var isInClass = classScopes.length > 0, + let isInClass = classScopes.length > 0, isParentGlobal = scopes.length === 0 && classScopes.length === 0, isParentStrict = scopes.length > 0 && scopes[scopes.length - 1], isStrict = useStrictDirectives.length > 0; @@ -194,7 +194,7 @@ module.exports = { * @returns {void} */ function enterFunction(node) { - var isBlock = node.body.type === "BlockStatement", + let isBlock = node.body.type === "BlockStatement", useStrictDirectives = isBlock ? getUseStrictDirectives(node.body.body) : []; @@ -212,7 +212,7 @@ module.exports = { rule = { Program: function(node) { - var useStrictDirectives = getUseStrictDirectives(node.body); + let useStrictDirectives = getUseStrictDirectives(node.body); if (node.sourceType === "module") { mode = "module"; diff --git a/tools/eslint/lib/rules/template-curly-spacing.js b/tools/eslint/lib/rules/template-curly-spacing.js index 144a03536907a0..36c33e533098ef 100644 --- a/tools/eslint/lib/rules/template-curly-spacing.js +++ b/tools/eslint/lib/rules/template-curly-spacing.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var OPEN_PAREN = /\$\{$/; -var CLOSE_PAREN = /^\}/; +let OPEN_PAREN = /\$\{$/; +let CLOSE_PAREN = /^\}/; //------------------------------------------------------------------------------ // Rule Definition @@ -38,9 +38,9 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var always = context.options[0] === "always"; - var prefix = always ? "Expected" : "Unexpected"; + let sourceCode = context.getSourceCode(); + let always = context.options[0] === "always"; + let prefix = always ? "Expected" : "Unexpected"; /** * Checks spacing before `}` of a given token. @@ -48,7 +48,7 @@ module.exports = { * @returns {void} */ function checkSpacingBefore(token) { - var prevToken = sourceCode.getTokenBefore(token); + let prevToken = sourceCode.getTokenBefore(token); if (prevToken && CLOSE_PAREN.test(token.value) && @@ -77,7 +77,7 @@ module.exports = { * @returns {void} */ function checkSpacingAfter(token) { - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); if (nextToken && OPEN_PAREN.test(token.value) && @@ -105,7 +105,7 @@ module.exports = { return { TemplateElement: function(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); checkSpacingBefore(token); checkSpacingAfter(token); diff --git a/tools/eslint/lib/rules/unicode-bom.js b/tools/eslint/lib/rules/unicode-bom.js index a152b03ac99206..931d840b55c768 100644 --- a/tools/eslint/lib/rules/unicode-bom.js +++ b/tools/eslint/lib/rules/unicode-bom.js @@ -35,7 +35,7 @@ module.exports = { Program: function checkUnicodeBOM(node) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), location = {column: 0, line: 1}, requireBOM = context.options[0] || "never"; diff --git a/tools/eslint/lib/rules/valid-jsdoc.js b/tools/eslint/lib/rules/valid-jsdoc.js index 65ed539d55fa5b..8af117e30eb478 100644 --- a/tools/eslint/lib/rules/valid-jsdoc.js +++ b/tools/eslint/lib/rules/valid-jsdoc.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var doctrine = require("doctrine"); +let doctrine = require("doctrine"); //------------------------------------------------------------------------------ // Rule Definition @@ -61,7 +61,7 @@ module.exports = { create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, prefer = options.prefer || {}, sourceCode = context.getSourceCode(), @@ -78,7 +78,7 @@ module.exports = { //-------------------------------------------------------------------------- // Using a stack to store if a function returns or not (handling nested functions) - var fns = []; + let fns = []; /** * Check if node type is a Class @@ -110,7 +110,7 @@ module.exports = { * @private */ function addReturn(node) { - var functionState = fns[fns.length - 1]; + let functionState = fns[fns.length - 1]; if (functionState && node.argument !== null) { functionState.returnPresent = true; @@ -148,8 +148,8 @@ module.exports = { * @private */ function getCurrentExpectedTypes(type) { - var currentType; - var expectedType; + let currentType; + let expectedType; if (type.name) { currentType = type.name; @@ -177,8 +177,8 @@ module.exports = { return; } - var typesToCheck = []; - var elements = []; + let typesToCheck = []; + let elements = []; switch (type.type) { case "TypeApplication": // {Array.} @@ -223,7 +223,7 @@ module.exports = { * @private */ function checkJSDoc(node) { - var jsdocNode = sourceCode.getJSDocComment(node), + let jsdocNode = sourceCode.getJSDocComment(node), functionData = fns.pop(), hasReturns = false, hasConstructor = false, @@ -336,7 +336,7 @@ module.exports = { } // check the parameters - var jsdocParams = Object.keys(params); + let jsdocParams = Object.keys(params); if (node.params) { node.params.forEach(function(param, i) { @@ -344,7 +344,7 @@ module.exports = { param = param.left; } - var name = param.name; + let name = param.name; // TODO(nzakas): Figure out logical things to do with destructured, default, rest params if (param.type === "Identifier") { @@ -363,7 +363,7 @@ module.exports = { } if (options.matchDescription) { - var regex = new RegExp(options.matchDescription); + let regex = new RegExp(options.matchDescription); if (!regex.test(jsdoc.description)) { context.report(jsdocNode, "JSDoc description does not satisfy the regex pattern."); diff --git a/tools/eslint/lib/rules/valid-typeof.js b/tools/eslint/lib/rules/valid-typeof.js index 289375a88bac3b..dc378d9401d79c 100644 --- a/tools/eslint/lib/rules/valid-typeof.js +++ b/tools/eslint/lib/rules/valid-typeof.js @@ -21,7 +21,7 @@ module.exports = { create: function(context) { - var VALID_TYPES = ["symbol", "undefined", "object", "boolean", "number", "string", "function"], + let VALID_TYPES = ["symbol", "undefined", "object", "boolean", "number", "string", "function"], OPERATORS = ["==", "===", "!=", "!=="]; //-------------------------------------------------------------------------- @@ -31,7 +31,7 @@ module.exports = { return { UnaryExpression: function(node) { - var parent, sibling; + let parent, sibling; if (node.operator === "typeof") { parent = context.getAncestors().pop(); @@ -40,7 +40,7 @@ module.exports = { sibling = parent.left === node ? parent.right : parent.left; if (sibling.type === "Literal" && VALID_TYPES.indexOf(sibling.value) === -1) { - context.report(sibling, "Invalid typeof comparison value"); + context.report(sibling, "Invalid typeof comparison value."); } } } diff --git a/tools/eslint/lib/rules/vars-on-top.js b/tools/eslint/lib/rules/vars-on-top.js index 25bef0411dba78..e94e4875593088 100644 --- a/tools/eslint/lib/rules/vars-on-top.js +++ b/tools/eslint/lib/rules/vars-on-top.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var errorMessage = "All 'var' declarations must be at the top of the function scope."; + let errorMessage = "All 'var' declarations must be at the top of the function scope."; //-------------------------------------------------------------------------- // Helpers @@ -29,7 +29,7 @@ module.exports = { /** * @param {ASTNode} node - any node - * @returns {Boolean} whether the given node structurally represents a directive + * @returns {boolean} whether the given node structurally represents a directive */ function looksLikeDirective(node) { return node.type === "ExpressionStatement" && @@ -39,7 +39,7 @@ module.exports = { /** * Check to see if its a ES6 import declaration * @param {ASTNode} node - any node - * @returns {Boolean} whether the given node represents a import declaration + * @returns {boolean} whether the given node represents a import declaration */ function looksLikeImport(node) { return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" || @@ -67,10 +67,10 @@ module.exports = { * Checks whether this variable is on top of the block body * @param {ASTNode} node - The node to check * @param {ASTNode[]} statements - collection of ASTNodes for the parent node block - * @returns {Boolean} True if var is on top otherwise false + * @returns {boolean} True if var is on top otherwise false */ function isVarOnTop(node, statements) { - var i = 0, + let i = 0, l = statements.length; // skip over directives @@ -125,9 +125,9 @@ module.exports = { return { VariableDeclaration: function(node) { - var ancestors = context.getAncestors(); - var parent = ancestors.pop(); - var grandParent = ancestors.pop(); + let ancestors = context.getAncestors(); + let parent = ancestors.pop(); + let grandParent = ancestors.pop(); if (node.kind === "var") { // check variable is `var` type and not `let` or `const` if (parent.type === "ExportNamedDeclaration") { diff --git a/tools/eslint/lib/rules/wrap-iife.js b/tools/eslint/lib/rules/wrap-iife.js index 2f73699a429571..78554091c9964f 100644 --- a/tools/eslint/lib/rules/wrap-iife.js +++ b/tools/eslint/lib/rules/wrap-iife.js @@ -26,9 +26,9 @@ module.exports = { create: function(context) { - var style = context.options[0] || "outside"; + let style = context.options[0] || "outside"; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check if the node is wrapped in () @@ -37,7 +37,7 @@ module.exports = { * @private */ function wrapped(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return previousToken && previousToken.value === "(" && @@ -48,7 +48,7 @@ module.exports = { CallExpression: function(node) { if (node.callee.type === "FunctionExpression") { - var callExpressionWrapped = wrapped(node), + let callExpressionWrapped = wrapped(node), functionExpressionWrapped = wrapped(node.callee); if (!callExpressionWrapped && !functionExpressionWrapped) { diff --git a/tools/eslint/lib/rules/wrap-regex.js b/tools/eslint/lib/rules/wrap-regex.js index 1aed713bdd0850..44750a3fbd1e1c 100644 --- a/tools/eslint/lib/rules/wrap-regex.js +++ b/tools/eslint/lib/rules/wrap-regex.js @@ -21,12 +21,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Literal: function(node) { - var token = sourceCode.getFirstToken(node), + let token = sourceCode.getFirstToken(node), nodeType = token.type, source, grandparent, diff --git a/tools/eslint/lib/rules/yield-star-spacing.js b/tools/eslint/lib/rules/yield-star-spacing.js index e2911b7200524c..c9ca64e0c255e3 100644 --- a/tools/eslint/lib/rules/yield-star-spacing.js +++ b/tools/eslint/lib/rules/yield-star-spacing.js @@ -39,9 +39,9 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var mode = (function(option) { + let mode = (function(option) { if (!option || typeof option === "string") { return { before: { before: true, after: false }, @@ -64,11 +64,11 @@ module.exports = { */ function checkSpacing(side, leftToken, rightToken) { if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken) !== mode[side]) { - var after = leftToken.value === "*"; - var spaceRequired = mode[side]; - var node = after ? leftToken : rightToken; - var type = spaceRequired ? "Missing" : "Unexpected"; - var message = type + " space " + side + " *."; + let after = leftToken.value === "*"; + let spaceRequired = mode[side]; + let node = after ? leftToken : rightToken; + let type = spaceRequired ? "Missing" : "Unexpected"; + let message = type + " space " + side + " *."; context.report({ node: node, @@ -96,10 +96,10 @@ module.exports = { return; } - var tokens = sourceCode.getFirstTokens(node, 3); - var yieldToken = tokens[0]; - var starToken = tokens[1]; - var nextToken = tokens[2]; + let tokens = sourceCode.getFirstTokens(node, 3); + let yieldToken = tokens[0]; + let starToken = tokens[1]; + let nextToken = tokens[2]; checkSpacing("before", yieldToken, starToken); checkSpacing("after", starToken, nextToken); diff --git a/tools/eslint/lib/rules/yoda.js b/tools/eslint/lib/rules/yoda.js index 0373e91a4a999c..29f0602b98de7e 100644 --- a/tools/eslint/lib/rules/yoda.js +++ b/tools/eslint/lib/rules/yoda.js @@ -10,7 +10,7 @@ /** * Determines whether an operator is a comparison operator. - * @param {String} operator The operator to check. + * @param {string} operator The operator to check. * @returns {boolean} Whether or not it is a comparison operator. */ function isComparisonOperator(operator) { @@ -19,7 +19,7 @@ function isComparisonOperator(operator) { /** * Determines whether an operator is an equality operator. - * @param {String} operator The operator to check. + * @param {string} operator The operator to check. * @returns {boolean} Whether or not it is an equality operator. */ function isEqualityOperator(operator) { @@ -29,7 +29,7 @@ function isEqualityOperator(operator) { /** * Determines whether an operator is one used in a range test. * Allowed operators are `<` and `<=`. - * @param {String} operator The operator to check. + * @param {string} operator The operator to check. * @returns {boolean} Whether the operator is used in range tests. */ function isRangeTestOperator(operator) { @@ -147,11 +147,11 @@ module.exports = { create: function(context) { // Default to "never" (!always) if no option - var always = (context.options[0] === "always"); - var exceptRange = (context.options[1] && context.options[1].exceptRange); - var onlyEquality = (context.options[1] && context.options[1].onlyEquality); + let always = (context.options[0] === "always"); + let exceptRange = (context.options[1] && context.options[1].exceptRange); + let onlyEquality = (context.options[1] && context.options[1].onlyEquality); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines whether node represents a range test. @@ -161,18 +161,18 @@ module.exports = { * must be less than or equal to the literal on the right side so that the * test makes any sense. * @param {ASTNode} node LogicalExpression node to test. - * @returns {Boolean} Whether node is a range test. + * @returns {boolean} Whether node is a range test. */ function isRangeTest(node) { - var left = node.left, + let left = node.left, right = node.right; /** * Determines whether node is of the form `0 <= x && x < 1`. - * @returns {Boolean} Whether node is a "between" range test. + * @returns {boolean} Whether node is a "between" range test. */ function isBetweenTest() { - var leftLiteral, rightLiteral; + let leftLiteral, rightLiteral; return (node.operator === "&&" && (leftLiteral = getNormalizedLiteral(left.left)) && @@ -183,10 +183,10 @@ module.exports = { /** * Determines whether node is of the form `x < 0 || 1 <= x`. - * @returns {Boolean} Whether node is an "outside" range test. + * @returns {boolean} Whether node is an "outside" range test. */ function isOutsideTest() { - var leftLiteral, rightLiteral; + let leftLiteral, rightLiteral; return (node.operator === "||" && (leftLiteral = getNormalizedLiteral(left.right)) && @@ -197,12 +197,12 @@ module.exports = { /** * Determines whether node is wrapped in parentheses. - * @returns {Boolean} Whether node is preceded immediately by an open + * @returns {boolean} Whether node is preceded immediately by an open * paren token and followed immediately by a close * paren token. */ function isParenWrapped() { - var tokenBefore, tokenAfter; + let tokenBefore, tokenAfter; return ((tokenBefore = sourceCode.getTokenBefore(node)) && tokenBefore.value === "(" && diff --git a/tools/eslint/lib/testers/event-generator-tester.js b/tools/eslint/lib/testers/event-generator-tester.js index 00b2d03307a883..f77152c0bba3fa 100644 --- a/tools/eslint/lib/testers/event-generator-tester.js +++ b/tools/eslint/lib/testers/event-generator-tester.js @@ -10,7 +10,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"); +let assert = require("assert"); //------------------------------------------------------------------------------ // Public Interface @@ -21,7 +21,7 @@ module.exports = { /** * Overrideable `describe` function to test. * @param {string} text - A description. - * @param {function} method - A test logic. + * @param {Function} method - A test logic. * @returns {any} The returned value with the test logic. */ describe: (typeof describe === "function") ? describe : /* istanbul ignore next */ function(text, method) { @@ -31,7 +31,7 @@ module.exports = { /** * Overrideable `it` function to test. * @param {string} text - A description. - * @param {function} method - A test logic. + * @param {Function} method - A test logic. * @returns {any} The returned value with the test logic. */ it: (typeof it === "function") ? it : /* istanbul ignore next */ function(text, method) { @@ -40,7 +40,7 @@ module.exports = { /** * Does some tests to check a given object implements the EventGenerator interface. - * @param {object} instance - An object to check. + * @param {Object} instance - An object to check. * @returns {void} */ testEventGeneratorInterface: function(instance) { diff --git a/tools/eslint/lib/testers/rule-tester.js b/tools/eslint/lib/testers/rule-tester.js index 2ee87eca6d4f27..703129ca057e53 100644 --- a/tools/eslint/lib/testers/rule-tester.js +++ b/tools/eslint/lib/testers/rule-tester.js @@ -40,7 +40,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), assert = require("assert"), util = require("util"), validator = require("../config/config-validator"), @@ -58,14 +58,14 @@ var lodash = require("lodash"), * testerDefaultConfig must not be modified as it allows to reset the tester to * the initial default configuration */ -var testerDefaultConfig = { rules: {} }; -var defaultConfig = { rules: {} }; +let testerDefaultConfig = { rules: {} }; +let defaultConfig = { rules: {} }; /* * List every parameters possible on a test case that are not related to eslint * configuration */ -var RuleTesterParameters = [ +let RuleTesterParameters = [ "code", "filename", "options", @@ -73,9 +73,9 @@ var RuleTesterParameters = [ "errors" ]; -var validateSchema = validate(metaSchema, { verbose: true }); +let validateSchema = validate(metaSchema, { verbose: true }); -var hasOwnProperty = Function.call.bind(Object.hasOwnProperty); +let hasOwnProperty = Function.call.bind(Object.hasOwnProperty); /** * Clones a given value deeply. @@ -90,9 +90,9 @@ function cloneDeeplyExcludesParent(x) { return x.map(cloneDeeplyExcludesParent); } - var retv = {}; + let retv = {}; - for (var key in x) { + for (let key in x) { if (key !== "parent" && hasOwnProperty(x, key)) { retv[key] = cloneDeeplyExcludesParent(x[key]); } @@ -115,7 +115,7 @@ function freezeDeeply(x) { if (Array.isArray(x)) { x.forEach(freezeDeeply); } else { - for (var key in x) { + for (let key in x) { if (key !== "parent" && hasOwnProperty(x, key)) { freezeDeeply(x[key]); } @@ -211,7 +211,7 @@ RuleTester.prototype = { */ run: function(ruleName, rule, test) { - var testerConfig = this.testerConfig, + let testerConfig = this.testerConfig, result = {}; /* eslint-disable no-shadow */ @@ -219,12 +219,12 @@ RuleTester.prototype = { /** * Run the rule for the given item * @param {string} ruleName name of the rule - * @param {string|object} item Item to run the rule against - * @returns {object} Eslint run result + * @param {string|Object} item Item to run the rule against + * @returns {Object} Eslint run result * @private */ function runRuleForItem(ruleName, item) { - var config = lodash.cloneDeep(testerConfig), + let config = lodash.cloneDeep(testerConfig), code, filename, schema, beforeAST, afterAST; if (typeof item === "string") { @@ -234,7 +234,7 @@ RuleTester.prototype = { // Assumes everything on the item is a config except for the // parameters used by this tester - var itemConfig = lodash.omit(item, RuleTesterParameters); + let itemConfig = lodash.omit(item, RuleTesterParameters); // Create the config object from the tester config and this item // specific configurations. @@ -249,7 +249,7 @@ RuleTester.prototype = { } if (item.options) { - var options = item.options.concat(); + let options = item.options.concat(); options.unshift(1); config.rules[ruleName] = options; @@ -290,11 +290,11 @@ RuleTester.prototype = { }); // Freezes rule-context properties. - var originalGet = rules.get; + let originalGet = rules.get; try { rules.get = function(ruleId) { - var rule = originalGet(ruleId); + let rule = originalGet(ruleId); if (typeof rule === "function") { return function(context) { @@ -349,13 +349,13 @@ RuleTester.prototype = { * Check if the template is valid or not * all valid cases go through this * @param {string} ruleName name of the rule - * @param {string|object} item Item to run the rule against + * @param {string|Object} item Item to run the rule against * @returns {void} * @private */ function testValidTemplate(ruleName, item) { - var result = runRuleForItem(ruleName, item); - var messages = result.messages; + let result = runRuleForItem(ruleName, item); + let messages = result.messages; assert.equal(messages.length, 0, util.format("Should have no errors but had %d: %s", messages.length, util.inspect(messages))); @@ -367,7 +367,7 @@ RuleTester.prototype = { * Check if the template is invalid or not * all invalid cases go through this. * @param {string} ruleName name of the rule - * @param {string|object} item Item to run the rule against + * @param {string|Object} item Item to run the rule against * @returns {void} * @private */ @@ -375,8 +375,8 @@ RuleTester.prototype = { assert.ok(item.errors || item.errors === 0, "Did not specify errors for an invalid test of " + ruleName); - var result = runRuleForItem(ruleName, item); - var messages = result.messages; + let result = runRuleForItem(ruleName, item); + let messages = result.messages; @@ -388,14 +388,14 @@ RuleTester.prototype = { util.format("Should have %d error%s but had %d: %s", item.errors.length, item.errors.length === 1 ? "" : "s", messages.length, util.inspect(messages))); - for (var i = 0, l = item.errors.length; i < l; i++) { + for (let i = 0, l = item.errors.length; i < l; i++) { assert.ok(!("fatal" in messages[i]), "A fatal parsing error occurred: " + messages[i].message); assert.equal(messages[i].ruleId, ruleName, "Error rule name should be the same as the name of the rule being tested"); if (typeof item.errors[i] === "string") { // Just an error message. - assert.equal(messages[i].message, item.errors[i], "Error message should be " + item.errors[i]); + assert.equal(messages[i].message, item.errors[i]); } else if (typeof item.errors[i] === "object") { /* @@ -404,7 +404,7 @@ RuleTester.prototype = { * column. */ if (item.errors[i].message) { - assert.equal(messages[i].message, item.errors[i].message, "Error message should be " + item.errors[i].message); + assert.equal(messages[i].message, item.errors[i].message); } if (item.errors[i].type) { @@ -418,6 +418,14 @@ RuleTester.prototype = { if (item.errors[i].hasOwnProperty("column")) { assert.equal(messages[i].column, item.errors[i].column, "Error column should be " + item.errors[i].column); } + + if (item.errors[i].hasOwnProperty("endLine")) { + assert.equal(messages[i].endLine, item.errors[i].endLine, "Error endLine should be " + item.errors[i].endLine); + } + + if (item.errors[i].hasOwnProperty("endColumn")) { + assert.equal(messages[i].endColumn, item.errors[i].endColumn, "Error endColumn should be " + item.errors[i].endColumn); + } } else { // Only string or object errors are valid. @@ -426,7 +434,7 @@ RuleTester.prototype = { } if (item.hasOwnProperty("output")) { - var fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages); + let fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages); assert.equal(fixResult.output, item.output, "Output is incorrect."); } diff --git a/tools/eslint/lib/timing.js b/tools/eslint/lib/timing.js index 6dfffc19d979eb..ff0dd7ffb27918 100644 --- a/tools/eslint/lib/timing.js +++ b/tools/eslint/lib/timing.js @@ -39,23 +39,23 @@ function alignRight(str, len, ch) { // Module definition //------------------------------------------------------------------------------ -var enabled = !!process.env.TIMING; +let enabled = !!process.env.TIMING; -var HEADERS = ["Rule", "Time (ms)", "Relative"]; -var ALIGN = [alignLeft, alignRight, alignRight]; +let HEADERS = ["Rule", "Time (ms)", "Relative"]; +let ALIGN = [alignLeft, alignRight, alignRight]; /* istanbul ignore next */ /** * display the data - * @param {object} data Data object to be displayed + * @param {Object} data Data object to be displayed * @returns {string} modified string * @private */ function display(data) { - var total = 0; - var rows = Object.keys(data) + let total = 0; + let rows = Object.keys(data) .map(function(key) { - var time = data[key]; + let time = data[key]; total += time; return [key, time]; @@ -72,10 +72,10 @@ function display(data) { rows.unshift(HEADERS); - var widths = []; + let widths = []; rows.forEach(function(row) { - var len = row.length, + let len = row.length, i, n; @@ -87,7 +87,7 @@ function display(data) { } }); - var table = rows.map(function(row) { + let table = rows.map(function(row) { return row.map(function(cell, index) { return ALIGN[index](cell, widths[index]); }).join(" | "); @@ -107,7 +107,7 @@ function display(data) { /* istanbul ignore next */ module.exports = (function() { - var data = Object.create(null); + let data = Object.create(null); /** * Time the run @@ -122,7 +122,7 @@ module.exports = (function() { } return function() { - var t = process.hrtime(); + let t = process.hrtime(); fn.apply(null, Array.prototype.slice.call(arguments)); t = process.hrtime(t); diff --git a/tools/eslint/lib/token-store.js b/tools/eslint/lib/token-store.js index 0262b69a521107..183c7363ec9560 100644 --- a/tools/eslint/lib/token-store.js +++ b/tools/eslint/lib/token-store.js @@ -9,7 +9,7 @@ //------------------------------------------------------------------------------ module.exports = function(tokens) { - var api = {}, + let api = {}, starts = Object.create(null), ends = Object.create(null), index, length, range; @@ -21,7 +21,7 @@ module.exports = function(tokens) { * @returns {Token[]} Tokens in the interval. */ function get(start, end) { - var result = [], + let result = [], i; for (i = Math.max(0, start); i < end && i < length; i++) { @@ -39,7 +39,7 @@ module.exports = function(tokens) { * @returns {int} Index in the tokens array of the node's last token. */ function lastTokenIndex(node) { - var end = node.range[1], + let end = node.range[1], cursor = ends[end]; // If the node extends beyond its last token, get the token before the @@ -73,7 +73,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getTokensBefore = function(node, beforeCount) { - var first = starts[node.range[0]]; + let first = starts[node.range[0]]; return get(first - (beforeCount || 0), first); }; @@ -98,7 +98,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getTokensAfter = function(node, afterCount) { - var start = lastTokenIndex(node) + 1; + let start = lastTokenIndex(node) + 1; return get(start, start + (afterCount || 0)); }; @@ -135,7 +135,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getFirstTokens = function(node, count) { - var first = starts[node.range[0]]; + let first = starts[node.range[0]]; return get( first, @@ -160,7 +160,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getLastTokens = function(node, count) { - var last = lastTokenIndex(node) + 1; + let last = lastTokenIndex(node) + 1; return get(Math.max(starts[node.range[0]], last - (count || 0)), last); }; diff --git a/tools/eslint/lib/util/comment-event-generator.js b/tools/eslint/lib/util/comment-event-generator.js index 2989f4ee26ae39..40771790b7f6ea 100644 --- a/tools/eslint/lib/util/comment-event-generator.js +++ b/tools/eslint/lib/util/comment-event-generator.js @@ -21,7 +21,7 @@ function emitComments(comments, emitter, locs, eventName) { if (comments.length > 0) { comments.forEach(function(node) { - var index = locs.indexOf(node.loc); + let index = locs.indexOf(node.loc); if (index >= 0) { locs.splice(index, 1); @@ -91,7 +91,7 @@ CommentEventGenerator.prototype = { * @returns {void} */ enterNode: function enterNode(node) { - var comments = this.sourceCode.getComments(node); + let comments = this.sourceCode.getComments(node); emitCommentsEnter(this, comments.leading); this.original.enterNode(node); @@ -104,7 +104,7 @@ CommentEventGenerator.prototype = { * @returns {void} */ leaveNode: function leaveNode(node) { - var comments = this.sourceCode.getComments(node); + let comments = this.sourceCode.getComments(node); emitCommentsExit(this, comments.trailing); this.original.leaveNode(node); diff --git a/tools/eslint/lib/util/glob-util.js b/tools/eslint/lib/util/glob-util.js index 1209dabd6a1ede..30784b2bfc1d31 100644 --- a/tools/eslint/lib/util/glob-util.js +++ b/tools/eslint/lib/util/glob-util.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug"), +let debug = require("debug"), fs = require("fs"), path = require("path"), glob = require("glob"), @@ -33,7 +33,7 @@ debug = debug("eslint:glob-util"); * * Also makes sure all path separators are POSIX style for `glob` compatibility. * - * @param {object} [options] An options object + * @param {Object} [options] An options object * @param {string[]} [options.extensions=[".js"]] An array of accepted extensions * @param {string} [options.cwd=process.cwd()] The cwd to use to resolve relative pathnames * @returns {Function} A function that takes a pathname and returns a glob that @@ -41,14 +41,14 @@ debug = debug("eslint:glob-util"); * pathname is a directory. */ function processPath(options) { - var cwd = (options && options.cwd) || process.cwd(); - var extensions = (options && options.extensions) || [".js"]; + let cwd = (options && options.cwd) || process.cwd(); + let extensions = (options && options.extensions) || [".js"]; extensions = extensions.map(function(ext) { return ext.charAt(0) === "." ? ext.substr(1) : ext; }); - var suffix = "/**"; + let suffix = "/**"; if (extensions.length === 1) { suffix += "/*." + extensions[0]; @@ -64,8 +64,8 @@ function processPath(options) { * @private */ return function(pathname) { - var newPath = pathname; - var resolvedPath = path.resolve(cwd, pathname); + let newPath = pathname; + let resolvedPath = path.resolve(cwd, pathname); if (shell.test("-d", resolvedPath)) { newPath = pathname.replace(/[\/\\]$/, "") + suffix; @@ -87,7 +87,7 @@ function processPath(options) { */ function resolveFileGlobPatterns(patterns, options) { - var processPathExtensions = processPath(options); + let processPathExtensions = processPath(options); return patterns.map(processPathExtensions); } @@ -105,12 +105,12 @@ function resolveFileGlobPatterns(patterns, options) { * @returns {string[]} Resolved absolute filenames. */ function listFilesToProcess(globPatterns, options) { - var ignoredPaths, + let ignoredPaths, files = [], added = {}, globOptions; - var cwd = (options && options.cwd) || process.cwd(); + let cwd = (options && options.cwd) || process.cwd(); /** * Executes the linter on a file defined by the `filename`. Skips @@ -121,8 +121,8 @@ function listFilesToProcess(globPatterns, options) { * @returns {void} */ function addFile(filename, shouldWarnIgnored) { - var ignored = false; - var isSilentlyIgnored; + let ignored = false; + let isSilentlyIgnored; if (ignoredPaths.contains(filename, "default")) { ignored = (options.ignore !== false) && shouldWarnIgnored; @@ -160,7 +160,7 @@ function listFilesToProcess(globPatterns, options) { debug("Creating list of files to process."); globPatterns.forEach(function(pattern) { - var file = path.resolve(cwd, pattern); + let file = path.resolve(cwd, pattern); if (shell.test("-f", file)) { addFile(fs.realpathSync(file), !shell.test("-d", file)); diff --git a/tools/eslint/lib/util/hash.js b/tools/eslint/lib/util/hash.js index 9f3b734c278e73..092c56e8633e1c 100644 --- a/tools/eslint/lib/util/hash.js +++ b/tools/eslint/lib/util/hash.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var murmur = require("imurmurhash"); +let murmur = require("imurmurhash"); //------------------------------------------------------------------------------ // Helpers diff --git a/tools/eslint/lib/util/module-resolver.js b/tools/eslint/lib/util/module-resolver.js index 251292280dd3d8..964988ec6ebcbe 100644 --- a/tools/eslint/lib/util/module-resolver.js +++ b/tools/eslint/lib/util/module-resolver.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), Module = require("module"); //------------------------------------------------------------------------------ // Private //------------------------------------------------------------------------------ -var DEFAULT_OPTIONS = { +let DEFAULT_OPTIONS = { /* * module.paths is an array of paths to search for resolving things relative @@ -60,7 +60,7 @@ ModuleResolver.prototype = { * subsequent calls to this function. Then, move the extraLookupPath to the * top of the lookup paths list so it will be searched first. */ - var lookupPaths = this.options.lookupPaths.concat(); + let lookupPaths = this.options.lookupPaths.concat(); lookupPaths.unshift(extraLookupPath); @@ -69,7 +69,7 @@ ModuleResolver.prototype = { * lookup file paths when require() is called. So, we are hooking into the * exact same logic that Node.js uses. */ - var result = Module._findPath(name, lookupPaths); // eslint-disable-line no-underscore-dangle + let result = Module._findPath(name, lookupPaths); // eslint-disable-line no-underscore-dangle if (!result) { throw new Error("Cannot find module '" + name + "'"); diff --git a/tools/eslint/lib/util/npm-util.js b/tools/eslint/lib/util/npm-util.js index 9f28dc2b7edc5a..e888f8feb61032 100644 --- a/tools/eslint/lib/util/npm-util.js +++ b/tools/eslint/lib/util/npm-util.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"), shell = require("shelljs"), log = require("../logging"); @@ -26,10 +26,10 @@ var fs = require("fs"), * @returns {string} Absolute path to closest package.json file */ function findPackageJson(startDir) { - var dir = path.resolve(startDir || process.cwd()); + let dir = path.resolve(startDir || process.cwd()); do { - var pkgfile = path.join(dir, "package.json"); + let pkgfile = path.join(dir, "package.json"); if (!fs.existsSync(pkgfile)) { dir = path.join(dir, ".."); @@ -68,9 +68,9 @@ function installSyncSaveDev(packages) { * and values are booleans indicating installation. */ function check(packages, opt) { - var deps = []; - var pkgJson = (opt) ? findPackageJson(opt.startDir) : findPackageJson(); - var fileJson; + let deps = []; + let pkgJson = (opt) ? findPackageJson(opt.startDir) : findPackageJson(); + let fileJson; if (!pkgJson) { throw new Error("Could not find a package.json file. Run 'npm init' to create one."); diff --git a/tools/eslint/lib/util/path-util.js b/tools/eslint/lib/util/path-util.js index a199046bb77b69..8add2064adcb95 100644 --- a/tools/eslint/lib/util/path-util.js +++ b/tools/eslint/lib/util/path-util.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var path = require("path"); +let path = require("path"); //------------------------------------------------------------------------------ // Private @@ -21,8 +21,8 @@ var path = require("path"); * @returns {string} Converted filepath */ function convertPathToPosix(filepath) { - var normalizedFilepath = path.normalize(filepath); - var posixFilepath = normalizedFilepath.replace(/\\/g, "/"); + let normalizedFilepath = path.normalize(filepath); + let posixFilepath = normalizedFilepath.replace(/\\/g, "/"); return posixFilepath; } @@ -48,7 +48,7 @@ function convertPathToPosix(filepath) { * @returns {string} Relative filepath */ function getRelativePath(filepath, baseDir) { - var relativePath; + let relativePath; if (!path.isAbsolute(filepath)) { filepath = path.resolve(filepath); diff --git a/tools/eslint/lib/util/source-code-fixer.js b/tools/eslint/lib/util/source-code-fixer.js index 042eff591f3ea0..d855edb206bef8 100644 --- a/tools/eslint/lib/util/source-code-fixer.js +++ b/tools/eslint/lib/util/source-code-fixer.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug")("eslint:text-fixer"); +let debug = require("debug")("eslint:text-fixer"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var BOM = "\uFEFF"; +let BOM = "\uFEFF"; /** * Compares items in a messages array by line and column. @@ -24,7 +24,7 @@ var BOM = "\uFEFF"; * @private */ function compareMessagesByLocation(a, b) { - var lineDiff = a.line - b.line; + let lineDiff = a.line - b.line; if (lineDiff === 0) { return a.column - b.column; @@ -66,7 +66,7 @@ SourceCodeFixer.applyFixes = function(sourceCode, messages) { } // clone the array - var remainingMessages = [], + let remainingMessages = [], fixes = [], text = sourceCode.text, lastFixPos = text.length + 1, @@ -89,13 +89,13 @@ SourceCodeFixer.applyFixes = function(sourceCode, messages) { }); // split into array of characters for easier manipulation - var chars = text.split(""); + let chars = text.split(""); fixes.forEach(function(problem) { - var fix = problem.fix; - var start = fix.range[0]; - var end = fix.range[1]; - var insertionText = fix.text; + let fix = problem.fix; + let start = fix.range[0]; + let end = fix.range[1]; + let insertionText = fix.text; if (end < lastFixPos) { if (start < 0) { diff --git a/tools/eslint/lib/util/source-code-util.js b/tools/eslint/lib/util/source-code-util.js index e51c1c124c798f..f07f61192b909e 100644 --- a/tools/eslint/lib/util/source-code-util.js +++ b/tools/eslint/lib/util/source-code-util.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), debug = require("debug"), CLIEngine = require("../cli-engine"), eslint = require("../eslint"), @@ -31,16 +31,16 @@ debug = debug("eslint:source-code-util"); */ function getSourceCodeOfFile(filename, options) { debug("getting sourceCode of", filename); - var opts = lodash.assign({}, options, { rules: {}}); - var cli = new CLIEngine(opts); - var results = cli.executeOnFiles([filename]); + let opts = lodash.assign({}, options, { rules: {}}); + let cli = new CLIEngine(opts); + let results = cli.executeOnFiles([filename]); if (results && results.results[0] && results.results[0].messages[0] && results.results[0].messages[0].fatal) { - var msg = results.results[0].messages[0]; + let msg = results.results[0].messages[0]; throw new Error("(" + filename + ":" + msg.line + ":" + msg.column + ") " + msg.message); } - var sourceCode = eslint.getSourceCode(); + let sourceCode = eslint.getSourceCode(); return sourceCode; } @@ -66,7 +66,7 @@ function getSourceCodeOfFile(filename, options) { * @returns {Object} The SourceCode of all processed files. */ function getSourceCodeOfFiles(patterns, options, cb) { - var sourceCodes = {}, + let sourceCodes = {}, filenames, opts; @@ -94,7 +94,7 @@ function getSourceCodeOfFiles(patterns, options, cb) { debug("Did not find any files matching pattern(s): " + patterns); } filenames.forEach(function(filename) { - var sourceCode = getSourceCodeOfFile(filename, opts); + let sourceCode = getSourceCodeOfFile(filename, opts); if (sourceCode) { debug("got sourceCode of", filename); diff --git a/tools/eslint/lib/util/source-code.js b/tools/eslint/lib/util/source-code.js index adf4df93a6b3ae..b8ed5841cd1764 100644 --- a/tools/eslint/lib/util/source-code.js +++ b/tools/eslint/lib/util/source-code.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), createTokenStore = require("../token-store.js"), Traverser = require("./traverser"); @@ -52,7 +52,7 @@ function validate(ast) { function findJSDocComment(comments, line) { if (comments) { - for (var i = comments.length - 1; i >= 0; i--) { + for (let i = comments.length - 1; i >= 0; i--) { if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") { if (line - comments[i].loc.end.line <= 1) { @@ -123,13 +123,13 @@ function SourceCode(text, ast) { }); // create token store methods - var tokenStore = createTokenStore(ast.tokens); + let tokenStore = createTokenStore(ast.tokens); Object.keys(tokenStore).forEach(function(methodName) { this[methodName] = tokenStore[methodName]; }, this); - var tokensAndCommentsStore = createTokenStore(this.tokensAndComments); + let tokensAndCommentsStore = createTokenStore(this.tokensAndComments); this.getTokenOrCommentBefore = tokensAndCommentsStore.getTokenBefore; this.getTokenOrCommentAfter = tokensAndCommentsStore.getTokenAfter; @@ -193,7 +193,7 @@ SourceCode.prototype = { */ getComments: function(node) { - var leadingComments = node.leadingComments || [], + let leadingComments = node.leadingComments || [], trailingComments = node.trailingComments || []; /* @@ -222,7 +222,7 @@ SourceCode.prototype = { */ getJSDocComment: function(node) { - var parent = node.parent; + let parent = node.parent; switch (node.type) { case "ClassDeclaration": @@ -261,7 +261,7 @@ SourceCode.prototype = { * @returns {ASTNode} The node if found or null if not found. */ getNodeByRangeIndex: function(index) { - var result = null, + let result = null, resultParent = null, traverser = new Traverser(); @@ -294,7 +294,7 @@ SourceCode.prototype = { * if there is anything other than whitespace between tokens. */ isSpaceBetweenTokens: function(first, second) { - var text = this.text.slice(first.range[1], second.range[0]); + let text = this.text.slice(first.range[1], second.range[0]); return /\s/.test(text.replace(/\/\*.*?\*\//g, "")); } diff --git a/tools/eslint/lib/util/traverser.js b/tools/eslint/lib/util/traverser.js index 03a1c376e153fd..b68d0993af3ab5 100644 --- a/tools/eslint/lib/util/traverser.js +++ b/tools/eslint/lib/util/traverser.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var estraverse = require("estraverse"); +let estraverse = require("estraverse"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var KEY_BLACKLIST = [ +let KEY_BLACKLIST = [ "parent", "leadingComments", "trailingComments" @@ -27,7 +27,7 @@ var KEY_BLACKLIST = [ */ function Traverser() { - var controller = Object.create(new estraverse.Controller()), + let controller = Object.create(new estraverse.Controller()), originalTraverse = controller.traverse; // intercept call to traverse() and add the fallback key to the visitor diff --git a/tools/eslint/lib/util/xml-escape.js b/tools/eslint/lib/util/xml-escape.js new file mode 100644 index 00000000000000..2c3abd39d5b482 --- /dev/null +++ b/tools/eslint/lib/util/xml-escape.js @@ -0,0 +1,34 @@ +/** + * @fileoverview XML character escaper + * @author George Chung + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +/** + * Returns the escaped value for a character + * @param {string} s string to examine + * @returns {string} severity level + * @private + */ +module.exports = function(s) { + return ("" + s).replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/g, function(c) { // eslint-disable-line no-control-regex + switch (c) { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "\"": + return """; + case "'": + return "'"; + default: + return "&#" + c.charCodeAt(0) + ";"; + } + }); +}; diff --git a/tools/eslint/node_modules/acorn-jsx/package.json b/tools/eslint/node_modules/acorn-jsx/package.json index 1982020ad52c2b..ecb4920524a435 100644 --- a/tools/eslint/node_modules/acorn-jsx/package.json +++ b/tools/eslint/node_modules/acorn-jsx/package.json @@ -1,7 +1,15 @@ { "_args": [ [ - "acorn-jsx@^3.0.0", + { + "raw": "acorn-jsx@^3.0.0", + "scope": null, + "escapedName": "acorn-jsx", + "name": "acorn-jsx", + "rawSpec": "^3.0.0", + "spec": ">=3.0.0 <4.0.0", + "type": "range" + }, "/Users/trott/io.js/tools/node_modules/espree" ] ], @@ -16,16 +24,17 @@ "tmp": "tmp/acorn-jsx-3.0.1.tgz_1462206645285_0.17844340158626437" }, "_npmUser": { - "email": "me@rreverser.com", - "name": "rreverser" + "name": "rreverser", + "email": "me@rreverser.com" }, "_npmVersion": "3.8.6", "_phantomChildren": {}, "_requested": { - "name": "acorn-jsx", "raw": "acorn-jsx@^3.0.0", - "rawSpec": "^3.0.0", "scope": null, + "escapedName": "acorn-jsx", + "name": "acorn-jsx", + "rawSpec": "^3.0.0", "spec": ">=3.0.0 <4.0.0", "type": "range" }, @@ -58,8 +67,8 @@ "license": "MIT", "maintainers": [ { - "email": "me@rreverser.com", - "name": "rreverser" + "name": "rreverser", + "email": "me@rreverser.com" } ], "name": "acorn-jsx", diff --git a/tools/eslint/node_modules/acorn/AUTHORS b/tools/eslint/node_modules/acorn/AUTHORS index c459c44642f3e1..1b2061cd4b3021 100644 --- a/tools/eslint/node_modules/acorn/AUTHORS +++ b/tools/eslint/node_modules/acorn/AUTHORS @@ -1,7 +1,8 @@ --e List of Acorn contributors. Updated before every release. +List of Acorn contributors. Updated before every release. Adrian Rakovsky Alistair Braidwood +Amila Welihinda Andres Suarez Angelo Aparajita Fishman @@ -10,6 +11,7 @@ Artem Govorov Brandon Mills Charles Hughes Conrad Irwin +Daniel Tschinder David Bonnet Domenico Matteo ForbesLindesay @@ -26,6 +28,7 @@ Jordan Klassen Jürg Lehni keeyipchan Keheliya Gallaba +Kevin Irish Kevin Kwok krator Marijn Haverbeke @@ -49,6 +52,7 @@ ReadmeCritic r-e-d Richard Gibson Rich Harris +Rich-Harris Sebastian McKenzie Timothy Gu Toru Nagashima diff --git a/tools/eslint/node_modules/acorn/bin/acorn b/tools/eslint/node_modules/acorn/bin/acorn index 63b7615e359ab7..cf4acd563179ad 100755 --- a/tools/eslint/node_modules/acorn/bin/acorn +++ b/tools/eslint/node_modules/acorn/bin/acorn @@ -1,71 +1,65 @@ #!/usr/bin/env node -"use strict"; +'use strict'; -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj["default"] = obj; return newObj; } } +var path = require('path'); +var fs = require('fs'); +var acorn = require('../dist/acorn.js'); -var _path = require("path"); - -var _fs = require("fs"); - -var _distAcornJs = require("../dist/acorn.js"); - -var acorn = _interopRequireWildcard(_distAcornJs); - -var infile = undefined, - forceFile = undefined, - silent = false, - compact = false, - tokenize = false; -var options = {}; +var infile; +var forceFile; +var silent = false; +var compact = false; +var tokenize = false; +var options = {} function help(status) { - var print = status == 0 ? console.log : console.error; - print("usage: " + (0, _path.basename)(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7]"); - print(" [--tokenize] [--locations] [---allow-hash-bang] [--compact] [--silent] [--module] [--help] [--] [infile]"); - process.exit(status); + var print = (status == 0) ? console.log : console.error + print("usage: " + path.basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7]") + print(" [--tokenize] [--locations] [---allow-hash-bang] [--compact] [--silent] [--module] [--help] [--] [infile]") + process.exit(status) } for (var i = 2; i < process.argv.length; ++i) { - var arg = process.argv[i]; - if ((arg == "-" || arg[0] != "-") && !infile) infile = arg;else if (arg == "--" && !infile && i + 2 == process.argv.length) forceFile = infile = process.argv[++i];else if (arg == "--ecma3") options.ecmaVersion = 3;else if (arg == "--ecma5") options.ecmaVersion = 5;else if (arg == "--ecma6") options.ecmaVersion = 6;else if (arg == "--ecma7") options.ecmaVersion = 7;else if (arg == "--locations") options.locations = true;else if (arg == "--allow-hash-bang") options.allowHashBang = true;else if (arg == "--silent") silent = true;else if (arg == "--compact") compact = true;else if (arg == "--help") help(0);else if (arg == "--tokenize") tokenize = true;else if (arg == "--module") options.sourceType = 'module';else help(1); + var arg = process.argv[i] + if ((arg == "-" || arg[0] != "-") && !infile) infile = arg + else if (arg == "--" && !infile && i + 2 == process.argv.length) forceFile = infile = process.argv[++i] + else if (arg == "--ecma3") options.ecmaVersion = 3 + else if (arg == "--ecma5") options.ecmaVersion = 5 + else if (arg == "--ecma6") options.ecmaVersion = 6 + else if (arg == "--ecma7") options.ecmaVersion = 7 + else if (arg == "--locations") options.locations = true + else if (arg == "--allow-hash-bang") options.allowHashBang = true + else if (arg == "--silent") silent = true + else if (arg == "--compact") compact = true + else if (arg == "--help") help(0) + else if (arg == "--tokenize") tokenize = true + else if (arg == "--module") options.sourceType = 'module' + else help(1) } function run(code) { - var result = undefined; + var result if (!tokenize) { - try { - result = acorn.parse(code, options); - } catch (e) { - console.error(e.message);process.exit(1); - } + try { result = acorn.parse(code, options) } + catch(e) { console.error(e.message); process.exit(1) } } else { - result = []; - var tokenizer = acorn.tokenizer(code, options), - token = undefined; + result = [] + var tokenizer = acorn.tokenizer(code, options), token while (true) { - try { - token = tokenizer.getToken(); - } catch (e) { - console.error(e.message);process.exit(1); - } - result.push(token); - if (token.type == acorn.tokTypes.eof) break; + try { token = tokenizer.getToken() } + catch(e) { console.error(e.message); process.exit(1) } + result.push(token) + if (token.type == acorn.tokTypes.eof) break } } - if (!silent) console.log(JSON.stringify(result, null, compact ? null : 2)); + if (!silent) console.log(JSON.stringify(result, null, compact ? null : 2)) } if (forceFile || infile && infile != "-") { - run((0, _fs.readFileSync)(infile, "utf8")); + run(fs.readFileSync(infile, "utf8")) } else { - (function () { - var code = ""; - process.stdin.resume(); - process.stdin.on("data", function (chunk) { - return code += chunk; - }); - process.stdin.on("end", function () { - return run(code); - }); - })(); + var code = "" + process.stdin.resume() + process.stdin.on("data", function (chunk) { return code += chunk; }) + process.stdin.on("end", function () { return run(code); }) } \ No newline at end of file diff --git a/tools/eslint/node_modules/acorn/bin/build-acorn.js b/tools/eslint/node_modules/acorn/bin/build-acorn.js deleted file mode 100644 index 71f2cf941f5b4d..00000000000000 --- a/tools/eslint/node_modules/acorn/bin/build-acorn.js +++ /dev/null @@ -1,82 +0,0 @@ -var fs = require("fs"), path = require("path") -var stream = require("stream") - -var browserify = require("browserify") -var babel = require('babel-core') -var babelify = require("babelify").configure({loose: "all"}) - -process.chdir(path.resolve(__dirname, "..")) - -browserify({standalone: "acorn"}) - .plugin(require('browserify-derequire')) - .transform(babelify) - .require("./src/index.js", {entry: true}) - .bundle() - .on("error", function (err) { console.log("Error: " + err.message) }) - .pipe(fs.createWriteStream("dist/acorn.js")) - -var ACORN_PLACEHOLDER = "this_function_call_should_be_replaced_with_a_call_to_load_acorn()"; -function acornShimPrepare(file) { - var tr = new stream.Transform - if (file == path.resolve(__dirname, "../src/index.js")) { - var sent = false - tr._transform = function(chunk, _, callback) { - if (!sent) { - sent = true - callback(null, ACORN_PLACEHOLDER); - } else { - callback() - } - } - } else { - tr._transform = function(chunk, _, callback) { callback(null, chunk) } - } - return tr -} -function acornShimComplete() { - var tr = new stream.Transform - var buffer = ""; - tr._transform = function(chunk, _, callback) { - buffer += chunk.toString("utf8"); - callback(); - }; - tr._flush = function (callback) { - tr.push(buffer.replace(ACORN_PLACEHOLDER, "module.exports = typeof acorn != 'undefined' ? acorn : require(\"./acorn\")")); - callback(null); - }; - return tr; -} - -browserify({standalone: "acorn.loose"}) - .plugin(require('browserify-derequire')) - .transform(acornShimPrepare) - .transform(babelify) - .require("./src/loose/index.js", {entry: true}) - .bundle() - .on("error", function (err) { console.log("Error: " + err.message) }) - .pipe(acornShimComplete()) - .pipe(fs.createWriteStream("dist/acorn_loose.js")) - -browserify({standalone: "acorn.walk"}) - .plugin(require('browserify-derequire')) - .transform(acornShimPrepare) - .transform(babelify) - .require("./src/walk/index.js", {entry: true}) - .bundle() - .on("error", function (err) { console.log("Error: " + err.message) }) - .pipe(acornShimComplete()) - .pipe(fs.createWriteStream("dist/walk.js")) - -babel.transformFile("./src/bin/acorn.js", function (err, result) { - if (err) return console.log("Error: " + err.message) - fs.writeFile("bin/acorn", result.code, function (err) { - if (err) return console.log("Error: " + err.message) - - // Make bin/acorn executable - if (process.platform === 'win32') - return - var stat = fs.statSync("bin/acorn") - var newPerm = stat.mode | parseInt('111', 8) - fs.chmodSync("bin/acorn", newPerm) - }) -}) diff --git a/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js b/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js index e9f355103234da..100e8cf280fc56 100644 --- a/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js +++ b/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js @@ -1,11 +1,13 @@ +'use strict'; + // Which Unicode version should be used? -var version = '8.0.0'; +var version = '9.0.0'; -var start = require('unicode-' + version + '/properties/ID_Start/code-points') - .filter(function(ch) { return ch > 127; }); +var start = require('unicode-' + version + '/Binary_Property/ID_Start/code-points.js') + .filter(function(ch) { return ch > 0x7f; }); var last = -1; -var cont = [0x200c, 0x200d].concat(require('unicode-' + version + '/properties/ID_Continue/code-points') - .filter(function(ch) { return ch > 127 && search(start, ch, last + 1) == -1; })); +var cont = [0x200c, 0x200d].concat(require('unicode-' + version + '/Binary_Property/ID_Continue/code-points.js') + .filter(function(ch) { return ch > 0x7f && search(start, ch, last + 1) == -1; })); function search(arr, ch, starting) { for (var i = starting; arr[i] <= ch && i < arr.length; last = i++) diff --git a/tools/eslint/node_modules/acorn/dist/acorn.es.js b/tools/eslint/node_modules/acorn/dist/acorn.es.js new file mode 100644 index 00000000000000..4460957fd78f1a --- /dev/null +++ b/tools/eslint/node_modules/acorn/dist/acorn.es.js @@ -0,0 +1,3112 @@ +// Reserved word lists for various dialects of the language + +var reservedWords = { + 3: "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile", + 5: "class enum extends super const export import", + 6: "enum", + 7: "enum", + strict: "implements interface let package private protected public static yield", + strictBind: "eval arguments" +} + +// And the keywords + +var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this" + +var keywords = { + 5: ecma5AndLessKeywords, + 6: ecma5AndLessKeywords + " const class extends export import super" +} + +// ## Character categories + +// Big ugly regular expressions that match characters in the +// whitespace, identifier, and identifier-start categories. These +// are only applied when a character is found to actually have a +// code point above 128. +// Generated by `bin/generate-identifier-regex.js`. + +var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc" +var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d4-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d01-\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f" + +var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]") +var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]") + +nonASCIIidentifierStartChars = nonASCIIidentifierChars = null + +// These are a run-length and offset encoded representation of the +// >0xffff code points that are a valid part of identifiers. The +// offset starts at 0x10000, and each pair of numbers represents an +// offset to the next range, and then a size of the range. They were +// generated by bin/generate-identifier-regex.js +var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,17,26,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,785,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,25,391,63,32,0,449,56,264,8,2,36,18,0,50,29,881,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,65,0,32,6124,20,754,9486,1,3071,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,10591,541] +var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,10,2,4,9,83,11,7,0,161,11,6,9,7,3,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,87,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,423,9,838,7,2,7,17,9,57,21,2,13,19882,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239] + +// This has a complexity linear to the value of the code. The +// assumption is that looking up astral identifier characters is +// rare. +function isInAstralSet(code, set) { + var pos = 0x10000 + for (var i = 0; i < set.length; i += 2) { + pos += set[i] + if (pos > code) return false + pos += set[i + 1] + if (pos >= code) return true + } +} + +// Test whether a given character code starts an identifier. + +function isIdentifierStart(code, astral) { + if (code < 65) return code === 36 + if (code < 91) return true + if (code < 97) return code === 95 + if (code < 123) return true + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)) + if (astral === false) return false + return isInAstralSet(code, astralIdentifierStartCodes) +} + +// Test whether a given character is part of an identifier. + +function isIdentifierChar(code, astral) { + if (code < 48) return code === 36 + if (code < 58) return true + if (code < 65) return false + if (code < 91) return true + if (code < 97) return code === 95 + if (code < 123) return true + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)) + if (astral === false) return false + return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes) +} + +// ## Token types + +// The assignment of fine-grained, information-carrying type objects +// allows the tokenizer to store the information it has about a +// token in a way that is very cheap for the parser to look up. + +// All token type variables start with an underscore, to make them +// easy to recognize. + +// The `beforeExpr` property is used to disambiguate between regular +// expressions and divisions. It is set on all token types that can +// be followed by an expression (thus, a slash after them would be a +// regular expression). +// +// The `startsExpr` property is used to check if the token ends a +// `yield` expression. It is set on all token types that either can +// directly start an expression (like a quotation mark) or can +// continue an expression (like the body of a string). +// +// `isLoop` marks a keyword as starting a loop, which is important +// to know when parsing a label, in order to allow or disallow +// continue jumps to that label. + +var TokenType = function TokenType(label, conf) { + if ( conf === void 0 ) conf = {}; + + this.label = label + this.keyword = conf.keyword + this.beforeExpr = !!conf.beforeExpr + this.startsExpr = !!conf.startsExpr + this.isLoop = !!conf.isLoop + this.isAssign = !!conf.isAssign + this.prefix = !!conf.prefix + this.postfix = !!conf.postfix + this.binop = conf.binop || null + this.updateContext = null +}; + +function binop(name, prec) { + return new TokenType(name, {beforeExpr: true, binop: prec}) +} +var beforeExpr = {beforeExpr: true}; +var startsExpr = {startsExpr: true}; +// Map keyword names to token types. + +var keywordTypes = {} + +// Succinct definitions of keyword token types +function kw(name, options) { + if ( options === void 0 ) options = {}; + + options.keyword = name + return keywordTypes[name] = new TokenType(name, options) +} + +var tt = { + num: new TokenType("num", startsExpr), + regexp: new TokenType("regexp", startsExpr), + string: new TokenType("string", startsExpr), + name: new TokenType("name", startsExpr), + eof: new TokenType("eof"), + + // Punctuation token types. + bracketL: new TokenType("[", {beforeExpr: true, startsExpr: true}), + bracketR: new TokenType("]"), + braceL: new TokenType("{", {beforeExpr: true, startsExpr: true}), + braceR: new TokenType("}"), + parenL: new TokenType("(", {beforeExpr: true, startsExpr: true}), + parenR: new TokenType(")"), + comma: new TokenType(",", beforeExpr), + semi: new TokenType(";", beforeExpr), + colon: new TokenType(":", beforeExpr), + dot: new TokenType("."), + question: new TokenType("?", beforeExpr), + arrow: new TokenType("=>", beforeExpr), + template: new TokenType("template"), + ellipsis: new TokenType("...", beforeExpr), + backQuote: new TokenType("`", startsExpr), + dollarBraceL: new TokenType("${", {beforeExpr: true, startsExpr: true}), + + // Operators. These carry several kinds of properties to help the + // parser use them properly (the presence of these properties is + // what categorizes them as operators). + // + // `binop`, when present, specifies that this operator is a binary + // operator, and will refer to its precedence. + // + // `prefix` and `postfix` mark the operator as a prefix or postfix + // unary operator. + // + // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as + // binary operators with a very low precedence, that should result + // in AssignmentExpression nodes. + + eq: new TokenType("=", {beforeExpr: true, isAssign: true}), + assign: new TokenType("_=", {beforeExpr: true, isAssign: true}), + incDec: new TokenType("++/--", {prefix: true, postfix: true, startsExpr: true}), + prefix: new TokenType("prefix", {beforeExpr: true, prefix: true, startsExpr: true}), + logicalOR: binop("||", 1), + logicalAND: binop("&&", 2), + bitwiseOR: binop("|", 3), + bitwiseXOR: binop("^", 4), + bitwiseAND: binop("&", 5), + equality: binop("==/!=", 6), + relational: binop("", 7), + bitShift: binop("<>", 8), + plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}), + modulo: binop("%", 10), + star: binop("*", 10), + slash: binop("/", 10), + starstar: new TokenType("**", {beforeExpr: true}), + + // Keyword token types. + _break: kw("break"), + _case: kw("case", beforeExpr), + _catch: kw("catch"), + _continue: kw("continue"), + _debugger: kw("debugger"), + _default: kw("default", beforeExpr), + _do: kw("do", {isLoop: true, beforeExpr: true}), + _else: kw("else", beforeExpr), + _finally: kw("finally"), + _for: kw("for", {isLoop: true}), + _function: kw("function", startsExpr), + _if: kw("if"), + _return: kw("return", beforeExpr), + _switch: kw("switch"), + _throw: kw("throw", beforeExpr), + _try: kw("try"), + _var: kw("var"), + _const: kw("const"), + _while: kw("while", {isLoop: true}), + _with: kw("with"), + _new: kw("new", {beforeExpr: true, startsExpr: true}), + _this: kw("this", startsExpr), + _super: kw("super", startsExpr), + _class: kw("class"), + _extends: kw("extends", beforeExpr), + _export: kw("export"), + _import: kw("import"), + _null: kw("null", startsExpr), + _true: kw("true", startsExpr), + _false: kw("false", startsExpr), + _in: kw("in", {beforeExpr: true, binop: 7}), + _instanceof: kw("instanceof", {beforeExpr: true, binop: 7}), + _typeof: kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true}), + _void: kw("void", {beforeExpr: true, prefix: true, startsExpr: true}), + _delete: kw("delete", {beforeExpr: true, prefix: true, startsExpr: true}) +} + +// Matches a whole line break (where CRLF is considered a single +// line break). Used to count lines. + +var lineBreak = /\r\n?|\n|\u2028|\u2029/ +var lineBreakG = new RegExp(lineBreak.source, "g") + +function isNewLine(code) { + return code === 10 || code === 13 || code === 0x2028 || code == 0x2029 +} + +var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/ + +var skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g + +function isArray(obj) { + return Object.prototype.toString.call(obj) === "[object Array]" +} + +// Checks if an object has a property. + +function has(obj, propName) { + return Object.prototype.hasOwnProperty.call(obj, propName) +} + +// These are used when `options.locations` is on, for the +// `startLoc` and `endLoc` properties. + +var Position = function Position(line, col) { + this.line = line + this.column = col +}; + +Position.prototype.offset = function offset (n) { + return new Position(this.line, this.column + n) +}; + +var SourceLocation = function SourceLocation(p, start, end) { + this.start = start + this.end = end + if (p.sourceFile !== null) this.source = p.sourceFile +}; + +// The `getLineInfo` function is mostly useful when the +// `locations` option is off (for performance reasons) and you +// want to find the line/column position for a given character +// offset. `input` should be the code string that the offset refers +// into. + +function getLineInfo(input, offset) { + for (var line = 1, cur = 0;;) { + lineBreakG.lastIndex = cur + var match = lineBreakG.exec(input) + if (match && match.index < offset) { + ++line + cur = match.index + match[0].length + } else { + return new Position(line, offset - cur) + } + } +} + +// A second optional argument can be given to further configure +// the parser process. These options are recognized: + +var defaultOptions = { + // `ecmaVersion` indicates the ECMAScript version to parse. Must + // be either 3, or 5, or 6. This influences support for strict + // mode, the set of reserved words, support for getters and + // setters and other features. The default is 6. + ecmaVersion: 6, + // Source type ("script" or "module") for different semantics + sourceType: "script", + // `onInsertedSemicolon` can be a callback that will be called + // when a semicolon is automatically inserted. It will be passed + // th position of the comma as an offset, and if `locations` is + // enabled, it is given the location as a `{line, column}` object + // as second argument. + onInsertedSemicolon: null, + // `onTrailingComma` is similar to `onInsertedSemicolon`, but for + // trailing commas. + onTrailingComma: null, + // By default, reserved words are only enforced if ecmaVersion >= 5. + // Set `allowReserved` to a boolean value to explicitly turn this on + // an off. When this option has the value "never", reserved words + // and keywords can also not be used as property names. + allowReserved: null, + // When enabled, a return at the top level is not considered an + // error. + allowReturnOutsideFunction: false, + // When enabled, import/export statements are not constrained to + // appearing at the top of the program. + allowImportExportEverywhere: false, + // When enabled, hashbang directive in the beginning of file + // is allowed and treated as a line comment. + allowHashBang: false, + // When `locations` is on, `loc` properties holding objects with + // `start` and `end` properties in `{line, column}` form (with + // line being 1-based and column 0-based) will be attached to the + // nodes. + locations: false, + // A function can be passed as `onToken` option, which will + // cause Acorn to call that function with object in the same + // format as tokens returned from `tokenizer().getToken()`. Note + // that you are not allowed to call the parser from the + // callback—that will corrupt its internal state. + onToken: null, + // A function can be passed as `onComment` option, which will + // cause Acorn to call that function with `(block, text, start, + // end)` parameters whenever a comment is skipped. `block` is a + // boolean indicating whether this is a block (`/* */`) comment, + // `text` is the content of the comment, and `start` and `end` are + // character offsets that denote the start and end of the comment. + // When the `locations` option is on, two more parameters are + // passed, the full `{line, column}` locations of the start and + // end of the comments. Note that you are not allowed to call the + // parser from the callback—that will corrupt its internal state. + onComment: null, + // Nodes have their start and end characters offsets recorded in + // `start` and `end` properties (directly on the node, rather than + // the `loc` object, which holds line/column data. To also add a + // [semi-standardized][range] `range` property holding a `[start, + // end]` array with the same numbers, set the `ranges` option to + // `true`. + // + // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 + ranges: false, + // It is possible to parse multiple files into a single AST by + // passing the tree produced by parsing the first file as + // `program` option in subsequent parses. This will add the + // toplevel forms of the parsed file to the `Program` (top) node + // of an existing parse tree. + program: null, + // When `locations` is on, you can pass this to record the source + // file in every node's `loc` object. + sourceFile: null, + // This value, if given, is stored in every node, whether + // `locations` is on or off. + directSourceFile: null, + // When enabled, parenthesized expressions are represented by + // (non-standard) ParenthesizedExpression nodes + preserveParens: false, + plugins: {} +} + +// Interpret and default an options object + +function getOptions(opts) { + var options = {} + for (var opt in defaultOptions) + options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt] + if (options.allowReserved == null) + options.allowReserved = options.ecmaVersion < 5 + + if (isArray(options.onToken)) { + var tokens = options.onToken + options.onToken = function (token) { return tokens.push(token); } + } + if (isArray(options.onComment)) + options.onComment = pushComment(options, options.onComment) + + return options +} + +function pushComment(options, array) { + return function (block, text, start, end, startLoc, endLoc) { + var comment = { + type: block ? 'Block' : 'Line', + value: text, + start: start, + end: end + } + if (options.locations) + comment.loc = new SourceLocation(this, startLoc, endLoc) + if (options.ranges) + comment.range = [start, end] + array.push(comment) + } +} + +// Registered plugins +var plugins = {} + +function keywordRegexp(words) { + return new RegExp("^(" + words.replace(/ /g, "|") + ")$") +} + +var Parser = function Parser(options, input, startPos) { + this.options = options = getOptions(options) + this.sourceFile = options.sourceFile + this.keywords = keywordRegexp(keywords[options.ecmaVersion >= 6 ? 6 : 5]) + var reserved = options.allowReserved ? "" : + reservedWords[options.ecmaVersion] + (options.sourceType == "module" ? " await" : "") + this.reservedWords = keywordRegexp(reserved) + var reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict + this.reservedWordsStrict = keywordRegexp(reservedStrict) + this.reservedWordsStrictBind = keywordRegexp(reservedStrict + " " + reservedWords.strictBind) + this.input = String(input) + + // Used to signal to callers of `readWord1` whether the word + // contained any escape sequences. This is needed because words with + // escape sequences must not be interpreted as keywords. + this.containsEsc = false + + // Load plugins + this.loadPlugins(options.plugins) + + // Set up token state + + // The current position of the tokenizer in the input. + if (startPos) { + this.pos = startPos + this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos)) + this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length + } else { + this.pos = this.lineStart = 0 + this.curLine = 1 + } + + // Properties of the current token: + // Its type + this.type = tt.eof + // For tokens that include more information than their type, the value + this.value = null + // Its start and end offset + this.start = this.end = this.pos + // And, if locations are used, the {line, column} object + // corresponding to those offsets + this.startLoc = this.endLoc = this.curPosition() + + // Position information for the previous token + this.lastTokEndLoc = this.lastTokStartLoc = null + this.lastTokStart = this.lastTokEnd = this.pos + + // The context stack is used to superficially track syntactic + // context to predict whether a regular expression is allowed in a + // given position. + this.context = this.initialContext() + this.exprAllowed = true + + // Figure out if it's a module code. + this.strict = this.inModule = options.sourceType === "module" + + // Used to signify the start of a potential arrow function + this.potentialArrowAt = -1 + + // Flags to track whether we are in a function, a generator. + this.inFunction = this.inGenerator = false + // Labels in scope. + this.labels = [] + + // If enabled, skip leading hashbang line. + if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === '#!') + this.skipLineComment(2) +}; + +// DEPRECATED Kept for backwards compatibility until 3.0 in case a plugin uses them +Parser.prototype.isKeyword = function isKeyword (word) { return this.keywords.test(word) }; +Parser.prototype.isReservedWord = function isReservedWord (word) { return this.reservedWords.test(word) }; + +Parser.prototype.extend = function extend (name, f) { + this[name] = f(this[name]) +}; + +Parser.prototype.loadPlugins = function loadPlugins (pluginConfigs) { + var this$1 = this; + + for (var name in pluginConfigs) { + var plugin = plugins[name] + if (!plugin) throw new Error("Plugin '" + name + "' not found") + plugin(this$1, pluginConfigs[name]) + } +}; + +Parser.prototype.parse = function parse () { + var node = this.options.program || this.startNode() + this.nextToken() + return this.parseTopLevel(node) +}; + +var pp = Parser.prototype + +// ## Parser utilities + +// Test whether a statement node is the string literal `"use strict"`. + +pp.isUseStrict = function(stmt) { + return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && + stmt.expression.type === "Literal" && + stmt.expression.raw.slice(1, -1) === "use strict" +} + +// Predicate that tests whether the next token is of the given +// type, and if yes, consumes it as a side effect. + +pp.eat = function(type) { + if (this.type === type) { + this.next() + return true + } else { + return false + } +} + +// Tests whether parsed token is a contextual keyword. + +pp.isContextual = function(name) { + return this.type === tt.name && this.value === name +} + +// Consumes contextual keyword if possible. + +pp.eatContextual = function(name) { + return this.value === name && this.eat(tt.name) +} + +// Asserts that following token is given contextual keyword. + +pp.expectContextual = function(name) { + if (!this.eatContextual(name)) this.unexpected() +} + +// Test whether a semicolon can be inserted at the current position. + +pp.canInsertSemicolon = function() { + return this.type === tt.eof || + this.type === tt.braceR || + lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) +} + +pp.insertSemicolon = function() { + if (this.canInsertSemicolon()) { + if (this.options.onInsertedSemicolon) + this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc) + return true + } +} + +// Consume a semicolon, or, failing that, see if we are allowed to +// pretend that there is a semicolon at this position. + +pp.semicolon = function() { + if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected() +} + +pp.afterTrailingComma = function(tokType) { + if (this.type == tokType) { + if (this.options.onTrailingComma) + this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc) + this.next() + return true + } +} + +// Expect a token of a given type. If found, consume it, otherwise, +// raise an unexpected token error. + +pp.expect = function(type) { + this.eat(type) || this.unexpected() +} + +// Raise an unexpected token error. + +pp.unexpected = function(pos) { + this.raise(pos != null ? pos : this.start, "Unexpected token") +} + +var DestructuringErrors = function DestructuringErrors() { + this.shorthandAssign = 0 + this.trailingComma = 0 +}; + +pp.checkPatternErrors = function(refDestructuringErrors, andThrow) { + var trailing = refDestructuringErrors && refDestructuringErrors.trailingComma + if (!andThrow) return !!trailing + if (trailing) this.raise(trailing, "Comma is not permitted after the rest element") +} + +pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) { + var pos = refDestructuringErrors && refDestructuringErrors.shorthandAssign + if (!andThrow) return !!pos + if (pos) this.raise(pos, "Shorthand property assignments are valid only in destructuring patterns") +} + +var pp$1 = Parser.prototype + +// ### Statement parsing + +// Parse a program. Initializes the parser, reads any number of +// statements, and wraps them in a Program node. Optionally takes a +// `program` argument. If present, the statements will be appended +// to its body instead of creating a new node. + +pp$1.parseTopLevel = function(node) { + var this$1 = this; + + var first = true + if (!node.body) node.body = [] + while (this.type !== tt.eof) { + var stmt = this$1.parseStatement(true, true) + node.body.push(stmt) + if (first) { + if (this$1.isUseStrict(stmt)) this$1.setStrict(true) + first = false + } + } + this.next() + if (this.options.ecmaVersion >= 6) { + node.sourceType = this.options.sourceType + } + return this.finishNode(node, "Program") +} + +var loopLabel = {kind: "loop"}; +var switchLabel = {kind: "switch"}; +pp$1.isLet = function() { + if (this.type !== tt.name || this.options.ecmaVersion < 6 || this.value != "let") return false + skipWhiteSpace.lastIndex = this.pos + var skip = skipWhiteSpace.exec(this.input) + var next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next) + if (nextCh === 91 || nextCh == 123) return true // '{' and '[' + if (isIdentifierStart(nextCh, true)) { + for (var pos = next + 1; isIdentifierChar(this.input.charCodeAt(pos), true); ++pos) {} + var ident = this.input.slice(next, pos) + if (!this.isKeyword(ident)) return true + } + return false +} + +// Parse a single statement. +// +// If expecting a statement and finding a slash operator, parse a +// regular expression literal. This is to handle cases like +// `if (foo) /blah/.exec(foo)`, where looking at the previous token +// does not help. + +pp$1.parseStatement = function(declaration, topLevel) { + var starttype = this.type, node = this.startNode(), kind + + if (this.isLet()) { + starttype = tt._var + kind = "let" + } + + // Most types of statements are recognized by the keyword they + // start with. Many are trivial to parse, some require a bit of + // complexity. + + switch (starttype) { + case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword) + case tt._debugger: return this.parseDebuggerStatement(node) + case tt._do: return this.parseDoStatement(node) + case tt._for: return this.parseForStatement(node) + case tt._function: + if (!declaration && this.options.ecmaVersion >= 6) this.unexpected() + return this.parseFunctionStatement(node) + case tt._class: + if (!declaration) this.unexpected() + return this.parseClass(node, true) + case tt._if: return this.parseIfStatement(node) + case tt._return: return this.parseReturnStatement(node) + case tt._switch: return this.parseSwitchStatement(node) + case tt._throw: return this.parseThrowStatement(node) + case tt._try: return this.parseTryStatement(node) + case tt._const: case tt._var: + kind = kind || this.value + if (!declaration && kind != "var") this.unexpected() + return this.parseVarStatement(node, kind) + case tt._while: return this.parseWhileStatement(node) + case tt._with: return this.parseWithStatement(node) + case tt.braceL: return this.parseBlock() + case tt.semi: return this.parseEmptyStatement(node) + case tt._export: + case tt._import: + if (!this.options.allowImportExportEverywhere) { + if (!topLevel) + this.raise(this.start, "'import' and 'export' may only appear at the top level") + if (!this.inModule) + this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'") + } + return starttype === tt._import ? this.parseImport(node) : this.parseExport(node) + + // If the statement does not start with a statement keyword or a + // brace, it's an ExpressionStatement or LabeledStatement. We + // simply start parsing an expression, and afterwards, if the + // next token is a colon and the expression was a simple + // Identifier node, we switch to interpreting it as a label. + default: + var maybeName = this.value, expr = this.parseExpression() + if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) + return this.parseLabeledStatement(node, maybeName, expr) + else return this.parseExpressionStatement(node, expr) + } +} + +pp$1.parseBreakContinueStatement = function(node, keyword) { + var this$1 = this; + + var isBreak = keyword == "break" + this.next() + if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null + else if (this.type !== tt.name) this.unexpected() + else { + node.label = this.parseIdent() + this.semicolon() + } + + // Verify that there is an actual destination to break or + // continue to. + for (var i = 0; i < this.labels.length; ++i) { + var lab = this$1.labels[i] + if (node.label == null || lab.name === node.label.name) { + if (lab.kind != null && (isBreak || lab.kind === "loop")) break + if (node.label && isBreak) break + } + } + if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword) + return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") +} + +pp$1.parseDebuggerStatement = function(node) { + this.next() + this.semicolon() + return this.finishNode(node, "DebuggerStatement") +} + +pp$1.parseDoStatement = function(node) { + this.next() + this.labels.push(loopLabel) + node.body = this.parseStatement(false) + this.labels.pop() + this.expect(tt._while) + node.test = this.parseParenExpression() + if (this.options.ecmaVersion >= 6) + this.eat(tt.semi) + else + this.semicolon() + return this.finishNode(node, "DoWhileStatement") +} + +// Disambiguating between a `for` and a `for`/`in` or `for`/`of` +// loop is non-trivial. Basically, we have to parse the init `var` +// statement or expression, disallowing the `in` operator (see +// the second parameter to `parseExpression`), and then check +// whether the next token is `in` or `of`. When there is no init +// part (semicolon immediately after the opening parenthesis), it +// is a regular `for` loop. + +pp$1.parseForStatement = function(node) { + this.next() + this.labels.push(loopLabel) + this.expect(tt.parenL) + if (this.type === tt.semi) return this.parseFor(node, null) + var isLet = this.isLet() + if (this.type === tt._var || this.type === tt._const || isLet) { + var init$1 = this.startNode(), kind = isLet ? "let" : this.value + this.next() + this.parseVar(init$1, true, kind) + this.finishNode(init$1, "VariableDeclaration") + if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init$1.declarations.length === 1 && + !(kind !== "var" && init$1.declarations[0].init)) + return this.parseForIn(node, init$1) + return this.parseFor(node, init$1) + } + var refDestructuringErrors = new DestructuringErrors + var init = this.parseExpression(true, refDestructuringErrors) + if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) { + this.checkPatternErrors(refDestructuringErrors, true) + this.toAssignable(init) + this.checkLVal(init) + return this.parseForIn(node, init) + } else { + this.checkExpressionErrors(refDestructuringErrors, true) + } + return this.parseFor(node, init) +} + +pp$1.parseFunctionStatement = function(node) { + this.next() + return this.parseFunction(node, true) +} + +pp$1.parseIfStatement = function(node) { + this.next() + node.test = this.parseParenExpression() + node.consequent = this.parseStatement(false) + node.alternate = this.eat(tt._else) ? this.parseStatement(false) : null + return this.finishNode(node, "IfStatement") +} + +pp$1.parseReturnStatement = function(node) { + if (!this.inFunction && !this.options.allowReturnOutsideFunction) + this.raise(this.start, "'return' outside of function") + this.next() + + // In `return` (and `break`/`continue`), the keywords with + // optional arguments, we eagerly look for a semicolon or the + // possibility to insert one. + + if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null + else { node.argument = this.parseExpression(); this.semicolon() } + return this.finishNode(node, "ReturnStatement") +} + +pp$1.parseSwitchStatement = function(node) { + var this$1 = this; + + this.next() + node.discriminant = this.parseParenExpression() + node.cases = [] + this.expect(tt.braceL) + this.labels.push(switchLabel) + + // Statements under must be grouped (by label) in SwitchCase + // nodes. `cur` is used to keep the node that we are currently + // adding statements to. + + for (var cur, sawDefault = false; this.type != tt.braceR;) { + if (this$1.type === tt._case || this$1.type === tt._default) { + var isCase = this$1.type === tt._case + if (cur) this$1.finishNode(cur, "SwitchCase") + node.cases.push(cur = this$1.startNode()) + cur.consequent = [] + this$1.next() + if (isCase) { + cur.test = this$1.parseExpression() + } else { + if (sawDefault) this$1.raiseRecoverable(this$1.lastTokStart, "Multiple default clauses") + sawDefault = true + cur.test = null + } + this$1.expect(tt.colon) + } else { + if (!cur) this$1.unexpected() + cur.consequent.push(this$1.parseStatement(true)) + } + } + if (cur) this.finishNode(cur, "SwitchCase") + this.next() // Closing brace + this.labels.pop() + return this.finishNode(node, "SwitchStatement") +} + +pp$1.parseThrowStatement = function(node) { + this.next() + if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) + this.raise(this.lastTokEnd, "Illegal newline after throw") + node.argument = this.parseExpression() + this.semicolon() + return this.finishNode(node, "ThrowStatement") +} + +// Reused empty array added for node fields that are always empty. + +var empty = [] + +pp$1.parseTryStatement = function(node) { + this.next() + node.block = this.parseBlock() + node.handler = null + if (this.type === tt._catch) { + var clause = this.startNode() + this.next() + this.expect(tt.parenL) + clause.param = this.parseBindingAtom() + this.checkLVal(clause.param, true) + this.expect(tt.parenR) + clause.body = this.parseBlock() + node.handler = this.finishNode(clause, "CatchClause") + } + node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null + if (!node.handler && !node.finalizer) + this.raise(node.start, "Missing catch or finally clause") + return this.finishNode(node, "TryStatement") +} + +pp$1.parseVarStatement = function(node, kind) { + this.next() + this.parseVar(node, false, kind) + this.semicolon() + return this.finishNode(node, "VariableDeclaration") +} + +pp$1.parseWhileStatement = function(node) { + this.next() + node.test = this.parseParenExpression() + this.labels.push(loopLabel) + node.body = this.parseStatement(false) + this.labels.pop() + return this.finishNode(node, "WhileStatement") +} + +pp$1.parseWithStatement = function(node) { + if (this.strict) this.raise(this.start, "'with' in strict mode") + this.next() + node.object = this.parseParenExpression() + node.body = this.parseStatement(false) + return this.finishNode(node, "WithStatement") +} + +pp$1.parseEmptyStatement = function(node) { + this.next() + return this.finishNode(node, "EmptyStatement") +} + +pp$1.parseLabeledStatement = function(node, maybeName, expr) { + var this$1 = this; + + for (var i = 0; i < this.labels.length; ++i) + if (this$1.labels[i].name === maybeName) this$1.raise(expr.start, "Label '" + maybeName + "' is already declared") + var kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null + for (var i$1 = this.labels.length - 1; i$1 >= 0; i$1--) { + var label = this$1.labels[i$1] + if (label.statementStart == node.start) { + label.statementStart = this$1.start + label.kind = kind + } else break + } + this.labels.push({name: maybeName, kind: kind, statementStart: this.start}) + node.body = this.parseStatement(true) + this.labels.pop() + node.label = expr + return this.finishNode(node, "LabeledStatement") +} + +pp$1.parseExpressionStatement = function(node, expr) { + node.expression = expr + this.semicolon() + return this.finishNode(node, "ExpressionStatement") +} + +// Parse a semicolon-enclosed block of statements, handling `"use +// strict"` declarations when `allowStrict` is true (used for +// function bodies). + +pp$1.parseBlock = function(allowStrict) { + var this$1 = this; + + var node = this.startNode(), first = true, oldStrict + node.body = [] + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + var stmt = this$1.parseStatement(true) + node.body.push(stmt) + if (first && allowStrict && this$1.isUseStrict(stmt)) { + oldStrict = this$1.strict + this$1.setStrict(this$1.strict = true) + } + first = false + } + if (oldStrict === false) this.setStrict(false) + return this.finishNode(node, "BlockStatement") +} + +// Parse a regular `for` loop. The disambiguation code in +// `parseStatement` will already have parsed the init statement or +// expression. + +pp$1.parseFor = function(node, init) { + node.init = init + this.expect(tt.semi) + node.test = this.type === tt.semi ? null : this.parseExpression() + this.expect(tt.semi) + node.update = this.type === tt.parenR ? null : this.parseExpression() + this.expect(tt.parenR) + node.body = this.parseStatement(false) + this.labels.pop() + return this.finishNode(node, "ForStatement") +} + +// Parse a `for`/`in` and `for`/`of` loop, which are almost +// same from parser's perspective. + +pp$1.parseForIn = function(node, init) { + var type = this.type === tt._in ? "ForInStatement" : "ForOfStatement" + this.next() + node.left = init + node.right = this.parseExpression() + this.expect(tt.parenR) + node.body = this.parseStatement(false) + this.labels.pop() + return this.finishNode(node, type) +} + +// Parse a list of variable declarations. + +pp$1.parseVar = function(node, isFor, kind) { + var this$1 = this; + + node.declarations = [] + node.kind = kind + for (;;) { + var decl = this$1.startNode() + this$1.parseVarId(decl) + if (this$1.eat(tt.eq)) { + decl.init = this$1.parseMaybeAssign(isFor) + } else if (kind === "const" && !(this$1.type === tt._in || (this$1.options.ecmaVersion >= 6 && this$1.isContextual("of")))) { + this$1.unexpected() + } else if (decl.id.type != "Identifier" && !(isFor && (this$1.type === tt._in || this$1.isContextual("of")))) { + this$1.raise(this$1.lastTokEnd, "Complex binding patterns require an initialization value") + } else { + decl.init = null + } + node.declarations.push(this$1.finishNode(decl, "VariableDeclarator")) + if (!this$1.eat(tt.comma)) break + } + return node +} + +pp$1.parseVarId = function(decl) { + decl.id = this.parseBindingAtom() + this.checkLVal(decl.id, true) +} + +// Parse a function declaration or literal (depending on the +// `isStatement` parameter). + +pp$1.parseFunction = function(node, isStatement, allowExpressionBody) { + this.initFunction(node) + if (this.options.ecmaVersion >= 6) + node.generator = this.eat(tt.star) + var oldInGen = this.inGenerator + this.inGenerator = node.generator + if (isStatement || this.type === tt.name) + node.id = this.parseIdent() + this.parseFunctionParams(node) + this.parseFunctionBody(node, allowExpressionBody) + this.inGenerator = oldInGen + return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") +} + +pp$1.parseFunctionParams = function(node) { + this.expect(tt.parenL) + node.params = this.parseBindingList(tt.parenR, false, false, true) +} + +// Parse a class declaration or literal (depending on the +// `isStatement` parameter). + +pp$1.parseClass = function(node, isStatement) { + var this$1 = this; + + this.next() + this.parseClassId(node, isStatement) + this.parseClassSuper(node) + var classBody = this.startNode() + var hadConstructor = false + classBody.body = [] + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (this$1.eat(tt.semi)) continue + var method = this$1.startNode() + var isGenerator = this$1.eat(tt.star) + var isMaybeStatic = this$1.type === tt.name && this$1.value === "static" + this$1.parsePropertyName(method) + method.static = isMaybeStatic && this$1.type !== tt.parenL + if (method.static) { + if (isGenerator) this$1.unexpected() + isGenerator = this$1.eat(tt.star) + this$1.parsePropertyName(method) + } + method.kind = "method" + var isGetSet = false + if (!method.computed) { + var key = method.key; + if (!isGenerator && key.type === "Identifier" && this$1.type !== tt.parenL && (key.name === "get" || key.name === "set")) { + isGetSet = true + method.kind = key.name + key = this$1.parsePropertyName(method) + } + if (!method.static && (key.type === "Identifier" && key.name === "constructor" || + key.type === "Literal" && key.value === "constructor")) { + if (hadConstructor) this$1.raise(key.start, "Duplicate constructor in the same class") + if (isGetSet) this$1.raise(key.start, "Constructor can't have get/set modifier") + if (isGenerator) this$1.raise(key.start, "Constructor can't be a generator") + method.kind = "constructor" + hadConstructor = true + } + } + this$1.parseClassMethod(classBody, method, isGenerator) + if (isGetSet) { + var paramCount = method.kind === "get" ? 0 : 1 + if (method.value.params.length !== paramCount) { + var start = method.value.start + if (method.kind === "get") + this$1.raiseRecoverable(start, "getter should have no params") + else + this$1.raiseRecoverable(start, "setter should have exactly one param") + } + if (method.kind === "set" && method.value.params[0].type === "RestElement") + this$1.raise(method.value.params[0].start, "Setter cannot use rest params") + } + } + node.body = this.finishNode(classBody, "ClassBody") + return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") +} + +pp$1.parseClassMethod = function(classBody, method, isGenerator) { + method.value = this.parseMethod(isGenerator) + classBody.body.push(this.finishNode(method, "MethodDefinition")) +} + +pp$1.parseClassId = function(node, isStatement) { + node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null +} + +pp$1.parseClassSuper = function(node) { + node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null +} + +// Parses module export declaration. + +pp$1.parseExport = function(node) { + var this$1 = this; + + this.next() + // export * from '...' + if (this.eat(tt.star)) { + this.expectContextual("from") + node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() + this.semicolon() + return this.finishNode(node, "ExportAllDeclaration") + } + if (this.eat(tt._default)) { // export default ... + var parens = this.type == tt.parenL + var expr = this.parseMaybeAssign() + var needsSemi = true + if (!parens && (expr.type == "FunctionExpression" || + expr.type == "ClassExpression")) { + needsSemi = false + if (expr.id) { + expr.type = expr.type == "FunctionExpression" + ? "FunctionDeclaration" + : "ClassDeclaration" + } + } + node.declaration = expr + if (needsSemi) this.semicolon() + return this.finishNode(node, "ExportDefaultDeclaration") + } + // export var|const|let|function|class ... + if (this.shouldParseExportStatement()) { + node.declaration = this.parseStatement(true) + node.specifiers = [] + node.source = null + } else { // export { x, y as z } [from '...'] + node.declaration = null + node.specifiers = this.parseExportSpecifiers() + if (this.eatContextual("from")) { + node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() + } else { + // check for keywords used as local names + for (var i = 0; i < node.specifiers.length; i++) { + if (this$1.keywords.test(node.specifiers[i].local.name) || this$1.reservedWords.test(node.specifiers[i].local.name)) { + this$1.unexpected(node.specifiers[i].local.start) + } + } + + node.source = null + } + this.semicolon() + } + return this.finishNode(node, "ExportNamedDeclaration") +} + +pp$1.shouldParseExportStatement = function() { + return this.type.keyword || this.isLet() +} + +// Parses a comma-separated list of module exports. + +pp$1.parseExportSpecifiers = function() { + var this$1 = this; + + var nodes = [], first = true + // export { x, y as z } [from '...'] + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (!first) { + this$1.expect(tt.comma) + if (this$1.afterTrailingComma(tt.braceR)) break + } else first = false + + var node = this$1.startNode() + node.local = this$1.parseIdent(this$1.type === tt._default) + node.exported = this$1.eatContextual("as") ? this$1.parseIdent(true) : node.local + nodes.push(this$1.finishNode(node, "ExportSpecifier")) + } + return nodes +} + +// Parses import declaration. + +pp$1.parseImport = function(node) { + this.next() + // import '...' + if (this.type === tt.string) { + node.specifiers = empty + node.source = this.parseExprAtom() + } else { + node.specifiers = this.parseImportSpecifiers() + this.expectContextual("from") + node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() + } + this.semicolon() + return this.finishNode(node, "ImportDeclaration") +} + +// Parses a comma-separated list of module imports. + +pp$1.parseImportSpecifiers = function() { + var this$1 = this; + + var nodes = [], first = true + if (this.type === tt.name) { + // import defaultObj, { x, y as z } from '...' + var node = this.startNode() + node.local = this.parseIdent() + this.checkLVal(node.local, true) + nodes.push(this.finishNode(node, "ImportDefaultSpecifier")) + if (!this.eat(tt.comma)) return nodes + } + if (this.type === tt.star) { + var node$1 = this.startNode() + this.next() + this.expectContextual("as") + node$1.local = this.parseIdent() + this.checkLVal(node$1.local, true) + nodes.push(this.finishNode(node$1, "ImportNamespaceSpecifier")) + return nodes + } + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (!first) { + this$1.expect(tt.comma) + if (this$1.afterTrailingComma(tt.braceR)) break + } else first = false + + var node$2 = this$1.startNode() + node$2.imported = this$1.parseIdent(true) + if (this$1.eatContextual("as")) { + node$2.local = this$1.parseIdent() + } else { + node$2.local = node$2.imported + if (this$1.isKeyword(node$2.local.name)) this$1.unexpected(node$2.local.start) + if (this$1.reservedWordsStrict.test(node$2.local.name)) this$1.raise(node$2.local.start, "The keyword '" + node$2.local.name + "' is reserved") + } + this$1.checkLVal(node$2.local, true) + nodes.push(this$1.finishNode(node$2, "ImportSpecifier")) + } + return nodes +} + +var pp$2 = Parser.prototype + +// Convert existing expression atom to assignable pattern +// if possible. + +pp$2.toAssignable = function(node, isBinding) { + var this$1 = this; + + if (this.options.ecmaVersion >= 6 && node) { + switch (node.type) { + case "Identifier": + case "ObjectPattern": + case "ArrayPattern": + break + + case "ObjectExpression": + node.type = "ObjectPattern" + for (var i = 0; i < node.properties.length; i++) { + var prop = node.properties[i] + if (prop.kind !== "init") this$1.raise(prop.key.start, "Object pattern can't contain getter or setter") + this$1.toAssignable(prop.value, isBinding) + } + break + + case "ArrayExpression": + node.type = "ArrayPattern" + this.toAssignableList(node.elements, isBinding) + break + + case "AssignmentExpression": + if (node.operator === "=") { + node.type = "AssignmentPattern" + delete node.operator + // falls through to AssignmentPattern + } else { + this.raise(node.left.end, "Only '=' operator can be used for specifying default value.") + break + } + + case "AssignmentPattern": + if (node.right.type === "YieldExpression") + this.raise(node.right.start, "Yield expression cannot be a default value") + break + + case "ParenthesizedExpression": + node.expression = this.toAssignable(node.expression, isBinding) + break + + case "MemberExpression": + if (!isBinding) break + + default: + this.raise(node.start, "Assigning to rvalue") + } + } + return node +} + +// Convert list of expression atoms to binding list. + +pp$2.toAssignableList = function(exprList, isBinding) { + var this$1 = this; + + var end = exprList.length + if (end) { + var last = exprList[end - 1] + if (last && last.type == "RestElement") { + --end + } else if (last && last.type == "SpreadElement") { + last.type = "RestElement" + var arg = last.argument + this.toAssignable(arg, isBinding) + if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") + this.unexpected(arg.start) + --end + } + + if (isBinding && last && last.type === "RestElement" && last.argument.type !== "Identifier") + this.unexpected(last.argument.start) + } + for (var i = 0; i < end; i++) { + var elt = exprList[i] + if (elt) this$1.toAssignable(elt, isBinding) + } + return exprList +} + +// Parses spread element. + +pp$2.parseSpread = function(refDestructuringErrors) { + var node = this.startNode() + this.next() + node.argument = this.parseMaybeAssign(false, refDestructuringErrors) + return this.finishNode(node, "SpreadElement") +} + +pp$2.parseRest = function(allowNonIdent) { + var node = this.startNode() + this.next() + + // RestElement inside of a function parameter must be an identifier + if (allowNonIdent) node.argument = this.type === tt.name ? this.parseIdent() : this.unexpected() + else node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected() + + return this.finishNode(node, "RestElement") +} + +// Parses lvalue (assignable) atom. + +pp$2.parseBindingAtom = function() { + if (this.options.ecmaVersion < 6) return this.parseIdent() + switch (this.type) { + case tt.name: + return this.parseIdent() + + case tt.bracketL: + var node = this.startNode() + this.next() + node.elements = this.parseBindingList(tt.bracketR, true, true) + return this.finishNode(node, "ArrayPattern") + + case tt.braceL: + return this.parseObj(true) + + default: + this.unexpected() + } +} + +pp$2.parseBindingList = function(close, allowEmpty, allowTrailingComma, allowNonIdent) { + var this$1 = this; + + var elts = [], first = true + while (!this.eat(close)) { + if (first) first = false + else this$1.expect(tt.comma) + if (allowEmpty && this$1.type === tt.comma) { + elts.push(null) + } else if (allowTrailingComma && this$1.afterTrailingComma(close)) { + break + } else if (this$1.type === tt.ellipsis) { + var rest = this$1.parseRest(allowNonIdent) + this$1.parseBindingListItem(rest) + elts.push(rest) + if (this$1.type === tt.comma) this$1.raise(this$1.start, "Comma is not permitted after the rest element") + this$1.expect(close) + break + } else { + var elem = this$1.parseMaybeDefault(this$1.start, this$1.startLoc) + this$1.parseBindingListItem(elem) + elts.push(elem) + } + } + return elts +} + +pp$2.parseBindingListItem = function(param) { + return param +} + +// Parses assignment pattern around given atom if possible. + +pp$2.parseMaybeDefault = function(startPos, startLoc, left) { + left = left || this.parseBindingAtom() + if (this.options.ecmaVersion < 6 || !this.eat(tt.eq)) return left + var node = this.startNodeAt(startPos, startLoc) + node.left = left + node.right = this.parseMaybeAssign() + return this.finishNode(node, "AssignmentPattern") +} + +// Verify that a node is an lval — something that can be assigned +// to. + +pp$2.checkLVal = function(expr, isBinding, checkClashes) { + var this$1 = this; + + switch (expr.type) { + case "Identifier": + if (this.strict && this.reservedWordsStrictBind.test(expr.name)) + this.raiseRecoverable(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode") + if (checkClashes) { + if (has(checkClashes, expr.name)) + this.raiseRecoverable(expr.start, "Argument name clash") + checkClashes[expr.name] = true + } + break + + case "MemberExpression": + if (isBinding) this.raiseRecoverable(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression") + break + + case "ObjectPattern": + for (var i = 0; i < expr.properties.length; i++) + this$1.checkLVal(expr.properties[i].value, isBinding, checkClashes) + break + + case "ArrayPattern": + for (var i$1 = 0; i$1 < expr.elements.length; i$1++) { + var elem = expr.elements[i$1] + if (elem) this$1.checkLVal(elem, isBinding, checkClashes) + } + break + + case "AssignmentPattern": + this.checkLVal(expr.left, isBinding, checkClashes) + break + + case "RestElement": + this.checkLVal(expr.argument, isBinding, checkClashes) + break + + case "ParenthesizedExpression": + this.checkLVal(expr.expression, isBinding, checkClashes) + break + + default: + this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue") + } +} + +var pp$3 = Parser.prototype + +// Check if property name clashes with already added. +// Object/class getters and setters are not allowed to clash — +// either with each other or with an init property — and in +// strict mode, init properties are also not allowed to be repeated. + +pp$3.checkPropClash = function(prop, propHash) { + if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand)) + return + var key = prop.key; + var name + switch (key.type) { + case "Identifier": name = key.name; break + case "Literal": name = String(key.value); break + default: return + } + var kind = prop.kind; + if (this.options.ecmaVersion >= 6) { + if (name === "__proto__" && kind === "init") { + if (propHash.proto) this.raiseRecoverable(key.start, "Redefinition of __proto__ property") + propHash.proto = true + } + return + } + name = "$" + name + var other = propHash[name] + if (other) { + var isGetSet = kind !== "init" + if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) + this.raiseRecoverable(key.start, "Redefinition of property") + } else { + other = propHash[name] = { + init: false, + get: false, + set: false + } + } + other[kind] = true +} + +// ### Expression parsing + +// These nest, from the most general expression type at the top to +// 'atomic', nondivisible expression types at the bottom. Most of +// the functions will simply let the function(s) below them parse, +// and, *if* the syntactic construct they handle is present, wrap +// the AST node that the inner parser gave them in another node. + +// Parse a full expression. The optional arguments are used to +// forbid the `in` operator (in for loops initalization expressions) +// and provide reference for storing '=' operator inside shorthand +// property assignment in contexts where both object expression +// and object pattern might appear (so it's possible to raise +// delayed syntax error at correct position). + +pp$3.parseExpression = function(noIn, refDestructuringErrors) { + var this$1 = this; + + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseMaybeAssign(noIn, refDestructuringErrors) + if (this.type === tt.comma) { + var node = this.startNodeAt(startPos, startLoc) + node.expressions = [expr] + while (this.eat(tt.comma)) node.expressions.push(this$1.parseMaybeAssign(noIn, refDestructuringErrors)) + return this.finishNode(node, "SequenceExpression") + } + return expr +} + +// Parse an assignment expression. This includes applications of +// operators like `+=`. + +pp$3.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { + if (this.inGenerator && this.isContextual("yield")) return this.parseYield() + + var ownDestructuringErrors = false + if (!refDestructuringErrors) { + refDestructuringErrors = new DestructuringErrors + ownDestructuringErrors = true + } + var startPos = this.start, startLoc = this.startLoc + if (this.type == tt.parenL || this.type == tt.name) + this.potentialArrowAt = this.start + var left = this.parseMaybeConditional(noIn, refDestructuringErrors) + if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc) + if (this.type.isAssign) { + this.checkPatternErrors(refDestructuringErrors, true) + if (!ownDestructuringErrors) DestructuringErrors.call(refDestructuringErrors) + var node = this.startNodeAt(startPos, startLoc) + node.operator = this.value + node.left = this.type === tt.eq ? this.toAssignable(left) : left + refDestructuringErrors.shorthandAssign = 0 // reset because shorthand default was used correctly + this.checkLVal(left) + this.next() + node.right = this.parseMaybeAssign(noIn) + return this.finishNode(node, "AssignmentExpression") + } else { + if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true) + } + return left +} + +// Parse a ternary conditional (`?:`) operator. + +pp$3.parseMaybeConditional = function(noIn, refDestructuringErrors) { + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseExprOps(noIn, refDestructuringErrors) + if (this.checkExpressionErrors(refDestructuringErrors)) return expr + if (this.eat(tt.question)) { + var node = this.startNodeAt(startPos, startLoc) + node.test = expr + node.consequent = this.parseMaybeAssign() + this.expect(tt.colon) + node.alternate = this.parseMaybeAssign(noIn) + return this.finishNode(node, "ConditionalExpression") + } + return expr +} + +// Start the precedence parser. + +pp$3.parseExprOps = function(noIn, refDestructuringErrors) { + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseMaybeUnary(refDestructuringErrors, false) + if (this.checkExpressionErrors(refDestructuringErrors)) return expr + return this.parseExprOp(expr, startPos, startLoc, -1, noIn) +} + +// Parse binary operators with the operator precedence parsing +// algorithm. `left` is the left-hand side of the operator. +// `minPrec` provides context that allows the function to stop and +// defer further parser to one of its callers when it encounters an +// operator that has a lower precedence than the set it is parsing. + +pp$3.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) { + var prec = this.type.binop + if (prec != null && (!noIn || this.type !== tt._in)) { + if (prec > minPrec) { + var logical = this.type === tt.logicalOR || this.type === tt.logicalAND + var op = this.value + this.next() + var startPos = this.start, startLoc = this.startLoc + var right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn) + var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical) + return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn) + } + } + return left +} + +pp$3.buildBinary = function(startPos, startLoc, left, right, op, logical) { + var node = this.startNodeAt(startPos, startLoc) + node.left = left + node.operator = op + node.right = right + return this.finishNode(node, logical ? "LogicalExpression" : "BinaryExpression") +} + +// Parse unary operators, both prefix and postfix. + +pp$3.parseMaybeUnary = function(refDestructuringErrors, sawUnary) { + var this$1 = this; + + var startPos = this.start, startLoc = this.startLoc, expr + if (this.type.prefix) { + var node = this.startNode(), update = this.type === tt.incDec + node.operator = this.value + node.prefix = true + this.next() + node.argument = this.parseMaybeUnary(null, true) + this.checkExpressionErrors(refDestructuringErrors, true) + if (update) this.checkLVal(node.argument) + else if (this.strict && node.operator === "delete" && + node.argument.type === "Identifier") + this.raiseRecoverable(node.start, "Deleting local variable in strict mode") + else sawUnary = true + expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression") + } else { + expr = this.parseExprSubscripts(refDestructuringErrors) + if (this.checkExpressionErrors(refDestructuringErrors)) return expr + while (this.type.postfix && !this.canInsertSemicolon()) { + var node$1 = this$1.startNodeAt(startPos, startLoc) + node$1.operator = this$1.value + node$1.prefix = false + node$1.argument = expr + this$1.checkLVal(expr) + this$1.next() + expr = this$1.finishNode(node$1, "UpdateExpression") + } + } + + if (!sawUnary && this.eat(tt.starstar)) + return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false), "**", false) + else + return expr +} + +// Parse call, dot, and `[]`-subscript expressions. + +pp$3.parseExprSubscripts = function(refDestructuringErrors) { + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseExprAtom(refDestructuringErrors) + var skipArrowSubscripts = expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")" + if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr + return this.parseSubscripts(expr, startPos, startLoc) +} + +pp$3.parseSubscripts = function(base, startPos, startLoc, noCalls) { + var this$1 = this; + + for (;;) { + if (this$1.eat(tt.dot)) { + var node = this$1.startNodeAt(startPos, startLoc) + node.object = base + node.property = this$1.parseIdent(true) + node.computed = false + base = this$1.finishNode(node, "MemberExpression") + } else if (this$1.eat(tt.bracketL)) { + var node$1 = this$1.startNodeAt(startPos, startLoc) + node$1.object = base + node$1.property = this$1.parseExpression() + node$1.computed = true + this$1.expect(tt.bracketR) + base = this$1.finishNode(node$1, "MemberExpression") + } else if (!noCalls && this$1.eat(tt.parenL)) { + var node$2 = this$1.startNodeAt(startPos, startLoc) + node$2.callee = base + node$2.arguments = this$1.parseExprList(tt.parenR, false) + base = this$1.finishNode(node$2, "CallExpression") + } else if (this$1.type === tt.backQuote) { + var node$3 = this$1.startNodeAt(startPos, startLoc) + node$3.tag = base + node$3.quasi = this$1.parseTemplate() + base = this$1.finishNode(node$3, "TaggedTemplateExpression") + } else { + return base + } + } +} + +// Parse an atomic expression — either a single token that is an +// expression, an expression started by a keyword like `function` or +// `new`, or an expression wrapped in punctuation like `()`, `[]`, +// or `{}`. + +pp$3.parseExprAtom = function(refDestructuringErrors) { + var node, canBeArrow = this.potentialArrowAt == this.start + switch (this.type) { + case tt._super: + if (!this.inFunction) + this.raise(this.start, "'super' outside of function or class") + + case tt._this: + var type = this.type === tt._this ? "ThisExpression" : "Super" + node = this.startNode() + this.next() + return this.finishNode(node, type) + + case tt.name: + var startPos = this.start, startLoc = this.startLoc + var id = this.parseIdent(this.type !== tt.name) + if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) + return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]) + return id + + case tt.regexp: + var value = this.value + node = this.parseLiteral(value.value) + node.regex = {pattern: value.pattern, flags: value.flags} + return node + + case tt.num: case tt.string: + return this.parseLiteral(this.value) + + case tt._null: case tt._true: case tt._false: + node = this.startNode() + node.value = this.type === tt._null ? null : this.type === tt._true + node.raw = this.type.keyword + this.next() + return this.finishNode(node, "Literal") + + case tt.parenL: + return this.parseParenAndDistinguishExpression(canBeArrow) + + case tt.bracketL: + node = this.startNode() + this.next() + node.elements = this.parseExprList(tt.bracketR, true, true, refDestructuringErrors) + return this.finishNode(node, "ArrayExpression") + + case tt.braceL: + return this.parseObj(false, refDestructuringErrors) + + case tt._function: + node = this.startNode() + this.next() + return this.parseFunction(node, false) + + case tt._class: + return this.parseClass(this.startNode(), false) + + case tt._new: + return this.parseNew() + + case tt.backQuote: + return this.parseTemplate() + + default: + this.unexpected() + } +} + +pp$3.parseLiteral = function(value) { + var node = this.startNode() + node.value = value + node.raw = this.input.slice(this.start, this.end) + this.next() + return this.finishNode(node, "Literal") +} + +pp$3.parseParenExpression = function() { + this.expect(tt.parenL) + var val = this.parseExpression() + this.expect(tt.parenR) + return val +} + +pp$3.parseParenAndDistinguishExpression = function(canBeArrow) { + var this$1 = this; + + var startPos = this.start, startLoc = this.startLoc, val + if (this.options.ecmaVersion >= 6) { + this.next() + + var innerStartPos = this.start, innerStartLoc = this.startLoc + var exprList = [], first = true + var refDestructuringErrors = new DestructuringErrors, spreadStart, innerParenStart + while (this.type !== tt.parenR) { + first ? first = false : this$1.expect(tt.comma) + if (this$1.type === tt.ellipsis) { + spreadStart = this$1.start + exprList.push(this$1.parseParenItem(this$1.parseRest())) + break + } else { + if (this$1.type === tt.parenL && !innerParenStart) { + innerParenStart = this$1.start + } + exprList.push(this$1.parseMaybeAssign(false, refDestructuringErrors, this$1.parseParenItem)) + } + } + var innerEndPos = this.start, innerEndLoc = this.startLoc + this.expect(tt.parenR) + + if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { + this.checkPatternErrors(refDestructuringErrors, true) + if (innerParenStart) this.unexpected(innerParenStart) + return this.parseParenArrowList(startPos, startLoc, exprList) + } + + if (!exprList.length) this.unexpected(this.lastTokStart) + if (spreadStart) this.unexpected(spreadStart) + this.checkExpressionErrors(refDestructuringErrors, true) + + if (exprList.length > 1) { + val = this.startNodeAt(innerStartPos, innerStartLoc) + val.expressions = exprList + this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc) + } else { + val = exprList[0] + } + } else { + val = this.parseParenExpression() + } + + if (this.options.preserveParens) { + var par = this.startNodeAt(startPos, startLoc) + par.expression = val + return this.finishNode(par, "ParenthesizedExpression") + } else { + return val + } +} + +pp$3.parseParenItem = function(item) { + return item +} + +pp$3.parseParenArrowList = function(startPos, startLoc, exprList) { + return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList) +} + +// New's precedence is slightly tricky. It must allow its argument to +// be a `[]` or dot subscript expression, but not a call — at least, +// not without wrapping it in parentheses. Thus, it uses the noCalls +// argument to parseSubscripts to prevent it from consuming the +// argument list. + +var empty$1 = [] + +pp$3.parseNew = function() { + var node = this.startNode() + var meta = this.parseIdent(true) + if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { + node.meta = meta + node.property = this.parseIdent(true) + if (node.property.name !== "target") + this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target") + if (!this.inFunction) + this.raiseRecoverable(node.start, "new.target can only be used in functions") + return this.finishNode(node, "MetaProperty") + } + var startPos = this.start, startLoc = this.startLoc + node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true) + if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, false) + else node.arguments = empty$1 + return this.finishNode(node, "NewExpression") +} + +// Parse template expression. + +pp$3.parseTemplateElement = function() { + var elem = this.startNode() + elem.value = { + raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, '\n'), + cooked: this.value + } + this.next() + elem.tail = this.type === tt.backQuote + return this.finishNode(elem, "TemplateElement") +} + +pp$3.parseTemplate = function() { + var this$1 = this; + + var node = this.startNode() + this.next() + node.expressions = [] + var curElt = this.parseTemplateElement() + node.quasis = [curElt] + while (!curElt.tail) { + this$1.expect(tt.dollarBraceL) + node.expressions.push(this$1.parseExpression()) + this$1.expect(tt.braceR) + node.quasis.push(curElt = this$1.parseTemplateElement()) + } + this.next() + return this.finishNode(node, "TemplateLiteral") +} + +// Parse an object literal or binding pattern. + +pp$3.parseObj = function(isPattern, refDestructuringErrors) { + var this$1 = this; + + var node = this.startNode(), first = true, propHash = {} + node.properties = [] + this.next() + while (!this.eat(tt.braceR)) { + if (!first) { + this$1.expect(tt.comma) + if (this$1.afterTrailingComma(tt.braceR)) break + } else first = false + + var prop = this$1.startNode(), isGenerator, startPos, startLoc + if (this$1.options.ecmaVersion >= 6) { + prop.method = false + prop.shorthand = false + if (isPattern || refDestructuringErrors) { + startPos = this$1.start + startLoc = this$1.startLoc + } + if (!isPattern) + isGenerator = this$1.eat(tt.star) + } + this$1.parsePropertyName(prop) + this$1.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refDestructuringErrors) + this$1.checkPropClash(prop, propHash) + node.properties.push(this$1.finishNode(prop, "Property")) + } + return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression") +} + +pp$3.parsePropertyValue = function(prop, isPattern, isGenerator, startPos, startLoc, refDestructuringErrors) { + if (this.eat(tt.colon)) { + prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refDestructuringErrors) + prop.kind = "init" + } else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) { + if (isPattern) this.unexpected() + prop.kind = "init" + prop.method = true + prop.value = this.parseMethod(isGenerator) + } else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && + (prop.key.name === "get" || prop.key.name === "set") && + (this.type != tt.comma && this.type != tt.braceR)) { + if (isGenerator || isPattern) this.unexpected() + prop.kind = prop.key.name + this.parsePropertyName(prop) + prop.value = this.parseMethod(false) + var paramCount = prop.kind === "get" ? 0 : 1 + if (prop.value.params.length !== paramCount) { + var start = prop.value.start + if (prop.kind === "get") + this.raiseRecoverable(start, "getter should have no params") + else + this.raiseRecoverable(start, "setter should have exactly one param") + } + if (prop.kind === "set" && prop.value.params[0].type === "RestElement") + this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params") + } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { + if (this.keywords.test(prop.key.name) || + (this.strict ? this.reservedWordsStrictBind : this.reservedWords).test(prop.key.name) || + (this.inGenerator && prop.key.name == "yield")) + this.raiseRecoverable(prop.key.start, "'" + prop.key.name + "' can not be used as shorthand property") + prop.kind = "init" + if (isPattern) { + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key) + } else if (this.type === tt.eq && refDestructuringErrors) { + if (!refDestructuringErrors.shorthandAssign) + refDestructuringErrors.shorthandAssign = this.start + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key) + } else { + prop.value = prop.key + } + prop.shorthand = true + } else this.unexpected() +} + +pp$3.parsePropertyName = function(prop) { + if (this.options.ecmaVersion >= 6) { + if (this.eat(tt.bracketL)) { + prop.computed = true + prop.key = this.parseMaybeAssign() + this.expect(tt.bracketR) + return prop.key + } else { + prop.computed = false + } + } + return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true) +} + +// Initialize empty function node. + +pp$3.initFunction = function(node) { + node.id = null + if (this.options.ecmaVersion >= 6) { + node.generator = false + node.expression = false + } +} + +// Parse object or class method. + +pp$3.parseMethod = function(isGenerator) { + var node = this.startNode(), oldInGen = this.inGenerator + this.inGenerator = isGenerator + this.initFunction(node) + this.expect(tt.parenL) + node.params = this.parseBindingList(tt.parenR, false, false) + if (this.options.ecmaVersion >= 6) + node.generator = isGenerator + this.parseFunctionBody(node, false) + this.inGenerator = oldInGen + return this.finishNode(node, "FunctionExpression") +} + +// Parse arrow function expression with given parameters. + +pp$3.parseArrowExpression = function(node, params) { + var oldInGen = this.inGenerator + this.inGenerator = false + this.initFunction(node) + node.params = this.toAssignableList(params, true) + this.parseFunctionBody(node, true) + this.inGenerator = oldInGen + return this.finishNode(node, "ArrowFunctionExpression") +} + +// Parse function body and check parameters. + +pp$3.parseFunctionBody = function(node, isArrowFunction) { + var isExpression = isArrowFunction && this.type !== tt.braceL + + if (isExpression) { + node.body = this.parseMaybeAssign() + node.expression = true + } else { + // Start a new scope with regard to labels and the `inFunction` + // flag (restore them to their old value afterwards). + var oldInFunc = this.inFunction, oldLabels = this.labels + this.inFunction = true; this.labels = [] + node.body = this.parseBlock(true) + node.expression = false + this.inFunction = oldInFunc; this.labels = oldLabels + } + + // If this is a strict mode function, verify that argument names + // are not repeated, and it does not try to bind the words `eval` + // or `arguments`. + var useStrict = (!isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) ? node.body.body[0] : null; + if (this.strict || useStrict) { + var oldStrict = this.strict + this.strict = true + if (node.id) + this.checkLVal(node.id, true) + this.checkParams(node, useStrict) + this.strict = oldStrict + } else if (isArrowFunction) { + this.checkParams(node, useStrict) + } +} + +// Checks function params for various disallowed patterns such as using "eval" +// or "arguments" and duplicate parameters. + +pp$3.checkParams = function(node, useStrict) { + var this$1 = this; + + var nameHash = {} + for (var i = 0; i < node.params.length; i++) { + if (useStrict && this$1.options.ecmaVersion >= 7 && node.params[i].type !== "Identifier") + this$1.raiseRecoverable(useStrict.start, "Illegal 'use strict' directive in function with non-simple parameter list"); + this$1.checkLVal(node.params[i], true, nameHash) + } +} + +// Parses a comma-separated list of expressions, and returns them as +// an array. `close` is the token type that ends the list, and +// `allowEmpty` can be turned on to allow subsequent commas with +// nothing in between them to be parsed as `null` (which is needed +// for array literals). + +pp$3.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructuringErrors) { + var this$1 = this; + + var elts = [], first = true + while (!this.eat(close)) { + if (!first) { + this$1.expect(tt.comma) + if (allowTrailingComma && this$1.afterTrailingComma(close)) break + } else first = false + + var elt + if (allowEmpty && this$1.type === tt.comma) + elt = null + else if (this$1.type === tt.ellipsis) { + elt = this$1.parseSpread(refDestructuringErrors) + if (this$1.type === tt.comma && refDestructuringErrors && !refDestructuringErrors.trailingComma) { + refDestructuringErrors.trailingComma = this$1.lastTokStart + } + } else + elt = this$1.parseMaybeAssign(false, refDestructuringErrors) + elts.push(elt) + } + return elts +} + +// Parse the next token as an identifier. If `liberal` is true (used +// when parsing properties), it will also convert keywords into +// identifiers. + +pp$3.parseIdent = function(liberal) { + var node = this.startNode() + if (liberal && this.options.allowReserved == "never") liberal = false + if (this.type === tt.name) { + if (!liberal && (this.strict ? this.reservedWordsStrict : this.reservedWords).test(this.value) && + (this.options.ecmaVersion >= 6 || + this.input.slice(this.start, this.end).indexOf("\\") == -1)) + this.raiseRecoverable(this.start, "The keyword '" + this.value + "' is reserved") + if (!liberal && this.inGenerator && this.value === "yield") + this.raiseRecoverable(this.start, "Can not use 'yield' as identifier inside a generator") + node.name = this.value + } else if (liberal && this.type.keyword) { + node.name = this.type.keyword + } else { + this.unexpected() + } + this.next() + return this.finishNode(node, "Identifier") +} + +// Parses yield expression inside generator. + +pp$3.parseYield = function() { + var node = this.startNode() + this.next() + if (this.type == tt.semi || this.canInsertSemicolon() || (this.type != tt.star && !this.type.startsExpr)) { + node.delegate = false + node.argument = null + } else { + node.delegate = this.eat(tt.star) + node.argument = this.parseMaybeAssign() + } + return this.finishNode(node, "YieldExpression") +} + +var pp$4 = Parser.prototype + +// This function is used to raise exceptions on parse errors. It +// takes an offset integer (into the current `input`) to indicate +// the location of the error, attaches the position to the end +// of the error message, and then raises a `SyntaxError` with that +// message. + +pp$4.raise = function(pos, message) { + var loc = getLineInfo(this.input, pos) + message += " (" + loc.line + ":" + loc.column + ")" + var err = new SyntaxError(message) + err.pos = pos; err.loc = loc; err.raisedAt = this.pos + throw err +} + +pp$4.raiseRecoverable = pp$4.raise + +pp$4.curPosition = function() { + if (this.options.locations) { + return new Position(this.curLine, this.pos - this.lineStart) + } +} + +var Node = function Node(parser, pos, loc) { + this.type = "" + this.start = pos + this.end = 0 + if (parser.options.locations) + this.loc = new SourceLocation(parser, loc) + if (parser.options.directSourceFile) + this.sourceFile = parser.options.directSourceFile + if (parser.options.ranges) + this.range = [pos, 0] +}; + +// Start an AST node, attaching a start offset. + +var pp$5 = Parser.prototype + +pp$5.startNode = function() { + return new Node(this, this.start, this.startLoc) +} + +pp$5.startNodeAt = function(pos, loc) { + return new Node(this, pos, loc) +} + +// Finish an AST node, adding `type` and `end` properties. + +function finishNodeAt(node, type, pos, loc) { + node.type = type + node.end = pos + if (this.options.locations) + node.loc.end = loc + if (this.options.ranges) + node.range[1] = pos + return node +} + +pp$5.finishNode = function(node, type) { + return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc) +} + +// Finish node at given position + +pp$5.finishNodeAt = function(node, type, pos, loc) { + return finishNodeAt.call(this, node, type, pos, loc) +} + +var TokContext = function TokContext(token, isExpr, preserveSpace, override) { + this.token = token + this.isExpr = !!isExpr + this.preserveSpace = !!preserveSpace + this.override = override +}; + +var types = { + b_stat: new TokContext("{", false), + b_expr: new TokContext("{", true), + b_tmpl: new TokContext("${", true), + p_stat: new TokContext("(", false), + p_expr: new TokContext("(", true), + q_tmpl: new TokContext("`", true, true, function (p) { return p.readTmplToken(); }), + f_expr: new TokContext("function", true) +} + +var pp$6 = Parser.prototype + +pp$6.initialContext = function() { + return [types.b_stat] +} + +pp$6.braceIsBlock = function(prevType) { + if (prevType === tt.colon) { + var parent = this.curContext() + if (parent === types.b_stat || parent === types.b_expr) + return !parent.isExpr + } + if (prevType === tt._return) + return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) + if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR) + return true + if (prevType == tt.braceL) + return this.curContext() === types.b_stat + return !this.exprAllowed +} + +pp$6.updateContext = function(prevType) { + var update, type = this.type + if (type.keyword && prevType == tt.dot) + this.exprAllowed = false + else if (update = type.updateContext) + update.call(this, prevType) + else + this.exprAllowed = type.beforeExpr +} + +// Token-specific context update code + +tt.parenR.updateContext = tt.braceR.updateContext = function() { + if (this.context.length == 1) { + this.exprAllowed = true + return + } + var out = this.context.pop() + if (out === types.b_stat && this.curContext() === types.f_expr) { + this.context.pop() + this.exprAllowed = false + } else if (out === types.b_tmpl) { + this.exprAllowed = true + } else { + this.exprAllowed = !out.isExpr + } +} + +tt.braceL.updateContext = function(prevType) { + this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr) + this.exprAllowed = true +} + +tt.dollarBraceL.updateContext = function() { + this.context.push(types.b_tmpl) + this.exprAllowed = true +} + +tt.parenL.updateContext = function(prevType) { + var statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while + this.context.push(statementParens ? types.p_stat : types.p_expr) + this.exprAllowed = true +} + +tt.incDec.updateContext = function() { + // tokExprAllowed stays unchanged +} + +tt._function.updateContext = function(prevType) { + if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else && + !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat)) + this.context.push(types.f_expr) + this.exprAllowed = false +} + +tt.backQuote.updateContext = function() { + if (this.curContext() === types.q_tmpl) + this.context.pop() + else + this.context.push(types.q_tmpl) + this.exprAllowed = false +} + +// Object type used to represent tokens. Note that normally, tokens +// simply exist as properties on the parser object. This is only +// used for the onToken callback and the external tokenizer. + +var Token = function Token(p) { + this.type = p.type + this.value = p.value + this.start = p.start + this.end = p.end + if (p.options.locations) + this.loc = new SourceLocation(p, p.startLoc, p.endLoc) + if (p.options.ranges) + this.range = [p.start, p.end] +}; + +// ## Tokenizer + +var pp$7 = Parser.prototype + +// Are we running under Rhino? +var isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]" + +// Move to the next token + +pp$7.next = function() { + if (this.options.onToken) + this.options.onToken(new Token(this)) + + this.lastTokEnd = this.end + this.lastTokStart = this.start + this.lastTokEndLoc = this.endLoc + this.lastTokStartLoc = this.startLoc + this.nextToken() +} + +pp$7.getToken = function() { + this.next() + return new Token(this) +} + +// If we're in an ES6 environment, make parsers iterable +if (typeof Symbol !== "undefined") + pp$7[Symbol.iterator] = function () { + var self = this + return {next: function () { + var token = self.getToken() + return { + done: token.type === tt.eof, + value: token + } + }} + } + +// Toggle strict mode. Re-reads the next number or string to please +// pedantic tests (`"use strict"; 010;` should fail). + +pp$7.setStrict = function(strict) { + var this$1 = this; + + this.strict = strict + if (this.type !== tt.num && this.type !== tt.string) return + this.pos = this.start + if (this.options.locations) { + while (this.pos < this.lineStart) { + this$1.lineStart = this$1.input.lastIndexOf("\n", this$1.lineStart - 2) + 1 + --this$1.curLine + } + } + this.nextToken() +} + +pp$7.curContext = function() { + return this.context[this.context.length - 1] +} + +// Read a single token, updating the parser object's token-related +// properties. + +pp$7.nextToken = function() { + var curContext = this.curContext() + if (!curContext || !curContext.preserveSpace) this.skipSpace() + + this.start = this.pos + if (this.options.locations) this.startLoc = this.curPosition() + if (this.pos >= this.input.length) return this.finishToken(tt.eof) + + if (curContext.override) return curContext.override(this) + else this.readToken(this.fullCharCodeAtPos()) +} + +pp$7.readToken = function(code) { + // Identifier or keyword. '\uXXXX' sequences are allowed in + // identifiers, so '\' also dispatches to that. + if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) + return this.readWord() + + return this.getTokenFromCode(code) +} + +pp$7.fullCharCodeAtPos = function() { + var code = this.input.charCodeAt(this.pos) + if (code <= 0xd7ff || code >= 0xe000) return code + var next = this.input.charCodeAt(this.pos + 1) + return (code << 10) + next - 0x35fdc00 +} + +pp$7.skipBlockComment = function() { + var this$1 = this; + + var startLoc = this.options.onComment && this.curPosition() + var start = this.pos, end = this.input.indexOf("*/", this.pos += 2) + if (end === -1) this.raise(this.pos - 2, "Unterminated comment") + this.pos = end + 2 + if (this.options.locations) { + lineBreakG.lastIndex = start + var match + while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) { + ++this$1.curLine + this$1.lineStart = match.index + match[0].length + } + } + if (this.options.onComment) + this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, + startLoc, this.curPosition()) +} + +pp$7.skipLineComment = function(startSkip) { + var this$1 = this; + + var start = this.pos + var startLoc = this.options.onComment && this.curPosition() + var ch = this.input.charCodeAt(this.pos+=startSkip) + while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { + ++this$1.pos + ch = this$1.input.charCodeAt(this$1.pos) + } + if (this.options.onComment) + this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, + startLoc, this.curPosition()) +} + +// Called at the start of the parse and after every token. Skips +// whitespace and comments, and. + +pp$7.skipSpace = function() { + var this$1 = this; + + loop: while (this.pos < this.input.length) { + var ch = this$1.input.charCodeAt(this$1.pos) + switch (ch) { + case 32: case 160: // ' ' + ++this$1.pos + break + case 13: + if (this$1.input.charCodeAt(this$1.pos + 1) === 10) { + ++this$1.pos + } + case 10: case 8232: case 8233: + ++this$1.pos + if (this$1.options.locations) { + ++this$1.curLine + this$1.lineStart = this$1.pos + } + break + case 47: // '/' + switch (this$1.input.charCodeAt(this$1.pos + 1)) { + case 42: // '*' + this$1.skipBlockComment() + break + case 47: + this$1.skipLineComment(2) + break + default: + break loop + } + break + default: + if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { + ++this$1.pos + } else { + break loop + } + } + } +} + +// Called at the end of every token. Sets `end`, `val`, and +// maintains `context` and `exprAllowed`, and skips the space after +// the token, so that the next one's `start` will point at the +// right position. + +pp$7.finishToken = function(type, val) { + this.end = this.pos + if (this.options.locations) this.endLoc = this.curPosition() + var prevType = this.type + this.type = type + this.value = val + + this.updateContext(prevType) +} + +// ### Token reading + +// This is the function that is called to fetch the next token. It +// is somewhat obscure, because it works in character codes rather +// than characters, and because operator parsing has been inlined +// into it. +// +// All in the name of speed. +// +pp$7.readToken_dot = function() { + var next = this.input.charCodeAt(this.pos + 1) + if (next >= 48 && next <= 57) return this.readNumber(true) + var next2 = this.input.charCodeAt(this.pos + 2) + if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.' + this.pos += 3 + return this.finishToken(tt.ellipsis) + } else { + ++this.pos + return this.finishToken(tt.dot) + } +} + +pp$7.readToken_slash = function() { // '/' + var next = this.input.charCodeAt(this.pos + 1) + if (this.exprAllowed) {++this.pos; return this.readRegexp()} + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.slash, 1) +} + +pp$7.readToken_mult_modulo_exp = function(code) { // '%*' + var next = this.input.charCodeAt(this.pos + 1) + var size = 1 + var tokentype = code === 42 ? tt.star : tt.modulo + + // exponentiation operator ** and **= + if (this.options.ecmaVersion >= 7 && next === 42) { + ++size + tokentype = tt.starstar + next = this.input.charCodeAt(this.pos + 2) + } + + if (next === 61) return this.finishOp(tt.assign, size + 1) + return this.finishOp(tokentype, size) +} + +pp$7.readToken_pipe_amp = function(code) { // '|&' + var next = this.input.charCodeAt(this.pos + 1) + if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2) + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1) +} + +pp$7.readToken_caret = function() { // '^' + var next = this.input.charCodeAt(this.pos + 1) + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.bitwiseXOR, 1) +} + +pp$7.readToken_plus_min = function(code) { // '+-' + var next = this.input.charCodeAt(this.pos + 1) + if (next === code) { + if (next == 45 && this.input.charCodeAt(this.pos + 2) == 62 && + lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) { + // A `-->` line comment + this.skipLineComment(3) + this.skipSpace() + return this.nextToken() + } + return this.finishOp(tt.incDec, 2) + } + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.plusMin, 1) +} + +pp$7.readToken_lt_gt = function(code) { // '<>' + var next = this.input.charCodeAt(this.pos + 1) + var size = 1 + if (next === code) { + size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2 + if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1) + return this.finishOp(tt.bitShift, size) + } + if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && + this.input.charCodeAt(this.pos + 3) == 45) { + if (this.inModule) this.unexpected() + // `` line comment + this.skipLineComment(3) + this.skipSpace() + return this.nextToken() + } + return this.finishOp(tt.incDec, 2) + } + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.plusMin, 1) + } -pp.readToken = function (code) { - // Identifier or keyword. '\uXXXX' sequences are allowed in - // identifiers, so '\' also dispatches to that. - if (_identifier.isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) return this.readWord(); - - return this.getTokenFromCode(code); -}; - -pp.fullCharCodeAtPos = function () { - var code = this.input.charCodeAt(this.pos); - if (code <= 0xd7ff || code >= 0xe000) return code; - var next = this.input.charCodeAt(this.pos + 1); - return (code << 10) + next - 0x35fdc00; -}; - -pp.skipBlockComment = function () { - var startLoc = this.options.onComment && this.curPosition(); - var start = this.pos, - end = this.input.indexOf("*/", this.pos += 2); - if (end === -1) this.raise(this.pos - 2, "Unterminated comment"); - this.pos = end + 2; - if (this.options.locations) { - _whitespace.lineBreakG.lastIndex = start; - var match = undefined; - while ((match = _whitespace.lineBreakG.exec(this.input)) && match.index < this.pos) { - ++this.curLine; - this.lineStart = match.index + match[0].length; - } - } - if (this.options.onComment) this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, startLoc, this.curPosition()); -}; - -pp.skipLineComment = function (startSkip) { - var start = this.pos; - var startLoc = this.options.onComment && this.curPosition(); - var ch = this.input.charCodeAt(this.pos += startSkip); - while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { - ++this.pos; - ch = this.input.charCodeAt(this.pos); - } - if (this.options.onComment) this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, startLoc, this.curPosition()); -}; - -// Called at the start of the parse and after every token. Skips -// whitespace and comments, and. - -pp.skipSpace = function () { - loop: while (this.pos < this.input.length) { - var ch = this.input.charCodeAt(this.pos); - switch (ch) { - case 32:case 160: - // ' ' - ++this.pos; - break; - case 13: - if (this.input.charCodeAt(this.pos + 1) === 10) { - ++this.pos; - } - case 10:case 8232:case 8233: - ++this.pos; - if (this.options.locations) { - ++this.curLine; - this.lineStart = this.pos; - } - break; - case 47: - // '/' - switch (this.input.charCodeAt(this.pos + 1)) { - case 42: - // '*' - this.skipBlockComment(); - break; - case 47: - this.skipLineComment(2); - break; - default: - break loop; - } - break; - default: - if (ch > 8 && ch < 14 || ch >= 5760 && _whitespace.nonASCIIwhitespace.test(String.fromCharCode(ch))) { - ++this.pos; - } else { - break loop; - } + pp$7.readToken_lt_gt = function(code) { // '<>' + var next = this.input.charCodeAt(this.pos + 1) + var size = 1 + if (next === code) { + size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2 + if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1) + return this.finishOp(tt.bitShift, size) + } + if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && + this.input.charCodeAt(this.pos + 3) == 45) { + if (this.inModule) this.unexpected() + // `` line comment - this.skipLineComment(3); - this.skipSpace(); - return this.nextToken(); - } - return this.finishOp(_tokentype.types.incDec, 2); - } - if (next === 61) return this.finishOp(_tokentype.types.assign, 2); - return this.finishOp(_tokentype.types.plusMin, 1); -}; - -pp.readToken_lt_gt = function (code) { - // '<>' - var next = this.input.charCodeAt(this.pos + 1); - var size = 1; - if (next === code) { - size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; - if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(_tokentype.types.assign, size + 1); - return this.finishOp(_tokentype.types.bitShift, size); - } - if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) { - if (this.inModule) this.unexpected(); - // `