You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
6.5 KiB
190 lines
6.5 KiB
"use strict"; |
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |
|
}) : (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
o[k2] = m[k]; |
|
})); |
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
|
Object.defineProperty(o, "default", { enumerable: true, value: v }); |
|
}) : function(o, v) { |
|
o["default"] = v; |
|
}); |
|
var __importStar = (this && this.__importStar) || function (mod) { |
|
if (mod && mod.__esModule) return mod; |
|
var result = {}; |
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
|
__setModuleDefault(result, mod); |
|
return result; |
|
}; |
|
var __importDefault = (this && this.__importDefault) || function (mod) { |
|
return (mod && mod.__esModule) ? mod : { "default": mod }; |
|
}; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
const assert_never_1 = __importDefault(require("assert-never")); |
|
const babel_walk_1 = require("babel-walk"); |
|
const t = __importStar(require("@babel/types")); |
|
const reference_1 = __importDefault(require("./reference")); |
|
const isScope = (node) => t.isFunctionParent(node) || t.isProgram(node); |
|
const isBlockScope = (node) => t.isBlockStatement(node) || isScope(node); |
|
const declaresArguments = (node) => t.isFunction(node) && !t.isArrowFunctionExpression(node); |
|
const declaresThis = declaresArguments; |
|
const LOCALS_SYMBOL = Symbol('locals'); |
|
const getLocals = (node) => node[LOCALS_SYMBOL]; |
|
const declareLocals = (node) => (node[LOCALS_SYMBOL] = node[LOCALS_SYMBOL] || new Set()); |
|
const setLocal = (node, name) => declareLocals(node).add(name); |
|
// First pass |
|
function declareFunction(node) { |
|
for (const param of node.params) { |
|
declarePattern(param, node); |
|
} |
|
const id = node.id; |
|
if (id) { |
|
setLocal(node, id.name); |
|
} |
|
} |
|
function declarePattern(node, parent) { |
|
switch (node.type) { |
|
case 'Identifier': |
|
setLocal(parent, node.name); |
|
break; |
|
case 'ObjectPattern': |
|
for (const prop of node.properties) { |
|
switch (prop.type) { |
|
case 'RestElement': |
|
declarePattern(prop.argument, parent); |
|
break; |
|
case 'ObjectProperty': |
|
declarePattern(prop.value, parent); |
|
break; |
|
default: |
|
assert_never_1.default(prop); |
|
break; |
|
} |
|
} |
|
break; |
|
case 'ArrayPattern': |
|
for (const element of node.elements) { |
|
if (element) |
|
declarePattern(element, parent); |
|
} |
|
break; |
|
case 'RestElement': |
|
declarePattern(node.argument, parent); |
|
break; |
|
case 'AssignmentPattern': |
|
declarePattern(node.left, parent); |
|
break; |
|
// istanbul ignore next |
|
default: |
|
throw new Error('Unrecognized pattern type: ' + node.type); |
|
} |
|
} |
|
function declareModuleSpecifier(node, _state, parents) { |
|
for (let i = parents.length - 2; i >= 0; i--) { |
|
if (isScope(parents[i])) { |
|
setLocal(parents[i], node.local.name); |
|
return; |
|
} |
|
} |
|
} |
|
const firstPass = babel_walk_1.ancestor({ |
|
VariableDeclaration(node, _state, parents) { |
|
for (let i = parents.length - 2; i >= 0; i--) { |
|
if (node.kind === 'var' |
|
? t.isFunctionParent(parents[i]) |
|
: isBlockScope(parents[i])) { |
|
for (const declaration of node.declarations) { |
|
declarePattern(declaration.id, parents[i]); |
|
} |
|
return; |
|
} |
|
} |
|
}, |
|
FunctionDeclaration(node, _state, parents) { |
|
if (node.id) { |
|
for (let i = parents.length - 2; i >= 0; i--) { |
|
if (isScope(parents[i])) { |
|
setLocal(parents[i], node.id.name); |
|
return; |
|
} |
|
} |
|
} |
|
}, |
|
Function: declareFunction, |
|
ClassDeclaration(node, _state, parents) { |
|
for (let i = parents.length - 2; i >= 0; i--) { |
|
if (isScope(parents[i])) { |
|
setLocal(parents[i], node.id.name); |
|
return; |
|
} |
|
} |
|
}, |
|
TryStatement(node) { |
|
if (node.handler === null) |
|
return; |
|
if (node.handler.param === null) |
|
return; |
|
declarePattern(node.handler.param, node.handler); |
|
}, |
|
ImportDefaultSpecifier: declareModuleSpecifier, |
|
ImportSpecifier: declareModuleSpecifier, |
|
ImportNamespaceSpecifier: declareModuleSpecifier, |
|
}); |
|
// Second pass |
|
const secondPass = babel_walk_1.ancestor({ |
|
Identifier(node, state, parents) { |
|
var _a; |
|
const name = node.name; |
|
if (name === 'undefined') |
|
return; |
|
const lastParent = parents[parents.length - 2]; |
|
if (lastParent) { |
|
if (!reference_1.default(node, lastParent)) |
|
return; |
|
for (const parent of parents) { |
|
if (name === 'arguments' && declaresArguments(parent)) { |
|
return; |
|
} |
|
if ((_a = getLocals(parent)) === null || _a === void 0 ? void 0 : _a.has(name)) { |
|
return; |
|
} |
|
} |
|
} |
|
state.globals.push(node); |
|
}, |
|
ThisExpression(node, state, parents) { |
|
for (const parent of parents) { |
|
if (declaresThis(parent)) { |
|
return; |
|
} |
|
} |
|
state.globals.push(node); |
|
}, |
|
}); |
|
function findGlobals(ast) { |
|
const globals = []; |
|
// istanbul ignore if |
|
if (!t.isNode(ast)) { |
|
throw new TypeError('Source must be a Babylon AST'); |
|
} |
|
firstPass(ast, undefined); |
|
secondPass(ast, { globals }); |
|
const groupedGlobals = new Map(); |
|
for (const node of globals) { |
|
const name = node.type === 'ThisExpression' ? 'this' : node.name; |
|
const existing = groupedGlobals.get(name); |
|
if (existing) { |
|
existing.push(node); |
|
} |
|
else { |
|
groupedGlobals.set(name, [node]); |
|
} |
|
} |
|
return [...groupedGlobals] |
|
.map(([name, nodes]) => ({ name, nodes })) |
|
.sort((a, b) => (a.name < b.name ? -1 : 1)); |
|
} |
|
exports.default = findGlobals; |
|
//# sourceMappingURL=globals.js.map
|