UNPKG

8.49 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = analyzeScope;
7
8var _core = require("@babel/core");
9
10var _eslintScope = _interopRequireDefault(require("eslint-scope"));
11
12var _definition = require("eslint-scope/lib/definition");
13
14var _patternVisitor = _interopRequireDefault(require("eslint-scope/lib/pattern-visitor"));
15
16var _referencer = _interopRequireDefault(require("eslint-scope/lib/referencer"));
17
18var _eslintVisitorKeys = require("eslint-visitor-keys");
19
20var _visitorKeys = _interopRequireDefault(require("./visitor-keys"));
21
22function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
24const flowFlippedAliasKeys = _core.types.FLIPPED_ALIAS_KEYS.Flow.concat(["ArrayPattern", "ClassDeclaration", "ClassExpression", "FunctionDeclaration", "FunctionExpression", "Identifier", "ObjectPattern", "RestElement"]);
25
26const visitorKeysMap = Object.entries(_core.types.VISITOR_KEYS).reduce((acc, [key, value]) => {
27 if (!flowFlippedAliasKeys.includes(value)) {
28 acc[key] = value;
29 }
30
31 return acc;
32}, {});
33const propertyTypes = {
34 callProperties: {
35 type: "loop",
36 values: ["value"]
37 },
38 indexers: {
39 type: "loop",
40 values: ["key", "value"]
41 },
42 properties: {
43 type: "loop",
44 values: ["argument", "value"]
45 },
46 types: {
47 type: "loop"
48 },
49 params: {
50 type: "loop"
51 },
52 argument: {
53 type: "single"
54 },
55 elementType: {
56 type: "single"
57 },
58 qualification: {
59 type: "single"
60 },
61 rest: {
62 type: "single"
63 },
64 returnType: {
65 type: "single"
66 },
67 typeAnnotation: {
68 type: "typeAnnotation"
69 },
70 typeParameters: {
71 type: "typeParameters"
72 },
73 id: {
74 type: "id"
75 }
76};
77
78class PatternVisitor extends _patternVisitor.default {
79 ArrayPattern(node) {
80 node.elements.forEach(this.visit, this);
81 }
82
83 ObjectPattern(node) {
84 node.properties.forEach(this.visit, this);
85 }
86
87}
88
89class Referencer extends _referencer.default {
90 visitPattern(node, options, callback) {
91 if (!node) {
92 return;
93 }
94
95 this._checkIdentifierOrVisit(node.typeAnnotation);
96
97 if (_core.types.isAssignmentPattern(node)) {
98 this._checkIdentifierOrVisit(node.left.typeAnnotation);
99 }
100
101 if (typeof options === "function") {
102 callback = options;
103 options = {
104 processRightHandNodes: false
105 };
106 }
107
108 const visitor = new PatternVisitor(this.options, node, callback);
109 visitor.visit(node);
110
111 if (options.processRightHandNodes) {
112 visitor.rightHandNodes.forEach(this.visit, this);
113 }
114 }
115
116 visitClass(node) {
117 this._visitArray(node.decorators);
118
119 const typeParamScope = this._nestTypeParamScope(node);
120
121 this._visitTypeAnnotation(node.implements);
122
123 this._visitTypeAnnotation(node.superTypeParameters && node.superTypeParameters.params);
124
125 super.visitClass(node);
126
127 if (typeParamScope) {
128 this.close(node);
129 }
130 }
131
132 visitFunction(node) {
133 const typeParamScope = this._nestTypeParamScope(node);
134
135 this._checkIdentifierOrVisit(node.returnType);
136
137 super.visitFunction(node);
138
139 if (typeParamScope) {
140 this.close(node);
141 }
142 }
143
144 visitProperty(node) {
145 var _node$value;
146
147 if (((_node$value = node.value) == null ? void 0 : _node$value.type) === "TypeCastExpression") {
148 this._visitTypeAnnotation(node.value);
149 }
150
151 this._visitArray(node.decorators);
152
153 super.visitProperty(node);
154 }
155
156 InterfaceDeclaration(node) {
157 this._createScopeVariable(node, node.id);
158
159 const typeParamScope = this._nestTypeParamScope(node);
160
161 this._visitArray(node.extends);
162
163 this.visit(node.body);
164
165 if (typeParamScope) {
166 this.close(node);
167 }
168 }
169
170 TypeAlias(node) {
171 this._createScopeVariable(node, node.id);
172
173 const typeParamScope = this._nestTypeParamScope(node);
174
175 this.visit(node.right);
176
177 if (typeParamScope) {
178 this.close(node);
179 }
180 }
181
182 ClassProperty(node) {
183 this._visitClassProperty(node);
184 }
185
186 ClassPrivateProperty(node) {
187 this._visitClassProperty(node);
188 }
189
190 ClassPrivateMethod(node) {
191 super.MethodDefinition(node);
192 }
193
194 DeclareModule(node) {
195 this._visitDeclareX(node);
196 }
197
198 DeclareFunction(node) {
199 this._visitDeclareX(node);
200 }
201
202 DeclareVariable(node) {
203 this._visitDeclareX(node);
204 }
205
206 DeclareClass(node) {
207 this._visitDeclareX(node);
208 }
209
210 OptionalMemberExpression(node) {
211 super.MemberExpression(node);
212 }
213
214 _visitClassProperty(node) {
215 this._visitTypeAnnotation(node.typeAnnotation);
216
217 this.visitProperty(node);
218 }
219
220 _visitDeclareX(node) {
221 if (node.id) {
222 this._createScopeVariable(node, node.id);
223 }
224
225 const typeParamScope = this._nestTypeParamScope(node);
226
227 if (typeParamScope) {
228 this.close(node);
229 }
230 }
231
232 _createScopeVariable(node, name) {
233 this.currentScope().variableScope.__define(name, new _definition.Definition("Variable", name, node, null, null, null));
234 }
235
236 _nestTypeParamScope(node) {
237 if (!node.typeParameters) {
238 return null;
239 }
240
241 const parentScope = this.scopeManager.__currentScope;
242 const scope = new _eslintScope.default.Scope(this.scopeManager, "type-parameters", parentScope, node, false);
243
244 this.scopeManager.__nestScope(scope);
245
246 for (let j = 0; j < node.typeParameters.params.length; j++) {
247 const name = node.typeParameters.params[j];
248
249 scope.__define(name, new _definition.Definition("TypeParameter", name, name));
250
251 if (name.typeAnnotation) {
252 this._checkIdentifierOrVisit(name);
253 }
254 }
255
256 scope.__define = function () {
257 return parentScope.__define.apply(parentScope, arguments);
258 };
259
260 return scope;
261 }
262
263 _visitTypeAnnotation(node) {
264 if (!node) {
265 return;
266 }
267
268 if (Array.isArray(node)) {
269 node.forEach(this._visitTypeAnnotation, this);
270 return;
271 }
272
273 const visitorValues = visitorKeysMap[node.type];
274
275 if (!visitorValues) {
276 return;
277 }
278
279 for (let i = 0; i < visitorValues.length; i++) {
280 const visitorValue = visitorValues[i];
281 const propertyType = propertyTypes[visitorValue];
282 const nodeProperty = node[visitorValue];
283
284 if (propertyType == null || nodeProperty == null) {
285 continue;
286 }
287
288 if (propertyType.type === "loop") {
289 for (let j = 0; j < nodeProperty.length; j++) {
290 if (Array.isArray(propertyType.values)) {
291 for (let k = 0; k < propertyType.values.length; k++) {
292 const loopPropertyNode = nodeProperty[j][propertyType.values[k]];
293
294 if (loopPropertyNode) {
295 this._checkIdentifierOrVisit(loopPropertyNode);
296 }
297 }
298 } else {
299 this._checkIdentifierOrVisit(nodeProperty[j]);
300 }
301 }
302 } else if (propertyType.type === "single") {
303 this._checkIdentifierOrVisit(nodeProperty);
304 } else if (propertyType.type === "typeAnnotation") {
305 this._visitTypeAnnotation(node.typeAnnotation);
306 } else if (propertyType.type === "typeParameters") {
307 for (let l = 0; l < node.typeParameters.params.length; l++) {
308 this._checkIdentifierOrVisit(node.typeParameters.params[l]);
309 }
310 } else if (propertyType.type === "id") {
311 if (node.id.type === "Identifier") {
312 this._checkIdentifierOrVisit(node.id);
313 } else {
314 this._visitTypeAnnotation(node.id);
315 }
316 }
317 }
318 }
319
320 _checkIdentifierOrVisit(node) {
321 if (node == null ? void 0 : node.typeAnnotation) {
322 this._visitTypeAnnotation(node.typeAnnotation);
323 } else if ((node == null ? void 0 : node.type) === "Identifier") {
324 this.visit(node);
325 } else {
326 this._visitTypeAnnotation(node);
327 }
328 }
329
330 _visitArray(nodeList) {
331 if (nodeList) {
332 for (const node of nodeList) {
333 this.visit(node);
334 }
335 }
336 }
337
338}
339
340function analyzeScope(ast, parserOptions) {
341 const options = {
342 ignoreEval: true,
343 optimistic: false,
344 directive: false,
345 nodejsScope: ast.sourceType === "script" && (parserOptions.ecmaFeatures && parserOptions.ecmaFeatures.globalReturn) === true,
346 impliedStrict: false,
347 sourceType: ast.sourceType,
348 ecmaVersion: parserOptions.ecmaVersion,
349 fallback: _eslintVisitorKeys.getKeys
350 };
351 options.childVisitorKeys = _visitorKeys.default;
352 const scopeManager = new _eslintScope.default.ScopeManager(options);
353 const referencer = new Referencer(options, scopeManager);
354 referencer.visit(ast);
355 return scopeManager;
356}
\No newline at end of file