1 | "use strict";
|
2 | var __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 | }));
|
9 | var __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 | });
|
14 | var __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 | };
|
21 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
22 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
23 | };
|
24 | Object.defineProperty(exports, "__esModule", { value: true });
|
25 | const assert_never_1 = __importDefault(require("assert-never"));
|
26 | const babel_walk_1 = require("babel-walk");
|
27 | const t = __importStar(require("@babel/types"));
|
28 | const reference_1 = __importDefault(require("./reference"));
|
29 | const isScope = (node) => t.isFunctionParent(node) || t.isProgram(node);
|
30 | const isBlockScope = (node) => t.isBlockStatement(node) || isScope(node);
|
31 | const declaresArguments = (node) => t.isFunction(node) && !t.isArrowFunctionExpression(node);
|
32 | const declaresThis = declaresArguments;
|
33 | const LOCALS_SYMBOL = Symbol('locals');
|
34 | const getLocals = (node) => node[LOCALS_SYMBOL];
|
35 | const declareLocals = (node) => (node[LOCALS_SYMBOL] = node[LOCALS_SYMBOL] || new Set());
|
36 | const setLocal = (node, name) => declareLocals(node).add(name);
|
37 |
|
38 | function 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 | }
|
47 | function 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 |
|
80 | default:
|
81 | throw new Error('Unrecognized pattern type: ' + node.type);
|
82 | }
|
83 | }
|
84 | function 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 | }
|
92 | const 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 |
|
136 | const 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 | });
|
166 | function findGlobals(ast) {
|
167 | const globals = [];
|
168 |
|
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 | }
|
189 | exports.default = findGlobals;
|
190 |
|
\ | No newline at end of file |