mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-15 03:08:20 +08:00
fix(js): a CommonJS require and a module path import the file they name (#2263)
* fix(js): a CommonJS require and a module path import the file they name
A `require('./application')` was only a call, so a CommonJS file depended
on nothing at file level: Express's lib/express.js showed no imports and
impact missed the files it loads. Local require specifiers are now read
after extraction (both the wasm extractor and the kernel, including its
deferred-decode transport) as `imports` refs from the file, and a JS/TS
module path resolves to its file the way the runtime finds it —
extensions, index files, aliases — which also lands an extensionless
`import './polyfills'` on its file instead of its own import node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(js): read require imports inside each extractor, so kernel parity holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
95f6f0f4a5
commit
c4babfce6a
@@ -1529,10 +1529,41 @@ export function resolvePhpImportedStaticCall(
|
||||
return { original: ref, targetNodeId: methods[0]!.id, confidence: 0.95, resolvedBy: 'import' };
|
||||
}
|
||||
|
||||
const JS_MODULE_LANGUAGES: ReadonlySet<string> = new Set(['javascript', 'jsx', 'typescript', 'tsx', 'arkts']);
|
||||
|
||||
/**
|
||||
* A module specifier written as a path — relative (`./x`, `../x`), rooted, or
|
||||
* an alias with a folder in it (`@/lib/x`, `~/x`, `$lib/x`) — rather than an
|
||||
* imported binding's name or a bare package (`react`, `lodash`).
|
||||
*/
|
||||
function isJsPathSpecifier(name: string): boolean {
|
||||
return name.startsWith('./') || name.startsWith('../') || name === '.' || name === '..' ||
|
||||
(name.includes('/') && !/\s/.test(name) && !/^@[\w.-]+\/[\w.-]+$/.test(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* A JS/TS `imports` reference that names a module by path. It names a FILE, not
|
||||
* a symbol, so it skips the resolver's name-exists pre-filter — a CommonJS
|
||||
* `require('./x')` has no import node of that name to pass it.
|
||||
*/
|
||||
export function isJsPathImportRef(ref: UnresolvedRef): boolean {
|
||||
return ref.referenceKind === 'imports' && JS_MODULE_LANGUAGES.has(ref.language) && isJsPathSpecifier(ref.referenceName);
|
||||
}
|
||||
|
||||
export function resolveViaImport(
|
||||
ref: UnresolvedRef,
|
||||
context: ResolutionContext
|
||||
): ResolvedRef | null {
|
||||
// A JS/TS module specifier — `import './polyfills'`, the module of `import x
|
||||
// from '../lib/a'`, a CommonJS `require('./application')` — names a FILE,
|
||||
// found the way the runtime finds it: extensions, `index` files, path
|
||||
// aliases. Matching the basename instead missed every extensionless one
|
||||
// (the common spelling) and could land on a same-named file elsewhere.
|
||||
if (isJsPathImportRef(ref)) {
|
||||
const file = resolveImportPath(ref.referenceName, ref.filePath, ref.language, context);
|
||||
const fileNode = file && file !== ref.filePath ? context.getNodesInFile(file).find((n) => n.kind === 'file') : undefined;
|
||||
if (fileNode) return { original: ref, targetNodeId: fileNode.id, confidence: 0.9, resolvedBy: 'import' };
|
||||
}
|
||||
// C/C++ #include references — resolve directly to the included file
|
||||
// (file→file edge), bypassing symbol lookup. The extractor emits these
|
||||
// with `referenceKind: 'imports'` and `referenceName: <include path>`
|
||||
|
||||
@@ -26,7 +26,7 @@ import { isVisibleCppMacro, clearCppMacroVisibility } from './cpp-macro-visibili
|
||||
import { isCppConstructorRef, matchCppConstructor } from './cpp-constructor';
|
||||
import { gateSwiftTypeTarget, clearSwiftTypeVisibility, swiftExtendedConformances } from './swift-type-visibility';
|
||||
import { gateTypeParameter, clearTypeParameterMemos } from './type-parameters';
|
||||
import { resolveViaImport, resolvePhpImportedStaticCall, resolveJvmImport, extractImportMappings, extractReExports, loadCppIncludeDirs, isPhpIncludePathRef, isCobolCopybookRef, isNixPathImportRef, isBoundToOutOfRepoImport, clearImportResolverMemos, resolveImportPath, isExternalImport } from './import-resolver';
|
||||
import { resolveViaImport, resolvePhpImportedStaticCall, resolveJvmImport, extractImportMappings, extractReExports, loadCppIncludeDirs, isPhpIncludePathRef, isCobolCopybookRef, isNixPathImportRef, isJsPathImportRef, isBoundToOutOfRepoImport, clearImportResolverMemos, resolveImportPath, isExternalImport } from './import-resolver';
|
||||
import { ResolverPool, minRefsForPool } from './resolver-pool';
|
||||
import { resolveAliasBinding } from './alias-binding';
|
||||
import { detectFrameworks } from './frameworks';
|
||||
@@ -1100,8 +1100,9 @@ export class ReferenceResolver {
|
||||
// ArkTS chained-attribute refs carry a leading dot (`.titleStyle`) that
|
||||
// routes them to the decorator-gated matcher; the symbol itself is
|
||||
// indexed under the bare name, so the existence check strips the dot.
|
||||
// Nix static path imports (`import ./x.nix`) name a FILE, not a symbol —
|
||||
// they bypass the symbol-existence check and resolve via resolveViaImport.
|
||||
// Nix static path imports (`import ./x.nix`) and JS/TS module paths
|
||||
// (`require('./x')`) name a FILE, not a symbol — they bypass the
|
||||
// symbol-existence check and resolve via resolveViaImport.
|
||||
let existenceName =
|
||||
ref.language === 'arkts' && ref.referenceName.startsWith('.')
|
||||
? ref.referenceName.slice(1)
|
||||
@@ -1112,6 +1113,7 @@ export class ReferenceResolver {
|
||||
const tPre = this.profileStages ? process.hrtime.bigint() : 0n;
|
||||
const preFilterPass =
|
||||
isNixPathImportRef(ref) ||
|
||||
isJsPathImportRef(ref) ||
|
||||
this.hasAnyPossibleMatch(existenceName) ||
|
||||
// PHP, Pascal, CFML, COBOL and VB.NET names ignore case: `formatprice()`
|
||||
// calls `FormatPrice`, which the exact-name set never lists.
|
||||
|
||||
Reference in New Issue
Block a user