summaryrefslogtreecommitdiff
path: root/tools/node_modules/babel-eslint/lib/analyze-scope.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/babel-eslint/lib/analyze-scope.js')
-rw-r--r--tools/node_modules/babel-eslint/lib/analyze-scope.js338
1 files changed, 338 insertions, 0 deletions
diff --git a/tools/node_modules/babel-eslint/lib/analyze-scope.js b/tools/node_modules/babel-eslint/lib/analyze-scope.js
new file mode 100644
index 0000000000..dd4cc3b35a
--- /dev/null
+++ b/tools/node_modules/babel-eslint/lib/analyze-scope.js
@@ -0,0 +1,338 @@
+"use strict";
+
+const t = require("@babel/types");
+const escope = require("eslint-scope");
+const Definition = require("eslint-scope/lib/definition").Definition;
+const OriginalPatternVisitor = require("eslint-scope/lib/pattern-visitor");
+const OriginalReferencer = require("eslint-scope/lib/referencer");
+const fallback = require("eslint-visitor-keys").getKeys;
+const childVisitorKeys = require("./visitor-keys");
+
+const flowFlippedAliasKeys = t.FLIPPED_ALIAS_KEYS.Flow.concat([
+ "ArrayPattern",
+ "ClassDeclaration",
+ "ClassExpression",
+ "FunctionDeclaration",
+ "FunctionExpression",
+ "Identifier",
+ "ObjectPattern",
+ "RestElement",
+]);
+const visitorKeysMap = Object.keys(t.VISITOR_KEYS).reduce(function(acc, key) {
+ const value = t.VISITOR_KEYS[key];
+ if (flowFlippedAliasKeys.indexOf(value) === -1) {
+ acc[key] = value;
+ }
+ return acc;
+}, {});
+
+const propertyTypes = {
+ // loops
+ callProperties: { type: "loop", values: ["value"] },
+ indexers: { type: "loop", values: ["key", "value"] },
+ properties: { type: "loop", values: ["argument", "value"] },
+ types: { type: "loop" },
+ params: { type: "loop" },
+ // single property
+ argument: { type: "single" },
+ elementType: { type: "single" },
+ qualification: { type: "single" },
+ rest: { type: "single" },
+ returnType: { type: "single" },
+ // others
+ typeAnnotation: { type: "typeAnnotation" },
+ typeParameters: { type: "typeParameters" },
+ id: { type: "id" },
+};
+
+class PatternVisitor extends OriginalPatternVisitor {
+ ArrayPattern(node) {
+ node.elements.forEach(this.visit, this);
+ }
+
+ ObjectPattern(node) {
+ node.properties.forEach(this.visit, this);
+ }
+}
+
+class Referencer extends OriginalReferencer {
+ // inherits.
+ visitPattern(node, options, callback) {
+ if (!node) {
+ return;
+ }
+
+ // Visit type annotations.
+ this._checkIdentifierOrVisit(node.typeAnnotation);
+ if (t.isAssignmentPattern(node)) {
+ this._checkIdentifierOrVisit(node.left.typeAnnotation);
+ }
+
+ // Overwrite `super.visitPattern(node, options, callback)` in order to not visit `ArrayPattern#typeAnnotation` and `ObjectPattern#typeAnnotation`.
+ if (typeof options === "function") {
+ callback = options;
+ options = { processRightHandNodes: false };
+ }
+
+ const visitor = new PatternVisitor(this.options, node, callback);
+ visitor.visit(node);
+
+ // Process the right hand nodes recursively.
+ if (options.processRightHandNodes) {
+ visitor.rightHandNodes.forEach(this.visit, this);
+ }
+ }
+
+ // inherits.
+ visitClass(node) {
+ // Decorators.
+ this._visitArray(node.decorators);
+
+ // Flow type parameters.
+ const typeParamScope = this._nestTypeParamScope(node);
+
+ // Flow super types.
+ this._visitTypeAnnotation(node.implements);
+ this._visitTypeAnnotation(
+ node.superTypeParameters && node.superTypeParameters.params
+ );
+
+ // Basic.
+ super.visitClass(node);
+
+ // Close the type parameter scope.
+ if (typeParamScope) {
+ this.close(node);
+ }
+ }
+
+ // inherits.
+ visitFunction(node) {
+ const typeParamScope = this._nestTypeParamScope(node);
+
+ // Flow return types.
+ this._checkIdentifierOrVisit(node.returnType);
+
+ // Basic.
+ super.visitFunction(node);
+
+ // Close the type parameter scope.
+ if (typeParamScope) {
+ this.close(node);
+ }
+ }
+
+ // inherits.
+ visitProperty(node) {
+ if (node.value && node.value.type === "TypeCastExpression") {
+ this._visitTypeAnnotation(node.value);
+ }
+ this._visitArray(node.decorators);
+ super.visitProperty(node);
+ }
+
+ InterfaceDeclaration(node) {
+ this._createScopeVariable(node, node.id);
+
+ const typeParamScope = this._nestTypeParamScope(node);
+
+ // TODO: Handle mixins
+ this._visitArray(node.extends);
+ this.visit(node.body);
+
+ if (typeParamScope) {
+ this.close(node);
+ }
+ }
+
+ TypeAlias(node) {
+ this._createScopeVariable(node, node.id);
+
+ const typeParamScope = this._nestTypeParamScope(node);
+
+ this.visit(node.right);
+
+ if (typeParamScope) {
+ this.close(node);
+ }
+ }
+
+ ClassProperty(node) {
+ this._visitClassProperty(node);
+ }
+
+ ClassPrivateProperty(node) {
+ this._visitClassProperty(node);
+ }
+
+ DeclareModule(node) {
+ this._visitDeclareX(node);
+ }
+
+ DeclareFunction(node) {
+ this._visitDeclareX(node);
+ }
+
+ DeclareVariable(node) {
+ this._visitDeclareX(node);
+ }
+
+ DeclareClass(node) {
+ this._visitDeclareX(node);
+ }
+
+ _visitClassProperty(node) {
+ this._visitTypeAnnotation(node.typeAnnotation);
+ this.visitProperty(node);
+ }
+
+ _visitDeclareX(node) {
+ if (node.id) {
+ this._createScopeVariable(node, node.id);
+ }
+
+ const typeParamScope = this._nestTypeParamScope(node);
+ if (typeParamScope) {
+ this.close(node);
+ }
+ }
+
+ _createScopeVariable(node, name) {
+ this.currentScope().variableScope.__define(
+ name,
+ new Definition("Variable", name, node, null, null, null)
+ );
+ }
+
+ _nestTypeParamScope(node) {
+ if (!node.typeParameters) {
+ return null;
+ }
+
+ const parentScope = this.scopeManager.__currentScope;
+ const scope = new escope.Scope(
+ this.scopeManager,
+ "type-parameters",
+ parentScope,
+ node,
+ false
+ );
+
+ this.scopeManager.__nestScope(scope);
+ for (let j = 0; j < node.typeParameters.params.length; j++) {
+ const name = node.typeParameters.params[j];
+ scope.__define(name, new Definition("TypeParameter", name, name));
+ if (name.typeAnnotation) {
+ this._checkIdentifierOrVisit(name);
+ }
+ }
+ scope.__define = function() {
+ return parentScope.__define.apply(parentScope, arguments);
+ };
+
+ return scope;
+ }
+
+ _visitTypeAnnotation(node) {
+ if (!node) {
+ return;
+ }
+ if (Array.isArray(node)) {
+ node.forEach(this._visitTypeAnnotation, this);
+ return;
+ }
+
+ // get property to check (params, id, etc...)
+ const visitorValues = visitorKeysMap[node.type];
+ if (!visitorValues) {
+ return;
+ }
+
+ // can have multiple properties
+ for (let i = 0; i < visitorValues.length; i++) {
+ const visitorValue = visitorValues[i];
+ const propertyType = propertyTypes[visitorValue];
+ const nodeProperty = node[visitorValue];
+ // check if property or type is defined
+ if (propertyType == null || nodeProperty == null) {
+ continue;
+ }
+ if (propertyType.type === "loop") {
+ for (let j = 0; j < nodeProperty.length; j++) {
+ if (Array.isArray(propertyType.values)) {
+ for (let k = 0; k < propertyType.values.length; k++) {
+ const loopPropertyNode = nodeProperty[j][propertyType.values[k]];
+ if (loopPropertyNode) {
+ this._checkIdentifierOrVisit(loopPropertyNode);
+ }
+ }
+ } else {
+ this._checkIdentifierOrVisit(nodeProperty[j]);
+ }
+ }
+ } else if (propertyType.type === "single") {
+ this._checkIdentifierOrVisit(nodeProperty);
+ } else if (propertyType.type === "typeAnnotation") {
+ this._visitTypeAnnotation(node.typeAnnotation);
+ } else if (propertyType.type === "typeParameters") {
+ for (let l = 0; l < node.typeParameters.params.length; l++) {
+ this._checkIdentifierOrVisit(node.typeParameters.params[l]);
+ }
+ } else if (propertyType.type === "id") {
+ if (node.id.type === "Identifier") {
+ this._checkIdentifierOrVisit(node.id);
+ } else {
+ this._visitTypeAnnotation(node.id);
+ }
+ }
+ }
+ }
+
+ _checkIdentifierOrVisit(node) {
+ if (node && node.typeAnnotation) {
+ this._visitTypeAnnotation(node.typeAnnotation);
+ } else if (node && node.type === "Identifier") {
+ this.visit(node);
+ } else {
+ this._visitTypeAnnotation(node);
+ }
+ }
+
+ _visitArray(nodeList) {
+ if (nodeList) {
+ for (const node of nodeList) {
+ this.visit(node);
+ }
+ }
+ }
+}
+
+module.exports = function(ast, parserOptions) {
+ const options = {
+ ignoreEval: true,
+ optimistic: false,
+ directive: false,
+ nodejsScope:
+ ast.sourceType === "script" &&
+ (parserOptions.ecmaFeatures &&
+ parserOptions.ecmaFeatures.globalReturn) === true,
+ impliedStrict: false,
+ sourceType: ast.sourceType,
+ ecmaVersion: parserOptions.ecmaVersion || 2018,
+ fallback,
+ };
+
+ if (OriginalReferencer._babelEslintPatched) {
+ require("./patch-eslint-scope")(parserOptions);
+ return escope.analyze(ast, options);
+ }
+
+ options.childVisitorKeys = childVisitorKeys;
+
+ const scopeManager = new escope.ScopeManager(options);
+ const referencer = new Referencer(options, scopeManager);
+
+ referencer.visit(ast);
+
+ return scopeManager;
+};