pax_global_header00006660000000000000000000000064135147550240014520gustar00rootroot0000000000000052 comment=dbddf14d5771b21b5da704213e4508c660ca1c64 eslint-scope-5.0.0/000077500000000000000000000000001351475502400141275ustar00rootroot00000000000000eslint-scope-5.0.0/.eslintignore000066400000000000000000000000161351475502400166270ustar00rootroot00000000000000!.eslintrc.js eslint-scope-5.0.0/.eslintrc.js000066400000000000000000000003471351475502400163720ustar00rootroot00000000000000"use strict"; module.exports = { root: true, extends: [ "eslint" ], overrides: [ { files: ["tests/**/*"], env: { mocha: true } } ] }; eslint-scope-5.0.0/.gitignore000066400000000000000000000001671351475502400161230ustar00rootroot00000000000000/node_modules coverage/ build/ npm-debug.log .DS_Store .idea *.iml /.vscode .sublimelinterrc .eslint-release-info.json eslint-scope-5.0.0/.npmrc000066400000000000000000000000231351475502400152420ustar00rootroot00000000000000package-lock=false eslint-scope-5.0.0/.travis.yml000066400000000000000000000001441351475502400162370ustar00rootroot00000000000000language: node_js node_js: - "8" - "9" - "10" - "11" sudo: false script: "npm test" eslint-scope-5.0.0/CHANGELOG.md000066400000000000000000000063361351475502400157500ustar00rootroot00000000000000v5.0.0 - July 20, 2019 * [`e9fa22e`](https://github.com/eslint/eslint-scope/commit/e9fa22ea412c26cf2761fa98af7e715644bdb464) Upgrade: update dependencies after dropping support for Node <8 (#53) (Kai Cataldo) * [`ee9f7c1`](https://github.com/eslint/eslint-scope/commit/ee9f7c12721aa195ba7e0e69551f49bfdb479951) Breaking: drop support for Node v6 (#54) (Kai Cataldo) v4.0.3 - March 15, 2019 * [`299df64`](https://github.com/eslint/eslint-scope/commit/299df64bdafb30b4d9372e4b7af0cf51a3818c4a) Fix: arrow function scope strictness (take 2) (#52) (futpib) v4.0.2 - March 1, 2019 * [`c925600`](https://github.com/eslint/eslint-scope/commit/c925600a684ae0f71b96f85339437a43b4d50d99) Revert "Fix: Arrow function scope strictness (fixes #49) (#50)" (#51) (Teddy Katz) v4.0.1 - March 1, 2019 * [`2533966`](https://github.com/eslint/eslint-scope/commit/2533966faf317df5a3847fab937ba462c16808b8) Fix: Arrow function scope strictness (fixes #49) (#50) (futpib) * [`0cbeea5`](https://github.com/eslint/eslint-scope/commit/0cbeea51dfb66ab88ea34b0e3b4ad5e6cc210f2f) Chore: add supported Node.js versions to CI (#47) (Kai Cataldo) * [`b423057`](https://github.com/eslint/eslint-scope/commit/b42305760638b8edf4667acf1445e450869bd983) Upgrade: eslint-release@1.0.0 (#46) (Teddy Katz) v4.0.0 - June 21, 2018 v4.0.0-rc.0 - June 9, 2018 * 3b919b8 Build: Adding rc release script to package.json (#38) (Kevin Partington) * 137732a Chore: avoid creating package-lock.json files (#37) (Teddy Katz) v4.0.0-alpha.0 - April 27, 2018 * 7cc3769 Upgrade: eslint-release ^0.11.1 (#36) (Teddy Katz) * c9f6967 Breaking: remove TDZScope (refs eslint/eslint#10245) (#35) (Toru Nagashima) * 982a71f Fix: wrong resolution about default parameters (#33) (Toru Nagashima) * 57889f1 Docs: Remove extra header line from LICENSE (#32) (Gyandeep Singh) v3.7.1 - April 12, 2017 * ced6262 Fix: restore previous Scope API exports from escope (#31) (Vitor Balocco) * 5c3d966 Fix: Remove and Modify tests that contain invalid ES6 syntax (#29) (Reyad Attiyat) v3.7.0 - March 17, 2017 * 9e27835 Chore: Add files section to package.json (#24) (Ilya Volodin) * 3e4d123 Upgrade: eslint-config-eslint to 4.0.0 (#21) (Teddy Katz) * 38c50fb Chore: Rename src to lib and test to tests (#20) (Corbin Uselton) * f4cd920 Chore: Remove esprima (#19) (Corbin Uselton) * f81fad5 Revert "Chore: Remove esprima" (#18) (James Henry) * 31b0085 Chore: Remove es6-map and es6-weakmap as they are included in node4 (#10) (#13) (Corbin Uselton) * 12a1ca1 Add Makefile.js and eslint (#15) (Reyad Attiyat) * 7d23f8e Chore: Remove es6-map and es6-weakmap as they are included in node4 (#10) (Corbin Uselton) * 019441e Chore: Convert to ES6 that is supported on Node 4, commonjs modules and remove Babel (#14) (Corbin Uselton) * c647f65 Update: Add check for node.body in referencer (#2) (Corbin Uselton) * eb5c9db Remove browserify and jsdoc (#12) (Corbin Uselton) * cf38df0 Chore: Update README.md (#3) (James Henry) * 8a142ca Chore: Add eslint-release scripts (#6) (James Henry) * e60d8cb Chore: Remove unused bower.json (#5) (James Henry) * 049c545 Chore: Fix tests for eslint-scope (#4) (James Henry) * f026aab Chore: Update package.json for eslint fork (#1) (James Henry) * a94d281 Chore: Update license with JSF copyright (Nicholas C. Zakas) eslint-scope-5.0.0/CONTRIBUTING.md000066400000000000000000000006221351475502400163600ustar00rootroot00000000000000## Project license: \ - You will only Submit Contributions where You have authored 100% of the content. - You will only Submit Contributions to which You have the necessary rights. This means that if You are employed You have received the necessary permissions from Your employer to make the Contributions. - Whatever content You Contribute will be provided under the Project License. eslint-scope-5.0.0/LICENSE000066400000000000000000000025561351475502400151440ustar00rootroot00000000000000Copyright JS Foundation and other contributors, https://js.foundation Copyright (C) 2012-2013 Yusuke Suzuki (twitter: @Constellation) and other contributors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. eslint-scope-5.0.0/Makefile.js000066400000000000000000000070771351475502400162150ustar00rootroot00000000000000/** * @fileoverview Build file * @author nzakas * @copyright jQuery Foundation and other contributors, https://jquery.org/ * MIT License */ /* global echo, exec, exit, set, target */ "use strict"; /* eslint no-console: 0*/ //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ require("shelljs/make"); set("+e"); const checker = require("npm-license"); //------------------------------------------------------------------------------ // Settings //------------------------------------------------------------------------------ const OPEN_SOURCE_LICENSES = [ /MIT/, /BSD/, /Apache/, /ISC/, /WTF/, /Public Domain/ ]; //------------------------------------------------------------------------------ // Data //------------------------------------------------------------------------------ const NODE = "node", NODE_MODULES = "./node_modules/", // Utilities - intentional extra space at the end of each string MOCHA = `${NODE_MODULES}mocha/bin/_mocha `, ESLINT = `${NODE} ${NODE_MODULES}/eslint/bin/eslint `, ISTANBUL = `${NODE} ${NODE_MODULES}/istanbul/lib/cli.js `, // Files MAKEFILE = "./Makefile.js", JS_FILES = "lib/**/*.js", TEST_FILES = "tests/*.js"; //------------------------------------------------------------------------------ // Tasks //------------------------------------------------------------------------------ target.all = function() { target.test(); }; target.lint = function() { let errors = 0, lastReturn; echo("Validating Makefile.js"); lastReturn = exec(ESLINT + MAKEFILE); if (lastReturn.code !== 0) { errors++; } echo("Validating JavaScript files"); lastReturn = exec(ESLINT + JS_FILES); if (lastReturn.code !== 0) { errors++; } echo("Validating JavaScript test files"); lastReturn = exec(ESLINT + TEST_FILES); if (lastReturn.code !== 0) { errors++; } if (errors) { exit(1); } }; target.test = function() { target.lint(); let errors = 0; const lastReturn = exec(`${ISTANBUL} cover ${MOCHA} -- -R progress -c ${TEST_FILES}`); if (lastReturn.code !== 0) { errors++; } if (errors) { exit(1); } target.checkLicenses(); }; target.checkLicenses = function() { /** * Returns true if the given dependency's licenses are all permissable for use in OSS * @param {Object} dependency object containing the name and licenses of the given dependency * @returns {boolean} is permissable dependency */ function isPermissible(dependency) { const licenses = dependency.licenses; if (Array.isArray(licenses)) { return licenses.some(license => isPermissible({ name: dependency.name, licenses: license })); } return OPEN_SOURCE_LICENSES.some(license => license.test(licenses)); } echo("Validating licenses"); checker.init({ start: __dirname }, deps => { const impermissible = Object.keys(deps).map(dependency => ({ name: dependency, licenses: deps[dependency].licenses })).filter(dependency => !isPermissible(dependency)); if (impermissible.length) { impermissible.forEach(dependency => { console.error("%s license for %s is impermissible.", dependency.licenses, dependency.name); }); exit(1); } }); }; eslint-scope-5.0.0/README.md000066400000000000000000000027401351475502400154110ustar00rootroot00000000000000# ESLint Scope ESLint Scope is the [ECMAScript](http://www.ecma-international.org/publications/standards/Ecma-262.htm) scope analyzer used in ESLint. It is a fork of [escope](http://github.com/estools/escope). ## Usage Install: ``` npm i eslint-scope --save ``` Example: ```js var eslintScope = require('eslint-scope'); var espree = require('espree'); var estraverse = require('estraverse'); var ast = espree.parse(code); var scopeManager = eslintScope.analyze(ast); var currentScope = scopeManager.acquire(ast); // global scope estraverse.traverse(ast, { enter: function(node, parent) { // do stuff if (/Function/.test(node.type)) { currentScope = scopeManager.acquire(node); // get current function scope } }, leave: function(node, parent) { if (/Function/.test(node.type)) { currentScope = currentScope.upper; // set to parent scope } // do stuff } }); ``` ## Contributing Issues and pull requests will be triaged and responded to as quickly as possible. We operate under the [ESLint Contributor Guidelines](http://eslint.org/docs/developer-guide/contributing), so please be sure to read them before contributing. If you're not sure where to dig in, check out the [issues](https://github.com/eslint/eslint-scope/issues). ## Build Commands * `npm test` - run all linting and tests * `npm run lint` - run all linting ## License ESLint Scope is licensed under a permissive BSD 2-clause license. eslint-scope-5.0.0/lib/000077500000000000000000000000001351475502400146755ustar00rootroot00000000000000eslint-scope-5.0.0/lib/definition.js000066400000000000000000000054621351475502400173720ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; const Variable = require("./variable"); /** * @class Definition */ class Definition { constructor(type, name, node, parent, index, kind) { /** * @member {String} Definition#type - type of the occurrence (e.g. "Parameter", "Variable", ...). */ this.type = type; /** * @member {espree.Identifier} Definition#name - the identifier AST node of the occurrence. */ this.name = name; /** * @member {espree.Node} Definition#node - the enclosing node of the identifier. */ this.node = node; /** * @member {espree.Node?} Definition#parent - the enclosing statement node of the identifier. */ this.parent = parent; /** * @member {Number?} Definition#index - the index in the declaration statement. */ this.index = index; /** * @member {String?} Definition#kind - the kind of the declaration statement. */ this.kind = kind; } } /** * @class ParameterDefinition */ class ParameterDefinition extends Definition { constructor(name, node, index, rest) { super(Variable.Parameter, name, node, null, index, null); /** * Whether the parameter definition is a part of a rest parameter. * @member {boolean} ParameterDefinition#rest */ this.rest = rest; } } module.exports = { ParameterDefinition, Definition }; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/lib/index.js000066400000000000000000000143371351475502400163520ustar00rootroot00000000000000/* Copyright (C) 2012-2014 Yusuke Suzuki Copyright (C) 2013 Alex Seville Copyright (C) 2014 Thiago de Arruda Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * Escope (escope) is an ECMAScript * scope analyzer extracted from the esmangle project. *

* escope finds lexical scopes in a source program, i.e. areas of that * program where different occurrences of the same identifier refer to the same * variable. With each scope the contained variables are collected, and each * identifier reference in code is linked to its corresponding variable (if * possible). *

* escope works on a syntax tree of the parsed source code which has * to adhere to the * Mozilla Parser API. E.g. espree is a parser * that produces such syntax trees. *

* The main interface is the {@link analyze} function. * @module escope */ "use strict"; /* eslint no-underscore-dangle: ["error", { "allow": ["__currentScope"] }] */ const assert = require("assert"); const ScopeManager = require("./scope-manager"); const Referencer = require("./referencer"); const Reference = require("./reference"); const Variable = require("./variable"); const Scope = require("./scope").Scope; const version = require("../package.json").version; /** * Set the default options * @returns {Object} options */ function defaultOptions() { return { optimistic: false, directive: false, nodejsScope: false, impliedStrict: false, sourceType: "script", // one of ['script', 'module'] ecmaVersion: 5, childVisitorKeys: null, fallback: "iteration" }; } /** * Preform deep update on option object * @param {Object} target - Options * @param {Object} override - Updates * @returns {Object} Updated options */ function updateDeeply(target, override) { /** * Is hash object * @param {Object} value - Test value * @returns {boolean} Result */ function isHashObject(value) { return typeof value === "object" && value instanceof Object && !(value instanceof Array) && !(value instanceof RegExp); } for (const key in override) { if (Object.prototype.hasOwnProperty.call(override, key)) { const val = override[key]; if (isHashObject(val)) { if (isHashObject(target[key])) { updateDeeply(target[key], val); } else { target[key] = updateDeeply({}, val); } } else { target[key] = val; } } } return target; } /** * Main interface function. Takes an Espree syntax tree and returns the * analyzed scopes. * @function analyze * @param {espree.Tree} tree - Abstract Syntax Tree * @param {Object} providedOptions - Options that tailor the scope analysis * @param {boolean} [providedOptions.optimistic=false] - the optimistic flag * @param {boolean} [providedOptions.directive=false]- the directive flag * @param {boolean} [providedOptions.ignoreEval=false]- whether to check 'eval()' calls * @param {boolean} [providedOptions.nodejsScope=false]- whether the whole * script is executed under node.js environment. When enabled, escope adds * a function scope immediately following the global scope. * @param {boolean} [providedOptions.impliedStrict=false]- implied strict mode * (if ecmaVersion >= 5). * @param {string} [providedOptions.sourceType='script']- the source type of the script. one of 'script' and 'module' * @param {number} [providedOptions.ecmaVersion=5]- which ECMAScript version is considered * @param {Object} [providedOptions.childVisitorKeys=null] - Additional known visitor keys. See [esrecurse](https://github.com/estools/esrecurse)'s the `childVisitorKeys` option. * @param {string} [providedOptions.fallback='iteration'] - A kind of the fallback in order to encounter with unknown node. See [esrecurse](https://github.com/estools/esrecurse)'s the `fallback` option. * @returns {ScopeManager} ScopeManager */ function analyze(tree, providedOptions) { const options = updateDeeply(defaultOptions(), providedOptions); const scopeManager = new ScopeManager(options); const referencer = new Referencer(options, scopeManager); referencer.visit(tree); assert(scopeManager.__currentScope === null, "currentScope should be null."); return scopeManager; } module.exports = { /** @name module:escope.version */ version, /** @name module:escope.Reference */ Reference, /** @name module:escope.Variable */ Variable, /** @name module:escope.Scope */ Scope, /** @name module:escope.ScopeManager */ ScopeManager, analyze }; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/lib/pattern-visitor.js000066400000000000000000000114741351475502400204140ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; /* eslint-disable no-undefined */ const Syntax = require("estraverse").Syntax; const esrecurse = require("esrecurse"); /** * Get last array element * @param {array} xs - array * @returns {any} Last elment */ function getLast(xs) { return xs[xs.length - 1] || null; } class PatternVisitor extends esrecurse.Visitor { static isPattern(node) { const nodeType = node.type; return ( nodeType === Syntax.Identifier || nodeType === Syntax.ObjectPattern || nodeType === Syntax.ArrayPattern || nodeType === Syntax.SpreadElement || nodeType === Syntax.RestElement || nodeType === Syntax.AssignmentPattern ); } constructor(options, rootPattern, callback) { super(null, options); this.rootPattern = rootPattern; this.callback = callback; this.assignments = []; this.rightHandNodes = []; this.restElements = []; } Identifier(pattern) { const lastRestElement = getLast(this.restElements); this.callback(pattern, { topLevel: pattern === this.rootPattern, rest: lastRestElement !== null && lastRestElement !== undefined && lastRestElement.argument === pattern, assignments: this.assignments }); } Property(property) { // Computed property's key is a right hand node. if (property.computed) { this.rightHandNodes.push(property.key); } // If it's shorthand, its key is same as its value. // If it's shorthand and has its default value, its key is same as its value.left (the value is AssignmentPattern). // If it's not shorthand, the name of new variable is its value's. this.visit(property.value); } ArrayPattern(pattern) { for (let i = 0, iz = pattern.elements.length; i < iz; ++i) { const element = pattern.elements[i]; this.visit(element); } } AssignmentPattern(pattern) { this.assignments.push(pattern); this.visit(pattern.left); this.rightHandNodes.push(pattern.right); this.assignments.pop(); } RestElement(pattern) { this.restElements.push(pattern); this.visit(pattern.argument); this.restElements.pop(); } MemberExpression(node) { // Computed property's key is a right hand node. if (node.computed) { this.rightHandNodes.push(node.property); } // the object is only read, write to its property. this.rightHandNodes.push(node.object); } // // ForInStatement.left and AssignmentExpression.left are LeftHandSideExpression. // By spec, LeftHandSideExpression is Pattern or MemberExpression. // (see also: https://github.com/estree/estree/pull/20#issuecomment-74584758) // But espree 2.0 parses to ArrayExpression, ObjectExpression, etc... // SpreadElement(node) { this.visit(node.argument); } ArrayExpression(node) { node.elements.forEach(this.visit, this); } AssignmentExpression(node) { this.assignments.push(node); this.visit(node.left); this.rightHandNodes.push(node.right); this.assignments.pop(); } CallExpression(node) { // arguments are right hand nodes. node.arguments.forEach(a => { this.rightHandNodes.push(a); }); this.visit(node.callee); } } module.exports = PatternVisitor; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/lib/reference.js000066400000000000000000000112431351475502400171720ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; const READ = 0x1; const WRITE = 0x2; const RW = READ | WRITE; /** * A Reference represents a single occurrence of an identifier in code. * @class Reference */ class Reference { constructor(ident, scope, flag, writeExpr, maybeImplicitGlobal, partial, init) { /** * Identifier syntax node. * @member {espreeIdentifier} Reference#identifier */ this.identifier = ident; /** * Reference to the enclosing Scope. * @member {Scope} Reference#from */ this.from = scope; /** * Whether the reference comes from a dynamic scope (such as 'eval', * 'with', etc.), and may be trapped by dynamic scopes. * @member {boolean} Reference#tainted */ this.tainted = false; /** * The variable this reference is resolved with. * @member {Variable} Reference#resolved */ this.resolved = null; /** * The read-write mode of the reference. (Value is one of {@link * Reference.READ}, {@link Reference.RW}, {@link Reference.WRITE}). * @member {number} Reference#flag * @private */ this.flag = flag; if (this.isWrite()) { /** * If reference is writeable, this is the tree being written to it. * @member {espreeNode} Reference#writeExpr */ this.writeExpr = writeExpr; /** * Whether the Reference might refer to a partial value of writeExpr. * @member {boolean} Reference#partial */ this.partial = partial; /** * Whether the Reference is to write of initialization. * @member {boolean} Reference#init */ this.init = init; } this.__maybeImplicitGlobal = maybeImplicitGlobal; } /** * Whether the reference is static. * @method Reference#isStatic * @returns {boolean} static */ isStatic() { return !this.tainted && this.resolved && this.resolved.scope.isStatic(); } /** * Whether the reference is writeable. * @method Reference#isWrite * @returns {boolean} write */ isWrite() { return !!(this.flag & Reference.WRITE); } /** * Whether the reference is readable. * @method Reference#isRead * @returns {boolean} read */ isRead() { return !!(this.flag & Reference.READ); } /** * Whether the reference is read-only. * @method Reference#isReadOnly * @returns {boolean} read only */ isReadOnly() { return this.flag === Reference.READ; } /** * Whether the reference is write-only. * @method Reference#isWriteOnly * @returns {boolean} write only */ isWriteOnly() { return this.flag === Reference.WRITE; } /** * Whether the reference is read-write. * @method Reference#isReadWrite * @returns {boolean} read write */ isReadWrite() { return this.flag === Reference.RW; } } /** * @constant Reference.READ * @private */ Reference.READ = READ; /** * @constant Reference.WRITE * @private */ Reference.WRITE = WRITE; /** * @constant Reference.RW * @private */ Reference.RW = RW; module.exports = Reference; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/lib/referencer.js000066400000000000000000000444341351475502400173640ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; /* eslint-disable no-underscore-dangle */ /* eslint-disable no-undefined */ const Syntax = require("estraverse").Syntax; const esrecurse = require("esrecurse"); const Reference = require("./reference"); const Variable = require("./variable"); const PatternVisitor = require("./pattern-visitor"); const definition = require("./definition"); const assert = require("assert"); const ParameterDefinition = definition.ParameterDefinition; const Definition = definition.Definition; /** * Traverse identifier in pattern * @param {Object} options - options * @param {pattern} rootPattern - root pattern * @param {Refencer} referencer - referencer * @param {callback} callback - callback * @returns {void} */ function traverseIdentifierInPattern(options, rootPattern, referencer, callback) { // Call the callback at left hand identifier nodes, and Collect right hand nodes. const visitor = new PatternVisitor(options, rootPattern, callback); visitor.visit(rootPattern); // Process the right hand nodes recursively. if (referencer !== null && referencer !== undefined) { visitor.rightHandNodes.forEach(referencer.visit, referencer); } } // Importing ImportDeclaration. // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-moduledeclarationinstantiation // https://github.com/estree/estree/blob/master/es6.md#importdeclaration // FIXME: Now, we don't create module environment, because the context is // implementation dependent. class Importer extends esrecurse.Visitor { constructor(declaration, referencer) { super(null, referencer.options); this.declaration = declaration; this.referencer = referencer; } visitImport(id, specifier) { this.referencer.visitPattern(id, pattern => { this.referencer.currentScope().__define(pattern, new Definition( Variable.ImportBinding, pattern, specifier, this.declaration, null, null )); }); } ImportNamespaceSpecifier(node) { const local = (node.local || node.id); if (local) { this.visitImport(local, node); } } ImportDefaultSpecifier(node) { const local = (node.local || node.id); this.visitImport(local, node); } ImportSpecifier(node) { const local = (node.local || node.id); if (node.name) { this.visitImport(node.name, node); } else { this.visitImport(local, node); } } } // Referencing variables and creating bindings. class Referencer extends esrecurse.Visitor { constructor(options, scopeManager) { super(null, options); this.options = options; this.scopeManager = scopeManager; this.parent = null; this.isInnerMethodDefinition = false; } currentScope() { return this.scopeManager.__currentScope; } close(node) { while (this.currentScope() && node === this.currentScope().block) { this.scopeManager.__currentScope = this.currentScope().__close(this.scopeManager); } } pushInnerMethodDefinition(isInnerMethodDefinition) { const previous = this.isInnerMethodDefinition; this.isInnerMethodDefinition = isInnerMethodDefinition; return previous; } popInnerMethodDefinition(isInnerMethodDefinition) { this.isInnerMethodDefinition = isInnerMethodDefinition; } referencingDefaultValue(pattern, assignments, maybeImplicitGlobal, init) { const scope = this.currentScope(); assignments.forEach(assignment => { scope.__referencing( pattern, Reference.WRITE, assignment.right, maybeImplicitGlobal, pattern !== assignment.left, init ); }); } visitPattern(node, options, callback) { let visitPatternOptions = options; let visitPatternCallback = callback; if (typeof options === "function") { visitPatternCallback = options; visitPatternOptions = { processRightHandNodes: false }; } traverseIdentifierInPattern( this.options, node, visitPatternOptions.processRightHandNodes ? this : null, visitPatternCallback ); } visitFunction(node) { let i, iz; // FunctionDeclaration name is defined in upper scope // NOTE: Not referring variableScope. It is intended. // Since // in ES5, FunctionDeclaration should be in FunctionBody. // in ES6, FunctionDeclaration should be block scoped. if (node.type === Syntax.FunctionDeclaration) { // id is defined in upper scope this.currentScope().__define(node.id, new Definition( Variable.FunctionName, node.id, node, null, null, null )); } // FunctionExpression with name creates its special scope; // FunctionExpressionNameScope. if (node.type === Syntax.FunctionExpression && node.id) { this.scopeManager.__nestFunctionExpressionNameScope(node); } // Consider this function is in the MethodDefinition. this.scopeManager.__nestFunctionScope(node, this.isInnerMethodDefinition); const that = this; /** * Visit pattern callback * @param {pattern} pattern - pattern * @param {Object} info - info * @returns {void} */ function visitPatternCallback(pattern, info) { that.currentScope().__define(pattern, new ParameterDefinition( pattern, node, i, info.rest )); that.referencingDefaultValue(pattern, info.assignments, null, true); } // Process parameter declarations. for (i = 0, iz = node.params.length; i < iz; ++i) { this.visitPattern(node.params[i], { processRightHandNodes: true }, visitPatternCallback); } // if there's a rest argument, add that if (node.rest) { this.visitPattern({ type: "RestElement", argument: node.rest }, pattern => { this.currentScope().__define(pattern, new ParameterDefinition( pattern, node, node.params.length, true )); }); } // In TypeScript there are a number of function-like constructs which have no body, // so check it exists before traversing if (node.body) { // Skip BlockStatement to prevent creating BlockStatement scope. if (node.body.type === Syntax.BlockStatement) { this.visitChildren(node.body); } else { this.visit(node.body); } } this.close(node); } visitClass(node) { if (node.type === Syntax.ClassDeclaration) { this.currentScope().__define(node.id, new Definition( Variable.ClassName, node.id, node, null, null, null )); } this.visit(node.superClass); this.scopeManager.__nestClassScope(node); if (node.id) { this.currentScope().__define(node.id, new Definition( Variable.ClassName, node.id, node )); } this.visit(node.body); this.close(node); } visitProperty(node) { let previous; if (node.computed) { this.visit(node.key); } const isMethodDefinition = node.type === Syntax.MethodDefinition; if (isMethodDefinition) { previous = this.pushInnerMethodDefinition(true); } this.visit(node.value); if (isMethodDefinition) { this.popInnerMethodDefinition(previous); } } visitForIn(node) { if (node.left.type === Syntax.VariableDeclaration && node.left.kind !== "var") { this.scopeManager.__nestForScope(node); } if (node.left.type === Syntax.VariableDeclaration) { this.visit(node.left); this.visitPattern(node.left.declarations[0].id, pattern => { this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true); }); } else { this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => { let maybeImplicitGlobal = null; if (!this.currentScope().isStrict) { maybeImplicitGlobal = { pattern, node }; } this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false); this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, true, false); }); } this.visit(node.right); this.visit(node.body); this.close(node); } visitVariableDeclaration(variableTargetScope, type, node, index) { const decl = node.declarations[index]; const init = decl.init; this.visitPattern(decl.id, { processRightHandNodes: true }, (pattern, info) => { variableTargetScope.__define( pattern, new Definition( type, pattern, decl, node, index, node.kind ) ); this.referencingDefaultValue(pattern, info.assignments, null, true); if (init) { this.currentScope().__referencing(pattern, Reference.WRITE, init, null, !info.topLevel, true); } }); } AssignmentExpression(node) { if (PatternVisitor.isPattern(node.left)) { if (node.operator === "=") { this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => { let maybeImplicitGlobal = null; if (!this.currentScope().isStrict) { maybeImplicitGlobal = { pattern, node }; } this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false); this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, !info.topLevel, false); }); } else { this.currentScope().__referencing(node.left, Reference.RW, node.right); } } else { this.visit(node.left); } this.visit(node.right); } CatchClause(node) { this.scopeManager.__nestCatchScope(node); this.visitPattern(node.param, { processRightHandNodes: true }, (pattern, info) => { this.currentScope().__define(pattern, new Definition( Variable.CatchClause, node.param, node, null, null, null )); this.referencingDefaultValue(pattern, info.assignments, null, true); }); this.visit(node.body); this.close(node); } Program(node) { this.scopeManager.__nestGlobalScope(node); if (this.scopeManager.__isNodejsScope()) { // Force strictness of GlobalScope to false when using node.js scope. this.currentScope().isStrict = false; this.scopeManager.__nestFunctionScope(node, false); } if (this.scopeManager.__isES6() && this.scopeManager.isModule()) { this.scopeManager.__nestModuleScope(node); } if (this.scopeManager.isStrictModeSupported() && this.scopeManager.isImpliedStrict()) { this.currentScope().isStrict = true; } this.visitChildren(node); this.close(node); } Identifier(node) { this.currentScope().__referencing(node); } UpdateExpression(node) { if (PatternVisitor.isPattern(node.argument)) { this.currentScope().__referencing(node.argument, Reference.RW, null); } else { this.visitChildren(node); } } MemberExpression(node) { this.visit(node.object); if (node.computed) { this.visit(node.property); } } Property(node) { this.visitProperty(node); } MethodDefinition(node) { this.visitProperty(node); } BreakStatement() {} // eslint-disable-line class-methods-use-this ContinueStatement() {} // eslint-disable-line class-methods-use-this LabeledStatement(node) { this.visit(node.body); } ForStatement(node) { // Create ForStatement declaration. // NOTE: In ES6, ForStatement dynamically generates // per iteration environment. However, escope is // a static analyzer, we only generate one scope for ForStatement. if (node.init && node.init.type === Syntax.VariableDeclaration && node.init.kind !== "var") { this.scopeManager.__nestForScope(node); } this.visitChildren(node); this.close(node); } ClassExpression(node) { this.visitClass(node); } ClassDeclaration(node) { this.visitClass(node); } CallExpression(node) { // Check this is direct call to eval if (!this.scopeManager.__ignoreEval() && node.callee.type === Syntax.Identifier && node.callee.name === "eval") { // NOTE: This should be `variableScope`. Since direct eval call always creates Lexical environment and // let / const should be enclosed into it. Only VariableDeclaration affects on the caller's environment. this.currentScope().variableScope.__detectEval(); } this.visitChildren(node); } BlockStatement(node) { if (this.scopeManager.__isES6()) { this.scopeManager.__nestBlockScope(node); } this.visitChildren(node); this.close(node); } ThisExpression() { this.currentScope().variableScope.__detectThis(); } WithStatement(node) { this.visit(node.object); // Then nest scope for WithStatement. this.scopeManager.__nestWithScope(node); this.visit(node.body); this.close(node); } VariableDeclaration(node) { const variableTargetScope = (node.kind === "var") ? this.currentScope().variableScope : this.currentScope(); for (let i = 0, iz = node.declarations.length; i < iz; ++i) { const decl = node.declarations[i]; this.visitVariableDeclaration(variableTargetScope, Variable.Variable, node, i); if (decl.init) { this.visit(decl.init); } } } // sec 13.11.8 SwitchStatement(node) { this.visit(node.discriminant); if (this.scopeManager.__isES6()) { this.scopeManager.__nestSwitchScope(node); } for (let i = 0, iz = node.cases.length; i < iz; ++i) { this.visit(node.cases[i]); } this.close(node); } FunctionDeclaration(node) { this.visitFunction(node); } FunctionExpression(node) { this.visitFunction(node); } ForOfStatement(node) { this.visitForIn(node); } ForInStatement(node) { this.visitForIn(node); } ArrowFunctionExpression(node) { this.visitFunction(node); } ImportDeclaration(node) { assert(this.scopeManager.__isES6() && this.scopeManager.isModule(), "ImportDeclaration should appear when the mode is ES6 and in the module context."); const importer = new Importer(node, this); importer.visit(node); } visitExportDeclaration(node) { if (node.source) { return; } if (node.declaration) { this.visit(node.declaration); return; } this.visitChildren(node); } ExportDeclaration(node) { this.visitExportDeclaration(node); } ExportNamedDeclaration(node) { this.visitExportDeclaration(node); } ExportSpecifier(node) { const local = (node.id || node.local); this.visit(local); } MetaProperty() { // eslint-disable-line class-methods-use-this // do nothing. } } module.exports = Referencer; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/lib/scope-manager.js000066400000000000000000000164431351475502400177640ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; /* eslint-disable no-underscore-dangle */ const Scope = require("./scope"); const assert = require("assert"); const GlobalScope = Scope.GlobalScope; const CatchScope = Scope.CatchScope; const WithScope = Scope.WithScope; const ModuleScope = Scope.ModuleScope; const ClassScope = Scope.ClassScope; const SwitchScope = Scope.SwitchScope; const FunctionScope = Scope.FunctionScope; const ForScope = Scope.ForScope; const FunctionExpressionNameScope = Scope.FunctionExpressionNameScope; const BlockScope = Scope.BlockScope; /** * @class ScopeManager */ class ScopeManager { constructor(options) { this.scopes = []; this.globalScope = null; this.__nodeToScope = new WeakMap(); this.__currentScope = null; this.__options = options; this.__declaredVariables = new WeakMap(); } __useDirective() { return this.__options.directive; } __isOptimistic() { return this.__options.optimistic; } __ignoreEval() { return this.__options.ignoreEval; } __isNodejsScope() { return this.__options.nodejsScope; } isModule() { return this.__options.sourceType === "module"; } isImpliedStrict() { return this.__options.impliedStrict; } isStrictModeSupported() { return this.__options.ecmaVersion >= 5; } // Returns appropriate scope for this node. __get(node) { return this.__nodeToScope.get(node); } /** * Get variables that are declared by the node. * * "are declared by the node" means the node is same as `Variable.defs[].node` or `Variable.defs[].parent`. * If the node declares nothing, this method returns an empty array. * CAUTION: This API is experimental. See https://github.com/estools/escope/pull/69 for more details. * * @param {Espree.Node} node - a node to get. * @returns {Variable[]} variables that declared by the node. */ getDeclaredVariables(node) { return this.__declaredVariables.get(node) || []; } /** * acquire scope from node. * @method ScopeManager#acquire * @param {Espree.Node} node - node for the acquired scope. * @param {boolean=} inner - look up the most inner scope, default value is false. * @returns {Scope?} Scope from node */ acquire(node, inner) { /** * predicate * @param {Scope} testScope - scope to test * @returns {boolean} predicate */ function predicate(testScope) { if (testScope.type === "function" && testScope.functionExpressionScope) { return false; } return true; } const scopes = this.__get(node); if (!scopes || scopes.length === 0) { return null; } // Heuristic selection from all scopes. // If you would like to get all scopes, please use ScopeManager#acquireAll. if (scopes.length === 1) { return scopes[0]; } if (inner) { for (let i = scopes.length - 1; i >= 0; --i) { const scope = scopes[i]; if (predicate(scope)) { return scope; } } } else { for (let i = 0, iz = scopes.length; i < iz; ++i) { const scope = scopes[i]; if (predicate(scope)) { return scope; } } } return null; } /** * acquire all scopes from node. * @method ScopeManager#acquireAll * @param {Espree.Node} node - node for the acquired scope. * @returns {Scopes?} Scope array */ acquireAll(node) { return this.__get(node); } /** * release the node. * @method ScopeManager#release * @param {Espree.Node} node - releasing node. * @param {boolean=} inner - look up the most inner scope, default value is false. * @returns {Scope?} upper scope for the node. */ release(node, inner) { const scopes = this.__get(node); if (scopes && scopes.length) { const scope = scopes[0].upper; if (!scope) { return null; } return this.acquire(scope.block, inner); } return null; } attach() { } // eslint-disable-line class-methods-use-this detach() { } // eslint-disable-line class-methods-use-this __nestScope(scope) { if (scope instanceof GlobalScope) { assert(this.__currentScope === null); this.globalScope = scope; } this.__currentScope = scope; return scope; } __nestGlobalScope(node) { return this.__nestScope(new GlobalScope(this, node)); } __nestBlockScope(node) { return this.__nestScope(new BlockScope(this, this.__currentScope, node)); } __nestFunctionScope(node, isMethodDefinition) { return this.__nestScope(new FunctionScope(this, this.__currentScope, node, isMethodDefinition)); } __nestForScope(node) { return this.__nestScope(new ForScope(this, this.__currentScope, node)); } __nestCatchScope(node) { return this.__nestScope(new CatchScope(this, this.__currentScope, node)); } __nestWithScope(node) { return this.__nestScope(new WithScope(this, this.__currentScope, node)); } __nestClassScope(node) { return this.__nestScope(new ClassScope(this, this.__currentScope, node)); } __nestSwitchScope(node) { return this.__nestScope(new SwitchScope(this, this.__currentScope, node)); } __nestModuleScope(node) { return this.__nestScope(new ModuleScope(this, this.__currentScope, node)); } __nestFunctionExpressionNameScope(node) { return this.__nestScope(new FunctionExpressionNameScope(this, this.__currentScope, node)); } __isES6() { return this.__options.ecmaVersion >= 6; } } module.exports = ScopeManager; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/lib/scope.js000066400000000000000000000522021351475502400163450ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; /* eslint-disable no-underscore-dangle */ /* eslint-disable no-undefined */ const Syntax = require("estraverse").Syntax; const Reference = require("./reference"); const Variable = require("./variable"); const Definition = require("./definition").Definition; const assert = require("assert"); /** * Test if scope is struct * @param {Scope} scope - scope * @param {Block} block - block * @param {boolean} isMethodDefinition - is method definiton * @param {boolean} useDirective - use directive * @returns {boolean} is strict scope */ function isStrictScope(scope, block, isMethodDefinition, useDirective) { let body; // When upper scope is exists and strict, inner scope is also strict. if (scope.upper && scope.upper.isStrict) { return true; } if (isMethodDefinition) { return true; } if (scope.type === "class" || scope.type === "module") { return true; } if (scope.type === "block" || scope.type === "switch") { return false; } if (scope.type === "function") { if (block.type === Syntax.ArrowFunctionExpression && block.body.type !== Syntax.BlockStatement) { return false; } if (block.type === Syntax.Program) { body = block; } else { body = block.body; } if (!body) { return false; } } else if (scope.type === "global") { body = block; } else { return false; } // Search 'use strict' directive. if (useDirective) { for (let i = 0, iz = body.body.length; i < iz; ++i) { const stmt = body.body[i]; if (stmt.type !== Syntax.DirectiveStatement) { break; } if (stmt.raw === "\"use strict\"" || stmt.raw === "'use strict'") { return true; } } } else { for (let i = 0, iz = body.body.length; i < iz; ++i) { const stmt = body.body[i]; if (stmt.type !== Syntax.ExpressionStatement) { break; } const expr = stmt.expression; if (expr.type !== Syntax.Literal || typeof expr.value !== "string") { break; } if (expr.raw !== null && expr.raw !== undefined) { if (expr.raw === "\"use strict\"" || expr.raw === "'use strict'") { return true; } } else { if (expr.value === "use strict") { return true; } } } } return false; } /** * Register scope * @param {ScopeManager} scopeManager - scope manager * @param {Scope} scope - scope * @returns {void} */ function registerScope(scopeManager, scope) { scopeManager.scopes.push(scope); const scopes = scopeManager.__nodeToScope.get(scope.block); if (scopes) { scopes.push(scope); } else { scopeManager.__nodeToScope.set(scope.block, [scope]); } } /** * Should be statically * @param {Object} def - def * @returns {boolean} should be statically */ function shouldBeStatically(def) { return ( (def.type === Variable.ClassName) || (def.type === Variable.Variable && def.parent.kind !== "var") ); } /** * @class Scope */ class Scope { constructor(scopeManager, type, upperScope, block, isMethodDefinition) { /** * One of 'module', 'block', 'switch', 'function', 'catch', 'with', 'function', 'class', 'global'. * @member {String} Scope#type */ this.type = type; /** * The scoped {@link Variable}s of this scope, as { Variable.name * : Variable }. * @member {Map} Scope#set */ this.set = new Map(); /** * The tainted variables of this scope, as { Variable.name : * boolean }. * @member {Map} Scope#taints */ this.taints = new Map(); /** * Generally, through the lexical scoping of JS you can always know * which variable an identifier in the source code refers to. There are * a few exceptions to this rule. With 'global' and 'with' scopes you * can only decide at runtime which variable a reference refers to. * Moreover, if 'eval()' is used in a scope, it might introduce new * bindings in this or its parent scopes. * All those scopes are considered 'dynamic'. * @member {boolean} Scope#dynamic */ this.dynamic = this.type === "global" || this.type === "with"; /** * A reference to the scope-defining syntax node. * @member {espree.Node} Scope#block */ this.block = block; /** * The {@link Reference|references} that are not resolved with this scope. * @member {Reference[]} Scope#through */ this.through = []; /** * The scoped {@link Variable}s of this scope. In the case of a * 'function' scope this includes the automatic argument arguments as * its first element, as well as all further formal arguments. * @member {Variable[]} Scope#variables */ this.variables = []; /** * Any variable {@link Reference|reference} found in this scope. This * includes occurrences of local variables as well as variables from * parent scopes (including the global scope). For local variables * this also includes defining occurrences (like in a 'var' statement). * In a 'function' scope this does not include the occurrences of the * formal parameter in the parameter list. * @member {Reference[]} Scope#references */ this.references = []; /** * For 'global' and 'function' scopes, this is a self-reference. For * other scope types this is the variableScope value of the * parent scope. * @member {Scope} Scope#variableScope */ this.variableScope = (this.type === "global" || this.type === "function" || this.type === "module") ? this : upperScope.variableScope; /** * Whether this scope is created by a FunctionExpression. * @member {boolean} Scope#functionExpressionScope */ this.functionExpressionScope = false; /** * Whether this is a scope that contains an 'eval()' invocation. * @member {boolean} Scope#directCallToEvalScope */ this.directCallToEvalScope = false; /** * @member {boolean} Scope#thisFound */ this.thisFound = false; this.__left = []; /** * Reference to the parent {@link Scope|scope}. * @member {Scope} Scope#upper */ this.upper = upperScope; /** * Whether 'use strict' is in effect in this scope. * @member {boolean} Scope#isStrict */ this.isStrict = isStrictScope(this, block, isMethodDefinition, scopeManager.__useDirective()); /** * List of nested {@link Scope}s. * @member {Scope[]} Scope#childScopes */ this.childScopes = []; if (this.upper) { this.upper.childScopes.push(this); } this.__declaredVariables = scopeManager.__declaredVariables; registerScope(scopeManager, this); } __shouldStaticallyClose(scopeManager) { return (!this.dynamic || scopeManager.__isOptimistic()); } __shouldStaticallyCloseForGlobal(ref) { // On global scope, let/const/class declarations should be resolved statically. const name = ref.identifier.name; if (!this.set.has(name)) { return false; } const variable = this.set.get(name); const defs = variable.defs; return defs.length > 0 && defs.every(shouldBeStatically); } __staticCloseRef(ref) { if (!this.__resolve(ref)) { this.__delegateToUpperScope(ref); } } __dynamicCloseRef(ref) { // notify all names are through to global let current = this; do { current.through.push(ref); current = current.upper; } while (current); } __globalCloseRef(ref) { // let/const/class declarations should be resolved statically. // others should be resolved dynamically. if (this.__shouldStaticallyCloseForGlobal(ref)) { this.__staticCloseRef(ref); } else { this.__dynamicCloseRef(ref); } } __close(scopeManager) { let closeRef; if (this.__shouldStaticallyClose(scopeManager)) { closeRef = this.__staticCloseRef; } else if (this.type !== "global") { closeRef = this.__dynamicCloseRef; } else { closeRef = this.__globalCloseRef; } // Try Resolving all references in this scope. for (let i = 0, iz = this.__left.length; i < iz; ++i) { const ref = this.__left[i]; closeRef.call(this, ref); } this.__left = null; return this.upper; } // To override by function scopes. // References in default parameters isn't resolved to variables which are in their function body. __isValidResolution(ref, variable) { // eslint-disable-line class-methods-use-this, no-unused-vars return true; } __resolve(ref) { const name = ref.identifier.name; if (!this.set.has(name)) { return false; } const variable = this.set.get(name); if (!this.__isValidResolution(ref, variable)) { return false; } variable.references.push(ref); variable.stack = variable.stack && ref.from.variableScope === this.variableScope; if (ref.tainted) { variable.tainted = true; this.taints.set(variable.name, true); } ref.resolved = variable; return true; } __delegateToUpperScope(ref) { if (this.upper) { this.upper.__left.push(ref); } this.through.push(ref); } __addDeclaredVariablesOfNode(variable, node) { if (node === null || node === undefined) { return; } let variables = this.__declaredVariables.get(node); if (variables === null || variables === undefined) { variables = []; this.__declaredVariables.set(node, variables); } if (variables.indexOf(variable) === -1) { variables.push(variable); } } __defineGeneric(name, set, variables, node, def) { let variable; variable = set.get(name); if (!variable) { variable = new Variable(name, this); set.set(name, variable); variables.push(variable); } if (def) { variable.defs.push(def); this.__addDeclaredVariablesOfNode(variable, def.node); this.__addDeclaredVariablesOfNode(variable, def.parent); } if (node) { variable.identifiers.push(node); } } __define(node, def) { if (node && node.type === Syntax.Identifier) { this.__defineGeneric( node.name, this.set, this.variables, node, def ); } } __referencing(node, assign, writeExpr, maybeImplicitGlobal, partial, init) { // because Array element may be null if (!node || node.type !== Syntax.Identifier) { return; } // Specially handle like `this`. if (node.name === "super") { return; } const ref = new Reference(node, this, assign || Reference.READ, writeExpr, maybeImplicitGlobal, !!partial, !!init); this.references.push(ref); this.__left.push(ref); } __detectEval() { let current = this; this.directCallToEvalScope = true; do { current.dynamic = true; current = current.upper; } while (current); } __detectThis() { this.thisFound = true; } __isClosed() { return this.__left === null; } /** * returns resolved {Reference} * @method Scope#resolve * @param {Espree.Identifier} ident - identifier to be resolved. * @returns {Reference} reference */ resolve(ident) { let ref, i, iz; assert(this.__isClosed(), "Scope should be closed."); assert(ident.type === Syntax.Identifier, "Target should be identifier."); for (i = 0, iz = this.references.length; i < iz; ++i) { ref = this.references[i]; if (ref.identifier === ident) { return ref; } } return null; } /** * returns this scope is static * @method Scope#isStatic * @returns {boolean} static */ isStatic() { return !this.dynamic; } /** * returns this scope has materialized arguments * @method Scope#isArgumentsMaterialized * @returns {boolean} arguemnts materialized */ isArgumentsMaterialized() { // eslint-disable-line class-methods-use-this return true; } /** * returns this scope has materialized `this` reference * @method Scope#isThisMaterialized * @returns {boolean} this materialized */ isThisMaterialized() { // eslint-disable-line class-methods-use-this return true; } isUsedName(name) { if (this.set.has(name)) { return true; } for (let i = 0, iz = this.through.length; i < iz; ++i) { if (this.through[i].identifier.name === name) { return true; } } return false; } } class GlobalScope extends Scope { constructor(scopeManager, block) { super(scopeManager, "global", null, block, false); this.implicit = { set: new Map(), variables: [], /** * List of {@link Reference}s that are left to be resolved (i.e. which * need to be linked to the variable they refer to). * @member {Reference[]} Scope#implicit#left */ left: [] }; } __close(scopeManager) { const implicit = []; for (let i = 0, iz = this.__left.length; i < iz; ++i) { const ref = this.__left[i]; if (ref.__maybeImplicitGlobal && !this.set.has(ref.identifier.name)) { implicit.push(ref.__maybeImplicitGlobal); } } // create an implicit global variable from assignment expression for (let i = 0, iz = implicit.length; i < iz; ++i) { const info = implicit[i]; this.__defineImplicit(info.pattern, new Definition( Variable.ImplicitGlobalVariable, info.pattern, info.node, null, null, null )); } this.implicit.left = this.__left; return super.__close(scopeManager); } __defineImplicit(node, def) { if (node && node.type === Syntax.Identifier) { this.__defineGeneric( node.name, this.implicit.set, this.implicit.variables, node, def ); } } } class ModuleScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "module", upperScope, block, false); } } class FunctionExpressionNameScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "function-expression-name", upperScope, block, false); this.__define(block.id, new Definition( Variable.FunctionName, block.id, block, null, null, null )); this.functionExpressionScope = true; } } class CatchScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "catch", upperScope, block, false); } } class WithScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "with", upperScope, block, false); } __close(scopeManager) { if (this.__shouldStaticallyClose(scopeManager)) { return super.__close(scopeManager); } for (let i = 0, iz = this.__left.length; i < iz; ++i) { const ref = this.__left[i]; ref.tainted = true; this.__delegateToUpperScope(ref); } this.__left = null; return this.upper; } } class BlockScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "block", upperScope, block, false); } } class SwitchScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "switch", upperScope, block, false); } } class FunctionScope extends Scope { constructor(scopeManager, upperScope, block, isMethodDefinition) { super(scopeManager, "function", upperScope, block, isMethodDefinition); // section 9.2.13, FunctionDeclarationInstantiation. // NOTE Arrow functions never have an arguments objects. if (this.block.type !== Syntax.ArrowFunctionExpression) { this.__defineArguments(); } } isArgumentsMaterialized() { // TODO(Constellation) // We can more aggressive on this condition like this. // // function t() { // // arguments of t is always hidden. // function arguments() { // } // } if (this.block.type === Syntax.ArrowFunctionExpression) { return false; } if (!this.isStatic()) { return true; } const variable = this.set.get("arguments"); assert(variable, "Always have arguments variable."); return variable.tainted || variable.references.length !== 0; } isThisMaterialized() { if (!this.isStatic()) { return true; } return this.thisFound; } __defineArguments() { this.__defineGeneric( "arguments", this.set, this.variables, null, null ); this.taints.set("arguments", true); } // References in default parameters isn't resolved to variables which are in their function body. // const x = 1 // function f(a = x) { // This `x` is resolved to the `x` in the outer scope. // const x = 2 // console.log(a) // } __isValidResolution(ref, variable) { // If `options.nodejsScope` is true, `this.block` becomes a Program node. if (this.block.type === "Program") { return true; } const bodyStart = this.block.body.range[0]; // It's invalid resolution in the following case: return !( variable.scope === this && ref.identifier.range[0] < bodyStart && // the reference is in the parameter part. variable.defs.every(d => d.name.range[0] >= bodyStart) // the variable is in the body. ); } } class ForScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "for", upperScope, block, false); } } class ClassScope extends Scope { constructor(scopeManager, upperScope, block) { super(scopeManager, "class", upperScope, block, false); } } module.exports = { Scope, GlobalScope, ModuleScope, FunctionExpressionNameScope, CatchScope, WithScope, BlockScope, SwitchScope, FunctionScope, ForScope, ClassScope }; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/lib/variable.js000066400000000000000000000061051351475502400170220ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; /** * A Variable represents a locally scoped identifier. These include arguments to * functions. * @class Variable */ class Variable { constructor(name, scope) { /** * The variable name, as given in the source code. * @member {String} Variable#name */ this.name = name; /** * List of defining occurrences of this variable (like in 'var ...' * statements or as parameter), as AST nodes. * @member {espree.Identifier[]} Variable#identifiers */ this.identifiers = []; /** * List of {@link Reference|references} of this variable (excluding parameter entries) * in its defining scope and all nested scopes. For defining * occurrences only see {@link Variable#defs}. * @member {Reference[]} Variable#references */ this.references = []; /** * List of defining occurrences of this variable (like in 'var ...' * statements or as parameter), as custom objects. * @member {Definition[]} Variable#defs */ this.defs = []; this.tainted = false; /** * Whether this is a stack variable. * @member {boolean} Variable#stack */ this.stack = true; /** * Reference to the enclosing Scope. * @member {Scope} Variable#scope */ this.scope = scope; } } Variable.CatchClause = "CatchClause"; Variable.Parameter = "Parameter"; Variable.FunctionName = "FunctionName"; Variable.ClassName = "ClassName"; Variable.Variable = "Variable"; Variable.ImportBinding = "ImportBinding"; Variable.ImplicitGlobalVariable = "ImplicitGlobalVariable"; module.exports = Variable; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/package.json000066400000000000000000000023701351475502400164170ustar00rootroot00000000000000{ "name": "eslint-scope", "description": "ECMAScript scope analyzer for ESLint", "homepage": "http://github.com/eslint/eslint-scope", "main": "lib/index.js", "version": "5.0.0", "engines": { "node": ">=8.0.0" }, "repository": "eslint/eslint-scope", "bugs": { "url": "https://github.com/eslint/eslint-scope/issues" }, "license": "BSD-2-Clause", "scripts": { "test": "node Makefile.js test", "lint": "node Makefile.js lint", "generate-release": "eslint-generate-release", "generate-alpharelease": "eslint-generate-prerelease alpha", "generate-betarelease": "eslint-generate-prerelease beta", "generate-rcrelease": "eslint-generate-prerelease rc", "publish-release": "eslint-publish-release" }, "files": [ "LICENSE", "README.md", "lib" ], "dependencies": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" }, "devDependencies": { "@typescript-eslint/parser": "^1.11.0", "chai": "^4.2.0", "eslint": "^6.0.1", "eslint-config-eslint": "^5.0.1", "eslint-plugin-node": "^9.1.0", "eslint-release": "^1.0.0", "espree": "^6.0.0", "istanbul": "^0.4.5", "mocha": "^6.1.4", "npm-license": "^0.3.3", "shelljs": "^0.8.3", "typescript": "^3.5.2" } } eslint-scope-5.0.0/tests/000077500000000000000000000000001351475502400152715ustar00rootroot00000000000000eslint-scope-5.0.0/tests/arguments.js000066400000000000000000000047621351475502400176450ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("arguments", () => { it("arguments are correctly materialized", () => { const ast = espree(` (function () { arguments; }()); `); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.isArgumentsMaterialized()).to.be.true; expect(scope.references).to.have.length(1); expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/catch-scope.js000066400000000000000000000053521351475502400200250ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("catch", () => { it("creates scope", () => { const ast = espree(` (function () { try { } catch (e) { } }()); `); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(3); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); let scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.isArgumentsMaterialized()).to.be.false; expect(scope.references).to.have.length(0); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("catch"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("e"); expect(scope.isArgumentsMaterialized()).to.be.true; expect(scope.references).to.have.length(0); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/child-visitor-keys.js000066400000000000000000000066101351475502400213630ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2016 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("childVisitorKeys option", () => { it("should handle as a known node if the childVisitorKeys option was given.", () => { const ast = espree(` var foo = 0; `); ast.body[0].declarations[0].init.type = "NumericLiteral"; // should no error analyze( ast, { fallback: "none", childVisitorKeys: { NumericLiteral: [] } } ); }); it("should not visit to properties which are not given.", () => { const ast = espree(` let foo = bar; `); ast.body[0].declarations[0].init = { type: "TestNode", argument: ast.body[0].declarations[0].init }; const result = analyze( ast, { childVisitorKeys: { TestNode: [] } } ); expect(result.scopes).to.have.length(1); const globalScope = result.scopes[0]; // `bar` in TestNode has not been visited. expect(globalScope.through).to.have.length(0); }); it("should visit to given properties.", () => { const ast = espree(` let foo = bar; `); ast.body[0].declarations[0].init = { type: "TestNode", argument: ast.body[0].declarations[0].init }; const result = analyze( ast, { childVisitorKeys: { TestNode: ["argument"] } } ); expect(result.scopes).to.have.length(1); const globalScope = result.scopes[0]; // `bar` in TestNode has been visited. expect(globalScope.through).to.have.length(1); expect(globalScope.through[0].identifier.name).to.equal("bar"); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-arrow-function-expression.js000066400000000000000000000132461351475502400235020ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 arrow function expression", () => { it("materialize scope for arrow function expression", () => { const ast = espree(` var arrow = () => { let i = 0; var j = 20; console.log(i); } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("ArrowFunctionExpression"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(2); // There's no "arguments" expect(scope.variables[0].name).to.be.equal("i"); expect(scope.variables[1].name).to.be.equal("j"); }); it("generate bindings for parameters", () => { const ast = espree("var arrow = (a, b, c, d) => {}"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("ArrowFunctionExpression"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(4); // There's no "arguments" expect(scope.variables[0].name).to.be.equal("a"); expect(scope.variables[1].name).to.be.equal("b"); expect(scope.variables[2].name).to.be.equal("c"); expect(scope.variables[3].name).to.be.equal("d"); }); it("inherits upper scope strictness", () => { const ast = espree(` "use strict"; var arrow = () => {}; `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("ArrowFunctionExpression"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(0); }); it("is strict when a strictness directive is used", () => { const ast = espree(` var arrow = () => { "use strict"; }; `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("ArrowFunctionExpression"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(0); }); it("works with no body", () => { const ast = espree("var arrow = a => a;"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("ArrowFunctionExpression"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-block-scope.js000066400000000000000000000160361351475502400205310ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 block scope", () => { it("let is materialized in ES6 block scope#1", () => { const ast = espree(` { let i = 20; i; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // Program and BlockStatement scope. let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); // No variable in Program scope. scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(1); // `i` in block scope. expect(scope.variables[0].name).to.be.equal("i"); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("i"); expect(scope.references[1].identifier.name).to.be.equal("i"); }); it("function delaration is materialized in ES6 block scope", () => { const ast = espree(` { function test() { } test(); } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("test"); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("test"); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); }); it("let is not hoistable#1", () => { const ast = espree(` var i = 42; (1) { i; // (2) ReferenceError at runtime. let i = 20; // (2) i; // (2) } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(1); expect(globalScope.variables[0].name).to.be.equal("i"); expect(globalScope.references).to.have.length(1); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("i"); expect(scope.references).to.have.length(3); expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); expect(scope.references[1].resolved).to.be.equal(scope.variables[0]); expect(scope.references[2].resolved).to.be.equal(scope.variables[0]); }); it("let is not hoistable#2", () => { const ast = espree(` (function () { var i = 42; // (1) i; // (1) { i; // (3) { i; // (2) let i = 20; // (2) i; // (2) } let i = 30; // (3) i; // (3) } i; // (1) }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(4); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); let scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("i"); const v1 = scope.variables[1]; expect(scope.references).to.have.length(3); expect(scope.references[0].resolved).to.be.equal(v1); expect(scope.references[1].resolved).to.be.equal(v1); expect(scope.references[2].resolved).to.be.equal(v1); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("i"); const v3 = scope.variables[0]; expect(scope.references).to.have.length(3); expect(scope.references[0].resolved).to.be.equal(v3); expect(scope.references[1].resolved).to.be.equal(v3); expect(scope.references[2].resolved).to.be.equal(v3); scope = scopeManager.scopes[3]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("i"); const v2 = scope.variables[0]; expect(scope.references).to.have.length(3); expect(scope.references[0].resolved).to.be.equal(v2); expect(scope.references[1].resolved).to.be.equal(v2); expect(scope.references[2].resolved).to.be.equal(v2); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-catch.js000066400000000000000000000071401351475502400174060ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 catch", () => { it("takes binding pattern", () => { const ast = espree(` try { } catch ({ a, b, c, d }) { let e = 20; a; b; c; d; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(4); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("block"); expect(scope.block.type).to.be.equal("BlockStatement"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("catch"); expect(scope.block.type).to.be.equal("CatchClause"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.be.equal("a"); expect(scope.variables[1].name).to.be.equal("b"); expect(scope.variables[2].name).to.be.equal("c"); expect(scope.variables[3].name).to.be.equal("d"); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[3]; expect(scope.type).to.be.equal("block"); expect(scope.block.type).to.be.equal("BlockStatement"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); expect(scope.variables.map(variable => variable.name)).to.be.eql([ "e" ]); expect(scope.references.map(ref => ref.identifier.name)).to.be.eql([ "e", "a", "b", "c", "d" ]); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-class.js000066400000000000000000000176171351475502400174430ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 class", () => { it("declaration name creates class scope", () => { const ast = espree(` class Derived extends Base { constructor() { } } new Derived(); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("Derived"); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("Base"); expect(scope.references[1].identifier.name).to.be.equal("Derived"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("class"); expect(scope.block.type).to.be.equal("ClassDeclaration"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("Derived"); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); }); it("expression name creates class scope#1", () => { const ast = espree(` (class Derived extends Base { constructor() { } }); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("Base"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("class"); expect(scope.block.type).to.be.equal("ClassExpression"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("Derived"); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); }); it("expression name creates class scope#2", () => { const ast = espree(` (class extends Base { constructor() { } }); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("Base"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("class"); expect(scope.block.type).to.be.equal("ClassExpression"); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); }); it("computed property key may refer variables", () => { const ast = espree(` (function () { var yuyushiki = 42; (class { [yuyushiki]() { } [yuyushiki + 40]() { } }); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(5); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("yuyushiki"); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("yuyushiki"); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("class"); expect(scope.block.type).to.be.equal("ClassExpression"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("yuyushiki"); expect(scope.references[1].identifier.name).to.be.equal("yuyushiki"); }); it("regression #49", () => { const ast = espree(` class Shoe { constructor() { //Shoe.x = true; } } let shoe = new Shoe(); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); const scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("Shoe"); expect(scope.variables[1].name).to.be.equal("shoe"); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("shoe"); expect(scope.references[1].identifier.name).to.be.equal("Shoe"); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-default-parameters.js000066400000000000000000000333151351475502400221140ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Toru Nagashima // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ /* eslint-disable guard-for-in */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 default parameters:", () => { describe("a default parameter creates a writable reference for its initialization:", () => { const patterns = { FunctionDeclaration: "function foo(a, b = 0) {}", FunctionExpression: "let foo = function(a, b = 0) {};", ArrowExpression: "let foo = (a, b = 0) => {};" }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const numVars = name === "ArrowExpression" ? 2 : 3; const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(numVars); // [arguments?, a, b] expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("b"); expect(reference.resolved).to.equal(scope.variables[numVars - 1]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); } }); describe("a default parameter creates a readable reference for references in right:", () => { const patterns = { FunctionDeclaration: ` let a; function foo(b = a) {} `, FunctionExpression: ` let a; let foo = function(b = a) {} `, ArrowExpression: ` let a; let foo = (b = a) => {}; ` }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const numVars = name === "ArrowExpression" ? 1 : 2; const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(numVars); // [arguments?, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); } }); describe("a default parameter creates a readable reference for references in right (for const):", () => { const patterns = { FunctionDeclaration: ` const a = 0; function foo(b = a) {} `, FunctionExpression: ` const a = 0; let foo = function(b = a) {} `, ArrowExpression: ` const a = 0; let foo = (b = a) => {}; ` }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const numVars = name === "ArrowExpression" ? 1 : 2; const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(numVars); // [arguments?, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); } }); describe("a default parameter creates a readable reference for references in right (partial):", () => { const patterns = { FunctionDeclaration: ` let a; function foo(b = a.c) {} `, FunctionExpression: ` let a; let foo = function(b = a.c) {} `, ArrowExpression: ` let a; let foo = (b = a.c) => {}; ` }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const numVars = name === "ArrowExpression" ? 1 : 2; const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(numVars); // [arguments?, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); } }); describe("a default parameter creates a readable reference for references in right's nested scope:", () => { const patterns = { FunctionDeclaration: ` let a; function foo(b = function() { return a; }) {} `, FunctionExpression: ` let a; let foo = function(b = function() { return a; }) {} `, ArrowExpression: ` let a; let foo = (b = function() { return a; }) => {}; ` }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, foo, anonymous] const scope = scopeManager.scopes[2]; expect(scope.variables).to.have.length(1); // [arguments] expect(scope.references).to.have.length(1); // [a] const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); } }); describe("a default parameter creates a readable reference for references in right. It's resolved to outer scope's even if there is the variable in the function body:", () => { const patterns = { FunctionDeclaration: ` let a; function foo(b = a) { let a; } `, FunctionExpression: ` let a; let foo = function(b = a) { let a; } `, ArrowExpression: ` let a; let foo = (b = a) => { let a; }; ` }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const numVars = name === "ArrowExpression" ? 2 : 3; const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(numVars); // [arguments?, b, a] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); } }); describe("a default parameter creates a readable reference for references in right. It's resolved to the parameter:", () => { const patterns = { FunctionDeclaration: ` let a; function foo(b = a, a) { } `, FunctionExpression: ` let a; let foo = function(b = a, a) { } `, ArrowExpression: ` let a; let foo = (b = a, a) => { }; ` }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const numVars = name === "ArrowExpression" ? 2 : 3; const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(numVars); // [arguments?, b, a] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[scope.variables.length - 1]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); } }); describe("a default parameter creates a readable reference for references in right (nested scope). It's resolved to outer scope's even if there is the variable in the function body:", () => { const patterns = { FunctionDeclaration: ` let a; function foo(b = function(){ a }) { let a; } `, FunctionExpression: ` let a; let foo = function(b = function(){ a }) { let a; } `, ArrowExpression: ` let a; let foo = (b = function(){ a }) => { let a; }; ` }; for (const name in patterns) { const code = patterns[name]; it(name, () => { const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, foo, anonymous function] const scope = scopeManager.scopes[2]; expect(scope.references).to.have.length(1); // [a] const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); } }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-destructuring-assignments.js000066400000000000000000001547241351475502400235720ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 destructuring assignments", () => { it("Pattern in var in ForInStatement", () => { const ast = espree(` (function () { for (var [a, b, c] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("a"); expect(scope.variables[2].name).to.be.equal("b"); expect(scope.variables[3].name).to.be.equal("c"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.be.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.be.equal(scope.variables[2]); expect(scope.references[2].identifier.name).to.be.equal("c"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.be.equal(scope.variables[3]); expect(scope.references[3].identifier.name).to.be.equal("array"); expect(scope.references[3].isWrite()).to.be.false; }); it("Pattern in let in ForInStatement", () => { const ast = espree(` (function () { for (let [a, b, c] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, function, for] let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.equal("array"); scope = scopeManager.scopes[2]; expect(scope.type).to.equal("for"); expect(scope.variables).to.have.length(3); expect(scope.variables[0].name).to.equal("a"); expect(scope.variables[1].name).to.equal("b"); expect(scope.variables[2].name).to.equal("c"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.equal(scope.variables[0]); expect(scope.references[1].identifier.name).to.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.equal(scope.variables[1]); expect(scope.references[2].identifier.name).to.equal("c"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.equal(scope.variables[2]); expect(scope.references[3].identifier.name).to.equal("array"); expect(scope.references[3].isWrite()).to.be.false; expect(scope.references[3].resolved).to.be.null; }); it("Pattern with default values in var in ForInStatement", () => { const ast = espree(` (function () { for (var [a, b, c = d] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(2); expect(scope.implicit.left[0].identifier.name).to.equal("d"); expect(scope.implicit.left[1].identifier.name).to.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.equal("arguments"); expect(scope.variables[1].name).to.equal("a"); expect(scope.variables[2].name).to.equal("b"); expect(scope.variables[3].name).to.equal("c"); expect(scope.references).to.have.length(6); expect(scope.references[0].identifier.name).to.equal("c"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].writeExpr.name).to.equal("d"); expect(scope.references[0].partial).to.be.false; expect(scope.references[0].resolved).to.equal(scope.variables[3]); expect(scope.references[1].identifier.name).to.equal("d"); expect(scope.references[1].isWrite()).to.be.false; expect(scope.references[2].identifier.name).to.equal("a"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.equal(scope.variables[1]); expect(scope.references[3].identifier.name).to.equal("b"); expect(scope.references[3].isWrite()).to.be.true; expect(scope.references[3].partial).to.be.true; expect(scope.references[3].resolved).to.equal(scope.variables[2]); expect(scope.references[4].identifier.name).to.equal("c"); expect(scope.references[4].isWrite()).to.be.true; expect(scope.references[4].writeExpr.name).to.equal("array"); expect(scope.references[4].partial).to.be.true; expect(scope.references[4].resolved).to.equal(scope.variables[3]); expect(scope.references[5].identifier.name).to.equal("array"); expect(scope.references[5].isWrite()).to.be.false; }); it("Pattern with default values in let in ForInStatement", () => { const ast = espree(` (function () { for (let [a, b, c = d] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, function, for] let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(2); expect(scope.implicit.left[0].identifier.name).to.equal("d"); expect(scope.implicit.left[0].from.type).to.equal("for"); expect(scope.implicit.left[1].identifier.name).to.equal("array"); expect(scope.implicit.left[1].from.type).to.equal("for"); scope = scopeManager.scopes[2]; expect(scope.type).to.equal("for"); expect(scope.variables).to.have.length(3); expect(scope.variables[0].name).to.equal("a"); expect(scope.variables[1].name).to.equal("b"); expect(scope.variables[2].name).to.equal("c"); expect(scope.references).to.have.length(6); expect(scope.references[0].identifier.name).to.equal("c"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].writeExpr.name).to.equal("d"); expect(scope.references[0].partial).to.be.false; expect(scope.references[0].resolved).to.equal(scope.variables[2]); expect(scope.references[1].identifier.name).to.equal("d"); expect(scope.references[1].isWrite()).to.be.false; expect(scope.references[2].identifier.name).to.equal("a"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].writeExpr.name).to.equal("array"); expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.equal(scope.variables[0]); expect(scope.references[3].identifier.name).to.equal("b"); expect(scope.references[3].isWrite()).to.be.true; expect(scope.references[3].writeExpr.name).to.equal("array"); expect(scope.references[3].partial).to.be.true; expect(scope.references[3].resolved).to.equal(scope.variables[1]); expect(scope.references[4].identifier.name).to.equal("c"); expect(scope.references[4].isWrite()).to.be.true; expect(scope.references[4].writeExpr.name).to.equal("array"); expect(scope.references[4].partial).to.be.true; expect(scope.references[4].resolved).to.equal(scope.variables[2]); expect(scope.references[5].identifier.name).to.equal("array"); expect(scope.references[5].isWrite()).to.be.false; expect(scope.references[5].resolved).to.be.null; }); it("Pattern with nested default values in var in ForInStatement", () => { const ast = espree(` (function () { for (var [a, [b, c = d] = e] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(3); expect(scope.implicit.left[0].identifier.name).to.equal("d"); expect(scope.implicit.left[1].identifier.name).to.equal("e"); expect(scope.implicit.left[2].identifier.name).to.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.equal("arguments"); expect(scope.variables[1].name).to.equal("a"); expect(scope.variables[2].name).to.equal("b"); expect(scope.variables[3].name).to.equal("c"); expect(scope.references).to.have.length(9); expect(scope.references[0].identifier.name).to.equal("b"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].writeExpr.name).to.equal("e"); expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.equal(scope.variables[2]); expect(scope.references[1].identifier.name).to.equal("c"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].writeExpr.name).to.equal("e"); expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.equal(scope.variables[3]); expect(scope.references[2].identifier.name).to.equal("c"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].writeExpr.name).to.equal("d"); expect(scope.references[2].partial).to.be.false; expect(scope.references[2].resolved).to.equal(scope.variables[3]); expect(scope.references[3].identifier.name).to.equal("d"); expect(scope.references[3].isWrite()).to.be.false; expect(scope.references[4].identifier.name).to.equal("e"); expect(scope.references[4].isWrite()).to.be.false; expect(scope.references[5].identifier.name).to.equal("a"); expect(scope.references[5].isWrite()).to.be.true; expect(scope.references[5].writeExpr.name).to.equal("array"); expect(scope.references[5].partial).to.be.true; expect(scope.references[5].resolved).to.equal(scope.variables[1]); expect(scope.references[6].identifier.name).to.equal("b"); expect(scope.references[6].isWrite()).to.be.true; expect(scope.references[6].writeExpr.name).to.equal("array"); expect(scope.references[6].partial).to.be.true; expect(scope.references[6].resolved).to.equal(scope.variables[2]); expect(scope.references[7].identifier.name).to.equal("c"); expect(scope.references[7].isWrite()).to.be.true; expect(scope.references[7].writeExpr.name).to.equal("array"); expect(scope.references[7].partial).to.be.true; expect(scope.references[7].resolved).to.equal(scope.variables[3]); expect(scope.references[8].identifier.name).to.equal("array"); expect(scope.references[8].isWrite()).to.be.false; }); it("Pattern with nested default values in let in ForInStatement", () => { const ast = espree(` (function () { for (let [a, [b, c = d] = e] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, function, for] let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(3); expect(scope.implicit.left[0].identifier.name).to.equal("d"); expect(scope.implicit.left[0].from.type).to.equal("for"); expect(scope.implicit.left[1].identifier.name).to.equal("e"); expect(scope.implicit.left[1].from.type).to.equal("for"); expect(scope.implicit.left[2].identifier.name).to.equal("array"); expect(scope.implicit.left[2].from.type).to.equal("for"); scope = scopeManager.scopes[2]; expect(scope.type).to.equal("for"); expect(scope.variables).to.have.length(3); expect(scope.variables[0].name).to.equal("a"); expect(scope.variables[1].name).to.equal("b"); expect(scope.variables[2].name).to.equal("c"); expect(scope.references).to.have.length(9); expect(scope.references[0].identifier.name).to.equal("b"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].writeExpr.name).to.equal("e"); expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.equal("c"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].writeExpr.name).to.equal("e"); expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.equal(scope.variables[2]); expect(scope.references[2].identifier.name).to.equal("c"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].writeExpr.name).to.equal("d"); expect(scope.references[2].partial).to.be.false; expect(scope.references[2].resolved).to.equal(scope.variables[2]); expect(scope.references[3].identifier.name).to.equal("d"); expect(scope.references[3].isWrite()).to.be.false; expect(scope.references[4].identifier.name).to.equal("e"); expect(scope.references[4].isWrite()).to.be.false; expect(scope.references[5].identifier.name).to.equal("a"); expect(scope.references[5].isWrite()).to.be.true; expect(scope.references[5].writeExpr.name).to.equal("array"); expect(scope.references[5].partial).to.be.true; expect(scope.references[5].resolved).to.equal(scope.variables[0]); expect(scope.references[6].identifier.name).to.equal("b"); expect(scope.references[6].isWrite()).to.be.true; expect(scope.references[6].writeExpr.name).to.equal("array"); expect(scope.references[6].partial).to.be.true; expect(scope.references[6].resolved).to.equal(scope.variables[1]); expect(scope.references[7].identifier.name).to.equal("c"); expect(scope.references[7].isWrite()).to.be.true; expect(scope.references[7].writeExpr.name).to.equal("array"); expect(scope.references[7].partial).to.be.true; expect(scope.references[7].resolved).to.equal(scope.variables[2]); expect(scope.references[8].identifier.name).to.equal("array"); expect(scope.references[8].isWrite()).to.be.false; expect(scope.references[8].resolved).to.be.null; }); it("Pattern with default values in var in ForInStatement (separate declarations)", () => { const ast = espree(` (function () { var a, b, c; for ([a, b, c = d] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(2); expect(scope.implicit.left[0].identifier.name).to.equal("d"); expect(scope.implicit.left[1].identifier.name).to.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.equal("arguments"); expect(scope.variables[1].name).to.equal("a"); expect(scope.variables[2].name).to.equal("b"); expect(scope.variables[3].name).to.equal("c"); expect(scope.references).to.have.length(6); expect(scope.references[0].identifier.name).to.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.equal(scope.variables[2]); expect(scope.references[2].identifier.name).to.equal("c"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].writeExpr.name).to.equal("d"); expect(scope.references[2].partial).to.be.false; expect(scope.references[2].resolved).to.equal(scope.variables[3]); expect(scope.references[3].identifier.name).to.equal("c"); expect(scope.references[3].isWrite()).to.be.true; expect(scope.references[3].writeExpr.name).to.equal("array"); expect(scope.references[3].partial).to.be.true; expect(scope.references[3].resolved).to.equal(scope.variables[3]); expect(scope.references[4].identifier.name).to.equal("d"); expect(scope.references[4].isWrite()).to.be.false; expect(scope.references[5].identifier.name).to.equal("array"); expect(scope.references[5].isWrite()).to.be.false; }); it("Pattern with default values in var in ForInStatement (separate declarations and with MemberExpression)", () => { const ast = espree(` (function () { var obj; for ([obj.a, obj.b, obj.c = d] in array); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(2); expect(scope.implicit.left[0].identifier.name).to.equal("d"); expect(scope.implicit.left[1].identifier.name).to.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.equal("function"); expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.equal("arguments"); expect(scope.variables[1].name).to.equal("obj"); expect(scope.references).to.have.length(5); expect(scope.references[0].identifier.name).to.equal("obj"); // obj.a expect(scope.references[0].isWrite()).to.be.false; expect(scope.references[0].isRead()).to.be.true; expect(scope.references[0].resolved).to.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.equal("obj"); // obj.b expect(scope.references[1].isWrite()).to.be.false; expect(scope.references[1].isRead()).to.be.true; expect(scope.references[1].resolved).to.equal(scope.variables[1]); expect(scope.references[2].identifier.name).to.equal("obj"); // obj.c expect(scope.references[2].isWrite()).to.be.false; expect(scope.references[2].isRead()).to.be.true; expect(scope.references[2].resolved).to.equal(scope.variables[1]); expect(scope.references[3].identifier.name).to.equal("d"); expect(scope.references[3].isWrite()).to.be.false; expect(scope.references[3].isRead()).to.be.true; expect(scope.references[4].identifier.name).to.equal("array"); expect(scope.references[4].isWrite()).to.be.false; expect(scope.references[4].isRead()).to.be.true; }); it("ArrayPattern in var", () => { const ast = espree(` (function () { var [a, b, c] = array; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("a"); expect(scope.variables[2].name).to.be.equal("b"); expect(scope.variables[3].name).to.be.equal("c"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.be.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.be.equal(scope.variables[2]); expect(scope.references[2].identifier.name).to.be.equal("c"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.be.equal(scope.variables[3]); expect(scope.references[3].identifier.name).to.be.equal("array"); expect(scope.references[3].isWrite()).to.be.false; }); it("SpreadElement in var", () => { let ast = espree(` (function () { var [a, b, ...rest] = array; }()); `); let scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("a"); expect(scope.variables[2].name).to.be.equal("b"); expect(scope.variables[3].name).to.be.equal("rest"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.be.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.be.equal(scope.variables[2]); expect(scope.references[2].identifier.name).to.be.equal("rest"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.be.equal(scope.variables[3]); expect(scope.references[3].identifier.name).to.be.equal("array"); expect(scope.references[3].isWrite()).to.be.false; ast = espree(` (function () { var [a, b, ...[c, d, ...rest]] = array; }()); `); scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(6); const expectedVariableNames = [ "arguments", "a", "b", "c", "d", "rest" ]; for (let index = 0; index < expectedVariableNames.length; index++) { expect(scope.variables[index].name).to.be.equal(expectedVariableNames[index]); } expect(scope.references).to.have.length(6); const expectedReferenceNames = [ "a", "b", "c", "d", "rest" ]; for (let index = 0; index < expectedReferenceNames.length; index++) { expect(scope.references[index].identifier.name).to.be.equal(expectedReferenceNames[index]); expect(scope.references[index].isWrite()).to.be.true; expect(scope.references[index].partial).to.be.true; } expect(scope.references[5].identifier.name).to.be.equal("array"); expect(scope.references[5].isWrite()).to.be.false; }); it("ObjectPattern in var", () => { const ast = espree(` (function () { var { shorthand, key: value, hello: { world } } = object; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("object"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("shorthand"); expect(scope.variables[2].name).to.be.equal("value"); expect(scope.variables[3].name).to.be.equal("world"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("shorthand"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.be.equal("value"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.be.equal(scope.variables[2]); expect(scope.references[2].identifier.name).to.be.equal("world"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.be.equal(scope.variables[3]); expect(scope.references[3].identifier.name).to.be.equal("object"); expect(scope.references[3].isWrite()).to.be.false; }); it("complex pattern in var", () => { const ast = espree(` (function () { var { shorthand, key: [ a, b, c, d, e ], hello: { world } } = object; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("object"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(8); const expectedVariableNames = [ "arguments", "shorthand", "a", "b", "c", "d", "e", "world" ]; for (let index = 0; index < expectedVariableNames.length; index++) { expect(scope.variables[index].name).to.be.equal(expectedVariableNames[index]); } expect(scope.references).to.have.length(8); const expectedReferenceNames = [ "shorthand", "a", "b", "c", "d", "e", "world" ]; for (let index = 0; index < expectedReferenceNames.length; index++) { expect(scope.references[index].identifier.name).to.be.equal(expectedReferenceNames[index]); expect(scope.references[index].isWrite()).to.be.true; expect(scope.references[index].partial).to.be.true; } expect(scope.references[7].identifier.name).to.be.equal("object"); expect(scope.references[7].isWrite()).to.be.false; }); it("ArrayPattern in AssignmentExpression", () => { const ast = espree(` (function () { [a, b, c] = array; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(4); expect(scope.implicit.left.map(left => left.identifier.name)).to.deep.equal([ "a", "b", "c", "array" ]); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.be.null; expect(scope.references[1].identifier.name).to.be.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.be.null; expect(scope.references[2].identifier.name).to.be.equal("c"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.be.null; expect(scope.references[3].identifier.name).to.be.equal("array"); expect(scope.references[3].isWrite()).to.be.false; }); it("ArrayPattern with MemberExpression in AssignmentExpression", () => { const ast = espree(` (function () { var obj; [obj.a, obj.b, obj.c] = array; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.equal("function"); expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.equal("arguments"); expect(scope.variables[1].name).to.equal("obj"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.equal("obj"); expect(scope.references[0].isWrite()).to.be.false; expect(scope.references[0].isRead()).to.be.true; expect(scope.references[0].resolved).to.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.equal("obj"); expect(scope.references[1].isWrite()).to.be.false; expect(scope.references[1].isRead()).to.be.true; expect(scope.references[1].resolved).to.equal(scope.variables[1]); expect(scope.references[2].identifier.name).to.equal("obj"); expect(scope.references[2].isWrite()).to.be.false; expect(scope.references[2].isRead()).to.be.true; expect(scope.references[2].resolved).to.equal(scope.variables[1]); expect(scope.references[3].identifier.name).to.equal("array"); expect(scope.references[3].isWrite()).to.be.false; expect(scope.references[3].isRead()).to.be.true; }); it("SpreadElement in AssignmentExpression", () => { let ast = espree(` (function () { [a, b, ...rest] = array; }()); `); let scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(4); expect(scope.implicit.left.map(left => left.identifier.name)).to.deep.equal([ "a", "b", "rest", "array" ]); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.be.null; expect(scope.references[1].identifier.name).to.be.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.be.null; expect(scope.references[2].identifier.name).to.be.equal("rest"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.be.null; expect(scope.references[3].identifier.name).to.be.equal("array"); expect(scope.references[3].isWrite()).to.be.false; ast = espree(` (function () { [a, b, ...[c, d, ...rest]] = array; }()); `); scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(6); expect(scope.implicit.left.map(left => left.identifier.name)).to.deep.equal([ "a", "b", "c", "d", "rest", "array" ]); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(6); const expectedReferenceNames = [ "a", "b", "c", "d", "rest" ]; for (let index = 0; index < expectedReferenceNames.length; index++) { expect(scope.references[index].identifier.name).to.be.equal(expectedReferenceNames[index]); expect(scope.references[index].isWrite()).to.be.true; expect(scope.references[index].partial).to.be.true; expect(scope.references[index].resolved).to.be.null; } expect(scope.references[5].identifier.name).to.be.equal("array"); expect(scope.references[5].isWrite()).to.be.false; }); it("SpreadElement with MemberExpression in AssignmentExpression", () => { const ast = espree(` (function () { [a, b, ...obj.rest] = array; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(4); expect(scope.implicit.left.map(left => left.identifier.name)).to.deep.equal([ "a", "b", "obj", "array" ]); scope = scopeManager.scopes[1]; expect(scope.type).to.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.equal("arguments"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.equal("a"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.be.null; expect(scope.references[1].identifier.name).to.equal("b"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.be.null; expect(scope.references[2].identifier.name).to.equal("obj"); expect(scope.references[2].isWrite()).to.be.false; expect(scope.references[3].identifier.name).to.equal("array"); expect(scope.references[3].isWrite()).to.be.false; }); it("ObjectPattern in AssignmentExpression", () => { const ast = espree(` (function () { ({ shorthand, key: value, hello: { world } } = object); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(4); expect(scope.implicit.left.map(left => left.identifier.name)).to.deep.equal([ "shorthand", "value", "world", "object" ]); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("shorthand"); expect(scope.references[0].isWrite()).to.be.true; expect(scope.references[0].partial).to.be.true; expect(scope.references[0].resolved).to.null; expect(scope.references[1].identifier.name).to.be.equal("value"); expect(scope.references[1].isWrite()).to.be.true; expect(scope.references[1].partial).to.be.true; expect(scope.references[1].resolved).to.null; expect(scope.references[2].identifier.name).to.be.equal("world"); expect(scope.references[2].isWrite()).to.be.true; expect(scope.references[2].partial).to.be.true; expect(scope.references[2].resolved).to.null; expect(scope.references[3].identifier.name).to.be.equal("object"); expect(scope.references[3].isWrite()).to.be.false; }); it("complex pattern in AssignmentExpression", () => { const ast = espree(` (function () { ({ shorthand, key: [ a, b, c, d, e ], hello: { world } } = object); }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); expect(scope.implicit.left).to.have.length(8); expect(scope.implicit.left.map(left => left.identifier.name)).to.deep.equal([ "shorthand", "a", "b", "c", "d", "e", "world", "object" ]); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(8); const expectedReferenceNames = [ "shorthand", "a", "b", "c", "d", "e", "world" ]; for (let index = 0; index < expectedReferenceNames.length; index++) { expect(scope.references[index].identifier.name).to.be.equal(expectedReferenceNames[index]); expect(scope.references[index].isWrite()).to.be.true; expect(scope.references[index].partial).to.be.true; } expect(scope.references[7].identifier.name).to.be.equal("object"); expect(scope.references[7].isWrite()).to.be.false; }); it("ArrayPattern in parameters", () => { const ast = espree(` (function ([a, b, c]) { }(array)); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("array"); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("a"); expect(scope.variables[2].name).to.be.equal("b"); expect(scope.variables[3].name).to.be.equal("c"); expect(scope.references).to.have.length(0); }); it("SpreadElement in parameters", () => { const ast = espree(` (function ([a, b, ...rest], ...rest2) { }(array)); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("array"); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("array"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(5); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("a"); expect(scope.variables[2].name).to.be.equal("b"); expect(scope.variables[3].name).to.be.equal("rest"); expect(scope.variables[3].defs[0].rest).to.be.true; expect(scope.variables[4].name).to.be.equal("rest2"); expect(scope.variables[4].defs[0].rest).to.be.true; expect(scope.references).to.have.length(0); }); it("ObjectPattern in parameters", () => { const ast = espree(` (function ({ shorthand, key: value, hello: { world } }) { }(object)); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("object"); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("object"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(4); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("shorthand"); expect(scope.variables[2].name).to.be.equal("value"); expect(scope.variables[3].name).to.be.equal("world"); expect(scope.references).to.have.length(0); }); it("complex pattern in parameters", () => { const ast = espree(` (function ({ shorthand, key: [ a, b, c, d, e ], hello: { world } }) { }(object)); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("object"); expect(scope.implicit.left).to.have.length(1); expect(scope.implicit.left[0].identifier.name).to.be.equal("object"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(8); const expectedVariableNames = [ "arguments", "shorthand", "a", "b", "c", "d", "e", "world" ]; for (let index = 0; index < expectedVariableNames.length; index++) { expect(scope.variables[index].name).to.be.equal(expectedVariableNames[index]); } expect(scope.references).to.have.length(0); }); it("default values and patterns in var", () => { const ast = espree(` (function () { var [a, b, c, d = 20 ] = array; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(5); const expectedVariableNames = [ "arguments", "a", "b", "c", "d" ]; for (let index = 0; index < expectedVariableNames.length; index++) { expect(scope.variables[index].name).to.be.equal(expectedVariableNames[index]); } expect(scope.references).to.have.length(6); const expectedReferenceNames = [ "a", "b", "c", "d", // assign 20 "d", // assign array "array" ]; for (let index = 0; index < expectedReferenceNames.length; index++) { expect(scope.references[index].identifier.name).to.be.equal(expectedReferenceNames[index]); } }); it("default values containing references and patterns in var", () => { const ast = espree(` (function () { var [a, b, c, d = e ] = array; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(5); const expectedVariableNames = [ "arguments", "a", "b", "c", "d" ]; for (let index = 0; index < expectedVariableNames.length; index++) { expect(scope.variables[index].name).to.be.equal(expectedVariableNames[index]); } expect(scope.references).to.have.length(7); const expectedReferenceNames = [ "a", // assign array "b", // assign array "c", // assign array "d", // assign e "d", // assign array "e", "array" ]; for (let index = 0; index < expectedReferenceNames.length; index++) { expect(scope.references[index].identifier.name).to.be.equal(expectedReferenceNames[index]); } }); it("nested default values containing references and patterns in var", () => { const ast = espree(` (function () { var [a, b, [c, d = e] = f ] = array; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.equal("global"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.equal("function"); expect(scope.variables).to.have.length(5); const expectedVariableNames = [ "arguments", "a", "b", "c", "d" ]; for (let index = 0; index < expectedVariableNames.length; index++) { expect(scope.variables[index].name).to.equal(expectedVariableNames[index]); } expect(scope.references).to.have.length(10); const expectedReferenceNames = [ "a", // assign array "b", // assign array "c", // assign f "c", // assign array "d", // assign f "d", // assign e "d", // assign array "e", "f", "array" ]; for (let index = 0; index < expectedReferenceNames.length; index++) { expect(scope.references[index].identifier.name).to.equal(expectedReferenceNames[index]); } }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-export.js000066400000000000000000000214511351475502400176460ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("export declaration", () => { // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-static-and-runtme-semantics-module-records it("should create variable bindings", () => { const ast = espree("export var v;"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("v"); expect(scope.variables[0].defs[0].type).to.be.equal("Variable"); expect(scope.references).to.have.length(0); }); it("should create function declaration bindings", () => { const ast = espree("export default function f(){};"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(3); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); let scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("f"); expect(scope.variables[0].defs[0].type).to.be.equal("FunctionName"); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); }); it("should export function expression", () => { const ast = espree("export default function(){};"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(3); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); let scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); }); it("should export literal", () => { const ast = espree("export default 42;"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); }); it("should refer exported references#1", () => { const ast = espree("const x = 1; export {x};"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("x"); expect(scope.references[1].identifier.name).to.be.equal("x"); }); it("should refer exported references#2", () => { const ast = espree("const v = 1; export {v as x};"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("v"); expect(scope.references[1].identifier.name).to.be.equal("v"); }); it("should not refer exported references from other source#1", () => { const ast = espree("export {x} from \"mod\";"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); }); it("should not refer exported references from other source#2", () => { const ast = espree("export {v as x} from \"mod\";"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); }); it("should not refer exported references from other source#3", () => { const ast = espree("export * from \"mod\";"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(0); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-import.js000066400000000000000000000122051351475502400176340ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("import declaration", () => { // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-static-and-runtme-semantics-module-records it("should import names from source", () => { const ast = espree("import v from \"mod\";"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("v"); expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); expect(scope.references).to.have.length(0); }); it("should import namespaces", () => { const ast = espree("import * as ns from \"mod\";"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("ns"); expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); expect(scope.references).to.have.length(0); }); it("should import insided names#1", () => { const ast = espree("import {x} from \"mod\";"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("x"); expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); expect(scope.references).to.have.length(0); }); it("should import insided names#2", () => { const ast = espree("import {x as v} from \"mod\";"); const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("v"); expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); expect(scope.references).to.have.length(0); }); // TODO: Should parse it. // import from "mod"; }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-iteration-scope.js000066400000000000000000000233101351475502400214260ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 iteration scope", () => { it("let materialize iteration scope for ForInStatement#1", () => { const ast = espree(` (function () { let i = 20; for (let i in i) { console.log(i); } }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(4); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("i"); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("i"); expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); const iterScope = scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("for"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("i"); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("i"); expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); expect(scope.references[1].identifier.name).to.be.equal("i"); expect(scope.references[1].resolved).to.be.equal(scope.variables[0]); scope = scopeManager.scopes[3]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("console"); expect(scope.references[0].resolved).to.be.equal(null); expect(scope.references[1].identifier.name).to.be.equal("i"); expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); }); it("let materialize iteration scope for ForInStatement#2", () => { const ast = espree(` (function () { let i = 20; for (let { i, j, k } in i) { console.log(i); } }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(4); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("i"); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("i"); expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); const iterScope = scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("for"); expect(scope.variables).to.have.length(3); expect(scope.variables[0].name).to.be.equal("i"); expect(scope.variables[1].name).to.be.equal("j"); expect(scope.variables[2].name).to.be.equal("k"); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("i"); expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); expect(scope.references[1].identifier.name).to.be.equal("j"); expect(scope.references[1].resolved).to.be.equal(scope.variables[1]); expect(scope.references[2].identifier.name).to.be.equal("k"); expect(scope.references[2].resolved).to.be.equal(scope.variables[2]); expect(scope.references[3].identifier.name).to.be.equal("i"); expect(scope.references[3].resolved).to.be.equal(scope.variables[0]); scope = scopeManager.scopes[3]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("console"); expect(scope.references[0].resolved).to.be.equal(null); expect(scope.references[1].identifier.name).to.be.equal("i"); expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); }); it("let materialize iteration scope for ForStatement#2", () => { const ast = espree(` (function () { let i = 20; let obj = {}; for (let { i, j, k } = obj; i < okok; ++i) { console.log(i, j, k); } }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(4); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(0); const functionScope = scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(3); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("i"); expect(scope.variables[2].name).to.be.equal("obj"); expect(scope.references).to.have.length(2); expect(scope.references[0].identifier.name).to.be.equal("i"); expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); expect(scope.references[1].identifier.name).to.be.equal("obj"); expect(scope.references[1].resolved).to.be.equal(scope.variables[2]); const iterScope = scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("for"); expect(scope.variables).to.have.length(3); expect(scope.variables[0].name).to.be.equal("i"); expect(scope.variables[0].defs[0].type).to.be.equal("Variable"); expect(scope.variables[1].name).to.be.equal("j"); expect(scope.variables[1].defs[0].type).to.be.equal("Variable"); expect(scope.variables[2].name).to.be.equal("k"); expect(scope.variables[2].defs[0].type).to.be.equal("Variable"); expect(scope.references).to.have.length(7); expect(scope.references[0].identifier.name).to.be.equal("i"); expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); expect(scope.references[1].identifier.name).to.be.equal("j"); expect(scope.references[1].resolved).to.be.equal(scope.variables[1]); expect(scope.references[2].identifier.name).to.be.equal("k"); expect(scope.references[2].resolved).to.be.equal(scope.variables[2]); expect(scope.references[3].identifier.name).to.be.equal("obj"); expect(scope.references[3].resolved).to.be.equal(functionScope.variables[2]); expect(scope.references[4].identifier.name).to.be.equal("i"); expect(scope.references[4].resolved).to.be.equal(scope.variables[0]); expect(scope.references[5].identifier.name).to.be.equal("okok"); expect(scope.references[5].resolved).to.be.null; expect(scope.references[6].identifier.name).to.be.equal("i"); expect(scope.references[6].resolved).to.be.equal(scope.variables[0]); scope = scopeManager.scopes[3]; expect(scope.type).to.be.equal("block"); expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(4); expect(scope.references[0].identifier.name).to.be.equal("console"); expect(scope.references[0].resolved).to.be.null; expect(scope.references[1].identifier.name).to.be.equal("i"); expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); expect(scope.references[2].identifier.name).to.be.equal("j"); expect(scope.references[2].resolved).to.be.equal(iterScope.variables[1]); expect(scope.references[3].identifier.name).to.be.equal("k"); expect(scope.references[3].resolved).to.be.equal(iterScope.variables[2]); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-new-target.js000066400000000000000000000045021351475502400204000ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 new.target", () => { it("should not make references of new.target", () => { const ast = espree(` class A { constructor() { new.target; } } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); const scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-object.js000066400000000000000000000073661351475502400176040ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 object", () => { it("method definition", () => { const ast = espree(` ({ constructor() { } })`); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); }); it("computed property key may refer variables", () => { const ast = espree(` (function () { var yuyushiki = 42; ({ [yuyushiki]() { }, [yuyushiki + 40]() { } }) }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(4); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("yuyushiki"); expect(scope.references).to.have.length(3); expect(scope.references[0].identifier.name).to.be.equal("yuyushiki"); expect(scope.references[1].identifier.name).to.be.equal("yuyushiki"); expect(scope.references[2].identifier.name).to.be.equal("yuyushiki"); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-rest-args.js000066400000000000000000000050461351475502400202360ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 rest arguments", () => { it("materialize rest argument in scope", () => { const ast = espree(` function foo(...bar) { return bar; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("bar"); expect(scope.variables[1].defs[0].name.name).to.be.equal("bar"); expect(scope.variables[1].defs[0].rest).to.be.true; }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-super.js000066400000000000000000000062171351475502400174660ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 super", () => { it("is not handled as reference", () => { const ast = espree(` class Foo extends Bar { constructor() { super(); } method() { super.method(); } } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(4); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("Foo"); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("Bar"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("class"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("Foo"); expect(scope.references).to.have.length(0); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); // super is specially handled like `this`. scope = scopeManager.scopes[3]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.references).to.have.length(0); // super is specially handled like `this`. }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-switch.js000066400000000000000000000062431351475502400176300ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 switch", () => { it("materialize scope", () => { const ast = espree(` switch (ok) { case hello: let i = 20; i; break; default: let test = 30; test; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); expect(scope.references).to.have.length(1); expect(scope.references[0].identifier.name).to.be.equal("ok"); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("switch"); expect(scope.block.type).to.be.equal("SwitchStatement"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("i"); expect(scope.variables[1].name).to.be.equal("test"); expect(scope.references).to.have.length(5); expect(scope.references[0].identifier.name).to.be.equal("hello"); expect(scope.references[1].identifier.name).to.be.equal("i"); expect(scope.references[2].identifier.name).to.be.equal("i"); expect(scope.references[3].identifier.name).to.be.equal("test"); expect(scope.references[4].identifier.name).to.be.equal("test"); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/es6-template-literal.js000066400000000000000000000064401351475502400215730ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ES6 template literal", () => { it("refer variables", () => { const ast = espree(` (function () { let i, j, k; function testing() { } let template = testing\`testing \${i} and \${j}\` return template; }()); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionExpression"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(6); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("i"); expect(scope.variables[2].name).to.be.equal("j"); expect(scope.variables[3].name).to.be.equal("k"); expect(scope.variables[4].name).to.be.equal("testing"); expect(scope.variables[5].name).to.be.equal("template"); expect(scope.references).to.have.length(5); expect(scope.references[0].identifier.name).to.be.equal("template"); expect(scope.references[1].identifier.name).to.be.equal("testing"); expect(scope.references[2].identifier.name).to.be.equal("i"); expect(scope.references[3].identifier.name).to.be.equal("j"); expect(scope.references[4].identifier.name).to.be.equal("template"); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/fallback.js000066400000000000000000000051251351475502400173710ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2016 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("fallback option", () => { it("should raise an error when it encountered an unknown node if no fallback.", () => { const ast = espree(` var foo = 0; `); ast.body[0].declarations[0].init.type = "NumericLiteral"; expect(() => { analyze(ast, { fallback: "none" }); }).to.throw("Unknown node type NumericLiteral"); }); it("should not raise an error even if it encountered an unknown node when fallback is iteration.", () => { const ast = espree(` var foo = 0; `); ast.body[0].declarations[0].init.type = "NumericLiteral"; analyze(ast); // default is `fallback: "iteration"` analyze(ast, { fallback: "iteration" }); }); it("should not raise an error even if it encountered an unknown node when fallback is a function.", () => { const ast = espree(` var foo = 0; `); ast.body[0].declarations[0].init.type = "NumericLiteral"; analyze(ast, { fallback: node => Object.keys(node) }); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/function-expression-name.js000066400000000000000000000057321351475502400225760ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("function name", () => { it("should create its special scope", () => { const ast = espree(` (function name() { }()); `); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(3); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); expect(globalScope.isArgumentsMaterialized()).to.be.true; // Function expression name scope let scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function-expression-name"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("name"); expect(scope.isArgumentsMaterialized()).to.be.true; expect(scope.references).to.have.length(0); expect(scope.upper === globalScope).to.be.true; // Function scope scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.isArgumentsMaterialized()).to.be.false; expect(scope.references).to.have.length(0); expect(scope.upper === scopeManager.scopes[1]).to.be.true; }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/get-declared-variables.js000066400000000000000000000174111351475502400221210ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Toru Nagashima // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; const expect = require("chai").expect; const visit = require("esrecurse").visit; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("ScopeManager.prototype.getDeclaredVariables", () => { /* eslint-disable require-jsdoc */ function verify(ast, type, expectedNamesList) { const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); visit(ast, { [type](node) { const expected = expectedNamesList.shift(); const actual = scopeManager.getDeclaredVariables(node); expect(actual).to.have.length(expected.length); if (actual.length > 0) { const end = actual.length - 1; for (let i = 0; i <= end; i++) { expect(actual[i].name).to.be.equal(expected[i]); } } this.visitChildren(node); } }); expect(expectedNamesList).to.have.length(0); } it("should get variables that declared on `VariableDeclaration`", () => { const ast = espree(` var {a, x: [b], y: {c = 0}} = foo; let {d, x: [e], y: {f = 0}} = foo; const {g, x: [h], y: {i = 0}} = foo, {j, k = function() { let l; }} = bar; `); verify(ast, "VariableDeclaration", [ ["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i", "j", "k"], ["l"] ]); }); it("should get variables that declared on `VariableDeclaration` in for-in/of", () => { const ast = espree(` for (var {a, x: [b], y: {c = 0}} in foo) { let g; } for (let {d, x: [e], y: {f = 0}} of foo) { let h; } `); verify(ast, "VariableDeclaration", [ ["a", "b", "c"], ["g"], ["d", "e", "f"], ["h"] ]); }); it("should get variables that declared on `VariableDeclarator`", () => { const ast = espree(` var {a, x: [b], y: {c = 0}} = foo; let {d, x: [e], y: {f = 0}} = foo; const {g, x: [h], y: {i = 0}} = foo, {j, k = function() { let l; }} = bar; `); verify(ast, "VariableDeclarator", [ ["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"], ["j", "k"], ["l"] ]); }); it("should get variables that declared on `FunctionDeclaration`", () => { const ast = espree(` function foo({a, x: [b], y: {c = 0}}, [d, e]) { let z; } function bar({f, x: [g], y: {h = 0}}, [i, j = function(q) { let w; }]) { let z; } `); verify(ast, "FunctionDeclaration", [ ["foo", "a", "b", "c", "d", "e"], ["bar", "f", "g", "h", "i", "j"] ]); }); it("should get variables that declared on `FunctionExpression`", () => { const ast = espree(` (function foo({a, x: [b], y: {c = 0}}, [d, e]) { let z; }); (function bar({f, x: [g], y: {h = 0}}, [i, j = function(q) { let w; }]) { let z; }); `); verify(ast, "FunctionExpression", [ ["foo", "a", "b", "c", "d", "e"], ["bar", "f", "g", "h", "i", "j"], ["q"] ]); }); it("should get variables that declared on `ArrowFunctionExpression`", () => { const ast = espree(` (({a, x: [b], y: {c = 0}}, [d, e]) => { let z; }); (({f, x: [g], y: {h = 0}}, [i, j]) => { let z; }); `); verify(ast, "ArrowFunctionExpression", [ ["a", "b", "c", "d", "e"], ["f", "g", "h", "i", "j"] ]); }); it("should get variables that declared on `ClassDeclaration`", () => { const ast = espree(` class A { foo(x) { let y; } } class B { foo(x) { let y; } } `); verify(ast, "ClassDeclaration", [ ["A", "A"], // outer scope"s and inner scope"s. ["B", "B"] ]); }); it("should get variables that declared on `ClassExpression`", () => { const ast = espree(` (class A { foo(x) { let y; } }); (class B { foo(x) { let y; } }); `); verify(ast, "ClassExpression", [ ["A"], ["B"] ]); }); it("should get variables that declared on `CatchClause`", () => { const ast = espree(` try {} catch ({a, b}) { let x; try {} catch ({c, d}) { let y; } } `); verify(ast, "CatchClause", [ ["a", "b"], ["c", "d"] ]); }); it("should get variables that declared on `ImportDeclaration`", () => { const ast = espree(` import "aaa"; import * as a from "bbb"; import b, {c, x as d} from "ccc";`); verify(ast, "ImportDeclaration", [ [], ["a"], ["b", "c", "d"] ]); }); it("should get variables that declared on `ImportSpecifier`", () => { const ast = espree(` import "aaa"; import * as a from "bbb"; import b, {c, x as d} from "ccc";`); verify(ast, "ImportSpecifier", [ ["c"], ["d"] ]); }); it("should get variables that declared on `ImportDefaultSpecifier`", () => { const ast = espree(` import "aaa"; import * as a from "bbb"; import b, {c, x as d} from "ccc";`); verify(ast, "ImportDefaultSpecifier", [ ["b"] ]); }); it("should get variables that declared on `ImportNamespaceSpecifier`", () => { const ast = espree(` import "aaa"; import * as a from "bbb"; import b, {c, x as d} from "ccc";`); verify(ast, "ImportNamespaceSpecifier", [ ["a"] ]); }); it("should not get duplicate even if it's declared twice", () => { const ast = espree("var a = 0, a = 1;"); verify(ast, "VariableDeclaration", [ ["a"] ]); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/global-increment.js000066400000000000000000000041071351475502400210530ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("global increment", () => { it("becomes read/write", () => { const ast = espree("b++;"); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(1); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(1); expect(globalScope.references[0].isReadWrite()).to.be.true; }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/implicit-global-reference.js000066400000000000000000000137401351475502400226400ustar00rootroot00000000000000// Copyright (C) 2013 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("implicit global reference", () => { it("assignments global scope", () => { const ast = espree(` var x = 20; x = 300; `); const scopes = analyze(ast).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.defs.map(def => def.type)))).to.be.eql( [ [ [ "Variable" ] ] ] ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql([]); }); it("assignments global scope without definition", () => { const ast = espree(` x = 300; x = 300; `); const scopes = analyze(ast).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.defs.map(def => def.type)))).to.be.eql( [ [ ] ] ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql( [ "x" ] ); }); it("assignments global scope without definition eval", () => { const ast = espree(` function inner() { eval(str); x = 300; } `); const scopes = analyze(ast).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.defs.map(def => def.type)))).to.be.eql( [ [ [ "FunctionName" ] ], [ [ ] ] ] ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql([]); }); it("assignment leaks", () => { const ast = espree(` function outer() { x = 20; } `); const scopes = analyze(ast).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.name))).to.be.eql( [ [ "outer" ], [ "arguments" ] ] ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql( [ "x" ] ); }); it("assignment doesn't leak", () => { const ast = espree(` function outer() { function inner() { x = 20; } var x; } `); const scopes = analyze(ast).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.name))).to.be.eql( [ [ "outer" ], [ "arguments", "inner", "x" ], [ "arguments" ] ] ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql([]); }); it("for-in-statement leaks", () => { const ast = espree(` function outer() { for (x in y) { } }`); const scopes = analyze(ast).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.name))).to.be.eql( [ [ "outer" ], [ "arguments" ] ] ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql( [ "x" ] ); }); it("for-in-statement doesn't leaks", () => { const ast = espree(` function outer() { function inner() { for (x in y) { } } var x; } `); const scopes = analyze(ast).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.name))).to.be.eql( [ [ "outer" ], [ "arguments", "inner", "x" ], [ "arguments" ] ] ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql([]); }); }); eslint-scope-5.0.0/tests/implied-strict.js000066400000000000000000000120131351475502400205550ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("impliedStrict option", () => { it("ensures all user scopes are strict if ecmaVersion >= 5", () => { const ast = espree(` function foo() { function bar() { "use strict"; } } `); const scopeManager = analyze(ast, { ecmaVersion: 5, impliedStrict: true }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.true; scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionDeclaration"); expect(scope.isStrict).to.be.true; scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionDeclaration"); expect(scope.isStrict).to.be.true; }); it("ensures impliedStrict option is only effective when ecmaVersion option >= 5", () => { const ast = espree(` function foo() {} `); const scopeManager = analyze(ast, { ecmaVersion: 3, impliedStrict: true }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionDeclaration"); expect(scope.isStrict).to.be.false; }); it("omits a nodejs global scope when ensuring all user scopes are strict", () => { const ast = espree(` function foo() {} `); const scopeManager = analyze(ast, { ecmaVersion: 5, nodejsScope: true, impliedStrict: true }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.true; scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionDeclaration"); expect(scope.isStrict).to.be.true; }); it("omits a module global scope when ensuring all user scopes are strict", () => { const ast = espree("function foo() {}"); const scopeManager = analyze(ast, { ecmaVersion: 6, impliedStrict: true, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("module"); expect(scope.isStrict).to.be.true; scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("FunctionDeclaration"); expect(scope.isStrict).to.be.true; }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/label.js000066400000000000000000000062471351475502400167170ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("label", () => { it("should not create variables", () => { const ast = espree("function bar() { q: for(;;) { break q; } }"); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(1); expect(globalScope.variables[0].name).to.be.equal("bar"); expect(globalScope.references).to.have.length(0); const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.isArgumentsMaterialized()).to.be.false; expect(scope.references).to.have.length(0); }); it("should count child node references", () => { const ast = espree(` var foo = 5; label: while (true) { console.log(foo); break; } `); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(1); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(1); expect(globalScope.variables[0].name).to.be.equal("foo"); expect(globalScope.through.length).to.be.equal(3); expect(globalScope.through[2].identifier.name).to.be.equal("foo"); expect(globalScope.through[2].isRead()).to.be.true; }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/nodejs-scope.js000066400000000000000000000073511351475502400202260ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("nodejsScope option", () => { it("creates a function scope following the global scope immediately", () => { const ast = espree(` "use strict"; var hello = 20; `); const scopeManager = analyze(ast, { ecmaVersion: 6, nodejsScope: true }); expect(scopeManager.scopes).to.have.length(2); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.true; expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.variables[1].name).to.be.equal("hello"); }); it("creates a function scope following the global scope immediately and creates module scope", () => { const ast = espree("import {x as v} from 'mod';"); const scopeManager = analyze(ast, { ecmaVersion: 6, nodejsScope: true, sourceType: "module" }); expect(scopeManager.scopes).to.have.length(3); let scope = scopeManager.scopes[0]; expect(scope.type).to.be.equal("global"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(0); scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.block.type).to.be.equal("Program"); expect(scope.isStrict).to.be.false; expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("module"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("v"); expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); expect(scope.references).to.have.length(0); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/object-expression.js000066400000000000000000000031021351475502400212660ustar00rootroot00000000000000"use strict"; const expect = require("chai").expect; const analyze = require("..").analyze; describe("object expression", () => { it("doesn't require property type", () => { // Hardcoded AST. Escope adds an extra "Property" // key/value to ObjectExpressions, so we're not using // it parse a program string. const ast = { type: "Program", body: [{ type: "VariableDeclaration", declarations: [{ type: "VariableDeclarator", id: { type: "Identifier", name: "a" }, init: { type: "ObjectExpression", properties: [{ kind: "init", key: { type: "Identifier", name: "foo" }, value: { type: "Identifier", name: "a" } }] } }] }] }; const scope = analyze(ast).scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(2); expect(scope.variables[0].name).to.be.equal("a"); expect(scope.references[0].identifier.name).to.be.equal("a"); expect(scope.references[1].identifier.name).to.be.equal("a"); }); }); eslint-scope-5.0.0/tests/optimistic.js000066400000000000000000000055241351475502400200210ustar00rootroot00000000000000// Copyright (C) 2013 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("optimistic", () => { it("direct call to eval", () => { const ast = espree(` function outer() { eval(str); var i = 20; function inner() { i; } } `); const scopes = analyze(ast, { optimistic: true }).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.name))).to.be.eql( [ [ "outer" ], [ "arguments", "i", "inner" ], [ "arguments" ] ] ); }); it("with statement", () => { const ast = espree(` function outer() { eval(str); var i = 20; with (obj) { i; } } `, "script"); const scopes = analyze(ast, { optimistic: true }).scopes; expect(scopes.map(scope => scope.variables.map(variable => variable.name))).to.be.eql( [ [ "outer" ], [ "arguments", "i" ], [ ] ] ); }); }); eslint-scope-5.0.0/tests/references.js000066400000000000000000000560201351475502400177530ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Toru Nagashima // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("References:", () => { describe("When there is a `let` declaration on global,", () => { it("the reference on global should be resolved.", () => { const ast = espree("let a = 0;"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(1); const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); it("the reference in functions should be resolved.", () => { const ast = espree(` let a = 0; function foo() { let b = a; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); it("the reference in default parameters should be resolved.", () => { const ast = espree(` let a = 0; function foo(b = a) { } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); }); describe("When there is a `const` declaration on global,", () => { it("the reference on global should be resolved.", () => { const ast = espree("const a = 0;"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(1); const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); it("the reference in functions should be resolved.", () => { const ast = espree(` const a = 0; function foo() { const b = a; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); }); describe("When there is a `var` declaration on global,", () => { it("the reference on global should NOT be resolved.", () => { const ast = espree("var a = 0;"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(1); const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.be.null; expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); it("the reference in functions should NOT be resolved.", () => { const ast = espree(` var a = 0; function foo() { var b = a; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.be.null; expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); }); describe("When there is a `function` declaration on global,", () => { it("the reference on global should NOT be resolved.", () => { const ast = espree(` function a() {} a(); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, a] const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.be.null; expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); it("the reference in functions should NOT be resolved.", () => { const ast = espree(` function a() {} function foo() { let b = a(); } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, a, foo] const scope = scopeManager.scopes[2]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.be.null; expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); }); describe("When there is a `class` declaration on global,", () => { it("the reference on global should be resolved.", () => { const ast = espree(` class A {} let b = new A(); `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, A] const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(2); // [A, b] expect(scope.references).to.have.length(2); // [b, A] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("A"); expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); it("the reference in functions should be resolved.", () => { const ast = espree(` class A {} function foo() { let b = new A(); } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, A, foo] const scope = scopeManager.scopes[2]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, A] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("A"); expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); }); describe("When there is a `let` declaration in functions,", () => { it("the reference on the function should be resolved.", () => { const ast = espree(` function foo() { let a = 0; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(2); // [arguments, a] expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[1]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); it("the reference in nested functions should be resolved.", () => { const ast = espree(` function foo() { let a = 0; function bar() { let b = a; } } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, foo, bar] const scope = scopeManager.scopes[2]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[1].variables[1]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); }); describe("When there is a `var` declaration in functions,", () => { it("the reference on the function should be resolved.", () => { const ast = espree(` function foo() { var a = 0; } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(2); // [global, foo] const scope = scopeManager.scopes[1]; expect(scope.variables).to.have.length(2); // [arguments, a] expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[1]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); it("the reference in nested functions should be resolved.", () => { const ast = espree(` function foo() { var a = 0; function bar() { var b = a; } } `); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(3); // [global, foo, bar] const scope = scopeManager.scopes[2]; expect(scope.variables).to.have.length(2); // [arguments, b] expect(scope.references).to.have.length(2); // [b, a] const reference = scope.references[1]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scopeManager.scopes[1].variables[1]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); }); describe("When there is a `let` declaration with destructuring assignment", () => { it("\"let [a] = [1];\", the reference should be resolved.", () => { const ast = espree("let [a] = [1];"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(1); const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); it("\"let {a} = {a: 1};\", the reference should be resolved.", () => { const ast = espree("let {a} = {a: 1};"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(1); const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); it("\"let {a: {a}} = {a: {a: 1}};\", the reference should be resolved.", () => { const ast = espree("let {a: {a}} = {a: {a: 1}};"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.have.length(1); const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length(1); const reference = scope.references[0]; expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); }); describe("Reference.init should be a boolean value of whether it is one to initialize or not.", () => { const trueCodes = [ "var a = 0;", "let a = 0;", "const a = 0;", "var [a] = [];", "let [a] = [];", "const [a] = [];", "var [a = 1] = [];", "let [a = 1] = [];", "const [a = 1] = [];", "var {a} = {};", "let {a} = {};", "const {a} = {};", "var {b: a} = {};", "let {b: a} = {};", "const {b: a} = {};", "var {b: a = 0} = {};", "let {b: a = 0} = {};", "const {b: a = 0} = {};", "for (var a in []);", "for (let a in []);", "for (var [a] in []);", "for (let [a] in []);", "for (var [a = 0] in []);", "for (let [a = 0] in []);", "for (var {a} in []);", "for (let {a} in []);", "for (var {a = 0} in []);", "for (let {a = 0} in []);", "new function(a = 0) {}", "new function([a = 0] = []) {}", "new function({b: a = 0} = {}) {}" ]; trueCodes.forEach(code => it(`"${code}", all references should be true.`, () => { const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.be.length.of.at.least(1); const scope = scopeManager.scopes[scopeManager.scopes.length - 1]; expect(scope.variables).to.have.length.of.at.least(1); expect(scope.references).to.have.length.of.at.least(1); scope.references.forEach(reference => { expect(reference.identifier.name).to.equal("a"); expect(reference.isWrite()).to.be.true; expect(reference.init).to.be.true; }); })); let falseCodes = [ "let a; a = 0;", "let a; [a] = [];", "let a; [a = 1] = [];", "let a; ({a} = {});", "let a; ({b: a} = {});", "let a; ({b: a = 0} = {});", "let a; for (a in []);", "let a; for ([a] in []);", "let a; for ([a = 0] in []);", "let a; for ({a} in []);", "let a; for ({a = 0} in []);" ]; falseCodes.forEach(code => it(`"${code}", all references should be false.`, () => { const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.be.length.of.at.least(1); const scope = scopeManager.scopes[scopeManager.scopes.length - 1]; expect(scope.variables).to.have.length(1); expect(scope.references).to.have.length.of.at.least(1); scope.references.forEach(reference => { expect(reference.identifier.name).to.equal("a"); expect(reference.isWrite()).to.be.true; expect(reference.init).to.be.false; }); })); falseCodes = [ "let a; let b = a;", "let a; let [b] = a;", "let a; let [b = a] = [];", "let a; for (var b in a);", "let a; for (var [b = a] in []);", "let a; for (let b in a);", "let a; for (let [b = a] in []);", "let a,b; b = a;", "let a,b; [b] = a;", "let a,b; [b = a] = [];", "let a,b; for (b in a);", "let a,b; for ([b = a] in []);", "let a; a.foo = 0;", "let a,b; b = a.foo;" ]; falseCodes.forEach(code => it(`"${code}", readonly references of "a" should be undefined.`, () => { const ast = espree(code); const scopeManager = analyze(ast, { ecmaVersion: 6 }); expect(scopeManager.scopes).to.be.length.of.at.least(1); const scope = scopeManager.scopes[0]; expect(scope.variables).to.have.length.of.at.least(1); expect(scope.variables[0].name).to.equal("a"); const references = scope.variables[0].references; expect(references).to.have.length.of.at.least(1); references.forEach(reference => { expect(reference.isRead()).to.be.true; expect(reference.init).to.be.undefined; }); })); }); }); // vim: set sw=4 ts=4 et tw=80 : eslint-scope-5.0.0/tests/typescript.js000066400000000000000000000034301351475502400200350ustar00rootroot00000000000000/** * @fileoverview Typescript scope tests * @author Reyad Attiyat */ "use strict"; /* eslint-disable no-unused-expressions */ //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ const expect = require("chai").expect, parse = require("@typescript-eslint/parser").parse, analyze = require("..").analyze; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ describe("typescript", () => { describe("multiple call signatures", () => { it("should create a function scope", () => { const ast = parse(` function foo(bar: number): number; function foo(bar: string): string; function foo(bar: string | number): string | number { return bar; } `); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(2); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(1); expect(globalScope.references).to.have.length(4); expect(globalScope.isArgumentsMaterialized()).to.be.true; const scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(2); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.isArgumentsMaterialized()).to.be.false; expect(scope.references).to.have.length(1); }); }); }); eslint-scope-5.0.0/tests/util/000077500000000000000000000000001351475502400162465ustar00rootroot00000000000000eslint-scope-5.0.0/tests/util/espree.js000066400000000000000000000031151351475502400200670ustar00rootroot00000000000000/* Copyright (C) 2015 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; const espree = require("espree"); module.exports = function(code, sourceType) { sourceType = sourceType || "module"; return espree.parse(code, { range: true, ecmaVersion: 7, sourceType }); }; /* vim: set sw=4 ts=4 et tw=80 : */ eslint-scope-5.0.0/tests/with-scope.js000066400000000000000000000054601351475502400177160ustar00rootroot00000000000000// -*- coding: utf-8 -*- // Copyright (C) 2015 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "use strict"; /* eslint-disable no-unused-expressions */ const expect = require("chai").expect; const espree = require("./util/espree"); const analyze = require("..").analyze; describe("with", () => { it("creates scope", () => { const ast = espree(` (function () { with (obj) { testing; } }()); `, "script"); const scopeManager = analyze(ast); expect(scopeManager.scopes).to.have.length(3); const globalScope = scopeManager.scopes[0]; expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(0); expect(globalScope.references).to.have.length(0); let scope = scopeManager.scopes[1]; expect(scope.type).to.be.equal("function"); expect(scope.variables).to.have.length(1); expect(scope.variables[0].name).to.be.equal("arguments"); expect(scope.isArgumentsMaterialized()).to.be.false; expect(scope.references).to.have.length(1); expect(scope.references[0].resolved).to.be.null; scope = scopeManager.scopes[2]; expect(scope.type).to.be.equal("with"); expect(scope.variables).to.have.length(0); expect(scope.isArgumentsMaterialized()).to.be.true; expect(scope.references).to.have.length(1); expect(scope.references[0].resolved).to.be.null; }); }); // vim: set sw=4 ts=4 et tw=80 :