@shrkcrft/graph 0.1.0-alpha.19 → 0.1.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -92,21 +92,62 @@ export function resolveImport(specifier, fromAbsPath, ctx) {
92
92
  }
93
93
  return { specifier, kind: ImportResolution.External };
94
94
  }
95
+ /**
96
+ * TS NodeNext / ESM resolution requires import specifiers to carry a JS-family
97
+ * extension even though the file on disk is TypeScript (`import './x.js'` →
98
+ * `x.ts`). Map each JS extension to the TS source extension(s) the compiler
99
+ * would have emitted it from. Without this, every `.js`-suffixed relative import
100
+ * in a NodeNext project is a false "unresolved import" — the single biggest
101
+ * source of under-counted graph dependents.
102
+ */
103
+ const JS_TO_TS_EXTS = {
104
+ '.js': ['.ts', '.tsx'],
105
+ '.jsx': ['.tsx', '.ts'],
106
+ '.mjs': ['.mts'],
107
+ '.cjs': ['.cts'],
108
+ };
109
+ /**
110
+ * The declaration extension. It cannot live in `PROBE_EXTS` because
111
+ * `extname('x.d.ts') === '.ts'` (so the `includes(ext)` literal-path guard would
112
+ * never match it), and it must always be tried LAST — a real implementation file
113
+ * wins over a declaration. But a declaration-only module (a hand-authored
114
+ * `.d.ts` with no sibling impl) is still a resolvable graph target, not an
115
+ * unresolved import, so it is appended as the final candidate everywhere.
116
+ */
117
+ const DECL_EXT = '.d.ts';
95
118
  function probeCandidate(absPathNoExt) {
96
119
  // If the path already has a known extension and exists, return it.
97
120
  const ext = nodePath.extname(absPathNoExt);
98
- if (PROBE_EXTS.includes(ext) && existsSafe(absPathNoExt) && isFile(absPathNoExt)) {
99
- return absPathNoExt;
121
+ if (PROBE_EXTS.includes(ext)) {
122
+ // A real file on disk at the literal path wins (a genuine `.js` next to no
123
+ // `.ts`, an asset, etc.).
124
+ if (existsSafe(absPathNoExt) && isFile(absPathNoExt)) {
125
+ return absPathNoExt;
126
+ }
127
+ // NodeNext: rewrite the JS-family extension to its TS source extension and
128
+ // probe those (then a declaration-only sibling) before giving up.
129
+ const tsExts = JS_TO_TS_EXTS[ext];
130
+ if (tsExts) {
131
+ const base = absPathNoExt.slice(0, -ext.length);
132
+ for (const e of tsExts) {
133
+ const cand = base + e;
134
+ if (existsSafe(cand) && isFile(cand))
135
+ return cand;
136
+ }
137
+ const dts = base + DECL_EXT;
138
+ if (existsSafe(dts) && isFile(dts))
139
+ return dts;
140
+ }
100
141
  }
101
- // Try appending each known extension.
102
- for (const e of PROBE_EXTS) {
142
+ // Try appending each known extension (extensionless specifier), then `.d.ts`.
143
+ for (const e of [...PROBE_EXTS, DECL_EXT]) {
103
144
  const cand = absPathNoExt + e;
104
145
  if (existsSafe(cand) && isFile(cand))
105
146
  return cand;
106
147
  }
107
- // Try as a directory with index.<ext>.
148
+ // Try as a directory with index.<ext> (then index.d.ts).
108
149
  if (existsSafe(absPathNoExt) && isDir(absPathNoExt)) {
109
- for (const e of PROBE_EXTS) {
150
+ for (const e of [...PROBE_EXTS, DECL_EXT]) {
110
151
  const cand = nodePath.join(absPathNoExt, `index${e}`);
111
152
  if (existsSafe(cand) && isFile(cand))
112
153
  return cand;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@shrkcrft/graph",
3
- "version": "0.1.0-alpha.19",
3
+ "version": "0.1.0-alpha.21",
4
4
  "description": "SharkCraft code intelligence graph: files, symbols, packages, imports and exports. Persistent JSONL store; on-disk index queried by every other code-intelligence package.",
5
5
  "license": "MIT",
6
6
  "author": "SharkCraft contributors",
7
7
  "type": "module",
8
8
  "main": "./dist/index.js",
9
- "types": "./dist/index.d.d.ts",
9
+ "types": "./dist/index.d.ts",
10
10
  "exports": {
11
11
  ".": {
12
12
  "types": "./dist/index.d.ts",
@@ -45,9 +45,9 @@
45
45
  "typecheck": "tsc --noEmit -p tsconfig.json"
46
46
  },
47
47
  "dependencies": {
48
- "@shrkcrft/core": "^0.1.0-alpha.19",
49
- "@shrkcrft/boundaries": "^0.1.0-alpha.19",
50
- "@shrkcrft/inspector": "^0.1.0-alpha.19",
48
+ "@shrkcrft/core": "^0.1.0-alpha.21",
49
+ "@shrkcrft/boundaries": "^0.1.0-alpha.21",
50
+ "@shrkcrft/inspector": "^0.1.0-alpha.21",
51
51
  "typescript": "^5.6.0"
52
52
  },
53
53
  "publishConfig": {