@@ -17,7 +17,37 @@ import { fileURLToPath } from 'node:url';
1717
1818const __filename = fileURLToPath ( import . meta. url ) ;
1919const __dirname = dirname ( __filename ) ;
20- const srcDir = resolve ( __dirname , '..' , 'src' ) ;
20+ const projectRoot = resolve ( __dirname , '..' ) ;
21+ const srcDir = resolve ( projectRoot , 'src' ) ;
22+
23+ // ── load package.json subpath imports ───────────────────────────────────
24+ const pkg = JSON . parse ( readFileSync ( resolve ( projectRoot , 'package.json' ) , 'utf8' ) ) ;
25+ const subpathImports : Record < string , unknown > = pkg . imports || { } ;
26+
27+ /** Resolve a #-prefixed subpath import to an absolute file path (source condition). */
28+ function resolveSubpathImport ( specifier : string ) : string | null {
29+ for ( const [ pattern , mapping ] of Object . entries ( subpathImports ) ) {
30+ const target =
31+ typeof mapping === 'string'
32+ ? mapping
33+ : ( mapping as Record < string , string > ) [ '@codegraph/source' ] ??
34+ ( mapping as Record < string , string > ) . default ;
35+ if ( ! target ) continue ;
36+
37+ // Exact match (e.g., "#types")
38+ if ( pattern === specifier ) return resolve ( projectRoot , target ) ;
39+
40+ // Wildcard match (e.g., "#shared/*")
41+ if ( pattern . includes ( '*' ) ) {
42+ const prefix = pattern . slice ( 0 , pattern . indexOf ( '*' ) ) ;
43+ if ( specifier . startsWith ( prefix ) ) {
44+ const rest = specifier . slice ( prefix . length ) ;
45+ return resolve ( projectRoot , target . replace ( '*' , rest ) ) ;
46+ }
47+ }
48+ }
49+ return null ;
50+ }
2151
2252// ── collect source files ────────────────────────────────────────────────
2353function walk ( dir ) {
@@ -102,6 +132,18 @@ function extractDynamicImports(filePath) {
102132
103133// ── resolve a specifier to a file on disk ───────────────────────────────
104134function resolveSpecifier ( specifier , fromFile ) {
135+ // Handle #-prefixed subpath imports via package.json "imports" field
136+ if ( specifier . startsWith ( '#' ) ) {
137+ const resolved = resolveSubpathImport ( specifier ) ;
138+ if ( ! resolved ) return specifier ; // no matching pattern — broken
139+ if ( existsSync ( resolved ) && statSync ( resolved ) . isFile ( ) ) return null ;
140+ if ( resolved . endsWith ( '.js' ) ) {
141+ const tsTarget = resolved . replace ( / \. j s $ / , '.ts' ) ;
142+ if ( existsSync ( tsTarget ) && statSync ( tsTarget ) . isFile ( ) ) return null ;
143+ }
144+ return specifier ; // mapped but file missing — broken
145+ }
146+
105147 // Skip bare specifiers (packages): 'node:*', '@scope/pkg', 'pkg'
106148 if ( ! specifier . startsWith ( '.' ) && ! specifier . startsWith ( '/' ) ) return null ;
107149
0 commit comments