1 | var babylonToEspree = require("./babylon-to-espree");
|
2 | var Module = require("module");
|
3 | var path = require("path");
|
4 | var parse = require("babylon").parse;
|
5 | var t = require("babel-types");
|
6 | var tt = require("babylon").tokTypes;
|
7 | var traverse = require("babel-traverse").default;
|
8 | var codeFrame = require("babel-code-frame");
|
9 |
|
10 | var hasPatched = false;
|
11 | var eslintOptions = {};
|
12 |
|
13 | function getModules() {
|
14 | try {
|
15 |
|
16 | var eslintLoc = Module._resolveFilename("eslint", module.parent);
|
17 | } catch (err) {
|
18 | try {
|
19 |
|
20 | eslintLoc = require.resolve("eslint");
|
21 | } catch (err) {
|
22 | throw new ReferenceError("couldn't resolve eslint");
|
23 | }
|
24 | }
|
25 |
|
26 |
|
27 | var eslintMod = new Module(eslintLoc);
|
28 | eslintMod.filename = eslintLoc;
|
29 | eslintMod.paths = Module._nodeModulePaths(path.dirname(eslintLoc));
|
30 |
|
31 | try {
|
32 | var escope = eslintMod.require("eslint-scope");
|
33 | var Definition = eslintMod.require("eslint-scope/lib/definition").Definition;
|
34 | var referencer = eslintMod.require("eslint-scope/lib/referencer");
|
35 | } catch (err) {
|
36 | escope = eslintMod.require("escope");
|
37 | Definition = eslintMod.require("escope/lib/definition").Definition;
|
38 | referencer = eslintMod.require("escope/lib/referencer");
|
39 | }
|
40 |
|
41 | var estraverse = eslintMod.require("estraverse");
|
42 |
|
43 | if (referencer.__esModule) referencer = referencer.default;
|
44 |
|
45 | return {
|
46 | Definition,
|
47 | escope,
|
48 | estraverse,
|
49 | referencer,
|
50 | };
|
51 | }
|
52 |
|
53 | function monkeypatch(modules) {
|
54 | var Definition = modules.Definition;
|
55 | var escope = modules.escope;
|
56 | var estraverse = modules.estraverse;
|
57 | var referencer = modules.referencer;
|
58 |
|
59 | Object.assign(estraverse.VisitorKeys, t.VISITOR_KEYS);
|
60 | estraverse.VisitorKeys.MethodDefinition.push("decorators");
|
61 | estraverse.VisitorKeys.Property.push("decorators");
|
62 |
|
63 | var analyze = escope.analyze;
|
64 | escope.analyze = function (ast, opts) {
|
65 | opts.ecmaVersion = eslintOptions.ecmaVersion;
|
66 | opts.sourceType = eslintOptions.sourceType;
|
67 | if (eslintOptions.globalReturn !== undefined) {
|
68 | opts.nodejsScope = eslintOptions.globalReturn;
|
69 | }
|
70 |
|
71 | var results = analyze.call(this, ast, opts);
|
72 | return results;
|
73 | };
|
74 |
|
75 |
|
76 | function visitDecorators(node) {
|
77 | if (!node.decorators) {
|
78 | return;
|
79 | }
|
80 | for (var i = 0; i < node.decorators.length; i++) {
|
81 | if (node.decorators[i].expression) {
|
82 | this.visit(node.decorators[i]);
|
83 | }
|
84 | }
|
85 | }
|
86 |
|
87 |
|
88 | var flowFlippedAliasKeys = t.FLIPPED_ALIAS_KEYS.Flow.concat([
|
89 | "ArrayPattern",
|
90 | "ClassDeclaration",
|
91 | "ClassExpression",
|
92 | "FunctionDeclaration",
|
93 | "FunctionExpression",
|
94 | "Identifier",
|
95 | "ObjectPattern",
|
96 | "RestElement"
|
97 | ]);
|
98 | var visitorKeysMap = Object.keys(t.VISITOR_KEYS).reduce(function(acc, key) {
|
99 | var value = t.VISITOR_KEYS[key];
|
100 | if (flowFlippedAliasKeys.indexOf(value) === -1) {
|
101 | acc[key] = value;
|
102 | }
|
103 | return acc;
|
104 | }, {});
|
105 |
|
106 | var propertyTypes = {
|
107 |
|
108 | callProperties: { type: "loop", values: ["value"] },
|
109 | indexers: { type: "loop", values: ["key", "value"] },
|
110 | properties: { type: "loop", values: ["argument", "value"] },
|
111 | types: { type: "loop" },
|
112 | params: { type: "loop" },
|
113 |
|
114 | argument: { type: "single" },
|
115 | elementType: { type: "single" },
|
116 | qualification: { type: "single" },
|
117 | rest: { type: "single" },
|
118 | returnType: { type: "single" },
|
119 |
|
120 | typeAnnotation: { type: "typeAnnotation" },
|
121 | typeParameters: { type: "typeParameters" },
|
122 | id: { type: "id" }
|
123 | };
|
124 |
|
125 | function visitTypeAnnotation(node) {
|
126 |
|
127 | var visitorValues = visitorKeysMap[node.type];
|
128 | if (!visitorValues) {
|
129 | return;
|
130 | }
|
131 |
|
132 |
|
133 | for (var i = 0; i < visitorValues.length; i++) {
|
134 | var visitorValue = visitorValues[i];
|
135 | var propertyType = propertyTypes[visitorValue];
|
136 | var nodeProperty = node[visitorValue];
|
137 |
|
138 | if (propertyType == null || nodeProperty == null) {
|
139 | continue;
|
140 | }
|
141 | if (propertyType.type === "loop") {
|
142 | for (var j = 0; j < nodeProperty.length; j++) {
|
143 | if (Array.isArray(propertyType.values)) {
|
144 | for (var k = 0; k < propertyType.values.length; k++) {
|
145 | var loopPropertyNode = nodeProperty[j][propertyType.values[k]];
|
146 | if (loopPropertyNode) {
|
147 | checkIdentifierOrVisit.call(this, loopPropertyNode);
|
148 | }
|
149 | }
|
150 | } else {
|
151 | checkIdentifierOrVisit.call(this, nodeProperty[j]);
|
152 | }
|
153 | }
|
154 | } else if (propertyType.type === "single") {
|
155 | checkIdentifierOrVisit.call(this, nodeProperty);
|
156 | } else if (propertyType.type === "typeAnnotation") {
|
157 | visitTypeAnnotation.call(this, node.typeAnnotation);
|
158 | } else if (propertyType.type === "typeParameters") {
|
159 | for (var l = 0; l < node.typeParameters.params.length; l++) {
|
160 | checkIdentifierOrVisit.call(this, node.typeParameters.params[l]);
|
161 | }
|
162 | } else if (propertyType.type === "id") {
|
163 | if (node.id.type === "Identifier") {
|
164 | checkIdentifierOrVisit.call(this, node.id);
|
165 | } else {
|
166 | visitTypeAnnotation.call(this, node.id);
|
167 | }
|
168 | }
|
169 | }
|
170 | }
|
171 |
|
172 | function checkIdentifierOrVisit(node) {
|
173 | if (node.typeAnnotation) {
|
174 | visitTypeAnnotation.call(this, node.typeAnnotation);
|
175 | } else if (node.type === "Identifier") {
|
176 | this.visit(node);
|
177 | } else {
|
178 | visitTypeAnnotation.call(this, node);
|
179 | }
|
180 | }
|
181 |
|
182 | function nestTypeParamScope(manager, node) {
|
183 | var parentScope = manager.__currentScope;
|
184 | var scope = new escope.Scope(manager, "type-parameters", parentScope, node, false);
|
185 | manager.__nestScope(scope);
|
186 | for (var j = 0; j < node.typeParameters.params.length; j++) {
|
187 | var name = node.typeParameters.params[j];
|
188 | scope.__define(name, new Definition("TypeParameter", name, name));
|
189 | if (name.typeAnnotation) {
|
190 | checkIdentifierOrVisit.call(this, name);
|
191 | }
|
192 | }
|
193 | scope.__define = function() {
|
194 | return parentScope.__define.apply(parentScope, arguments);
|
195 | };
|
196 | return scope;
|
197 | }
|
198 |
|
199 |
|
200 | var visitClass = referencer.prototype.visitClass;
|
201 | referencer.prototype.visitClass = function(node) {
|
202 | visitDecorators.call(this, node);
|
203 | var typeParamScope;
|
204 | if (node.typeParameters) {
|
205 | typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
206 | }
|
207 |
|
208 | if (node.implements) {
|
209 | for (var i = 0; i < node.implements.length; i++) {
|
210 | checkIdentifierOrVisit.call(this, node.implements[i]);
|
211 | }
|
212 | }
|
213 | if (node.superTypeParameters) {
|
214 | for (var k = 0; k < node.superTypeParameters.params.length; k++) {
|
215 | checkIdentifierOrVisit.call(this, node.superTypeParameters.params[k]);
|
216 | }
|
217 | }
|
218 | visitClass.call(this, node);
|
219 | if (typeParamScope) {
|
220 | this.close(node);
|
221 | }
|
222 | };
|
223 |
|
224 |
|
225 | var visitProperty = referencer.prototype.visitProperty;
|
226 | referencer.prototype.visitProperty = function(node) {
|
227 | if (node.value && node.value.type === "TypeCastExpression") {
|
228 | visitTypeAnnotation.call(this, node.value);
|
229 | }
|
230 | visitDecorators.call(this, node);
|
231 | visitProperty.call(this, node);
|
232 | };
|
233 |
|
234 |
|
235 | referencer.prototype.ClassProperty = function(node) {
|
236 | if (node.typeAnnotation) {
|
237 | visitTypeAnnotation.call(this, node.typeAnnotation);
|
238 | }
|
239 | this.visitProperty(node);
|
240 | };
|
241 |
|
242 |
|
243 | var visitFunction = referencer.prototype.visitFunction;
|
244 | referencer.prototype.visitFunction = function(node) {
|
245 | var typeParamScope;
|
246 | if (node.typeParameters) {
|
247 | typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
248 | }
|
249 | if (node.returnType) {
|
250 | checkIdentifierOrVisit.call(this, node.returnType);
|
251 | }
|
252 |
|
253 | if (node.params) {
|
254 | for (var i = 0; i < node.params.length; i++) {
|
255 | var param = node.params[i];
|
256 | if (param.typeAnnotation) {
|
257 | checkIdentifierOrVisit.call(this, param);
|
258 | } else if (t.isAssignmentPattern(param)) {
|
259 | if (param.left.typeAnnotation) {
|
260 | checkIdentifierOrVisit.call(this, param.left);
|
261 | }
|
262 | }
|
263 | }
|
264 | }
|
265 |
|
266 |
|
267 | estraverse.VisitorKeys.ObjectPattern = ["properties"];
|
268 | estraverse.VisitorKeys.ArrayPattern = ["elements"];
|
269 | visitFunction.call(this, node);
|
270 |
|
271 | estraverse.VisitorKeys.ObjectPattern = t.VISITOR_KEYS.ObjectPattern;
|
272 | estraverse.VisitorKeys.ArrayPattern = t.VISITOR_KEYS.ArrayPattern;
|
273 | if (typeParamScope) {
|
274 | this.close(node);
|
275 | }
|
276 | };
|
277 |
|
278 |
|
279 | var variableDeclaration = referencer.prototype.VariableDeclaration;
|
280 | referencer.prototype.VariableDeclaration = function(node) {
|
281 | if (node.declarations) {
|
282 | for (var i = 0; i < node.declarations.length; i++) {
|
283 | var id = node.declarations[i].id;
|
284 | var typeAnnotation = id.typeAnnotation;
|
285 | if (typeAnnotation) {
|
286 | checkIdentifierOrVisit.call(this, typeAnnotation);
|
287 | }
|
288 | }
|
289 | }
|
290 | variableDeclaration.call(this, node);
|
291 | };
|
292 |
|
293 | function createScopeVariable (node, name) {
|
294 | this.currentScope().variableScope.__define(name,
|
295 | new Definition(
|
296 | "Variable",
|
297 | name,
|
298 | node,
|
299 | null,
|
300 | null,
|
301 | null
|
302 | )
|
303 | );
|
304 | }
|
305 |
|
306 | referencer.prototype.InterfaceDeclaration = function(node) {
|
307 | createScopeVariable.call(this, node, node.id);
|
308 | var typeParamScope;
|
309 | if (node.typeParameters) {
|
310 | typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
311 | }
|
312 |
|
313 | for (var i = 0; i < node.extends.length; i++) {
|
314 | visitTypeAnnotation.call(this, node.extends[i]);
|
315 | }
|
316 | visitTypeAnnotation.call(this, node.body);
|
317 | if (typeParamScope) {
|
318 | this.close(node);
|
319 | }
|
320 | };
|
321 |
|
322 | referencer.prototype.TypeAlias = function(node) {
|
323 | createScopeVariable.call(this, node, node.id);
|
324 | var typeParamScope;
|
325 | if (node.typeParameters) {
|
326 | typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
327 | }
|
328 | if (node.right) {
|
329 | visitTypeAnnotation.call(this, node.right);
|
330 | }
|
331 | if (typeParamScope) {
|
332 | this.close(node);
|
333 | }
|
334 | };
|
335 |
|
336 | referencer.prototype.DeclareModule =
|
337 | referencer.prototype.DeclareFunction =
|
338 | referencer.prototype.DeclareVariable =
|
339 | referencer.prototype.DeclareClass = function(node) {
|
340 | if (node.id) {
|
341 | createScopeVariable.call(this, node, node.id);
|
342 | }
|
343 |
|
344 | var typeParamScope;
|
345 | if (node.typeParameters) {
|
346 | typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
347 | }
|
348 | if (typeParamScope) {
|
349 | this.close(node);
|
350 | }
|
351 | };
|
352 | }
|
353 |
|
354 | exports.parse = function (code, options) {
|
355 | options = options || {};
|
356 | eslintOptions.ecmaVersion = options.ecmaVersion = options.ecmaVersion || 6;
|
357 | eslintOptions.sourceType = options.sourceType = options.sourceType || "module";
|
358 | eslintOptions.allowImportExportEverywhere = options.allowImportExportEverywhere = options.allowImportExportEverywhere || false;
|
359 | if (options.sourceType === "module") {
|
360 | eslintOptions.globalReturn = false;
|
361 | } else {
|
362 | delete eslintOptions.globalReturn;
|
363 | }
|
364 |
|
365 | if (!hasPatched) {
|
366 | hasPatched = true;
|
367 | try {
|
368 | monkeypatch(getModules());
|
369 | } catch (err) {
|
370 | console.error(err.stack);
|
371 | process.exit(1);
|
372 | }
|
373 | }
|
374 |
|
375 | return exports.parseNoPatch(code, options);
|
376 | };
|
377 |
|
378 | exports.parseNoPatch = function (code, options) {
|
379 | var opts = {
|
380 | codeFrame: options.hasOwnProperty("codeFrame") ? options.codeFrame : true,
|
381 | sourceType: options.sourceType,
|
382 | allowImportExportEverywhere: options.allowImportExportEverywhere,
|
383 | allowReturnOutsideFunction: true,
|
384 | allowSuperOutsideMethod: true,
|
385 | plugins: [
|
386 | "flow",
|
387 | "jsx",
|
388 | "asyncFunctions",
|
389 | "asyncGenerators",
|
390 | "classConstructorCall",
|
391 | "classProperties",
|
392 | "decorators",
|
393 | "doExpressions",
|
394 | "exponentiationOperator",
|
395 | "exportExtensions",
|
396 | "functionBind",
|
397 | "functionSent",
|
398 | "objectRestSpread",
|
399 | "trailingFunctionCommas",
|
400 | "dynamicImport"
|
401 | ]
|
402 | };
|
403 |
|
404 | var ast;
|
405 | try {
|
406 | ast = parse(code, opts);
|
407 | } catch (err) {
|
408 | if (err instanceof SyntaxError) {
|
409 |
|
410 | err.lineNumber = err.loc.line;
|
411 | err.column = err.loc.column;
|
412 |
|
413 | if (opts.codeFrame) {
|
414 | err.lineNumber = err.loc.line;
|
415 | err.column = err.loc.column + 1;
|
416 |
|
417 |
|
418 | err.message = "Line " + err.lineNumber + ": " + err.message.replace(/ \((\d+):(\d+)\)$/, "") +
|
419 |
|
420 | "\n\n" +
|
421 | codeFrame(code, err.lineNumber, err.column, { highlightCode: true });
|
422 | }
|
423 | }
|
424 |
|
425 | throw err;
|
426 | }
|
427 |
|
428 | babylonToEspree(ast, traverse, tt, code);
|
429 |
|
430 | return ast;
|
431 | };
|