source: trip-planner-front/node_modules/eslint-scope/lib/referencer.js@ 6a80231

Last change on this file since 6a80231 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 18.5 KB
Line 
1/*
2 Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
17 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*/
24"use strict";
25
26/* eslint-disable no-underscore-dangle */
27/* eslint-disable no-undefined */
28
29const Syntax = require("estraverse").Syntax;
30const esrecurse = require("esrecurse");
31const Reference = require("./reference");
32const Variable = require("./variable");
33const PatternVisitor = require("./pattern-visitor");
34const definition = require("./definition");
35const assert = require("assert");
36
37const ParameterDefinition = definition.ParameterDefinition;
38const Definition = definition.Definition;
39
40/**
41 * Traverse identifier in pattern
42 * @param {Object} options - options
43 * @param {pattern} rootPattern - root pattern
44 * @param {Refencer} referencer - referencer
45 * @param {callback} callback - callback
46 * @returns {void}
47 */
48function traverseIdentifierInPattern(options, rootPattern, referencer, callback) {
49
50 // Call the callback at left hand identifier nodes, and Collect right hand nodes.
51 const visitor = new PatternVisitor(options, rootPattern, callback);
52
53 visitor.visit(rootPattern);
54
55 // Process the right hand nodes recursively.
56 if (referencer !== null && referencer !== undefined) {
57 visitor.rightHandNodes.forEach(referencer.visit, referencer);
58 }
59}
60
61// Importing ImportDeclaration.
62// http://people.mozilla.org/~jorendorff/es6-draft.html#sec-moduledeclarationinstantiation
63// https://github.com/estree/estree/blob/master/es6.md#importdeclaration
64// FIXME: Now, we don't create module environment, because the context is
65// implementation dependent.
66
67class Importer extends esrecurse.Visitor {
68 constructor(declaration, referencer) {
69 super(null, referencer.options);
70 this.declaration = declaration;
71 this.referencer = referencer;
72 }
73
74 visitImport(id, specifier) {
75 this.referencer.visitPattern(id, pattern => {
76 this.referencer.currentScope().__define(pattern,
77 new Definition(
78 Variable.ImportBinding,
79 pattern,
80 specifier,
81 this.declaration,
82 null,
83 null
84 ));
85 });
86 }
87
88 ImportNamespaceSpecifier(node) {
89 const local = (node.local || node.id);
90
91 if (local) {
92 this.visitImport(local, node);
93 }
94 }
95
96 ImportDefaultSpecifier(node) {
97 const local = (node.local || node.id);
98
99 this.visitImport(local, node);
100 }
101
102 ImportSpecifier(node) {
103 const local = (node.local || node.id);
104
105 if (node.name) {
106 this.visitImport(node.name, node);
107 } else {
108 this.visitImport(local, node);
109 }
110 }
111}
112
113// Referencing variables and creating bindings.
114class Referencer extends esrecurse.Visitor {
115 constructor(options, scopeManager) {
116 super(null, options);
117 this.options = options;
118 this.scopeManager = scopeManager;
119 this.parent = null;
120 this.isInnerMethodDefinition = false;
121 }
122
123 currentScope() {
124 return this.scopeManager.__currentScope;
125 }
126
127 close(node) {
128 while (this.currentScope() && node === this.currentScope().block) {
129 this.scopeManager.__currentScope = this.currentScope().__close(this.scopeManager);
130 }
131 }
132
133 pushInnerMethodDefinition(isInnerMethodDefinition) {
134 const previous = this.isInnerMethodDefinition;
135
136 this.isInnerMethodDefinition = isInnerMethodDefinition;
137 return previous;
138 }
139
140 popInnerMethodDefinition(isInnerMethodDefinition) {
141 this.isInnerMethodDefinition = isInnerMethodDefinition;
142 }
143
144 referencingDefaultValue(pattern, assignments, maybeImplicitGlobal, init) {
145 const scope = this.currentScope();
146
147 assignments.forEach(assignment => {
148 scope.__referencing(
149 pattern,
150 Reference.WRITE,
151 assignment.right,
152 maybeImplicitGlobal,
153 pattern !== assignment.left,
154 init
155 );
156 });
157 }
158
159 visitPattern(node, options, callback) {
160 let visitPatternOptions = options;
161 let visitPatternCallback = callback;
162
163 if (typeof options === "function") {
164 visitPatternCallback = options;
165 visitPatternOptions = { processRightHandNodes: false };
166 }
167
168 traverseIdentifierInPattern(
169 this.options,
170 node,
171 visitPatternOptions.processRightHandNodes ? this : null,
172 visitPatternCallback
173 );
174 }
175
176 visitFunction(node) {
177 let i, iz;
178
179 // FunctionDeclaration name is defined in upper scope
180 // NOTE: Not referring variableScope. It is intended.
181 // Since
182 // in ES5, FunctionDeclaration should be in FunctionBody.
183 // in ES6, FunctionDeclaration should be block scoped.
184
185 if (node.type === Syntax.FunctionDeclaration) {
186
187 // id is defined in upper scope
188 this.currentScope().__define(node.id,
189 new Definition(
190 Variable.FunctionName,
191 node.id,
192 node,
193 null,
194 null,
195 null
196 ));
197 }
198
199 // FunctionExpression with name creates its special scope;
200 // FunctionExpressionNameScope.
201 if (node.type === Syntax.FunctionExpression && node.id) {
202 this.scopeManager.__nestFunctionExpressionNameScope(node);
203 }
204
205 // Consider this function is in the MethodDefinition.
206 this.scopeManager.__nestFunctionScope(node, this.isInnerMethodDefinition);
207
208 const that = this;
209
210 /**
211 * Visit pattern callback
212 * @param {pattern} pattern - pattern
213 * @param {Object} info - info
214 * @returns {void}
215 */
216 function visitPatternCallback(pattern, info) {
217 that.currentScope().__define(pattern,
218 new ParameterDefinition(
219 pattern,
220 node,
221 i,
222 info.rest
223 ));
224
225 that.referencingDefaultValue(pattern, info.assignments, null, true);
226 }
227
228 // Process parameter declarations.
229 for (i = 0, iz = node.params.length; i < iz; ++i) {
230 this.visitPattern(node.params[i], { processRightHandNodes: true }, visitPatternCallback);
231 }
232
233 // if there's a rest argument, add that
234 if (node.rest) {
235 this.visitPattern({
236 type: "RestElement",
237 argument: node.rest
238 }, pattern => {
239 this.currentScope().__define(pattern,
240 new ParameterDefinition(
241 pattern,
242 node,
243 node.params.length,
244 true
245 ));
246 });
247 }
248
249 // In TypeScript there are a number of function-like constructs which have no body,
250 // so check it exists before traversing
251 if (node.body) {
252
253 // Skip BlockStatement to prevent creating BlockStatement scope.
254 if (node.body.type === Syntax.BlockStatement) {
255 this.visitChildren(node.body);
256 } else {
257 this.visit(node.body);
258 }
259 }
260
261 this.close(node);
262 }
263
264 visitClass(node) {
265 if (node.type === Syntax.ClassDeclaration) {
266 this.currentScope().__define(node.id,
267 new Definition(
268 Variable.ClassName,
269 node.id,
270 node,
271 null,
272 null,
273 null
274 ));
275 }
276
277 this.visit(node.superClass);
278
279 this.scopeManager.__nestClassScope(node);
280
281 if (node.id) {
282 this.currentScope().__define(node.id,
283 new Definition(
284 Variable.ClassName,
285 node.id,
286 node
287 ));
288 }
289 this.visit(node.body);
290
291 this.close(node);
292 }
293
294 visitProperty(node) {
295 let previous;
296
297 if (node.computed) {
298 this.visit(node.key);
299 }
300
301 const isMethodDefinition = node.type === Syntax.MethodDefinition;
302
303 if (isMethodDefinition) {
304 previous = this.pushInnerMethodDefinition(true);
305 }
306 this.visit(node.value);
307 if (isMethodDefinition) {
308 this.popInnerMethodDefinition(previous);
309 }
310 }
311
312 visitForIn(node) {
313 if (node.left.type === Syntax.VariableDeclaration && node.left.kind !== "var") {
314 this.scopeManager.__nestForScope(node);
315 }
316
317 if (node.left.type === Syntax.VariableDeclaration) {
318 this.visit(node.left);
319 this.visitPattern(node.left.declarations[0].id, pattern => {
320 this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true);
321 });
322 } else {
323 this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => {
324 let maybeImplicitGlobal = null;
325
326 if (!this.currentScope().isStrict) {
327 maybeImplicitGlobal = {
328 pattern,
329 node
330 };
331 }
332 this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
333 this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, true, false);
334 });
335 }
336 this.visit(node.right);
337 this.visit(node.body);
338
339 this.close(node);
340 }
341
342 visitVariableDeclaration(variableTargetScope, type, node, index) {
343
344 const decl = node.declarations[index];
345 const init = decl.init;
346
347 this.visitPattern(decl.id, { processRightHandNodes: true }, (pattern, info) => {
348 variableTargetScope.__define(
349 pattern,
350 new Definition(
351 type,
352 pattern,
353 decl,
354 node,
355 index,
356 node.kind
357 )
358 );
359
360 this.referencingDefaultValue(pattern, info.assignments, null, true);
361 if (init) {
362 this.currentScope().__referencing(pattern, Reference.WRITE, init, null, !info.topLevel, true);
363 }
364 });
365 }
366
367 AssignmentExpression(node) {
368 if (PatternVisitor.isPattern(node.left)) {
369 if (node.operator === "=") {
370 this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => {
371 let maybeImplicitGlobal = null;
372
373 if (!this.currentScope().isStrict) {
374 maybeImplicitGlobal = {
375 pattern,
376 node
377 };
378 }
379 this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
380 this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, !info.topLevel, false);
381 });
382 } else {
383 this.currentScope().__referencing(node.left, Reference.RW, node.right);
384 }
385 } else {
386 this.visit(node.left);
387 }
388 this.visit(node.right);
389 }
390
391 CatchClause(node) {
392 this.scopeManager.__nestCatchScope(node);
393
394 this.visitPattern(node.param, { processRightHandNodes: true }, (pattern, info) => {
395 this.currentScope().__define(pattern,
396 new Definition(
397 Variable.CatchClause,
398 node.param,
399 node,
400 null,
401 null,
402 null
403 ));
404 this.referencingDefaultValue(pattern, info.assignments, null, true);
405 });
406 this.visit(node.body);
407
408 this.close(node);
409 }
410
411 Program(node) {
412 this.scopeManager.__nestGlobalScope(node);
413
414 if (this.scopeManager.__isNodejsScope()) {
415
416 // Force strictness of GlobalScope to false when using node.js scope.
417 this.currentScope().isStrict = false;
418 this.scopeManager.__nestFunctionScope(node, false);
419 }
420
421 if (this.scopeManager.__isES6() && this.scopeManager.isModule()) {
422 this.scopeManager.__nestModuleScope(node);
423 }
424
425 if (this.scopeManager.isStrictModeSupported() && this.scopeManager.isImpliedStrict()) {
426 this.currentScope().isStrict = true;
427 }
428
429 this.visitChildren(node);
430 this.close(node);
431 }
432
433 Identifier(node) {
434 this.currentScope().__referencing(node);
435 }
436
437 UpdateExpression(node) {
438 if (PatternVisitor.isPattern(node.argument)) {
439 this.currentScope().__referencing(node.argument, Reference.RW, null);
440 } else {
441 this.visitChildren(node);
442 }
443 }
444
445 MemberExpression(node) {
446 this.visit(node.object);
447 if (node.computed) {
448 this.visit(node.property);
449 }
450 }
451
452 Property(node) {
453 this.visitProperty(node);
454 }
455
456 MethodDefinition(node) {
457 this.visitProperty(node);
458 }
459
460 BreakStatement() {} // eslint-disable-line class-methods-use-this
461
462 ContinueStatement() {} // eslint-disable-line class-methods-use-this
463
464 LabeledStatement(node) {
465 this.visit(node.body);
466 }
467
468 ForStatement(node) {
469
470 // Create ForStatement declaration.
471 // NOTE: In ES6, ForStatement dynamically generates
472 // per iteration environment. However, escope is
473 // a static analyzer, we only generate one scope for ForStatement.
474 if (node.init && node.init.type === Syntax.VariableDeclaration && node.init.kind !== "var") {
475 this.scopeManager.__nestForScope(node);
476 }
477
478 this.visitChildren(node);
479
480 this.close(node);
481 }
482
483 ClassExpression(node) {
484 this.visitClass(node);
485 }
486
487 ClassDeclaration(node) {
488 this.visitClass(node);
489 }
490
491 CallExpression(node) {
492
493 // Check this is direct call to eval
494 if (!this.scopeManager.__ignoreEval() && node.callee.type === Syntax.Identifier && node.callee.name === "eval") {
495
496 // NOTE: This should be `variableScope`. Since direct eval call always creates Lexical environment and
497 // let / const should be enclosed into it. Only VariableDeclaration affects on the caller's environment.
498 this.currentScope().variableScope.__detectEval();
499 }
500 this.visitChildren(node);
501 }
502
503 BlockStatement(node) {
504 if (this.scopeManager.__isES6()) {
505 this.scopeManager.__nestBlockScope(node);
506 }
507
508 this.visitChildren(node);
509
510 this.close(node);
511 }
512
513 ThisExpression() {
514 this.currentScope().variableScope.__detectThis();
515 }
516
517 WithStatement(node) {
518 this.visit(node.object);
519
520 // Then nest scope for WithStatement.
521 this.scopeManager.__nestWithScope(node);
522
523 this.visit(node.body);
524
525 this.close(node);
526 }
527
528 VariableDeclaration(node) {
529 const variableTargetScope = (node.kind === "var") ? this.currentScope().variableScope : this.currentScope();
530
531 for (let i = 0, iz = node.declarations.length; i < iz; ++i) {
532 const decl = node.declarations[i];
533
534 this.visitVariableDeclaration(variableTargetScope, Variable.Variable, node, i);
535 if (decl.init) {
536 this.visit(decl.init);
537 }
538 }
539 }
540
541 // sec 13.11.8
542 SwitchStatement(node) {
543 this.visit(node.discriminant);
544
545 if (this.scopeManager.__isES6()) {
546 this.scopeManager.__nestSwitchScope(node);
547 }
548
549 for (let i = 0, iz = node.cases.length; i < iz; ++i) {
550 this.visit(node.cases[i]);
551 }
552
553 this.close(node);
554 }
555
556 FunctionDeclaration(node) {
557 this.visitFunction(node);
558 }
559
560 FunctionExpression(node) {
561 this.visitFunction(node);
562 }
563
564 ForOfStatement(node) {
565 this.visitForIn(node);
566 }
567
568 ForInStatement(node) {
569 this.visitForIn(node);
570 }
571
572 ArrowFunctionExpression(node) {
573 this.visitFunction(node);
574 }
575
576 ImportDeclaration(node) {
577 assert(this.scopeManager.__isES6() && this.scopeManager.isModule(), "ImportDeclaration should appear when the mode is ES6 and in the module context.");
578
579 const importer = new Importer(node, this);
580
581 importer.visit(node);
582 }
583
584 visitExportDeclaration(node) {
585 if (node.source) {
586 return;
587 }
588 if (node.declaration) {
589 this.visit(node.declaration);
590 return;
591 }
592
593 this.visitChildren(node);
594 }
595
596 // TODO: ExportDeclaration doesn't exist. for bc?
597 ExportDeclaration(node) {
598 this.visitExportDeclaration(node);
599 }
600
601 ExportAllDeclaration(node) {
602 this.visitExportDeclaration(node);
603 }
604
605 ExportDefaultDeclaration(node) {
606 this.visitExportDeclaration(node);
607 }
608
609 ExportNamedDeclaration(node) {
610 this.visitExportDeclaration(node);
611 }
612
613 ExportSpecifier(node) {
614
615 // TODO: `node.id` doesn't exist. for bc?
616 const local = (node.id || node.local);
617
618 this.visit(local);
619 }
620
621 MetaProperty() { // eslint-disable-line class-methods-use-this
622
623 // do nothing.
624 }
625}
626
627module.exports = Referencer;
628
629/* vim: set sw=4 ts=4 et tw=80 : */
Note: See TracBrowser for help on using the repository browser.