UNPKG

6.61 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21var __importDefault = (this && this.__importDefault) || function (mod) {
22 return (mod && mod.__esModule) ? mod : { "default": mod };
23};
24Object.defineProperty(exports, "__esModule", { value: true });
25const assert_never_1 = __importDefault(require("assert-never"));
26const babel_walk_1 = require("babel-walk");
27const t = __importStar(require("@babel/types"));
28const reference_1 = __importDefault(require("./reference"));
29const isScope = (node) => t.isFunctionParent(node) || t.isProgram(node);
30const isBlockScope = (node) => t.isBlockStatement(node) || isScope(node);
31const declaresArguments = (node) => t.isFunction(node) && !t.isArrowFunctionExpression(node);
32const declaresThis = declaresArguments;
33const LOCALS_SYMBOL = Symbol('locals');
34const getLocals = (node) => node[LOCALS_SYMBOL];
35const declareLocals = (node) => (node[LOCALS_SYMBOL] = node[LOCALS_SYMBOL] || new Set());
36const setLocal = (node, name) => declareLocals(node).add(name);
37// First pass
38function declareFunction(node) {
39 for (const param of node.params) {
40 declarePattern(param, node);
41 }
42 const id = node.id;
43 if (id) {
44 setLocal(node, id.name);
45 }
46}
47function declarePattern(node, parent) {
48 switch (node.type) {
49 case 'Identifier':
50 setLocal(parent, node.name);
51 break;
52 case 'ObjectPattern':
53 for (const prop of node.properties) {
54 switch (prop.type) {
55 case 'RestElement':
56 declarePattern(prop.argument, parent);
57 break;
58 case 'ObjectProperty':
59 declarePattern(prop.value, parent);
60 break;
61 default:
62 assert_never_1.default(prop);
63 break;
64 }
65 }
66 break;
67 case 'ArrayPattern':
68 for (const element of node.elements) {
69 if (element)
70 declarePattern(element, parent);
71 }
72 break;
73 case 'RestElement':
74 declarePattern(node.argument, parent);
75 break;
76 case 'AssignmentPattern':
77 declarePattern(node.left, parent);
78 break;
79 // istanbul ignore next
80 default:
81 throw new Error('Unrecognized pattern type: ' + node.type);
82 }
83}
84function declareModuleSpecifier(node, _state, parents) {
85 for (let i = parents.length - 2; i >= 0; i--) {
86 if (isScope(parents[i])) {
87 setLocal(parents[i], node.local.name);
88 return;
89 }
90 }
91}
92const firstPass = babel_walk_1.ancestor({
93 VariableDeclaration(node, _state, parents) {
94 for (let i = parents.length - 2; i >= 0; i--) {
95 if (node.kind === 'var'
96 ? t.isFunctionParent(parents[i])
97 : isBlockScope(parents[i])) {
98 for (const declaration of node.declarations) {
99 declarePattern(declaration.id, parents[i]);
100 }
101 return;
102 }
103 }
104 },
105 FunctionDeclaration(node, _state, parents) {
106 if (node.id) {
107 for (let i = parents.length - 2; i >= 0; i--) {
108 if (isScope(parents[i])) {
109 setLocal(parents[i], node.id.name);
110 return;
111 }
112 }
113 }
114 },
115 Function: declareFunction,
116 ClassDeclaration(node, _state, parents) {
117 for (let i = parents.length - 2; i >= 0; i--) {
118 if (isScope(parents[i])) {
119 setLocal(parents[i], node.id.name);
120 return;
121 }
122 }
123 },
124 TryStatement(node) {
125 if (node.handler === null)
126 return;
127 if (node.handler.param === null)
128 return;
129 declarePattern(node.handler.param, node.handler);
130 },
131 ImportDefaultSpecifier: declareModuleSpecifier,
132 ImportSpecifier: declareModuleSpecifier,
133 ImportNamespaceSpecifier: declareModuleSpecifier,
134});
135// Second pass
136const secondPass = babel_walk_1.ancestor({
137 Identifier(node, state, parents) {
138 var _a;
139 const name = node.name;
140 if (name === 'undefined')
141 return;
142 const lastParent = parents[parents.length - 2];
143 if (lastParent) {
144 if (!reference_1.default(node, lastParent))
145 return;
146 for (const parent of parents) {
147 if (name === 'arguments' && declaresArguments(parent)) {
148 return;
149 }
150 if ((_a = getLocals(parent)) === null || _a === void 0 ? void 0 : _a.has(name)) {
151 return;
152 }
153 }
154 }
155 state.globals.push(node);
156 },
157 ThisExpression(node, state, parents) {
158 for (const parent of parents) {
159 if (declaresThis(parent)) {
160 return;
161 }
162 }
163 state.globals.push(node);
164 },
165});
166function findGlobals(ast) {
167 const globals = [];
168 // istanbul ignore if
169 if (!t.isNode(ast)) {
170 throw new TypeError('Source must be a Babylon AST');
171 }
172 firstPass(ast, undefined);
173 secondPass(ast, { globals });
174 const groupedGlobals = new Map();
175 for (const node of globals) {
176 const name = node.type === 'ThisExpression' ? 'this' : node.name;
177 const existing = groupedGlobals.get(name);
178 if (existing) {
179 existing.push(node);
180 }
181 else {
182 groupedGlobals.set(name, [node]);
183 }
184 }
185 return [...groupedGlobals]
186 .map(([name, nodes]) => ({ name, nodes }))
187 .sort((a, b) => (a.name < b.name ? -1 : 1));
188}
189exports.default = findGlobals;
190//# sourceMappingURL=globals.js.map
\No newline at end of file