Skip to content

Commit 8b31daa

Browse files
committed
perf(linter/plugins): small optimizations to ScopeManager (#15334)
Follow-on after #14890. Small optimizations to `ScopeManager`. * Remove temp vars. * Test vars with `=== null` or `=== undefined` instead of `!`. * Avoid reading out of bounds of arrays. * Get length of array once before loop, rather than on each turn of loop. Also add comments about potential future optimizations.
1 parent a7d9f1d commit 8b31daa

File tree

1 file changed

+20
-19
lines changed

1 file changed

+20
-19
lines changed

apps/oxlint/src-js/plugins/scope.ts

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -207,29 +207,30 @@ export function isGlobalReference(node: ESTree.Node): boolean {
207207
}
208208

209209
const { name } = node;
210+
// TODO: Is this check required? Isn't an `Identifier`'s `name` property always a string?
210211
if (typeof name !== 'string') {
211212
return false;
212213
}
213214

214215
if (tsScopeManager === null) initTsScopeManager();
215-
const globalScope = tsScopeManager.scopes[0];
216-
if (!globalScope) return false;
216+
217+
const { scopes } = tsScopeManager;
218+
if (scopes.length === 0) return false;
219+
const globalScope = scopes[0];
217220

218221
// If the identifier is a reference to a global variable, the global scope should have a variable with the name
219222
const variable = globalScope.set.get(name);
220223

221224
// Global variables are not defined by any node, so they should have no definitions
222-
if (!variable || variable.defs.length > 0) {
225+
if (variable === undefined || variable.defs.length > 0) {
223226
return false;
224227
}
225228

226229
// If there is a variable by the same name exists in the global scope,
227230
// we need to check our node is one of its references
228231
const { references } = variable;
229-
230-
for (let i = 0; i < references.length; i++) {
231-
const reference = references[i];
232-
if (reference.identifier === node) {
232+
for (let i = 0, len = references.length; i < len; i++) {
233+
if (references[i].identifier === node) {
233234
return true;
234235
}
235236
}
@@ -266,20 +267,20 @@ export function getScope(node: ESTree.Node): Scope {
266267
const inner = node.type !== 'Program';
267268

268269
// Traverse up the AST to find a `Node` whose scope can be acquired.
269-
for (let current: any = node; current; current = current.parent) {
270-
const scope = tsScopeManager.acquire(current, inner);
271-
272-
if (scope) {
273-
if (scope.type === 'function-expression-name') {
274-
// @ts-expect-error // TODO: Our types don't quite align yet
275-
return scope.childScopes[0];
276-
}
277-
278-
// @ts-expect-error // TODO: Our types don't quite align yet
279-
return scope;
270+
do {
271+
// @ts-expect-error // TODO: Our types don't quite align yet
272+
const scope = tsScopeManager.acquire(node, inner) as Scope;
273+
if (scope !== null) {
274+
return scope.type === 'function-expression-name' ? scope.childScopes[0] : scope;
280275
}
281-
}
282276

277+
// TODO: AST nodes' `parent` property should not be optional.
278+
// TODO: `TSParameterProperty` type should have a `parent` property.
279+
// @ts-expect-error
280+
node = node.parent;
281+
} while (node !== null);
282+
283+
// TODO: Is it possible to get here? Doesn't `Program` always have a scope?
283284
// @ts-expect-error // TODO: Our types don't quite align yet
284285
return tsScopeManager.scopes[0];
285286
}

0 commit comments

Comments
 (0)