mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-29 06:32:28 +00:00
refactor(routes): share CommonJS checks and trim per-node work
- `isCommonJsGlobal`/`isModuleExports` in lexical-bindings replace the two copies in fetch-wrapper and framework-route-facts (both resolve the same scope from the same start position). - LEXICAL_FUNCTION_TYPES is derived from the TypeScript FUNCTION_NODE_TYPES instead of a third hand-kept copy; the drift test still pins it. - `unwrap` reads UNWRAPPED_TYPES, the set the cursor walk mirrors, and the class-body region is no longer shadowed under the name `deferred`. - framework-route-facts reads each node's type once per loop iteration. - The position index returns the latest-starting scope when it already contains the point, before the max-end tree search; that entry is the search's rightmost match. - carried() returns a shared empty set for argument forms that cannot carry a value, the resolution file set is built without intermediate arrays, and the routes phase reads the call list once. No behavior change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d8833c7ddf
commit
3db8657ba7
6 changed files with 78 additions and 69 deletions
|
|
@ -203,6 +203,9 @@ function wrapIndex(files: ReadonlyMap<string, FileIndex>, size: number): Positio
|
||||||
|
|
||||||
const endIdx = findLastStartLteIndex(file.entries, line, col);
|
const endIdx = findLastStartLteIndex(file.entries, line, col);
|
||||||
if (endIdx < 0) return undefined;
|
if (endIdx < 0) return undefined;
|
||||||
|
// The innermost scope usually starts last; it is then the rightmost match.
|
||||||
|
const latest = file.entries[endIdx];
|
||||||
|
if (latest && endIsAtOrAfter(latest.range, line, col)) return latest.id;
|
||||||
|
|
||||||
const match = findLastContainingEntry(file, endIdx, line, col);
|
const match = findLastContainingEntry(file, endIdx, line, col);
|
||||||
return match < 0 ? undefined : file.entries[match]!.id;
|
return match < 0 ? undefined : file.entries[match]!.id;
|
||||||
|
|
|
||||||
|
|
@ -1566,12 +1566,14 @@ export async function runChunkedParseAndResolve(
|
||||||
|
|
||||||
const routeFilePaths = new Set(allPaths);
|
const routeFilePaths = new Set(allPaths);
|
||||||
const routeResolutionConfigs = new Map<SupportedLanguages, unknown>();
|
const routeResolutionConfigs = new Map<SupportedLanguages, unknown>();
|
||||||
const resolutionFilePaths = new Set([
|
const resolutionFilePaths = new Set<string>();
|
||||||
...allRouteFacts.map((file) => file.filePath),
|
for (const facts of [
|
||||||
...allFetchWrapperDefs.map((definition) => definition.filePath),
|
allRouteFacts,
|
||||||
...allFetchWrapperCalls.map((call) => call.filePath),
|
allFetchWrapperDefs,
|
||||||
...allFetchWrapperReexports.map((reexport) => reexport.filePath),
|
allFetchWrapperCalls,
|
||||||
]);
|
allFetchWrapperReexports,
|
||||||
|
] as const)
|
||||||
|
for (const { filePath } of facts) resolutionFilePaths.add(filePath);
|
||||||
for (const filePath of resolutionFilePaths) {
|
for (const filePath of resolutionFilePaths) {
|
||||||
const language = getLanguageFromFilename(filePath);
|
const language = getLanguageFromFilename(filePath);
|
||||||
if (language === null || routeResolutionConfigs.has(language)) continue;
|
if (language === null || routeResolutionConfigs.has(language)) continue;
|
||||||
|
|
|
||||||
|
|
@ -507,9 +507,10 @@ export const routesPhase: PipelinePhase<RoutesOutput> = {
|
||||||
(n): n is string => typeof n === 'string' && n.trim().length > 0,
|
(n): n is string => typeof n === 'string' && n.trim().length > 0,
|
||||||
);
|
);
|
||||||
// The index is only worth building when a candidate call can match a route.
|
// The index is only worth building when a candidate call can match a route.
|
||||||
if (routeRegistry.size > 0 && (allFetchWrapperCalls?.length ?? 0) > 0) {
|
const wrapperCalls = allFetchWrapperCalls ?? [];
|
||||||
|
if (routeRegistry.size > 0 && wrapperCalls.length > 0) {
|
||||||
const wrappers = buildFetchWrapperIndex(allFetchWrapperDefs ?? [], configuredWrappers);
|
const wrappers = buildFetchWrapperIndex(allFetchWrapperDefs ?? [], configuredWrappers);
|
||||||
for (const call of allFetchWrapperCalls ?? []) {
|
for (const call of wrapperCalls) {
|
||||||
if (wrappers.isWrapperCall(call)) allFetchCalls.push(call);
|
if (wrappers.isWrapperCall(call)) allFetchCalls.push(call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import {
|
||||||
bindingKey,
|
bindingKey,
|
||||||
createLexicalBindings,
|
createLexicalBindings,
|
||||||
importBindingKey,
|
importBindingKey,
|
||||||
|
isCommonJsGlobal,
|
||||||
|
isModuleExports,
|
||||||
LEXICAL_FUNCTION_TYPES,
|
LEXICAL_FUNCTION_TYPES,
|
||||||
parameterPattern,
|
parameterPattern,
|
||||||
patternBindingNames,
|
patternBindingNames,
|
||||||
|
|
@ -76,15 +78,21 @@ function calleeName(node: Parser.SyntaxNode | null): string | undefined {
|
||||||
return parts.reverse().join('.');
|
return parts.reverse().join('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
function unwrap(node: Node | null): Node | null {
|
|
||||||
while (node && (TRANSPARENT_EXPRESSION_TYPES.has(node.type) || node.type === 'await_expression'))
|
|
||||||
node = firstNamed(node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
const UNWRAPPED_TYPES: ReadonlySet<string> = new Set([
|
const UNWRAPPED_TYPES: ReadonlySet<string> = new Set([
|
||||||
...TRANSPARENT_EXPRESSION_TYPES,
|
...TRANSPARENT_EXPRESSION_TYPES,
|
||||||
'await_expression',
|
'await_expression',
|
||||||
]);
|
]);
|
||||||
|
function unwrap(node: Node | null): Node | null {
|
||||||
|
while (node && UNWRAPPED_TYPES.has(node.type)) node = firstNamed(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
/** Argument forms that can carry a parameter's value into a call. */
|
||||||
|
const CARRYING_TYPES: ReadonlySet<string> = new Set([
|
||||||
|
'identifier',
|
||||||
|
'template_string',
|
||||||
|
'binary_expression',
|
||||||
|
]);
|
||||||
|
const NO_BINDINGS: ReadonlySet<string> = new Set();
|
||||||
const SKIPPED_TYPES: ReadonlySet<string> = new Set([
|
const SKIPPED_TYPES: ReadonlySet<string> = new Set([
|
||||||
'comment',
|
'comment',
|
||||||
'type_annotation',
|
'type_annotation',
|
||||||
|
|
@ -312,16 +320,10 @@ export function createFetchWrapperContext(
|
||||||
exported(node, name);
|
exported(node, name);
|
||||||
else if (node) exportedValues.push({ value: node, name });
|
else if (node) exportedValues.push({ value: node, name });
|
||||||
};
|
};
|
||||||
const commonJsGlobal = (node: Node | null, name: string) =>
|
|
||||||
node?.type === 'identifier' && node.text === name && bindings.isGlobal(node, name);
|
|
||||||
const moduleExports = (node: Node | null) =>
|
|
||||||
node?.type === 'member_expression' &&
|
|
||||||
node.childForFieldName('property')?.text === 'exports' &&
|
|
||||||
commonJsGlobal(node.childForFieldName('object'), 'module');
|
|
||||||
// `module.exports = …`, `module.exports.name = …` and `exports.name = …`.
|
// `module.exports = …`, `module.exports.name = …` and `exports.name = …`.
|
||||||
const commonJsExport = (left: Node | null, right: Node | null) => {
|
const commonJsExport = (left: Node | null, right: Node | null) => {
|
||||||
if (left?.type !== 'member_expression') return;
|
if (left?.type !== 'member_expression') return;
|
||||||
if (moduleExports(left)) {
|
if (isModuleExports(bindings, left)) {
|
||||||
const value = unwrap(right);
|
const value = unwrap(right);
|
||||||
if (value?.type !== 'object') return exportValue(value, 'default');
|
if (value?.type !== 'object') return exportValue(value, 'default');
|
||||||
for (const member of value.namedChildren) {
|
for (const member of value.namedChildren) {
|
||||||
|
|
@ -343,7 +345,7 @@ export function createFetchWrapperContext(
|
||||||
const property = left.childForFieldName('property');
|
const property = left.childForFieldName('property');
|
||||||
if (
|
if (
|
||||||
property?.type === 'property_identifier' &&
|
property?.type === 'property_identifier' &&
|
||||||
(commonJsGlobal(object, 'exports') || moduleExports(object))
|
(isCommonJsGlobal(bindings, object, 'exports') || isModuleExports(bindings, object))
|
||||||
)
|
)
|
||||||
exportValue(right, property.text);
|
exportValue(right, property.text);
|
||||||
};
|
};
|
||||||
|
|
@ -479,13 +481,13 @@ export function createFetchWrapperContext(
|
||||||
}
|
}
|
||||||
if (type === 'class_declaration' || type === 'class') {
|
if (type === 'class_declaration' || type === 'class') {
|
||||||
const node = cursor.currentNode;
|
const node = cursor.currentNode;
|
||||||
const deferred = region(node);
|
const classBody = region(node);
|
||||||
const name = node.childForFieldName('name');
|
const name = node.childForFieldName('name');
|
||||||
const stored = storedAt(frames, first, cursor.currentFieldName);
|
const stored = storedAt(frames, first, cursor.currentFieldName);
|
||||||
bindRegion(stored ?? name, deferred);
|
bindRegion(stored ?? name, classBody);
|
||||||
if (stored && name) bindRegion(name, deferred);
|
if (stored && name) bindRegion(name, classBody);
|
||||||
if (!stored && !name) active.edges.add(deferred);
|
if (!stored && !name) active.edges.add(classBody);
|
||||||
return { ...frame, children: 'class', inner: deferred };
|
return { ...frame, children: 'class', inner: classBody };
|
||||||
}
|
}
|
||||||
if (type === 'field_definition' || type === 'public_field_definition') {
|
if (type === 'field_definition' || type === 'public_field_definition') {
|
||||||
const isStatic = cursor.currentNode.children.some((child) => child.type === 'static');
|
const isStatic = cursor.currentNode.children.some((child) => child.type === 'static');
|
||||||
|
|
@ -576,13 +578,11 @@ export function createFetchWrapperContext(
|
||||||
};
|
};
|
||||||
const argumentBindings = new Map<number, ReadonlySet<string>>();
|
const argumentBindings = new Map<number, ReadonlySet<string>>();
|
||||||
const carried = (argument: Node | undefined): ReadonlySet<string> => {
|
const carried = (argument: Node | undefined): ReadonlySet<string> => {
|
||||||
if (!argument) return new Set();
|
if (!argument || !CARRYING_TYPES.has(argument.type)) return NO_BINDINGS;
|
||||||
const cached = argumentBindings.get(argument.id);
|
const cached = argumentBindings.get(argument.id);
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
const result = new Set<string>();
|
const result = new Set<string>();
|
||||||
const stack = ['identifier', 'template_string', 'binary_expression'].includes(argument.type)
|
const stack = [argument];
|
||||||
? [argument]
|
|
||||||
: [];
|
|
||||||
while (stack.length) {
|
while (stack.length) {
|
||||||
const node = stack.pop()!;
|
const node = stack.pop()!;
|
||||||
if (node.type === 'identifier') {
|
if (node.type === 'identifier') {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import type { FrameworkExpression, FrameworkRouteFacts } from './framework-route
|
||||||
import {
|
import {
|
||||||
createLexicalBindings,
|
createLexicalBindings,
|
||||||
importBindingKey,
|
importBindingKey,
|
||||||
|
isCommonJsGlobal,
|
||||||
|
isModuleExports,
|
||||||
LEXICAL_FUNCTION_TYPES,
|
LEXICAL_FUNCTION_TYPES,
|
||||||
parameterPattern,
|
parameterPattern,
|
||||||
patternBindingNames,
|
patternBindingNames,
|
||||||
|
|
@ -201,11 +203,12 @@ export function extractFrameworkRouteFacts(
|
||||||
const nodes: { node: Node; enclosingFunction?: Node }[] = [{ node: tree.rootNode }];
|
const nodes: { node: Node; enclosingFunction?: Node }[] = [{ node: tree.rootNode }];
|
||||||
while (nodes.length) {
|
while (nodes.length) {
|
||||||
const { node, enclosingFunction } = nodes.pop()!;
|
const { node, enclosingFunction } = nodes.pop()!;
|
||||||
if (node.type === 'ERROR') continue;
|
const type = node.type;
|
||||||
const childFunction = LEXICAL_FUNCTION_TYPES.has(node.type) ? node : enclosingFunction;
|
if (type === 'ERROR') continue;
|
||||||
|
const childFunction = LEXICAL_FUNCTION_TYPES.has(type) ? node : enclosingFunction;
|
||||||
for (const child of children(node).reverse())
|
for (const child of children(node).reverse())
|
||||||
nodes.push({ node: child, enclosingFunction: childFunction });
|
nodes.push({ node: child, enclosingFunction: childFunction });
|
||||||
if (node.type === 'import_statement') {
|
if (type === 'import_statement') {
|
||||||
// ESM decomposition already carries precise aliases/type-only flags. CJS
|
// ESM decomposition already carries precise aliases/type-only flags. CJS
|
||||||
// imports are intentionally handled at their AST calls to guard require.
|
// imports are intentionally handled at their AST calls to guard require.
|
||||||
const position = `${node.startPosition.row + 1 + lineOffset}:${node.startPosition.column}`;
|
const position = `${node.startPosition.row + 1 + lineOffset}:${node.startPosition.column}`;
|
||||||
|
|
@ -224,7 +227,7 @@ export function extractFrameworkRouteFacts(
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (node.type === 'variable_declarator') {
|
} else if (type === 'variable_declarator') {
|
||||||
const name = node.childForFieldName('name');
|
const name = node.childForFieldName('name');
|
||||||
const value = node.childForFieldName('value');
|
const value = node.childForFieldName('value');
|
||||||
if (value && enclosingFunction) {
|
if (value && enclosingFunction) {
|
||||||
|
|
@ -241,17 +244,14 @@ export function extractFrameworkRouteFacts(
|
||||||
name,
|
name,
|
||||||
value && FUNCTION_TYPES.includes(value.type) ? functionValue(value) : expression(value),
|
value && FUNCTION_TYPES.includes(value.type) ? functionValue(value) : expression(value),
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (type === 'function_declaration' || type === 'generator_function_declaration') {
|
||||||
node.type === 'function_declaration' ||
|
|
||||||
node.type === 'generator_function_declaration'
|
|
||||||
) {
|
|
||||||
const name = node.childForFieldName('name');
|
const name = node.childForFieldName('name');
|
||||||
if (name && enclosingFunction) {
|
if (name && enclosingFunction) {
|
||||||
const id = bindingId(name);
|
const id = bindingId(name);
|
||||||
if (id && parametersOf(enclosingFunction).has(id)) invalid.add(id);
|
if (id && parametersOf(enclosingFunction).has(id)) invalid.add(id);
|
||||||
}
|
}
|
||||||
if (name) bind(name, functionValue(node));
|
if (name) bind(name, functionValue(node));
|
||||||
} else if (node.type === 'export_statement') {
|
} else if (type === 'export_statement') {
|
||||||
const sourceNode = node.childForFieldName('source');
|
const sourceNode = node.childForFieldName('source');
|
||||||
const source = sourceNode && plainString(sourceNode);
|
const source = sourceNode && plainString(sourceNode);
|
||||||
if (node.children.some((child) => child.type === 'type')) continue;
|
if (node.children.some((child) => child.type === 'type')) continue;
|
||||||
|
|
@ -302,31 +302,26 @@ export function extractFrameworkRouteFacts(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
node.type === 'assignment_expression' ||
|
type === 'assignment_expression' ||
|
||||||
node.type === 'augmented_assignment_expression' ||
|
type === 'augmented_assignment_expression' ||
|
||||||
node.type === 'update_expression' ||
|
type === 'update_expression' ||
|
||||||
node.type === 'for_in_statement' ||
|
type === 'for_in_statement' ||
|
||||||
(node.type === 'unary_expression' && node.children.some((child) => child.type === 'delete'))
|
(type === 'unary_expression' && node.children.some((child) => child.type === 'delete'))
|
||||||
) {
|
) {
|
||||||
const left = node.childForFieldName('left') ?? node.childForFieldName('argument');
|
const left = node.childForFieldName('left') ?? node.childForFieldName('argument');
|
||||||
const right = node.childForFieldName('right');
|
const right = node.childForFieldName('right');
|
||||||
const object = left?.childForFieldName('object');
|
const object = left?.childForFieldName('object');
|
||||||
const property = left?.childForFieldName('property');
|
const property = left?.childForFieldName('property');
|
||||||
if (left?.type === 'identifier' && left.text === 'exports' && isGlobal(left, 'exports'))
|
if (isCommonJsGlobal(lexical, left, 'exports')) cjsShortcutDetached = true;
|
||||||
cjsShortcutDetached = true;
|
|
||||||
const moduleExports = (candidate: Node | null | undefined): boolean =>
|
|
||||||
candidate?.type === 'member_expression' &&
|
|
||||||
candidate.childForFieldName('object')?.text === 'module' &&
|
|
||||||
candidate.childForFieldName('property')?.text === 'exports' &&
|
|
||||||
isGlobal(candidate, 'module');
|
|
||||||
const writesExportProperty =
|
const writesExportProperty =
|
||||||
moduleExports(object) || (object?.text === 'exports' && isGlobal(object, 'exports'));
|
isModuleExports(lexical, object) || isCommonJsGlobal(lexical, object, 'exports');
|
||||||
if (
|
if (
|
||||||
(left?.type === 'subscript_expression' && writesExportProperty) ||
|
(left?.type === 'subscript_expression' && writesExportProperty) ||
|
||||||
(node.type !== 'assignment_expression' && (moduleExports(left) || writesExportProperty))
|
(type !== 'assignment_expression' &&
|
||||||
|
(isModuleExports(lexical, left) || writesExportProperty))
|
||||||
)
|
)
|
||||||
cjsUnknownWrite = true;
|
cjsUnknownWrite = true;
|
||||||
if (node.type === 'assignment_expression' && moduleExports(left)) {
|
if (type === 'assignment_expression' && isModuleExports(lexical, left)) {
|
||||||
cjsDefaultAssignments++;
|
cjsDefaultAssignments++;
|
||||||
cjsExports.length = 0;
|
cjsExports.length = 0;
|
||||||
if (right?.type === 'object') {
|
if (right?.type === 'object') {
|
||||||
|
|
@ -349,7 +344,7 @@ export function extractFrameworkRouteFacts(
|
||||||
}
|
}
|
||||||
} else cjsExports.push({ name: 'default', value: expression(right) });
|
} else cjsExports.push({ name: 'default', value: expression(right) });
|
||||||
} else if (
|
} else if (
|
||||||
node.type === 'assignment_expression' &&
|
type === 'assignment_expression' &&
|
||||||
left?.type === 'member_expression' &&
|
left?.type === 'member_expression' &&
|
||||||
property?.type === 'property_identifier' &&
|
property?.type === 'property_identifier' &&
|
||||||
writesExportProperty
|
writesExportProperty
|
||||||
|
|
@ -412,7 +407,7 @@ export function extractFrameworkRouteFacts(
|
||||||
};
|
};
|
||||||
invalidate(left);
|
invalidate(left);
|
||||||
}
|
}
|
||||||
} else if (node.type === 'call_expression') {
|
} else if (type === 'call_expression') {
|
||||||
const callee = node.childForFieldName('function');
|
const callee = node.childForFieldName('function');
|
||||||
const method = callee?.childForFieldName('property')?.text;
|
const method = callee?.childForFieldName('property')?.text;
|
||||||
if (callee?.type === 'member_expression' && method && METHODS.has(method)) {
|
if (callee?.type === 'member_expression' && method && METHODS.has(method)) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import type Parser from 'tree-sitter';
|
import type Parser from 'tree-sitter';
|
||||||
import { buildPositionIndex, buildScopeTree, lookupLexicalName } from 'gitnexus-shared';
|
import { buildPositionIndex, buildScopeTree, lookupLexicalName } from 'gitnexus-shared';
|
||||||
import type { NameClaimResult, ParsedFile, ParsedImport } from 'gitnexus-shared';
|
import type { NameClaimResult, ParsedFile, ParsedImport } from 'gitnexus-shared';
|
||||||
|
import { FUNCTION_NODE_TYPES } from '../languages/typescript/captures.js';
|
||||||
|
|
||||||
type Node = Parser.SyntaxNode;
|
type Node = Parser.SyntaxNode;
|
||||||
export interface LexicalBindings {
|
export interface LexicalBindings {
|
||||||
|
|
@ -10,18 +11,9 @@ export interface LexicalBindings {
|
||||||
ambiguous(bindingId: string): boolean;
|
ambiguous(bindingId: string): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Callable boundaries, including methods that can contain their own var declarations. */
|
/** Callable boundaries: the TypeScript function scopes, which cover JavaScript's. */
|
||||||
export const LEXICAL_FUNCTION_TYPES: ReadonlySet<string> = new Set([
|
export const LEXICAL_FUNCTION_TYPES: ReadonlySet<string> = new Set(FUNCTION_NODE_TYPES);
|
||||||
'arrow_function',
|
const LEXICAL_FUNCTION_TYPE_LIST: string[] = [...FUNCTION_NODE_TYPES];
|
||||||
'function_expression',
|
|
||||||
'function_declaration',
|
|
||||||
'generator_function',
|
|
||||||
'generator_function_declaration',
|
|
||||||
'method_definition',
|
|
||||||
'function_signature',
|
|
||||||
'method_signature',
|
|
||||||
'abstract_method_signature',
|
|
||||||
]);
|
|
||||||
|
|
||||||
/** Expressions that wrap a value or an assignment target without changing it. */
|
/** Expressions that wrap a value or an assignment target without changing it. */
|
||||||
export const TRANSPARENT_EXPRESSION_TYPES: ReadonlySet<string> = new Set([
|
export const TRANSPARENT_EXPRESSION_TYPES: ReadonlySet<string> = new Set([
|
||||||
|
|
@ -46,6 +38,22 @@ export const importBindingKey = (
|
||||||
imported: Extract<ParsedImport, { localName: string }>,
|
imported: Extract<ParsedImport, { localName: string }>,
|
||||||
): string => bindingKey(imported.declaredAtScope ?? parsedFile.moduleScope, imported.localName);
|
): string => bindingKey(imported.declaredAtScope ?? parsedFile.moduleScope, imported.localName);
|
||||||
|
|
||||||
|
/** An unshadowed CommonJS `module` or `exports` reference. */
|
||||||
|
export const isCommonJsGlobal = (
|
||||||
|
bindings: LexicalBindings,
|
||||||
|
node: Node | null | undefined,
|
||||||
|
name: 'module' | 'exports',
|
||||||
|
): boolean => node?.type === 'identifier' && node.text === name && bindings.isGlobal(node, name);
|
||||||
|
|
||||||
|
/** `module.exports` through an unshadowed `module`. */
|
||||||
|
export const isModuleExports = (
|
||||||
|
bindings: LexicalBindings,
|
||||||
|
node: Node | null | undefined,
|
||||||
|
): boolean =>
|
||||||
|
node?.type === 'member_expression' &&
|
||||||
|
node.childForFieldName('property')?.text === 'exports' &&
|
||||||
|
isCommonJsGlobal(bindings, node.childForFieldName('object'), 'module');
|
||||||
|
|
||||||
/** The pattern a formal parameter declares, without its type or default value. */
|
/** The pattern a formal parameter declares, without its type or default value. */
|
||||||
export function parameterPattern(node: Node | null): Node | null {
|
export function parameterPattern(node: Node | null): Node | null {
|
||||||
if (node?.type === 'required_parameter' || node?.type === 'optional_parameter')
|
if (node?.type === 'required_parameter' || node?.type === 'optional_parameter')
|
||||||
|
|
@ -234,7 +242,7 @@ export function createLexicalBindings(
|
||||||
// functions have neither, so a native type search finds the few that do and
|
// functions have neither, so a native type search finds the few that do and
|
||||||
// only their formals and bodies are walked.
|
// only their formals and bodies are walked.
|
||||||
const ambiguous = new Set<string>();
|
const ambiguous = new Set<string>();
|
||||||
for (const fn of rootNode.descendantsOfType([...LEXICAL_FUNCTION_TYPES])) {
|
for (const fn of rootNode.descendantsOfType(LEXICAL_FUNCTION_TYPE_LIST)) {
|
||||||
const parameters = fn.childForFieldName('parameters') ?? fn.childForFieldName('parameter');
|
const parameters = fn.childForFieldName('parameters') ?? fn.childForFieldName('parameter');
|
||||||
if (!parameters || !containsParameterExpression(parameters)) continue;
|
if (!parameters || !containsParameterExpression(parameters)) continue;
|
||||||
let functionScope = scopes.getScope(scopeAt(parameters) ?? '');
|
let functionScope = scopes.getScope(scopeAt(parameters) ?? '');
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue