carrick 0.3.106 → 0.3.107

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.
@@ -132,7 +132,14 @@ export function refreshInBackground(root, status, options = {}) {
132
132
  return null;
133
133
  if (!claimRefresh(marker, now, cooldown))
134
134
  return null;
135
- (options.start ?? startDetached)(binary(env), ["refresh", "--workspace", root], env);
135
+ // Nobody started this refresh and nobody is reading it, so it does not keep
136
+ // the machine awake: that hold is for a scan a person is waiting on, and it
137
+ // comes with a line saying so that this one has nowhere to print
138
+ // (carrick#1889).
139
+ (options.start ?? startDetached)(binary(env), ["refresh", "--workspace", root], {
140
+ ...env,
141
+ CARRICK_NO_KEEP_AWAKE: "1",
142
+ });
136
143
  return "Carrick: a repo here is connected with no hosted index yet, so a refresh is running in the background. Its rows arrive in the next session.";
137
144
  }
138
145
  //# sourceMappingURL=refresh.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/hook/refresh.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/hook/refresh.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carrick",
3
- "version": "0.3.106",
3
+ "version": "0.3.107",
4
4
  "description": "Maps your entire TypeScript codebase across services and repositories, giving AI agents full context on existing types, routes, and function behaviours over MCP before they write duplicate or breaking code.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -58,11 +58,11 @@
58
58
  "zod": "^3.23.0"
59
59
  },
60
60
  "optionalDependencies": {
61
- "@carrick-tools/cli-darwin-arm64": "0.3.106",
62
- "@carrick-tools/cli-darwin-x64": "0.3.106",
63
- "@carrick-tools/cli-linux-arm64": "0.3.106",
64
- "@carrick-tools/cli-linux-x64": "0.3.106",
65
- "@carrick-tools/cli-win32-x64": "0.3.106"
61
+ "@carrick-tools/cli-darwin-arm64": "0.3.107",
62
+ "@carrick-tools/cli-darwin-x64": "0.3.107",
63
+ "@carrick-tools/cli-linux-arm64": "0.3.107",
64
+ "@carrick-tools/cli-linux-x64": "0.3.107",
65
+ "@carrick-tools/cli-win32-x64": "0.3.107"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/node": "^24.13.3",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "carrick",
3
3
  "description": "Claude Code plugin for Carrick, which indexes TypeScript codebases across service and repository boundaries. After each edit it adds the file's routes, calls, and cross-service type mismatches to the session, and it registers Carrick's language server. It pairs with the Carrick MCP server, which lets agents search functions by intent rather than name.",
4
- "version": "0.3.106",
4
+ "version": "0.3.107",
5
5
  "author": {
6
6
  "name": "Carrick",
7
7
  "email": "hello@carrick.tools"
@@ -56,8 +56,21 @@ export interface ResolvedAnchor {
56
56
  */
57
57
  namesUnemittedModule?: true;
58
58
  }
59
- /** Repo-root-relative source file -> extensionless specifier from entryDir. */
60
- export declare function entryRelativeSpecifier(entryDir: string, repoRoot: string, sourceFile: string): string;
59
+ /**
60
+ * Repo-root-relative source file -> the specifier the surface entry imports
61
+ * it by: its path from `entryDir`, in the form the entry resolves.
62
+ *
63
+ * With the extension removed (`./a`), where `resolveFromEntry` says the entry
64
+ * resolves that to the module. It does not always (carrick#1911): under
65
+ * `module` `node16`..`nodenext` an entry in a `"type": "module"` package is
66
+ * an ES module, which must name the file the module compiles to, and a `.mts`
67
+ * or `.cts` module has no extensionless form under any setting. There, and
68
+ * with no resolver to ask, the specifier is that output name: `./a.js` for
69
+ * `.ts` and `.tsx`, `./a.mjs` for `.mts`, `./a.cjs` for `.cts`, which every
70
+ * module setting maps back to the source and, in the stub, to its
71
+ * declaration.
72
+ */
73
+ export declare function entryRelativeSpecifier(entryDir: string, repoRoot: string, sourceFile: string, resolveFromEntry?: (specifier: string) => string | undefined): string;
61
74
  /**
62
75
  * Resolve one anchor against the analysis program. `placeholder` is the
63
76
  * anchor's own placeholder alias declaration in the entry file -- the
@@ -11,15 +11,32 @@ import { typeIsOrContainsMachinery } from './machinery.js';
11
11
  import { installedPackageSpecifier } from './installed-package.js';
12
12
  import { realPath } from './service-config.js';
13
13
  import { unresolvedAtAnchor, unresolvedSpecifiersReachableFrom, } from './unresolved.js';
14
- /** Repo-root-relative source file -> extensionless specifier from entryDir. */
15
- export function entryRelativeSpecifier(entryDir, repoRoot, sourceFile) {
16
- const target = path
17
- .join(repoRoot, sourceFile)
18
- .replace(/\.(ts|tsx|mts|cts)$/, '');
19
- let rel = path.relative(entryDir, target).split(path.sep).join('/');
20
- if (!rel.startsWith('.'))
21
- rel = `./${rel}`;
22
- return rel;
14
+ /**
15
+ * Repo-root-relative source file -> the specifier the surface entry imports
16
+ * it by: its path from `entryDir`, in the form the entry resolves.
17
+ *
18
+ * With the extension removed (`./a`), where `resolveFromEntry` says the entry
19
+ * resolves that to the module. It does not always (carrick#1911): under
20
+ * `module` `node16`..`nodenext` an entry in a `"type": "module"` package is
21
+ * an ES module, which must name the file the module compiles to, and a `.mts`
22
+ * or `.cts` module has no extensionless form under any setting. There, and
23
+ * with no resolver to ask, the specifier is that output name: `./a.js` for
24
+ * `.ts` and `.tsx`, `./a.mjs` for `.mts`, `./a.cjs` for `.cts`, which every
25
+ * module setting maps back to the source and, in the stub, to its
26
+ * declaration.
27
+ */
28
+ export function entryRelativeSpecifier(entryDir, repoRoot, sourceFile, resolveFromEntry) {
29
+ const target = path.join(repoRoot, sourceFile);
30
+ const from = (file) => {
31
+ const rel = path.relative(entryDir, file).split(path.sep).join('/');
32
+ return rel.startsWith('.') ? rel : `./${rel}`;
33
+ };
34
+ const bare = from(target.replace(/\.(ts|tsx|mts|cts)$/, ''));
35
+ const resolved = resolveFromEntry?.(bare);
36
+ if (resolved !== undefined && realPath(resolved) === realPath(target))
37
+ return bare;
38
+ const kind = /(?:\.d)?\.([cm]?)[jt]sx?$/.exec(target);
39
+ return kind ? from(`${target.slice(0, kind.index)}.${kind[1]}js`) : bare;
23
40
  }
24
41
  function moduleExport(checker, sourceFile, name) {
25
42
  const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
@@ -100,7 +117,7 @@ export function resolveAnchor(program, request, args) {
100
117
  if (!sourceFile) {
101
118
  return demote(`source file not in program: ${request.source_file}`);
102
119
  }
103
- const spec = entryRelativeSpecifier(args.entryDir, args.repoRoot, request.source_file);
120
+ const spec = entryRelativeSpecifier(args.entryDir, args.repoRoot, request.source_file, args.resolveFromEntry);
104
121
  if (request.kind === 'symbol') {
105
122
  const exported = moduleExport(checker, sourceFile, request.symbol_name);
106
123
  if (!exported) {
@@ -436,7 +453,7 @@ function qualifyNamesFromSource(text, program, sourceFileRel, printed, args) {
436
453
  return undefined;
437
454
  if (rel.split(path.sep).includes('node_modules'))
438
455
  return undefined;
439
- return entryRelativeSpecifier(args.entryDir, args.repoRoot, rel.split(path.sep).join('/'));
456
+ return entryRelativeSpecifier(args.entryDir, args.repoRoot, rel.split(path.sep).join('/'), args.resolveFromEntry);
440
457
  };
441
458
  const imports = new Map();
442
459
  const importFor = (name) => {
@@ -27,7 +27,7 @@
27
27
  import ts from 'typescript';
28
28
  import * as fs from 'node:fs';
29
29
  import * as path from 'node:path';
30
- import { collectSpecifiers, isRelative } from './specifiers.js';
30
+ import { collectSpecifiers, declarationCandidates, isDeclarationFileName, isRelative, } from './specifiers.js';
31
31
  /** One index per assembled stub, keyed by service name. */
32
32
  export function buildPoisonIndexes(ws) {
33
33
  const indexes = new Map();
@@ -45,14 +45,14 @@ function buildOne(ws, serviceName, packageDir) {
45
45
  return undefined;
46
46
  const keyPrefix = `packages/${packageDir}/types`;
47
47
  const surfaceFile = `${keyPrefix}/surface.d.ts`;
48
- // Collect the whole `.d.ts` tree, keyed as `packages/<dir>/types/<rel>`.
48
+ // Collect the whole declaration tree, keyed as `packages/<dir>/types/<rel>`.
49
49
  const treeAbs = [];
50
50
  const walk = (dir) => {
51
51
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
52
52
  const p = path.join(dir, entry.name);
53
53
  if (entry.isDirectory())
54
54
  walk(p);
55
- else if (entry.name.endsWith('.d.ts'))
55
+ else if (isDeclarationFileName(entry.name))
56
56
  treeAbs.push(p);
57
57
  }
58
58
  };
@@ -63,17 +63,7 @@ function buildOne(ws, serviceName, packageDir) {
63
63
  if (!isRelative(spec))
64
64
  return undefined;
65
65
  const base = path.resolve(path.dirname(fromAbs), spec);
66
- const candidates = [
67
- `${base}.d.ts`,
68
- path.join(base, 'index.d.ts'),
69
- base.endsWith('.js') ? `${base.slice(0, -3)}.d.ts` : undefined,
70
- base, // already `.d.ts`
71
- ].filter((c) => c !== undefined);
72
- for (const c of candidates) {
73
- if (treeAbsSet.has(path.resolve(c)))
74
- return c;
75
- }
76
- return undefined;
66
+ return declarationCandidates(base).find((candidate) => treeAbsSet.has(candidate));
77
67
  };
78
68
  // Per-file relative-import adjacency, over the fileKey namespace.
79
69
  const adjacency = new Map();
@@ -34,13 +34,13 @@ import { entryRelativeSpecifier, resolveAnchor } from './anchors.js';
34
34
  import { findAugmentationFiles } from './augmentations.js';
35
35
  import { installedVersions, lockfileVersions } from './lockfile.js';
36
36
  import { rewriteEmittedSpecifiers } from './paths-rewrite.js';
37
- import { typesPackageOf, withInstalledPackages } from './installed-package.js';
37
+ import { installedPackageSpecifier, typesPackageOf, withInstalledPackages } from './installed-package.js';
38
38
  import { selfCheckStub } from './self-check.js';
39
39
  import { collectSpecifiers, isRelative, packageNameOf } from './specifiers.js';
40
40
  import { DenoProject, findDenoConfig } from './deno-project.js';
41
41
  import { emitsAlike, ProjectGraph } from './project-references.js';
42
42
  import { findServiceTsconfig } from './service-config.js';
43
- import { placeEmittedTree } from './outside-root.js';
43
+ import { placeEmittedTree, surfaceModuleInTree } from './outside-root.js';
44
44
  import { WriteGuard } from './guarded-fs.js';
45
45
  export { DenoProject, findDenoConfig } from './deno-project.js';
46
46
  export { serviceConfigPath } from './project-references.js';
@@ -351,7 +351,14 @@ export function captureStub(opts) {
351
351
  if (emitPartial) {
352
352
  errors.push(`declaration emit was partial: kept ${emitted.size} emitted file(s); ` +
353
353
  'aliases referencing unemitted modules are demoted to structural_fallback');
354
- resolved = demoteDanglingAliases({ resolved, emitted, declarationSources, staging, surfaceDeclaration });
354
+ resolved = demoteDanglingAliases({
355
+ resolved,
356
+ emitted,
357
+ declarationSources,
358
+ staging,
359
+ entryDir,
360
+ surfaceDeclaration,
361
+ });
355
362
  }
356
363
  // ---- Relocate the emitted tree into the stub package ----
357
364
  const typesDir = path.join(stubDir, 'types');
@@ -520,43 +527,47 @@ export function captureStub(opts) {
520
527
  };
521
528
  }
522
529
  /**
523
- * Partial-emit demotion: with the set of modules that DID reach the tree
524
- * (emitted .d.ts plus verbatim declaration sources), demote every anchor
525
- * whose alias text references a relative module absent from that set, and
530
+ * Partial-emit demotion: demote every anchor whose alias text names, by a
531
+ * relative or an absolute path, a module the stub will not resolve, and
526
532
  * rewrite the demoted aliases' lines in the emitted surface to `unknown`.
533
+ *
534
+ * A path resolves when the tree holds its module (`surfaceModuleInTree`: an
535
+ * emitted declaration inside rootDir or outside it, or a verbatim declaration
536
+ * source), read from where the entry was written, not from where the surface
537
+ * sits in the tree. An absolute path into an installed package resolves too
538
+ * (carrick#1773): no emit writes that module, and the specifier rewrite turns
539
+ * the path into the package's bare specifier and a pin, as it does when the
540
+ * emit is whole. A relative path into a package is not rewritten, so it stays
541
+ * demoted (carrick#1857).
542
+ *
527
543
  * Anchors already demoted stay as they are; anchors whose text is
528
544
  * self-contained (node-builder structural prints, literal object text) are
529
545
  * untouched even when their source file failed to emit — their surface line
530
546
  * references nothing that can dangle.
531
547
  */
532
548
  function demoteDanglingAliases(args) {
533
- // Extensionless, entryDir-relative POSIX module ids present in the tree.
534
- const treeModules = new Set();
535
- let surfaceKey;
536
- for (const fileName of args.emitted.keys()) {
537
- const rel = path.relative(args.staging, fileName).split(path.sep).join('/');
538
- if (path.basename(rel) === args.surfaceDeclaration)
539
- surfaceKey = fileName;
540
- if (rel.endsWith('.d.ts'))
541
- treeModules.add(rel.slice(0, -'.d.ts'.length));
542
- }
543
- for (const rel of args.declarationSources.keys()) {
544
- if (rel.endsWith('.d.ts'))
545
- treeModules.add(rel.slice(0, -'.d.ts'.length));
546
- }
547
- // Deno's temporary surface lives in the cache inside the emitted tree.
548
- const surfaceDir = surfaceKey ? path.posix.dirname(path.relative(args.staging, surfaceKey).split(path.sep).join('/')) : '.';
549
- const moduleInTree = (spec) => {
550
- const id = path.posix.normalize(path.posix.join(surfaceDir, spec));
551
- if (id.startsWith('..'))
552
- return false;
553
- return treeModules.has(id) || treeModules.has(`${id}/index`);
549
+ const surfaceKey = [...args.emitted.keys()].find((fileName) => path.basename(fileName) === args.surfaceDeclaration);
550
+ const inTree = surfaceModuleInTree({
551
+ emitted: args.emitted.keys(),
552
+ declarationSources: args.declarationSources.keys(),
553
+ staging: args.staging,
554
+ entryDir: args.entryDir,
555
+ surfaceDeclaration: args.surfaceDeclaration,
556
+ });
557
+ const resolves = new Map();
558
+ const moduleResolves = (spec) => {
559
+ let answer = resolves.get(spec);
560
+ if (answer === undefined) {
561
+ answer = inTree(spec) || (spec.startsWith('/') && installedPackageSpecifier(spec) !== undefined);
562
+ resolves.set(spec, answer);
563
+ }
564
+ return answer;
554
565
  };
555
566
  const demoted = new Set();
556
567
  const next = args.resolved.map((anchor) => {
557
568
  if (anchor.failureReason !== undefined)
558
569
  return anchor;
559
- const dangling = [...collectSpecifiers(anchor.aliasText)].find((spec) => isRelative(spec) && !moduleInTree(spec));
570
+ const dangling = [...collectSpecifiers(anchor.aliasText)].find((spec) => isRelative(spec) && !moduleResolves(spec));
560
571
  if (dangling === undefined)
561
572
  return anchor;
562
573
  demoted.add(anchor.request.alias);
@@ -661,6 +672,20 @@ function resolveAnchors(opts, parsed, ctx, deno) {
661
672
  placeholders.set(stmt.name.text, stmt);
662
673
  }
663
674
  }
675
+ // A module specifier as the entry resolves it, under the program's own
676
+ // resolution (the Deno graph's, for a Deno service). Asked once per
677
+ // specifier: every anchor of a module asks for the same one.
678
+ const entryMode = entrySource?.impliedNodeFormat;
679
+ const fromEntry = new Map();
680
+ const resolveFromEntry = (specifier) => {
681
+ if (!fromEntry.has(specifier)) {
682
+ fromEntry.set(specifier, (deno
683
+ ? deno.resolve(specifier, ctx.entryPath, options)
684
+ : ts.resolveModuleName(specifier, ctx.entryPath, options, ts.sys, undefined, undefined, entryMode)
685
+ .resolvedModule)?.resolvedFileName);
686
+ }
687
+ return fromEntry.get(specifier);
688
+ };
664
689
  // A literal anchor whose text is a bare identifier resolves through a
665
690
  // sibling symbol anchor's module when one names the same symbol.
666
691
  const siblingSymbolSpecs = new Map();
@@ -668,16 +693,9 @@ function resolveAnchors(opts, parsed, ctx, deno) {
668
693
  if (anchor.kind !== 'symbol')
669
694
  continue;
670
695
  if (!siblingSymbolSpecs.has(anchor.symbol_name)) {
671
- siblingSymbolSpecs.set(anchor.symbol_name, entryRelativeSpecifier(ctx.entryDir, ctx.repoRoot, anchor.source_file));
696
+ siblingSymbolSpecs.set(anchor.symbol_name, entryRelativeSpecifier(ctx.entryDir, ctx.repoRoot, anchor.source_file, resolveFromEntry));
672
697
  }
673
698
  }
674
- // A module specifier as the entry resolves it, under the program's own
675
- // resolution (the Deno graph's, for a Deno service).
676
- const entryMode = entrySource?.impliedNodeFormat;
677
- const resolveFromEntry = (specifier) => (deno
678
- ? deno.resolve(specifier, ctx.entryPath, options)
679
- : ts.resolveModuleName(specifier, ctx.entryPath, options, ts.sys, undefined, undefined, entryMode)
680
- .resolvedModule)?.resolvedFileName;
681
699
  return opts.anchors.map((request) => resolveAnchor(program, request, {
682
700
  repoRoot: ctx.repoRoot,
683
701
  entryDir: ctx.entryDir,
@@ -41,6 +41,8 @@ export interface InstalledPackageSpecifier {
41
41
  * deciding whether a runtime name is covered by a pinned types package.
42
42
  */
43
43
  export declare function typesPackageOf(name: string): string;
44
+ /** A path or specifier without its script, source or declaration extension. */
45
+ export declare function withoutExtension(subpath: string): string;
44
46
  /**
45
47
  * A compiler host that also resolves the packages an absolute specifier was
46
48
  * rewritten into, each from its own install directory. The capture's
@@ -101,7 +101,8 @@ function existingFile(spec) {
101
101
  }
102
102
  return undefined;
103
103
  }
104
- function withoutExtension(subpath) {
104
+ /** A path or specifier without its script, source or declaration extension. */
105
+ export function withoutExtension(subpath) {
105
106
  return subpath.replace(/(?:\.d)?\.(?:ts|mts|cts|js|mjs|cjs|tsx|jsx)$/, '');
106
107
  }
107
108
  /** Every string target an exports value names, whatever its conditions. */
@@ -39,3 +39,22 @@ export declare function placeEmittedTree(args: {
39
39
  entryDir: string;
40
40
  surfaceDeclaration: string;
41
41
  }): PlacedTree;
42
+ /**
43
+ * A test for whether the tree holds the module a specifier in the surface
44
+ * entry names (carrick#1773).
45
+ *
46
+ * The specifier is read the way the placement above reads one: resolved from
47
+ * the surface's SOURCE-side directory, so an absolute path stays what it is
48
+ * and `../` leaves rootDir, then looked up among the source-side paths of the
49
+ * declarations the tree holds. Those are every emitted declaration, inside
50
+ * rootDir or placed under `OUTSIDE_DIR`, and the declaration sources shipped
51
+ * verbatim (`declarationSources`, relative to rootDir).
52
+ */
53
+ export declare function surfaceModuleInTree(args: {
54
+ /** tsc's file name for each emitted declaration. */
55
+ emitted: Iterable<string>;
56
+ declarationSources: Iterable<string>;
57
+ staging: string;
58
+ entryDir: string;
59
+ surfaceDeclaration: string;
60
+ }): (spec: string) => boolean;
@@ -15,6 +15,7 @@
15
15
  * A capture whose program stays inside rootDir is placed exactly as before.
16
16
  */
17
17
  import * as path from 'node:path';
18
+ import { withoutExtension } from './installed-package.js';
18
19
  import { rewriteSpecifiers } from './specifiers.js';
19
20
  /** Tree directory holding declarations of sources outside rootDir. */
20
21
  export const OUTSIDE_DIR = '__outside__';
@@ -31,13 +32,12 @@ export function placeEmittedTree(args) {
31
32
  const sourceSideOf = new Map();
32
33
  const outsideFiles = [];
33
34
  for (const fileName of args.emitted.keys()) {
35
+ sourceSideOf.set(fileName, sourceSidePath(fileName, args.staging, args.entryDir));
34
36
  const rel = posix(path.relative(args.staging, fileName));
35
37
  if (escapes(rel)) {
36
38
  outsideFiles.push(fileName);
37
- sourceSideOf.set(fileName, path.resolve(fileName));
38
39
  continue;
39
40
  }
40
- sourceSideOf.set(fileName, path.join(args.entryDir, rel));
41
41
  relOf.set(fileName, path.basename(rel) === args.surfaceDeclaration ? 'surface.d.ts' : rel);
42
42
  }
43
43
  const outside = new Map();
@@ -82,6 +82,43 @@ export function placeEmittedTree(args) {
82
82
  }
83
83
  return { relOf, textOf, outside, rewrites };
84
84
  }
85
+ /**
86
+ * Where tsc would have written an emitted declaration in the source tree. A
87
+ * file under the staging dir mirrors rootDir; one outside it arrived at its
88
+ * source's own path.
89
+ */
90
+ function sourceSidePath(fileName, staging, entryDir) {
91
+ const rel = posix(path.relative(staging, fileName));
92
+ return escapes(rel) ? path.resolve(fileName) : path.join(entryDir, rel);
93
+ }
94
+ /**
95
+ * A test for whether the tree holds the module a specifier in the surface
96
+ * entry names (carrick#1773).
97
+ *
98
+ * The specifier is read the way the placement above reads one: resolved from
99
+ * the surface's SOURCE-side directory, so an absolute path stays what it is
100
+ * and `../` leaves rootDir, then looked up among the source-side paths of the
101
+ * declarations the tree holds. Those are every emitted declaration, inside
102
+ * rootDir or placed under `OUTSIDE_DIR`, and the declaration sources shipped
103
+ * verbatim (`declarationSources`, relative to rootDir).
104
+ */
105
+ export function surfaceModuleInTree(args) {
106
+ const held = new Set();
107
+ let surfaceDir = args.entryDir;
108
+ for (const fileName of args.emitted) {
109
+ const sourceSide = sourceSidePath(fileName, args.staging, args.entryDir);
110
+ if (path.basename(sourceSide) === args.surfaceDeclaration)
111
+ surfaceDir = path.dirname(sourceSide);
112
+ held.add(sourceSide.replace(DECLARATION_EXT, ''));
113
+ }
114
+ for (const rel of args.declarationSources) {
115
+ held.add(path.join(args.entryDir, rel).replace(DECLARATION_EXT, ''));
116
+ }
117
+ return (spec) => {
118
+ const target = path.resolve(surfaceDir, withoutExtension(spec));
119
+ return held.has(target) || held.has(path.join(target, 'index'));
120
+ };
121
+ }
85
122
  function posix(p) {
86
123
  return p.split(path.sep).join('/');
87
124
  }
@@ -32,7 +32,7 @@
32
32
  import ts from 'typescript';
33
33
  import * as fs from 'node:fs';
34
34
  import * as path from 'node:path';
35
- import { collectSpecifiers, isRelative, packageNameOf } from './specifiers.js';
35
+ import { collectSpecifiers, declarationCandidates, isDeclarationFileName, isRelative, packageNameOf, } from './specifiers.js';
36
36
  import { repairDanglingImports } from './repair-dangling.js';
37
37
  import { findDisqualifyingTopTypes, findUnresolvedPlaceholders, isErrorPlaceholder, provenanceOf, unemittedModuleProvenance, unresolvedInTreeProvenance, } from './deep-walk.js';
38
38
  export function selfCheckStub(args) {
@@ -43,7 +43,7 @@ export function selfCheckStub(args) {
43
43
  const p = path.join(dir, entry.name);
44
44
  if (entry.isDirectory())
45
45
  walk(p);
46
- else if (entry.name.endsWith('.d.ts'))
46
+ else if (isDeclarationFileName(entry.name))
47
47
  treeFiles.push(p);
48
48
  }
49
49
  };
@@ -464,15 +464,5 @@ function resolveTreeSpecifier(fromAbs, spec, tree) {
464
464
  if (!isRelative(spec))
465
465
  return undefined;
466
466
  const base = path.resolve(path.dirname(fromAbs), spec);
467
- const candidates = [
468
- `${base}.d.ts`,
469
- path.join(base, 'index.d.ts'),
470
- base.endsWith('.js') ? `${base.slice(0, -3)}.d.ts` : undefined,
471
- base, // already .d.ts
472
- ].filter((c) => c !== undefined);
473
- for (const candidate of candidates) {
474
- if (tree.has(candidate))
475
- return candidate;
476
- }
477
- return undefined;
467
+ return declarationCandidates(base).find((candidate) => tree.has(candidate));
478
468
  }
@@ -4,6 +4,20 @@
4
4
  * pattern matching for the post-emit rewrite pass.
5
5
  */
6
6
  export declare function isRelative(spec: string): boolean;
7
+ /** A declaration file of any module format: `.d.ts`, `.d.mts`, `.d.cts`. */
8
+ export declare function isDeclarationFileName(name: string): boolean;
9
+ /**
10
+ * The declaration files a relative specifier can name in a stub's tree, in
11
+ * the order tried, given the path it resolves to from the file that holds it.
12
+ *
13
+ * A specifier names its module with no extension (`./a`: `a.d.ts`, or the
14
+ * directory's `index.d.ts`), by the file the module compiles to (`./a.js`:
15
+ * `a.d.ts`, `./a.mjs`: `a.d.mts`, `./a.cjs`: `a.d.cts`), or by the
16
+ * declaration file itself. The surface names an anchor's module the second
17
+ * way where the first does not resolve (carrick#1911), and so does any source
18
+ * written for `node16`..`nodenext`.
19
+ */
20
+ export declare function declarationCandidates(resolved: string): string[];
7
21
  /** zod -> zod, @scope/pkg/sub -> @scope/pkg, pkg/sub -> pkg */
8
22
  export declare function packageNameOf(spec: string): string;
9
23
  /** Extract every module specifier mentioned in a .d.ts text: `from "x"`,
@@ -3,9 +3,34 @@
3
3
  * declaration text, external/internal classification, and tsconfig-`paths`
4
4
  * pattern matching for the post-emit rewrite pass.
5
5
  */
6
+ import * as path from 'node:path';
6
7
  export function isRelative(spec) {
7
8
  return spec.startsWith('./') || spec.startsWith('../') || spec.startsWith('/');
8
9
  }
10
+ /** A declaration file of any module format: `.d.ts`, `.d.mts`, `.d.cts`. */
11
+ export function isDeclarationFileName(name) {
12
+ return /\.d\.[cm]?ts$/.test(name);
13
+ }
14
+ /**
15
+ * The declaration files a relative specifier can name in a stub's tree, in
16
+ * the order tried, given the path it resolves to from the file that holds it.
17
+ *
18
+ * A specifier names its module with no extension (`./a`: `a.d.ts`, or the
19
+ * directory's `index.d.ts`), by the file the module compiles to (`./a.js`:
20
+ * `a.d.ts`, `./a.mjs`: `a.d.mts`, `./a.cjs`: `a.d.cts`), or by the
21
+ * declaration file itself. The surface names an anchor's module the second
22
+ * way where the first does not resolve (carrick#1911), and so does any source
23
+ * written for `node16`..`nodenext`.
24
+ */
25
+ export function declarationCandidates(resolved) {
26
+ const output = /\.([cm]?)jsx?$/.exec(resolved);
27
+ return [
28
+ `${resolved}.d.ts`,
29
+ path.join(resolved, 'index.d.ts'),
30
+ ...(output ? [`${resolved.slice(0, output.index)}.d.${output[1]}ts`] : []),
31
+ resolved,
32
+ ];
33
+ }
9
34
  /** zod -> zod, @scope/pkg/sub -> @scope/pkg, pkg/sub -> pkg */
10
35
  export function packageNameOf(spec) {
11
36
  const parts = spec.split('/');
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The function a line names, from an index built once per source file
3
+ * (carrick#1915).
4
+ *
5
+ * A signature request carries only the line its function starts on, and a
6
+ * signature pass sends one request per unannotated slot: thousands of
7
+ * lookups, several per function and many per file. Answering each by walking
8
+ * the file's every node cost the file's size per slot, and was 81% of the
9
+ * pass on a 2,345-file program. Here the file is walked once, over the
10
+ * compiler's own nodes, and each lookup reads the few entries near its line.
11
+ *
12
+ * The index belongs to the compiler's source file node, not to the file's
13
+ * name: replacing a file's text gives it a new node, so a file rewritten for
14
+ * one reading (the unwidened reading, the retype check) and then restored is
15
+ * indexed again each time, and never answered from positions it no longer has.
16
+ */
17
+ import { type ArrowFunction, type FunctionDeclaration, type FunctionExpression, type MethodDeclaration, type SourceFile } from 'ts-morph';
18
+ /** The declarations a line can name. */
19
+ export type LineFunction = FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration;
20
+ /**
21
+ * The function whose declaration starts at, or within `LINE_TOLERANCE` lines
22
+ * of, the given line: the closest, then the smallest, then the first in the
23
+ * file. A function starting after the line is passed over when a statement
24
+ * that opens on the line or after it, on a line before the function's, does
25
+ * not contain the function. Undefined when no function is left.
26
+ *
27
+ * These are `TypeInferrer.findFunctionByLine`'s rules, which says why each is
28
+ * there; this is where they are computed.
29
+ */
30
+ export declare function functionAtLine(sourceFile: SourceFile, line: number): LineFunction | undefined;