Add semantic token highlighting for 'that' variable and comment file references in VS Code extension Add Phone_Text_Input and Currency_Input components with formatting utilities Implement client widgets, form standardization, and soft delete functionality Add modal scroll lock and update documentation Implement comprehensive modal system with form integration and validation Fix modal component instantiation using jQuery plugin API Implement modal system with responsive sizing, queuing, and validation support Implement form submission with validation, error handling, and loading states Implement country/state selectors with dynamic data loading and Bootstrap styling Revert Rsx::Route() highlighting in Blade/PHP files Target specific PHP scopes for Rsx::Route() highlighting in Blade Expand injection selector for Rsx::Route() highlighting Add custom syntax highlighting for Rsx::Route() and Rsx.Route() calls Update jqhtml packages to v2.2.165 Add bundle path validation for common mistakes (development mode only) Create Ajax_Select_Input widget and Rsx_Reference_Data controller Create Country_Select_Input widget with default country support Initialize Tom Select on Select_Input widgets Add Tom Select bundle for enhanced select dropdowns Implement ISO 3166 geographic data system for country/region selection Implement widget-based form system with disabled state support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1044 lines
31 KiB
JavaScript
1044 lines
31 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
var _renamer = require("./lib/renamer.js");
|
|
var _index = require("../index.js");
|
|
var _traverseForScope = require("./traverseForScope.js");
|
|
var _binding = require("./binding.js");
|
|
var _t = require("@babel/types");
|
|
var t = _t;
|
|
var _cache = require("../cache.js");
|
|
const globalsBuiltinLower = require("@babel/helper-globals/data/builtin-lower.json"),
|
|
globalsBuiltinUpper = require("@babel/helper-globals/data/builtin-upper.json");
|
|
const {
|
|
assignmentExpression,
|
|
callExpression,
|
|
cloneNode,
|
|
getBindingIdentifiers,
|
|
identifier,
|
|
isArrayExpression,
|
|
isBinary,
|
|
isCallExpression,
|
|
isClass,
|
|
isClassBody,
|
|
isClassDeclaration,
|
|
isExportAllDeclaration,
|
|
isExportDefaultDeclaration,
|
|
isExportNamedDeclaration,
|
|
isFunctionDeclaration,
|
|
isIdentifier,
|
|
isImportDeclaration,
|
|
isLiteral,
|
|
isMemberExpression,
|
|
isMethod,
|
|
isModuleSpecifier,
|
|
isNullLiteral,
|
|
isObjectExpression,
|
|
isProperty,
|
|
isPureish,
|
|
isRegExpLiteral,
|
|
isSuper,
|
|
isTaggedTemplateExpression,
|
|
isTemplateLiteral,
|
|
isThisExpression,
|
|
isUnaryExpression,
|
|
isVariableDeclaration,
|
|
expressionStatement,
|
|
matchesPattern,
|
|
memberExpression,
|
|
numericLiteral,
|
|
toIdentifier,
|
|
variableDeclaration,
|
|
variableDeclarator,
|
|
isRecordExpression,
|
|
isTupleExpression,
|
|
isObjectProperty,
|
|
isTopicReference,
|
|
isMetaProperty,
|
|
isPrivateName,
|
|
isExportDeclaration,
|
|
buildUndefinedNode,
|
|
sequenceExpression
|
|
} = _t;
|
|
function gatherNodeParts(node, parts) {
|
|
switch (node == null ? void 0 : node.type) {
|
|
default:
|
|
if (isImportDeclaration(node) || isExportDeclaration(node)) {
|
|
var _node$specifiers;
|
|
if ((isExportAllDeclaration(node) || isExportNamedDeclaration(node) || isImportDeclaration(node)) && node.source) {
|
|
gatherNodeParts(node.source, parts);
|
|
} else if ((isExportNamedDeclaration(node) || isImportDeclaration(node)) && (_node$specifiers = node.specifiers) != null && _node$specifiers.length) {
|
|
for (const e of node.specifiers) gatherNodeParts(e, parts);
|
|
} else if ((isExportDefaultDeclaration(node) || isExportNamedDeclaration(node)) && node.declaration) {
|
|
gatherNodeParts(node.declaration, parts);
|
|
}
|
|
} else if (isModuleSpecifier(node)) {
|
|
gatherNodeParts(node.local, parts);
|
|
} else if (isLiteral(node) && !isNullLiteral(node) && !isRegExpLiteral(node) && !isTemplateLiteral(node)) {
|
|
parts.push(node.value);
|
|
}
|
|
break;
|
|
case "MemberExpression":
|
|
case "OptionalMemberExpression":
|
|
case "JSXMemberExpression":
|
|
gatherNodeParts(node.object, parts);
|
|
gatherNodeParts(node.property, parts);
|
|
break;
|
|
case "Identifier":
|
|
case "JSXIdentifier":
|
|
parts.push(node.name);
|
|
break;
|
|
case "CallExpression":
|
|
case "OptionalCallExpression":
|
|
case "NewExpression":
|
|
gatherNodeParts(node.callee, parts);
|
|
break;
|
|
case "ObjectExpression":
|
|
case "ObjectPattern":
|
|
for (const e of node.properties) {
|
|
gatherNodeParts(e, parts);
|
|
}
|
|
break;
|
|
case "SpreadElement":
|
|
case "RestElement":
|
|
gatherNodeParts(node.argument, parts);
|
|
break;
|
|
case "ObjectProperty":
|
|
case "ObjectMethod":
|
|
case "ClassProperty":
|
|
case "ClassMethod":
|
|
case "ClassPrivateProperty":
|
|
case "ClassPrivateMethod":
|
|
gatherNodeParts(node.key, parts);
|
|
break;
|
|
case "ThisExpression":
|
|
parts.push("this");
|
|
break;
|
|
case "Super":
|
|
parts.push("super");
|
|
break;
|
|
case "Import":
|
|
case "ImportExpression":
|
|
parts.push("import");
|
|
break;
|
|
case "DoExpression":
|
|
parts.push("do");
|
|
break;
|
|
case "YieldExpression":
|
|
parts.push("yield");
|
|
gatherNodeParts(node.argument, parts);
|
|
break;
|
|
case "AwaitExpression":
|
|
parts.push("await");
|
|
gatherNodeParts(node.argument, parts);
|
|
break;
|
|
case "AssignmentExpression":
|
|
gatherNodeParts(node.left, parts);
|
|
break;
|
|
case "VariableDeclarator":
|
|
gatherNodeParts(node.id, parts);
|
|
break;
|
|
case "FunctionExpression":
|
|
case "FunctionDeclaration":
|
|
case "ClassExpression":
|
|
case "ClassDeclaration":
|
|
gatherNodeParts(node.id, parts);
|
|
break;
|
|
case "PrivateName":
|
|
gatherNodeParts(node.id, parts);
|
|
break;
|
|
case "ParenthesizedExpression":
|
|
gatherNodeParts(node.expression, parts);
|
|
break;
|
|
case "UnaryExpression":
|
|
case "UpdateExpression":
|
|
gatherNodeParts(node.argument, parts);
|
|
break;
|
|
case "MetaProperty":
|
|
gatherNodeParts(node.meta, parts);
|
|
gatherNodeParts(node.property, parts);
|
|
break;
|
|
case "JSXElement":
|
|
gatherNodeParts(node.openingElement, parts);
|
|
break;
|
|
case "JSXOpeningElement":
|
|
gatherNodeParts(node.name, parts);
|
|
break;
|
|
case "JSXFragment":
|
|
gatherNodeParts(node.openingFragment, parts);
|
|
break;
|
|
case "JSXOpeningFragment":
|
|
parts.push("Fragment");
|
|
break;
|
|
case "JSXNamespacedName":
|
|
gatherNodeParts(node.namespace, parts);
|
|
gatherNodeParts(node.name, parts);
|
|
break;
|
|
}
|
|
}
|
|
function resetScope(scope) {
|
|
{
|
|
scope.references = Object.create(null);
|
|
scope.uids = Object.create(null);
|
|
}
|
|
scope.bindings = Object.create(null);
|
|
scope.globals = Object.create(null);
|
|
}
|
|
function isAnonymousFunctionExpression(path) {
|
|
return path.isFunctionExpression() && !path.node.id || path.isArrowFunctionExpression();
|
|
}
|
|
{
|
|
var NOT_LOCAL_BINDING = Symbol.for("should not be considered a local binding");
|
|
}
|
|
const collectorVisitor = {
|
|
ForStatement(path) {
|
|
const declar = path.get("init");
|
|
if (declar.isVar()) {
|
|
const {
|
|
scope
|
|
} = path;
|
|
const parentScope = scope.getFunctionParent() || scope.getProgramParent();
|
|
parentScope.registerBinding("var", declar);
|
|
}
|
|
},
|
|
Declaration(path) {
|
|
if (path.isBlockScoped()) return;
|
|
if (path.isImportDeclaration()) return;
|
|
if (path.isExportDeclaration()) return;
|
|
const parent = path.scope.getFunctionParent() || path.scope.getProgramParent();
|
|
parent.registerDeclaration(path);
|
|
},
|
|
ImportDeclaration(path) {
|
|
const parent = path.scope.getBlockParent();
|
|
parent.registerDeclaration(path);
|
|
},
|
|
TSImportEqualsDeclaration(path) {
|
|
const parent = path.scope.getBlockParent();
|
|
parent.registerDeclaration(path);
|
|
},
|
|
ReferencedIdentifier(path, state) {
|
|
if (t.isTSQualifiedName(path.parent) && path.parent.right === path.node) {
|
|
return;
|
|
}
|
|
if (path.parentPath.isTSImportEqualsDeclaration()) return;
|
|
state.references.push(path);
|
|
},
|
|
ForXStatement(path, state) {
|
|
const left = path.get("left");
|
|
if (left.isPattern() || left.isIdentifier()) {
|
|
state.constantViolations.push(path);
|
|
} else if (left.isVar()) {
|
|
const {
|
|
scope
|
|
} = path;
|
|
const parentScope = scope.getFunctionParent() || scope.getProgramParent();
|
|
parentScope.registerBinding("var", left);
|
|
}
|
|
},
|
|
ExportDeclaration: {
|
|
exit(path) {
|
|
const {
|
|
node,
|
|
scope
|
|
} = path;
|
|
if (isExportAllDeclaration(node)) return;
|
|
const declar = node.declaration;
|
|
if (isClassDeclaration(declar) || isFunctionDeclaration(declar)) {
|
|
const id = declar.id;
|
|
if (!id) return;
|
|
const binding = scope.getBinding(id.name);
|
|
binding == null || binding.reference(path);
|
|
} else if (isVariableDeclaration(declar)) {
|
|
for (const decl of declar.declarations) {
|
|
for (const name of Object.keys(getBindingIdentifiers(decl))) {
|
|
const binding = scope.getBinding(name);
|
|
binding == null || binding.reference(path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
LabeledStatement(path) {
|
|
path.scope.getBlockParent().registerDeclaration(path);
|
|
},
|
|
AssignmentExpression(path, state) {
|
|
state.assignments.push(path);
|
|
},
|
|
UpdateExpression(path, state) {
|
|
state.constantViolations.push(path);
|
|
},
|
|
UnaryExpression(path, state) {
|
|
if (path.node.operator === "delete") {
|
|
state.constantViolations.push(path);
|
|
}
|
|
},
|
|
BlockScoped(path) {
|
|
let scope = path.scope;
|
|
if (scope.path === path) scope = scope.parent;
|
|
const parent = scope.getBlockParent();
|
|
parent.registerDeclaration(path);
|
|
if (path.isClassDeclaration() && path.node.id) {
|
|
const id = path.node.id;
|
|
const name = id.name;
|
|
path.scope.bindings[name] = path.scope.parent.getBinding(name);
|
|
}
|
|
},
|
|
CatchClause(path) {
|
|
path.scope.registerBinding("let", path);
|
|
},
|
|
Function(path) {
|
|
const params = path.get("params");
|
|
for (const param of params) {
|
|
path.scope.registerBinding("param", param);
|
|
}
|
|
if (path.isFunctionExpression() && path.node.id && !path.node.id[NOT_LOCAL_BINDING]) {
|
|
path.scope.registerBinding("local", path.get("id"), path);
|
|
}
|
|
},
|
|
ClassExpression(path) {
|
|
if (path.node.id && !path.node.id[NOT_LOCAL_BINDING]) {
|
|
path.scope.registerBinding("local", path.get("id"), path);
|
|
}
|
|
},
|
|
TSTypeAnnotation(path) {
|
|
path.skip();
|
|
}
|
|
};
|
|
let scopeVisitor;
|
|
let uid = 0;
|
|
class Scope {
|
|
constructor(path) {
|
|
this.uid = void 0;
|
|
this.path = void 0;
|
|
this.block = void 0;
|
|
this.inited = void 0;
|
|
this.labels = void 0;
|
|
this.bindings = void 0;
|
|
this.referencesSet = void 0;
|
|
this.globals = void 0;
|
|
this.uidsSet = void 0;
|
|
this.data = void 0;
|
|
this.crawling = void 0;
|
|
const {
|
|
node
|
|
} = path;
|
|
const cached = _cache.scope.get(node);
|
|
if ((cached == null ? void 0 : cached.path) === path) {
|
|
return cached;
|
|
}
|
|
_cache.scope.set(node, this);
|
|
this.uid = uid++;
|
|
this.block = node;
|
|
this.path = path;
|
|
this.labels = new Map();
|
|
this.inited = false;
|
|
{
|
|
Object.defineProperties(this, {
|
|
references: {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: Object.create(null)
|
|
},
|
|
uids: {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: Object.create(null)
|
|
}
|
|
});
|
|
}
|
|
}
|
|
get parent() {
|
|
var _parent;
|
|
let parent,
|
|
path = this.path;
|
|
do {
|
|
var _path;
|
|
const shouldSkip = path.key === "key" || path.listKey === "decorators";
|
|
path = path.parentPath;
|
|
if (shouldSkip && path.isMethod()) path = path.parentPath;
|
|
if ((_path = path) != null && _path.isScope()) parent = path;
|
|
} while (path && !parent);
|
|
return (_parent = parent) == null ? void 0 : _parent.scope;
|
|
}
|
|
get references() {
|
|
throw new Error("Scope#references is not available in Babel 8. Use Scope#referencesSet instead.");
|
|
}
|
|
get uids() {
|
|
throw new Error("Scope#uids is not available in Babel 8. Use Scope#uidsSet instead.");
|
|
}
|
|
generateDeclaredUidIdentifier(name) {
|
|
const id = this.generateUidIdentifier(name);
|
|
this.push({
|
|
id
|
|
});
|
|
return cloneNode(id);
|
|
}
|
|
generateUidIdentifier(name) {
|
|
return identifier(this.generateUid(name));
|
|
}
|
|
generateUid(name = "temp") {
|
|
name = toIdentifier(name).replace(/^_+/, "").replace(/\d+$/g, "");
|
|
let uid;
|
|
let i = 0;
|
|
do {
|
|
uid = `_${name}`;
|
|
if (i >= 11) uid += i - 1;else if (i >= 9) uid += i - 9;else if (i >= 1) uid += i + 1;
|
|
i++;
|
|
} while (this.hasLabel(uid) || this.hasBinding(uid) || this.hasGlobal(uid) || this.hasReference(uid));
|
|
const program = this.getProgramParent();
|
|
{
|
|
program.references[uid] = true;
|
|
program.uids[uid] = true;
|
|
}
|
|
return uid;
|
|
}
|
|
generateUidBasedOnNode(node, defaultName) {
|
|
const parts = [];
|
|
gatherNodeParts(node, parts);
|
|
let id = parts.join("$");
|
|
id = id.replace(/^_/, "") || defaultName || "ref";
|
|
return this.generateUid(id.slice(0, 20));
|
|
}
|
|
generateUidIdentifierBasedOnNode(node, defaultName) {
|
|
return identifier(this.generateUidBasedOnNode(node, defaultName));
|
|
}
|
|
isStatic(node) {
|
|
if (isThisExpression(node) || isSuper(node) || isTopicReference(node)) {
|
|
return true;
|
|
}
|
|
if (isIdentifier(node)) {
|
|
const binding = this.getBinding(node.name);
|
|
if (binding) {
|
|
return binding.constant;
|
|
} else {
|
|
return this.hasBinding(node.name);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
maybeGenerateMemoised(node, dontPush) {
|
|
if (this.isStatic(node)) {
|
|
return null;
|
|
} else {
|
|
const id = this.generateUidIdentifierBasedOnNode(node);
|
|
if (!dontPush) {
|
|
this.push({
|
|
id
|
|
});
|
|
return cloneNode(id);
|
|
}
|
|
return id;
|
|
}
|
|
}
|
|
checkBlockScopedCollisions(local, kind, name, id) {
|
|
if (kind === "param") return;
|
|
if (local.kind === "local") return;
|
|
const duplicate = kind === "let" || local.kind === "let" || local.kind === "const" || local.kind === "module" || local.kind === "param" && kind === "const";
|
|
if (duplicate) {
|
|
throw this.path.hub.buildError(id, `Duplicate declaration "${name}"`, TypeError);
|
|
}
|
|
}
|
|
rename(oldName, newName) {
|
|
const binding = this.getBinding(oldName);
|
|
if (binding) {
|
|
newName || (newName = this.generateUidIdentifier(oldName).name);
|
|
const renamer = new _renamer.default(binding, oldName, newName);
|
|
{
|
|
renamer.rename(arguments[2]);
|
|
}
|
|
}
|
|
}
|
|
dump() {
|
|
const sep = "-".repeat(60);
|
|
console.log(sep);
|
|
let scope = this;
|
|
do {
|
|
console.log("#", scope.block.type);
|
|
for (const name of Object.keys(scope.bindings)) {
|
|
const binding = scope.bindings[name];
|
|
console.log(" -", name, {
|
|
constant: binding.constant,
|
|
references: binding.references,
|
|
violations: binding.constantViolations.length,
|
|
kind: binding.kind
|
|
});
|
|
}
|
|
} while (scope = scope.parent);
|
|
console.log(sep);
|
|
}
|
|
hasLabel(name) {
|
|
return !!this.getLabel(name);
|
|
}
|
|
getLabel(name) {
|
|
return this.labels.get(name);
|
|
}
|
|
registerLabel(path) {
|
|
this.labels.set(path.node.label.name, path);
|
|
}
|
|
registerDeclaration(path) {
|
|
if (path.isLabeledStatement()) {
|
|
this.registerLabel(path);
|
|
} else if (path.isFunctionDeclaration()) {
|
|
this.registerBinding("hoisted", path.get("id"), path);
|
|
} else if (path.isVariableDeclaration()) {
|
|
const declarations = path.get("declarations");
|
|
const {
|
|
kind
|
|
} = path.node;
|
|
for (const declar of declarations) {
|
|
this.registerBinding(kind === "using" || kind === "await using" ? "const" : kind, declar);
|
|
}
|
|
} else if (path.isClassDeclaration()) {
|
|
if (path.node.declare) return;
|
|
this.registerBinding("let", path);
|
|
} else if (path.isImportDeclaration()) {
|
|
const isTypeDeclaration = path.node.importKind === "type" || path.node.importKind === "typeof";
|
|
const specifiers = path.get("specifiers");
|
|
for (const specifier of specifiers) {
|
|
const isTypeSpecifier = isTypeDeclaration || specifier.isImportSpecifier() && (specifier.node.importKind === "type" || specifier.node.importKind === "typeof");
|
|
this.registerBinding(isTypeSpecifier ? "unknown" : "module", specifier);
|
|
}
|
|
} else if (path.isExportDeclaration()) {
|
|
const declar = path.get("declaration");
|
|
if (declar.isClassDeclaration() || declar.isFunctionDeclaration() || declar.isVariableDeclaration()) {
|
|
this.registerDeclaration(declar);
|
|
}
|
|
} else {
|
|
this.registerBinding("unknown", path);
|
|
}
|
|
}
|
|
buildUndefinedNode() {
|
|
return buildUndefinedNode();
|
|
}
|
|
registerConstantViolation(path) {
|
|
const ids = path.getAssignmentIdentifiers();
|
|
for (const name of Object.keys(ids)) {
|
|
var _this$getBinding;
|
|
(_this$getBinding = this.getBinding(name)) == null || _this$getBinding.reassign(path);
|
|
}
|
|
}
|
|
registerBinding(kind, path, bindingPath = path) {
|
|
if (!kind) throw new ReferenceError("no `kind`");
|
|
if (path.isVariableDeclaration()) {
|
|
const declarators = path.get("declarations");
|
|
for (const declar of declarators) {
|
|
this.registerBinding(kind, declar);
|
|
}
|
|
return;
|
|
}
|
|
const parent = this.getProgramParent();
|
|
const ids = path.getOuterBindingIdentifiers(true);
|
|
for (const name of Object.keys(ids)) {
|
|
{
|
|
parent.references[name] = true;
|
|
}
|
|
for (const id of ids[name]) {
|
|
const local = this.getOwnBinding(name);
|
|
if (local) {
|
|
if (local.identifier === id) continue;
|
|
this.checkBlockScopedCollisions(local, kind, name, id);
|
|
}
|
|
if (local) {
|
|
local.reassign(bindingPath);
|
|
} else {
|
|
this.bindings[name] = new _binding.default({
|
|
identifier: id,
|
|
scope: this,
|
|
path: bindingPath,
|
|
kind: kind
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
addGlobal(node) {
|
|
this.globals[node.name] = node;
|
|
}
|
|
hasUid(name) {
|
|
{
|
|
let scope = this;
|
|
do {
|
|
if (scope.uids[name]) return true;
|
|
} while (scope = scope.parent);
|
|
return false;
|
|
}
|
|
}
|
|
hasGlobal(name) {
|
|
let scope = this;
|
|
do {
|
|
if (scope.globals[name]) return true;
|
|
} while (scope = scope.parent);
|
|
return false;
|
|
}
|
|
hasReference(name) {
|
|
{
|
|
return !!this.getProgramParent().references[name];
|
|
}
|
|
}
|
|
isPure(node, constantsOnly) {
|
|
if (isIdentifier(node)) {
|
|
const binding = this.getBinding(node.name);
|
|
if (!binding) return false;
|
|
if (constantsOnly) return binding.constant;
|
|
return true;
|
|
} else if (isThisExpression(node) || isMetaProperty(node) || isTopicReference(node) || isPrivateName(node)) {
|
|
return true;
|
|
} else if (isClass(node)) {
|
|
var _node$decorators;
|
|
if (node.superClass && !this.isPure(node.superClass, constantsOnly)) {
|
|
return false;
|
|
}
|
|
if (((_node$decorators = node.decorators) == null ? void 0 : _node$decorators.length) > 0) {
|
|
return false;
|
|
}
|
|
return this.isPure(node.body, constantsOnly);
|
|
} else if (isClassBody(node)) {
|
|
for (const method of node.body) {
|
|
if (!this.isPure(method, constantsOnly)) return false;
|
|
}
|
|
return true;
|
|
} else if (isBinary(node)) {
|
|
return this.isPure(node.left, constantsOnly) && this.isPure(node.right, constantsOnly);
|
|
} else if (isArrayExpression(node) || isTupleExpression(node)) {
|
|
for (const elem of node.elements) {
|
|
if (elem !== null && !this.isPure(elem, constantsOnly)) return false;
|
|
}
|
|
return true;
|
|
} else if (isObjectExpression(node) || isRecordExpression(node)) {
|
|
for (const prop of node.properties) {
|
|
if (!this.isPure(prop, constantsOnly)) return false;
|
|
}
|
|
return true;
|
|
} else if (isMethod(node)) {
|
|
var _node$decorators2;
|
|
if (node.computed && !this.isPure(node.key, constantsOnly)) return false;
|
|
if (((_node$decorators2 = node.decorators) == null ? void 0 : _node$decorators2.length) > 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
} else if (isProperty(node)) {
|
|
var _node$decorators3;
|
|
if (node.computed && !this.isPure(node.key, constantsOnly)) return false;
|
|
if (((_node$decorators3 = node.decorators) == null ? void 0 : _node$decorators3.length) > 0) {
|
|
return false;
|
|
}
|
|
if (isObjectProperty(node) || node.static) {
|
|
if (node.value !== null && !this.isPure(node.value, constantsOnly)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} else if (isUnaryExpression(node)) {
|
|
return this.isPure(node.argument, constantsOnly);
|
|
} else if (isTemplateLiteral(node)) {
|
|
for (const expression of node.expressions) {
|
|
if (!this.isPure(expression, constantsOnly)) return false;
|
|
}
|
|
return true;
|
|
} else if (isTaggedTemplateExpression(node)) {
|
|
return matchesPattern(node.tag, "String.raw") && !this.hasBinding("String", {
|
|
noGlobals: true
|
|
}) && this.isPure(node.quasi, constantsOnly);
|
|
} else if (isMemberExpression(node)) {
|
|
return !node.computed && isIdentifier(node.object) && node.object.name === "Symbol" && isIdentifier(node.property) && node.property.name !== "for" && !this.hasBinding("Symbol", {
|
|
noGlobals: true
|
|
});
|
|
} else if (isCallExpression(node)) {
|
|
return matchesPattern(node.callee, "Symbol.for") && !this.hasBinding("Symbol", {
|
|
noGlobals: true
|
|
}) && node.arguments.length === 1 && t.isStringLiteral(node.arguments[0]);
|
|
} else {
|
|
return isPureish(node);
|
|
}
|
|
}
|
|
setData(key, val) {
|
|
return this.data[key] = val;
|
|
}
|
|
getData(key) {
|
|
let scope = this;
|
|
do {
|
|
const data = scope.data[key];
|
|
if (data != null) return data;
|
|
} while (scope = scope.parent);
|
|
}
|
|
removeData(key) {
|
|
let scope = this;
|
|
do {
|
|
const data = scope.data[key];
|
|
if (data != null) scope.data[key] = null;
|
|
} while (scope = scope.parent);
|
|
}
|
|
init() {
|
|
if (!this.inited) {
|
|
this.inited = true;
|
|
this.crawl();
|
|
}
|
|
}
|
|
crawl() {
|
|
const path = this.path;
|
|
;
|
|
resetScope(this);
|
|
this.data = Object.create(null);
|
|
let scope = this;
|
|
do {
|
|
if (scope.crawling) return;
|
|
if (scope.path.isProgram()) {
|
|
break;
|
|
}
|
|
} while (scope = scope.parent);
|
|
const programParent = scope;
|
|
const state = {
|
|
references: [],
|
|
constantViolations: [],
|
|
assignments: []
|
|
};
|
|
this.crawling = true;
|
|
scopeVisitor || (scopeVisitor = _index.default.visitors.merge([{
|
|
Scope(path) {
|
|
resetScope(path.scope);
|
|
}
|
|
}, collectorVisitor]));
|
|
if (path.type !== "Program") {
|
|
const typeVisitors = scopeVisitor[path.type];
|
|
if (typeVisitors) {
|
|
for (const visit of typeVisitors.enter) {
|
|
visit.call(state, path, state);
|
|
}
|
|
}
|
|
}
|
|
{
|
|
path.traverse(scopeVisitor, state);
|
|
}
|
|
this.crawling = false;
|
|
for (const path of state.assignments) {
|
|
const ids = path.getAssignmentIdentifiers();
|
|
for (const name of Object.keys(ids)) {
|
|
if (path.scope.getBinding(name)) continue;
|
|
programParent.addGlobal(ids[name]);
|
|
}
|
|
path.scope.registerConstantViolation(path);
|
|
}
|
|
for (const ref of state.references) {
|
|
const binding = ref.scope.getBinding(ref.node.name);
|
|
if (binding) {
|
|
binding.reference(ref);
|
|
} else {
|
|
programParent.addGlobal(ref.node);
|
|
}
|
|
}
|
|
for (const path of state.constantViolations) {
|
|
path.scope.registerConstantViolation(path);
|
|
}
|
|
}
|
|
push(opts) {
|
|
let path = this.path;
|
|
if (path.isPattern()) {
|
|
path = this.getPatternParent().path;
|
|
} else if (!path.isBlockStatement() && !path.isProgram()) {
|
|
path = this.getBlockParent().path;
|
|
}
|
|
if (path.isSwitchStatement()) {
|
|
path = (this.getFunctionParent() || this.getProgramParent()).path;
|
|
}
|
|
const {
|
|
init,
|
|
unique,
|
|
kind = "var",
|
|
id
|
|
} = opts;
|
|
if (!init && !unique && (kind === "var" || kind === "let") && isAnonymousFunctionExpression(path) && isCallExpression(path.parent, {
|
|
callee: path.node
|
|
}) && path.parent.arguments.length <= path.node.params.length && isIdentifier(id)) {
|
|
path.pushContainer("params", id);
|
|
path.scope.registerBinding("param", path.get("params")[path.node.params.length - 1]);
|
|
return;
|
|
}
|
|
if (path.isLoop() || path.isCatchClause() || path.isFunction()) {
|
|
path.ensureBlock();
|
|
path = path.get("body");
|
|
}
|
|
const blockHoist = opts._blockHoist == null ? 2 : opts._blockHoist;
|
|
const dataKey = `declaration:${kind}:${blockHoist}`;
|
|
let declarPath = !unique && path.getData(dataKey);
|
|
if (!declarPath) {
|
|
const declar = variableDeclaration(kind, []);
|
|
declar._blockHoist = blockHoist;
|
|
[declarPath] = path.unshiftContainer("body", [declar]);
|
|
if (!unique) path.setData(dataKey, declarPath);
|
|
}
|
|
const declarator = variableDeclarator(id, init);
|
|
const len = declarPath.node.declarations.push(declarator);
|
|
path.scope.registerBinding(kind, declarPath.get("declarations")[len - 1]);
|
|
}
|
|
getProgramParent() {
|
|
let scope = this;
|
|
do {
|
|
if (scope.path.isProgram()) {
|
|
return scope;
|
|
}
|
|
} while (scope = scope.parent);
|
|
throw new Error("Couldn't find a Program");
|
|
}
|
|
getFunctionParent() {
|
|
let scope = this;
|
|
do {
|
|
if (scope.path.isFunctionParent()) {
|
|
return scope;
|
|
}
|
|
} while (scope = scope.parent);
|
|
return null;
|
|
}
|
|
getBlockParent() {
|
|
let scope = this;
|
|
do {
|
|
if (scope.path.isBlockParent()) {
|
|
return scope;
|
|
}
|
|
} while (scope = scope.parent);
|
|
throw new Error("We couldn't find a BlockStatement, For, Switch, Function, Loop or Program...");
|
|
}
|
|
getPatternParent() {
|
|
let scope = this;
|
|
do {
|
|
if (!scope.path.isPattern()) {
|
|
return scope.getBlockParent();
|
|
}
|
|
} while (scope = scope.parent.parent);
|
|
throw new Error("We couldn't find a BlockStatement, For, Switch, Function, Loop or Program...");
|
|
}
|
|
getAllBindings() {
|
|
const ids = Object.create(null);
|
|
let scope = this;
|
|
do {
|
|
for (const key of Object.keys(scope.bindings)) {
|
|
if (key in ids === false) {
|
|
ids[key] = scope.bindings[key];
|
|
}
|
|
}
|
|
scope = scope.parent;
|
|
} while (scope);
|
|
return ids;
|
|
}
|
|
bindingIdentifierEquals(name, node) {
|
|
return this.getBindingIdentifier(name) === node;
|
|
}
|
|
getBinding(name) {
|
|
let scope = this;
|
|
let previousPath;
|
|
do {
|
|
const binding = scope.getOwnBinding(name);
|
|
if (binding) {
|
|
var _previousPath;
|
|
if ((_previousPath = previousPath) != null && _previousPath.isPattern() && binding.kind !== "param" && binding.kind !== "local") {} else {
|
|
return binding;
|
|
}
|
|
} else if (!binding && name === "arguments" && scope.path.isFunction() && !scope.path.isArrowFunctionExpression()) {
|
|
break;
|
|
}
|
|
previousPath = scope.path;
|
|
} while (scope = scope.parent);
|
|
}
|
|
getOwnBinding(name) {
|
|
return this.bindings[name];
|
|
}
|
|
getBindingIdentifier(name) {
|
|
var _this$getBinding2;
|
|
return (_this$getBinding2 = this.getBinding(name)) == null ? void 0 : _this$getBinding2.identifier;
|
|
}
|
|
getOwnBindingIdentifier(name) {
|
|
const binding = this.bindings[name];
|
|
return binding == null ? void 0 : binding.identifier;
|
|
}
|
|
hasOwnBinding(name) {
|
|
return !!this.getOwnBinding(name);
|
|
}
|
|
hasBinding(name, opts) {
|
|
if (!name) return false;
|
|
let noGlobals;
|
|
let noUids;
|
|
let upToScope;
|
|
if (typeof opts === "object") {
|
|
noGlobals = opts.noGlobals;
|
|
noUids = opts.noUids;
|
|
upToScope = opts.upToScope;
|
|
} else if (typeof opts === "boolean") {
|
|
noGlobals = opts;
|
|
}
|
|
let scope = this;
|
|
do {
|
|
if (upToScope === scope) {
|
|
break;
|
|
}
|
|
if (scope.hasOwnBinding(name)) {
|
|
return true;
|
|
}
|
|
} while (scope = scope.parent);
|
|
if (!noUids && this.hasUid(name)) return true;
|
|
if (!noGlobals && Scope.globals.includes(name)) return true;
|
|
if (!noGlobals && Scope.contextVariables.includes(name)) return true;
|
|
return false;
|
|
}
|
|
parentHasBinding(name, opts) {
|
|
var _this$parent;
|
|
return (_this$parent = this.parent) == null ? void 0 : _this$parent.hasBinding(name, opts);
|
|
}
|
|
moveBindingTo(name, scope) {
|
|
const info = this.getBinding(name);
|
|
if (info) {
|
|
info.scope.removeOwnBinding(name);
|
|
info.scope = scope;
|
|
scope.bindings[name] = info;
|
|
}
|
|
}
|
|
removeOwnBinding(name) {
|
|
delete this.bindings[name];
|
|
}
|
|
removeBinding(name) {
|
|
var _this$getBinding3;
|
|
(_this$getBinding3 = this.getBinding(name)) == null || _this$getBinding3.scope.removeOwnBinding(name);
|
|
{
|
|
let scope = this;
|
|
do {
|
|
if (scope.uids[name]) {
|
|
scope.uids[name] = false;
|
|
}
|
|
} while (scope = scope.parent);
|
|
}
|
|
}
|
|
hoistVariables(emit = id => this.push({
|
|
id
|
|
})) {
|
|
this.crawl();
|
|
const seen = new Set();
|
|
for (const name of Object.keys(this.bindings)) {
|
|
const binding = this.bindings[name];
|
|
if (!binding) continue;
|
|
const {
|
|
path
|
|
} = binding;
|
|
if (!path.isVariableDeclarator()) continue;
|
|
const {
|
|
parent,
|
|
parentPath
|
|
} = path;
|
|
if (parent.kind !== "var" || seen.has(parent)) continue;
|
|
seen.add(path.parent);
|
|
let firstId;
|
|
const init = [];
|
|
for (const decl of parent.declarations) {
|
|
firstId != null ? firstId : firstId = decl.id;
|
|
if (decl.init) {
|
|
init.push(assignmentExpression("=", decl.id, decl.init));
|
|
}
|
|
const ids = Object.keys(getBindingIdentifiers(decl, false, true, true));
|
|
for (const name of ids) {
|
|
emit(identifier(name), decl.init != null);
|
|
}
|
|
}
|
|
if (parentPath.parentPath.isForXStatement({
|
|
left: parent
|
|
})) {
|
|
parentPath.replaceWith(firstId);
|
|
} else if (init.length === 0) {
|
|
parentPath.remove();
|
|
} else {
|
|
const expr = init.length === 1 ? init[0] : sequenceExpression(init);
|
|
if (parentPath.parentPath.isForStatement({
|
|
init: parent
|
|
})) {
|
|
parentPath.replaceWith(expr);
|
|
} else {
|
|
parentPath.replaceWith(expressionStatement(expr));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
exports.default = Scope;
|
|
Scope.globals = [...globalsBuiltinLower, ...globalsBuiltinUpper];
|
|
Scope.contextVariables = ["arguments", "undefined", "Infinity", "NaN"];
|
|
{
|
|
Scope.prototype._renameFromMap = function _renameFromMap(map, oldName, newName, value) {
|
|
if (map[oldName]) {
|
|
map[newName] = value;
|
|
map[oldName] = null;
|
|
}
|
|
};
|
|
Scope.prototype.traverse = function (node, opts, state) {
|
|
(0, _index.default)(node, opts, this, state, this.path);
|
|
};
|
|
Scope.prototype._generateUid = function _generateUid(name, i) {
|
|
let id = name;
|
|
if (i > 1) id += i;
|
|
return `_${id}`;
|
|
};
|
|
Scope.prototype.toArray = function toArray(node, i, arrayLikeIsIterable) {
|
|
if (isIdentifier(node)) {
|
|
const binding = this.getBinding(node.name);
|
|
if (binding != null && binding.constant && binding.path.isGenericType("Array")) {
|
|
return node;
|
|
}
|
|
}
|
|
if (isArrayExpression(node)) {
|
|
return node;
|
|
}
|
|
if (isIdentifier(node, {
|
|
name: "arguments"
|
|
})) {
|
|
return callExpression(memberExpression(memberExpression(memberExpression(identifier("Array"), identifier("prototype")), identifier("slice")), identifier("call")), [node]);
|
|
}
|
|
let helperName;
|
|
const args = [node];
|
|
if (i === true) {
|
|
helperName = "toConsumableArray";
|
|
} else if (typeof i === "number") {
|
|
args.push(numericLiteral(i));
|
|
helperName = "slicedToArray";
|
|
} else {
|
|
helperName = "toArray";
|
|
}
|
|
if (arrayLikeIsIterable) {
|
|
args.unshift(this.path.hub.addHelper(helperName));
|
|
helperName = "maybeArrayLike";
|
|
}
|
|
return callExpression(this.path.hub.addHelper(helperName), args);
|
|
};
|
|
Scope.prototype.getAllBindingsOfKind = function getAllBindingsOfKind(...kinds) {
|
|
const ids = Object.create(null);
|
|
for (const kind of kinds) {
|
|
let scope = this;
|
|
do {
|
|
for (const name of Object.keys(scope.bindings)) {
|
|
const binding = scope.bindings[name];
|
|
if (binding.kind === kind) ids[name] = binding;
|
|
}
|
|
scope = scope.parent;
|
|
} while (scope);
|
|
}
|
|
return ids;
|
|
};
|
|
Object.defineProperties(Scope.prototype, {
|
|
parentBlock: {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get() {
|
|
return this.path.parent;
|
|
}
|
|
},
|
|
hub: {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get() {
|
|
return this.path.hub;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
//# sourceMappingURL=index.js.map
|