mirror of
https://github.com/Sevichecc/Urara-Blog.git
synced 2025-05-06 07:19:14 +08:00
363 lines
No EOL
15 KiB
Text
363 lines
No EOL
15 KiB
Text
"use strict";
|
|
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
};
|
|
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
};
|
|
var _ScopeBase_declaredVariables, _ScopeBase_dynamic, _ScopeBase_staticCloseRef, _ScopeBase_dynamicCloseRef, _ScopeBase_globalCloseRef;
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ScopeBase = void 0;
|
|
const types_1 = require("@typescript-eslint/types");
|
|
const ScopeType_1 = require("./ScopeType");
|
|
const assert_1 = require("../assert");
|
|
const definition_1 = require("../definition");
|
|
const ID_1 = require("../ID");
|
|
const Reference_1 = require("../referencer/Reference");
|
|
const variable_1 = require("../variable");
|
|
/**
|
|
* Test if scope is strict
|
|
*/
|
|
function isStrictScope(scope, block, isMethodDefinition) {
|
|
var _a;
|
|
let body;
|
|
// When upper scope is exists and strict, inner scope is also strict.
|
|
if ((_a = scope.upper) === null || _a === void 0 ? void 0 : _a.isStrict) {
|
|
return true;
|
|
}
|
|
if (isMethodDefinition) {
|
|
return true;
|
|
}
|
|
if (scope.type === ScopeType_1.ScopeType.class ||
|
|
scope.type === ScopeType_1.ScopeType.conditionalType ||
|
|
scope.type === ScopeType_1.ScopeType.functionType ||
|
|
scope.type === ScopeType_1.ScopeType.mappedType ||
|
|
scope.type === ScopeType_1.ScopeType.module ||
|
|
scope.type === ScopeType_1.ScopeType.tsEnum ||
|
|
scope.type === ScopeType_1.ScopeType.tsModule ||
|
|
scope.type === ScopeType_1.ScopeType.type) {
|
|
return true;
|
|
}
|
|
if (scope.type === ScopeType_1.ScopeType.block || scope.type === ScopeType_1.ScopeType.switch) {
|
|
return false;
|
|
}
|
|
if (scope.type === ScopeType_1.ScopeType.function) {
|
|
const functionBody = block;
|
|
switch (functionBody.type) {
|
|
case types_1.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
if (functionBody.body.type !== types_1.AST_NODE_TYPES.BlockStatement) {
|
|
return false;
|
|
}
|
|
body = functionBody.body;
|
|
break;
|
|
case types_1.AST_NODE_TYPES.Program:
|
|
body = functionBody;
|
|
break;
|
|
default:
|
|
body = functionBody.body;
|
|
}
|
|
if (!body) {
|
|
return false;
|
|
}
|
|
}
|
|
else if (scope.type === ScopeType_1.ScopeType.global) {
|
|
body = block;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
// Search 'use strict' directive.
|
|
for (const stmt of body.body) {
|
|
if (stmt.type !== types_1.AST_NODE_TYPES.ExpressionStatement) {
|
|
break;
|
|
}
|
|
if (stmt.directive === 'use strict') {
|
|
return true;
|
|
}
|
|
const expr = stmt.expression;
|
|
if (expr.type !== types_1.AST_NODE_TYPES.Literal) {
|
|
break;
|
|
}
|
|
if (expr.raw === '"use strict"' || expr.raw === "'use strict'") {
|
|
return true;
|
|
}
|
|
if (expr.value === 'use strict') {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* Register scope
|
|
*/
|
|
function registerScope(scopeManager, scope) {
|
|
scopeManager.scopes.push(scope);
|
|
const scopes = scopeManager.nodeToScope.get(scope.block);
|
|
if (scopes) {
|
|
scopes.push(scope);
|
|
}
|
|
else {
|
|
scopeManager.nodeToScope.set(scope.block, [scope]);
|
|
}
|
|
}
|
|
const generator = (0, ID_1.createIdGenerator)();
|
|
const VARIABLE_SCOPE_TYPES = new Set([
|
|
ScopeType_1.ScopeType.classFieldInitializer,
|
|
ScopeType_1.ScopeType.classStaticBlock,
|
|
ScopeType_1.ScopeType.function,
|
|
ScopeType_1.ScopeType.global,
|
|
ScopeType_1.ScopeType.module,
|
|
ScopeType_1.ScopeType.tsModule,
|
|
]);
|
|
class ScopeBase {
|
|
constructor(scopeManager, type, upperScope, block, isMethodDefinition) {
|
|
/**
|
|
* A unique ID for this instance - primarily used to help debugging and testing
|
|
*/
|
|
this.$id = generator();
|
|
/**
|
|
* The array of child scopes. This does not include grandchild scopes.
|
|
* @public
|
|
*/
|
|
this.childScopes = [];
|
|
/**
|
|
* A map of the variables for each node in this scope.
|
|
* This is map is a pointer to the one in the parent ScopeManager instance
|
|
*/
|
|
_ScopeBase_declaredVariables.set(this, void 0);
|
|
/**
|
|
* Generally, through the lexical scoping of JS you can always know which variable an identifier in the source code
|
|
* refers to. There are a few exceptions to this rule. With `global` and `with` scopes you can only decide at runtime
|
|
* which variable a reference refers to.
|
|
* All those scopes are considered "dynamic".
|
|
*/
|
|
_ScopeBase_dynamic.set(this, void 0);
|
|
/**
|
|
* Whether this scope is created by a FunctionExpression.
|
|
* @public
|
|
*/
|
|
this.functionExpressionScope = false;
|
|
/**
|
|
* List of {@link Reference}s that are left to be resolved (i.e. which
|
|
* need to be linked to the variable they refer to).
|
|
*/
|
|
this.leftToResolve = [];
|
|
/**
|
|
* Any variable {@link Reference} found in this scope.
|
|
* This includes occurrences of local variables as well as variables from parent scopes (including the global scope).
|
|
* For local variables this also includes defining occurrences (like in a 'var' statement).
|
|
* In a 'function' scope this does not include the occurrences of the formal parameter in the parameter list.
|
|
* @public
|
|
*/
|
|
this.references = [];
|
|
/**
|
|
* The map from variable names to variable objects.
|
|
* @public
|
|
*/
|
|
this.set = new Map();
|
|
/**
|
|
* The {@link Reference}s that are not resolved with this scope.
|
|
* @public
|
|
*/
|
|
this.through = [];
|
|
/**
|
|
* The scoped {@link Variable}s of this scope.
|
|
* In the case of a 'function' scope this includes the automatic argument `arguments` as its first element, as well
|
|
* as all further formal arguments.
|
|
* This does not include variables which are defined in child scopes.
|
|
* @public
|
|
*/
|
|
this.variables = [];
|
|
_ScopeBase_staticCloseRef.set(this, (ref) => {
|
|
const resolve = () => {
|
|
const name = ref.identifier.name;
|
|
const variable = this.set.get(name);
|
|
if (!variable) {
|
|
return false;
|
|
}
|
|
if (!this.isValidResolution(ref, variable)) {
|
|
return false;
|
|
}
|
|
// make sure we don't match a type reference to a value variable
|
|
const isValidTypeReference = ref.isTypeReference && variable.isTypeVariable;
|
|
const isValidValueReference = ref.isValueReference && variable.isValueVariable;
|
|
if (!isValidTypeReference && !isValidValueReference) {
|
|
return false;
|
|
}
|
|
variable.references.push(ref);
|
|
ref.resolved = variable;
|
|
return true;
|
|
};
|
|
if (!resolve()) {
|
|
this.delegateToUpperScope(ref);
|
|
}
|
|
});
|
|
_ScopeBase_dynamicCloseRef.set(this, (ref) => {
|
|
// notify all names are through to global
|
|
let current = this;
|
|
do {
|
|
current.through.push(ref);
|
|
current = current.upper;
|
|
} while (current);
|
|
});
|
|
_ScopeBase_globalCloseRef.set(this, (ref, scopeManager) => {
|
|
// let/const/class declarations should be resolved statically.
|
|
// others should be resolved dynamically.
|
|
if (this.shouldStaticallyCloseForGlobal(ref, scopeManager)) {
|
|
__classPrivateFieldGet(this, _ScopeBase_staticCloseRef, "f").call(this, ref);
|
|
}
|
|
else {
|
|
__classPrivateFieldGet(this, _ScopeBase_dynamicCloseRef, "f").call(this, ref);
|
|
}
|
|
});
|
|
const upperScopeAsScopeBase = upperScope;
|
|
this.type = type;
|
|
__classPrivateFieldSet(this, _ScopeBase_dynamic, this.type === ScopeType_1.ScopeType.global || this.type === ScopeType_1.ScopeType.with, "f");
|
|
this.block = block;
|
|
this.variableScope = this.isVariableScope()
|
|
? this
|
|
: upperScopeAsScopeBase.variableScope;
|
|
this.upper = upperScope;
|
|
/**
|
|
* Whether 'use strict' is in effect in this scope.
|
|
* @member {boolean} Scope#isStrict
|
|
*/
|
|
this.isStrict = isStrictScope(this, block, isMethodDefinition);
|
|
if (upperScopeAsScopeBase) {
|
|
// this is guaranteed to be correct at runtime
|
|
upperScopeAsScopeBase.childScopes.push(this);
|
|
}
|
|
__classPrivateFieldSet(this, _ScopeBase_declaredVariables, scopeManager.declaredVariables, "f");
|
|
registerScope(scopeManager, this);
|
|
}
|
|
isVariableScope() {
|
|
return VARIABLE_SCOPE_TYPES.has(this.type);
|
|
}
|
|
shouldStaticallyClose() {
|
|
return !__classPrivateFieldGet(this, _ScopeBase_dynamic, "f");
|
|
}
|
|
shouldStaticallyCloseForGlobal(ref, scopeManager) {
|
|
// On global scope, let/const/class declarations should be resolved statically.
|
|
const name = ref.identifier.name;
|
|
const variable = this.set.get(name);
|
|
if (!variable) {
|
|
return false;
|
|
}
|
|
// variable exists on the scope
|
|
// in module mode, we can statically resolve everything, regardless of its decl type
|
|
if (scopeManager.isModule()) {
|
|
return true;
|
|
}
|
|
// in script mode, only certain cases should be statically resolved
|
|
// Example:
|
|
// a `var` decl is ignored by the runtime if it clashes with a global name
|
|
// this means that we should not resolve the reference to the variable
|
|
const defs = variable.defs;
|
|
return (defs.length > 0 &&
|
|
defs.every(def => {
|
|
var _a;
|
|
if (def.type === definition_1.DefinitionType.Variable &&
|
|
((_a = def.parent) === null || _a === void 0 ? void 0 : _a.type) === types_1.AST_NODE_TYPES.VariableDeclaration &&
|
|
def.parent.kind === 'var') {
|
|
return false;
|
|
}
|
|
return true;
|
|
}));
|
|
}
|
|
close(scopeManager) {
|
|
let closeRef;
|
|
if (this.shouldStaticallyClose()) {
|
|
closeRef = __classPrivateFieldGet(this, _ScopeBase_staticCloseRef, "f");
|
|
}
|
|
else if (this.type !== 'global') {
|
|
closeRef = __classPrivateFieldGet(this, _ScopeBase_dynamicCloseRef, "f");
|
|
}
|
|
else {
|
|
closeRef = __classPrivateFieldGet(this, _ScopeBase_globalCloseRef, "f");
|
|
}
|
|
// Try Resolving all references in this scope.
|
|
(0, assert_1.assert)(this.leftToResolve);
|
|
this.leftToResolve.forEach(ref => closeRef(ref, scopeManager));
|
|
this.leftToResolve = null;
|
|
return this.upper;
|
|
}
|
|
/**
|
|
* To override by function scopes.
|
|
* References in default parameters isn't resolved to variables which are in their function body.
|
|
*/
|
|
isValidResolution(_ref, _variable) {
|
|
return true;
|
|
}
|
|
delegateToUpperScope(ref) {
|
|
const upper = this.upper;
|
|
if (upper === null || upper === void 0 ? void 0 : upper.leftToResolve) {
|
|
upper.leftToResolve.push(ref);
|
|
}
|
|
this.through.push(ref);
|
|
}
|
|
addDeclaredVariablesOfNode(variable, node) {
|
|
if (node == null) {
|
|
return;
|
|
}
|
|
let variables = __classPrivateFieldGet(this, _ScopeBase_declaredVariables, "f").get(node);
|
|
if (variables == null) {
|
|
variables = [];
|
|
__classPrivateFieldGet(this, _ScopeBase_declaredVariables, "f").set(node, variables);
|
|
}
|
|
if (!variables.includes(variable)) {
|
|
variables.push(variable);
|
|
}
|
|
}
|
|
defineVariable(nameOrVariable, set, variables, node, def) {
|
|
const name = typeof nameOrVariable === 'string' ? nameOrVariable : nameOrVariable.name;
|
|
let variable = set.get(name);
|
|
if (!variable) {
|
|
variable =
|
|
typeof nameOrVariable === 'string'
|
|
? new variable_1.Variable(name, this)
|
|
: nameOrVariable;
|
|
set.set(name, variable);
|
|
variables.push(variable);
|
|
}
|
|
if (def) {
|
|
variable.defs.push(def);
|
|
this.addDeclaredVariablesOfNode(variable, def.node);
|
|
this.addDeclaredVariablesOfNode(variable, def.parent);
|
|
}
|
|
if (node) {
|
|
variable.identifiers.push(node);
|
|
}
|
|
}
|
|
defineIdentifier(node, def) {
|
|
this.defineVariable(node.name, this.set, this.variables, node, def);
|
|
}
|
|
defineLiteralIdentifier(node, def) {
|
|
this.defineVariable(node.value, this.set, this.variables, null, def);
|
|
}
|
|
referenceValue(node, assign = Reference_1.ReferenceFlag.Read, writeExpr, maybeImplicitGlobal, init = false) {
|
|
var _a;
|
|
const ref = new Reference_1.Reference(node, this, assign, writeExpr, maybeImplicitGlobal, init, Reference_1.ReferenceTypeFlag.Value);
|
|
this.references.push(ref);
|
|
(_a = this.leftToResolve) === null || _a === void 0 ? void 0 : _a.push(ref);
|
|
}
|
|
referenceType(node) {
|
|
var _a;
|
|
const ref = new Reference_1.Reference(node, this, Reference_1.ReferenceFlag.Read, null, null, false, Reference_1.ReferenceTypeFlag.Type);
|
|
this.references.push(ref);
|
|
(_a = this.leftToResolve) === null || _a === void 0 ? void 0 : _a.push(ref);
|
|
}
|
|
referenceDualValueType(node) {
|
|
var _a;
|
|
const ref = new Reference_1.Reference(node, this, Reference_1.ReferenceFlag.Read, null, null, false, Reference_1.ReferenceTypeFlag.Type | Reference_1.ReferenceTypeFlag.Value);
|
|
this.references.push(ref);
|
|
(_a = this.leftToResolve) === null || _a === void 0 ? void 0 : _a.push(ref);
|
|
}
|
|
}
|
|
exports.ScopeBase = ScopeBase;
|
|
_ScopeBase_declaredVariables = new WeakMap(), _ScopeBase_dynamic = new WeakMap(), _ScopeBase_staticCloseRef = new WeakMap(), _ScopeBase_dynamicCloseRef = new WeakMap(), _ScopeBase_globalCloseRef = new WeakMap();
|
|
//# sourceMappingURL=ScopeBase.js.map |