carrick 0.3.76 → 0.3.78
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.
- package/package.json +6 -6
- package/sidecar/dist/src/capture/deno-project.d.ts +11 -0
- package/sidecar/dist/src/capture/deno-project.js +37 -1
- package/sidecar/dist/src/capture/index.d.ts +19 -0
- package/sidecar/dist/src/capture/index.js +32 -5
- package/sidecar/dist/src/index.js +13 -3
- package/sidecar/dist/src/project-loader.d.ts +13 -0
- package/sidecar/dist/src/project-loader.js +16 -0
- package/sidecar/dist/src/type-inferrer.d.ts +27 -8
- package/sidecar/dist/src/type-inferrer.js +24 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "carrick",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.78",
|
|
4
4
|
"description": "The API contract index for a TypeScript workspace: what the other services do with the routes and calls in the file you are editing, in your editor and in your agent's context",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -57,11 +57,11 @@
|
|
|
57
57
|
"zod": "^3.23.0"
|
|
58
58
|
},
|
|
59
59
|
"optionalDependencies": {
|
|
60
|
-
"@carrick-tools/cli-darwin-arm64": "0.3.
|
|
61
|
-
"@carrick-tools/cli-darwin-x64": "0.3.
|
|
62
|
-
"@carrick-tools/cli-linux-arm64": "0.3.
|
|
63
|
-
"@carrick-tools/cli-linux-x64": "0.3.
|
|
64
|
-
"@carrick-tools/cli-win32-x64": "0.3.
|
|
60
|
+
"@carrick-tools/cli-darwin-arm64": "0.3.78",
|
|
61
|
+
"@carrick-tools/cli-darwin-x64": "0.3.78",
|
|
62
|
+
"@carrick-tools/cli-linux-arm64": "0.3.78",
|
|
63
|
+
"@carrick-tools/cli-linux-x64": "0.3.78",
|
|
64
|
+
"@carrick-tools/cli-win32-x64": "0.3.78"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/node": "^24.13.3",
|
|
@@ -19,6 +19,7 @@ export declare class DenoProject {
|
|
|
19
19
|
readonly pinned: Record<string, string>;
|
|
20
20
|
private readonly modules;
|
|
21
21
|
private readonly localPaths;
|
|
22
|
+
private readonly specifiersByPath;
|
|
22
23
|
private readonly edges;
|
|
23
24
|
private readonly redirects;
|
|
24
25
|
private readonly npmPackages;
|
|
@@ -27,6 +28,16 @@ export declare class DenoProject {
|
|
|
27
28
|
private targetPath;
|
|
28
29
|
resolve(spec: string, from: string, options: ts.CompilerOptions, host?: ts.ModuleResolutionHost): ts.ResolvedModule | undefined;
|
|
29
30
|
private npmOwner;
|
|
31
|
+
/** Which registry package a resolved file belongs to (carrick#1260).
|
|
32
|
+
*
|
|
33
|
+
* The inverse of resolution, and the only answer available for a Deno
|
|
34
|
+
* project: nothing it resolves sits under `node_modules`, so reading a
|
|
35
|
+
* package name off the path cannot work. An npm dependency is owned by the
|
|
36
|
+
* graph entry whose cache directory contains the file; a JSR one is named by
|
|
37
|
+
* its own specifier, since its cached copy is content-addressed and carries
|
|
38
|
+
* no identity. A file the workspace itself owns belongs to no package and
|
|
39
|
+
* answers nothing, exactly as a workspace-declared type does under Node. */
|
|
40
|
+
packageOf(file: string): string | undefined;
|
|
30
41
|
private isNpmFile;
|
|
31
42
|
/** Let TypeScript interpret real package exports/types using Deno's exact
|
|
32
43
|
* dependency graph. Only the resolution host sees virtual node_modules;
|
|
@@ -12,6 +12,22 @@ function readConfig(file) {
|
|
|
12
12
|
throw new Error(ts.flattenDiagnosticMessageText(parsed.error.messageText, '\n'));
|
|
13
13
|
return parsed.config;
|
|
14
14
|
}
|
|
15
|
+
/** The package a JSR module specifier names, in the form the registry uses
|
|
16
|
+
* (`@scope/name`). Both the specifier Deno records after resolution
|
|
17
|
+
* (`https://jsr.io/@scope/name/1.2.3/mod.ts`) and the one an import map writes
|
|
18
|
+
* (`jsr:@scope/name@1`) name it in their first two segments. Anything else —
|
|
19
|
+
* a `file:` module, an `https://` module from a host that is not a package
|
|
20
|
+
* registry — names no package. */
|
|
21
|
+
function jsrPackageName(specifier) {
|
|
22
|
+
const tail = /^jsr:\/{0,2}(.*)$/.exec(specifier)?.[1]
|
|
23
|
+
?? /^https:\/\/jsr\.io\/(.*)$/.exec(specifier)?.[1];
|
|
24
|
+
if (!tail)
|
|
25
|
+
return undefined;
|
|
26
|
+
const [scope, name] = tail.split('/');
|
|
27
|
+
if (!scope?.startsWith('@') || !name)
|
|
28
|
+
return undefined;
|
|
29
|
+
return `${scope}/${name.split('@')[0]}`;
|
|
30
|
+
}
|
|
15
31
|
/** Explicit TS configs keep their existing behaviour, including mixed repos. */
|
|
16
32
|
export function findDenoConfig(repoRoot, explicit) {
|
|
17
33
|
if (explicit && !/^deno\.jsonc?$/.test(path.basename(explicit)))
|
|
@@ -78,6 +94,7 @@ export class DenoProject {
|
|
|
78
94
|
pinned = {};
|
|
79
95
|
modules = new Map();
|
|
80
96
|
localPaths = new Map();
|
|
97
|
+
specifiersByPath = new Map();
|
|
81
98
|
edges = new Map();
|
|
82
99
|
redirects;
|
|
83
100
|
npmPackages;
|
|
@@ -168,6 +185,7 @@ export class DenoProject {
|
|
|
168
185
|
fs.copyFileSync(module.local, local);
|
|
169
186
|
}
|
|
170
187
|
this.localPaths.set(module.specifier, path.resolve(local));
|
|
188
|
+
this.specifiersByPath.set(path.resolve(local), module.specifier);
|
|
171
189
|
}
|
|
172
190
|
for (const module of graph.modules) {
|
|
173
191
|
const local = this.localPaths.get(module.specifier);
|
|
@@ -236,8 +254,26 @@ export class DenoProject {
|
|
|
236
254
|
return this.resolveNpm(spec, from, options) ?? ts.resolveModuleName(spec, from, options, host).resolvedModule;
|
|
237
255
|
}
|
|
238
256
|
npmOwner(file) {
|
|
257
|
+
const target = path.normalize(file);
|
|
239
258
|
return Object.values(this.npmPackages).find(pkg => pkg.localPath &&
|
|
240
|
-
(
|
|
259
|
+
(target === pkg.localPath || target.startsWith(pkg.localPath + path.sep)));
|
|
260
|
+
}
|
|
261
|
+
/** Which registry package a resolved file belongs to (carrick#1260).
|
|
262
|
+
*
|
|
263
|
+
* The inverse of resolution, and the only answer available for a Deno
|
|
264
|
+
* project: nothing it resolves sits under `node_modules`, so reading a
|
|
265
|
+
* package name off the path cannot work. An npm dependency is owned by the
|
|
266
|
+
* graph entry whose cache directory contains the file; a JSR one is named by
|
|
267
|
+
* its own specifier, since its cached copy is content-addressed and carries
|
|
268
|
+
* no identity. A file the workspace itself owns belongs to no package and
|
|
269
|
+
* answers nothing, exactly as a workspace-declared type does under Node. */
|
|
270
|
+
packageOf(file) {
|
|
271
|
+
const resolved = path.resolve(file);
|
|
272
|
+
const owner = this.npmOwner(resolved);
|
|
273
|
+
if (owner)
|
|
274
|
+
return owner.name;
|
|
275
|
+
const specifier = this.specifiersByPath.get(resolved);
|
|
276
|
+
return specifier ? jsrPackageName(specifier) : undefined;
|
|
241
277
|
}
|
|
242
278
|
isNpmFile(file) {
|
|
243
279
|
return !!this.npmOwner(file) || file.split(path.sep).includes('node_modules');
|
|
@@ -32,6 +32,25 @@ export type { CaptureStubOptions, CaptureStubResult } from './api.js';
|
|
|
32
32
|
export { DenoProject, findDenoConfig } from './deno-project.js';
|
|
33
33
|
export { runCheck } from './check.js';
|
|
34
34
|
export type { CheckProgress } from './check.js';
|
|
35
|
+
/**
|
|
36
|
+
* The name of THIS capture's surface entry, without an extension
|
|
37
|
+
* (carrick#1046).
|
|
38
|
+
*
|
|
39
|
+
* The entry has to live inside the effective `rootDir` — an entry beside a
|
|
40
|
+
* `rootDir` of `src` fails TS6059 — so it is written into the scanned tree and
|
|
41
|
+
* unlinked afterwards. One name per repo root made two captures of the same
|
|
42
|
+
* tree share a single file: whichever finished first unlinked it while the
|
|
43
|
+
* other's program was still reading it, and every alias whose print anchors in
|
|
44
|
+
* that destination then demoted to `structural_fallback` with an accessibility
|
|
45
|
+
* reason that described the harness rather than the code. Concurrent captures
|
|
46
|
+
* of one tree are ordinary — the test suite does it on every run, and two
|
|
47
|
+
* services of a monorepo can share a root — so the name, not the locking, is
|
|
48
|
+
* what has to give.
|
|
49
|
+
*
|
|
50
|
+
* A leftover from an interrupted capture is also identifiable as one process's
|
|
51
|
+
* (carrick#1069), rather than a fixed name the next scan reads as source.
|
|
52
|
+
*/
|
|
53
|
+
export declare function surfaceEntryFileName(): string;
|
|
35
54
|
/** Same normalization intent as bundle_file_stems on the Rust side. */
|
|
36
55
|
export declare function sanitizeServiceName(name: string): string;
|
|
37
56
|
export declare function captureStub(opts: CaptureStubOptions): CaptureStubResult;
|
|
@@ -44,6 +44,31 @@ export { DenoProject, findDenoConfig } from './deno-project.js';
|
|
|
44
44
|
// reaches it only through this door (index.js).
|
|
45
45
|
export { runCheck } from './check.js';
|
|
46
46
|
const SURFACE_ENTRY_BASENAME = '__carrick_surface__';
|
|
47
|
+
/** Captures made by this process, so each one's entry file has a name of its
|
|
48
|
+
* own. Paired with the pid it is unique across processes too. */
|
|
49
|
+
let surfaceEntrySequence = 0;
|
|
50
|
+
/**
|
|
51
|
+
* The name of THIS capture's surface entry, without an extension
|
|
52
|
+
* (carrick#1046).
|
|
53
|
+
*
|
|
54
|
+
* The entry has to live inside the effective `rootDir` — an entry beside a
|
|
55
|
+
* `rootDir` of `src` fails TS6059 — so it is written into the scanned tree and
|
|
56
|
+
* unlinked afterwards. One name per repo root made two captures of the same
|
|
57
|
+
* tree share a single file: whichever finished first unlinked it while the
|
|
58
|
+
* other's program was still reading it, and every alias whose print anchors in
|
|
59
|
+
* that destination then demoted to `structural_fallback` with an accessibility
|
|
60
|
+
* reason that described the harness rather than the code. Concurrent captures
|
|
61
|
+
* of one tree are ordinary — the test suite does it on every run, and two
|
|
62
|
+
* services of a monorepo can share a root — so the name, not the locking, is
|
|
63
|
+
* what has to give.
|
|
64
|
+
*
|
|
65
|
+
* A leftover from an interrupted capture is also identifiable as one process's
|
|
66
|
+
* (carrick#1069), rather than a fixed name the next scan reads as source.
|
|
67
|
+
*/
|
|
68
|
+
export function surfaceEntryFileName() {
|
|
69
|
+
surfaceEntrySequence += 1;
|
|
70
|
+
return `${SURFACE_ENTRY_BASENAME}.${process.pid}.${surfaceEntrySequence}`;
|
|
71
|
+
}
|
|
47
72
|
/** Same normalization intent as bundle_file_stems on the Rust side. */
|
|
48
73
|
export function sanitizeServiceName(name) {
|
|
49
74
|
return name.toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
@@ -153,9 +178,11 @@ export function captureStub(opts) {
|
|
|
153
178
|
const entryDir = parsed.options.rootDir
|
|
154
179
|
? path.resolve(path.dirname(configPath), parsed.options.rootDir)
|
|
155
180
|
: repoRoot;
|
|
181
|
+
const surfaceEntry = surfaceEntryFileName();
|
|
182
|
+
const surfaceDeclaration = `${surfaceEntry}.d.ts`;
|
|
156
183
|
const entryPath = deno
|
|
157
|
-
? path.join(deno.cacheDir, `${
|
|
158
|
-
: path.join(entryDir, `${
|
|
184
|
+
? path.join(deno.cacheDir, `${surfaceEntry}.ts`)
|
|
185
|
+
: path.join(entryDir, `${surfaceEntry}.ts`);
|
|
159
186
|
fs.mkdirSync(path.dirname(entryPath), { recursive: true });
|
|
160
187
|
// ---- Phase A: analysis program over placeholder entry + anchor sources ----
|
|
161
188
|
let resolved;
|
|
@@ -250,7 +277,7 @@ export function captureStub(opts) {
|
|
|
250
277
|
if (emitPartial) {
|
|
251
278
|
errors.push(`declaration emit was partial: kept ${emitted.size} emitted file(s); ` +
|
|
252
279
|
'aliases referencing unemitted modules are demoted to structural_fallback');
|
|
253
|
-
resolved = demoteDanglingAliases({ resolved, emitted, declarationSources, staging });
|
|
280
|
+
resolved = demoteDanglingAliases({ resolved, emitted, declarationSources, staging, surfaceDeclaration });
|
|
254
281
|
}
|
|
255
282
|
// ---- Relocate the emitted tree into the stub package ----
|
|
256
283
|
const typesDir = path.join(stubDir, 'types');
|
|
@@ -260,7 +287,7 @@ export function captureStub(opts) {
|
|
|
260
287
|
let surfaceAbsPath = '';
|
|
261
288
|
for (const [fileName, text] of emitted) {
|
|
262
289
|
let rel = path.relative(staging, fileName).split(path.sep).join('/');
|
|
263
|
-
if (path.basename(rel) ===
|
|
290
|
+
if (path.basename(rel) === surfaceDeclaration) {
|
|
264
291
|
const source = sourceByEmitted.get(rel);
|
|
265
292
|
sourceByEmitted.delete(rel);
|
|
266
293
|
rel = 'surface.d.ts';
|
|
@@ -422,7 +449,7 @@ function demoteDanglingAliases(args) {
|
|
|
422
449
|
let surfaceKey;
|
|
423
450
|
for (const fileName of args.emitted.keys()) {
|
|
424
451
|
const rel = path.relative(args.staging, fileName).split(path.sep).join('/');
|
|
425
|
-
if (path.basename(rel) ===
|
|
452
|
+
if (path.basename(rel) === args.surfaceDeclaration)
|
|
426
453
|
surfaceKey = fileName;
|
|
427
454
|
if (rel.endsWith('.d.ts'))
|
|
428
455
|
treeModules.add(rel.slice(0, -'.d.ts'.length));
|
|
@@ -37,12 +37,22 @@ function projectComponents() {
|
|
|
37
37
|
throw new Error('Sidecar not initialized. Call init first.');
|
|
38
38
|
}
|
|
39
39
|
if (!components) {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
// Bound here rather than read from the module slot inside the components:
|
|
41
|
+
// a re-init drops `components` and points the slot at another service, and
|
|
42
|
+
// nothing built over this project may follow it there.
|
|
43
|
+
const loader = projectLoader;
|
|
44
|
+
const project = loader.getProject();
|
|
45
|
+
const repoRoot = loader.getRepoRoot();
|
|
42
46
|
components = {
|
|
43
47
|
typeBundler: new TypeBundler({ project, repoRoot }),
|
|
44
48
|
surfaceEmitter: new SurfaceEmitter({ project, repoRoot }),
|
|
45
|
-
|
|
49
|
+
// The module graph, where the project resolved through one, is the only
|
|
50
|
+
// thing that can name the package a file belongs to: a Deno service
|
|
51
|
+
// resolves nothing under `node_modules` (carrick#1260).
|
|
52
|
+
typeInferrer: new TypeInferrer({
|
|
53
|
+
project,
|
|
54
|
+
packageOf: (filePath) => loader.packageOf(filePath),
|
|
55
|
+
}),
|
|
46
56
|
definitionResolver: new DefinitionResolver({ project }),
|
|
47
57
|
};
|
|
48
58
|
}
|
|
@@ -54,6 +54,13 @@ export declare class ProjectLoader {
|
|
|
54
54
|
private project;
|
|
55
55
|
/** Set by `load()`; builds the ts-morph project on first `getProject()`. */
|
|
56
56
|
private buildProject;
|
|
57
|
+
/**
|
|
58
|
+
* The Deno graph this project resolved through, when it did (carrick#1260).
|
|
59
|
+
* It is the only thing that can name the package a resolved file belongs to,
|
|
60
|
+
* because a Deno project resolves nothing under `node_modules`. Set by the
|
|
61
|
+
* build, so it is there from the first `getProject()` onwards.
|
|
62
|
+
*/
|
|
63
|
+
private denoProject;
|
|
57
64
|
private readonly repoRoot;
|
|
58
65
|
private readonly tsconfigPath;
|
|
59
66
|
private readonly tsconfigSnapshot;
|
|
@@ -82,6 +89,12 @@ export declare class ProjectLoader {
|
|
|
82
89
|
* @throws Error if load() has not succeeded, or if the build fails
|
|
83
90
|
*/
|
|
84
91
|
getProject(): Project;
|
|
92
|
+
/**
|
|
93
|
+
* The registry package a resolved file belongs to, when the module graph
|
|
94
|
+
* names one (carrick#1260). `undefined` for a project that did not resolve
|
|
95
|
+
* through Deno, and for a file the workspace itself owns.
|
|
96
|
+
*/
|
|
97
|
+
packageOf(filePath: string): string | undefined;
|
|
85
98
|
/**
|
|
86
99
|
* Check if the project has been successfully initialized
|
|
87
100
|
*/
|
|
@@ -108,6 +108,13 @@ export class ProjectLoader {
|
|
|
108
108
|
project = null;
|
|
109
109
|
/** Set by `load()`; builds the ts-morph project on first `getProject()`. */
|
|
110
110
|
buildProject = null;
|
|
111
|
+
/**
|
|
112
|
+
* The Deno graph this project resolved through, when it did (carrick#1260).
|
|
113
|
+
* It is the only thing that can name the package a resolved file belongs to,
|
|
114
|
+
* because a Deno project resolves nothing under `node_modules`. Set by the
|
|
115
|
+
* build, so it is there from the first `getProject()` onwards.
|
|
116
|
+
*/
|
|
117
|
+
denoProject;
|
|
111
118
|
repoRoot;
|
|
112
119
|
tsconfigPath;
|
|
113
120
|
tsconfigSnapshot;
|
|
@@ -175,6 +182,7 @@ export class ProjectLoader {
|
|
|
175
182
|
this.log(`Project will load with Deno config: ${denoConfig.configPath}`);
|
|
176
183
|
this.buildProject = () => {
|
|
177
184
|
const deno = new DenoProject(denoConfig, this.repoRoot);
|
|
185
|
+
this.denoProject = deno;
|
|
178
186
|
const project = new Project({
|
|
179
187
|
compilerOptions: deno.parsed.options,
|
|
180
188
|
skipAddingFilesFromTsConfig: true,
|
|
@@ -317,6 +325,14 @@ export class ProjectLoader {
|
|
|
317
325
|
}
|
|
318
326
|
return this.project;
|
|
319
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* The registry package a resolved file belongs to, when the module graph
|
|
330
|
+
* names one (carrick#1260). `undefined` for a project that did not resolve
|
|
331
|
+
* through Deno, and for a file the workspace itself owns.
|
|
332
|
+
*/
|
|
333
|
+
packageOf(filePath) {
|
|
334
|
+
return this.denoProject?.packageOf(filePath);
|
|
335
|
+
}
|
|
320
336
|
/**
|
|
321
337
|
* Check if the project has been successfully initialized
|
|
322
338
|
*/
|
|
@@ -62,6 +62,13 @@ export declare function isExternalOrigin(filePath: string): boolean;
|
|
|
62
62
|
export interface TypeInferrerOptions {
|
|
63
63
|
/** The ts-morph Project instance */
|
|
64
64
|
project: Project;
|
|
65
|
+
/**
|
|
66
|
+
* The registry package a resolved file belongs to, when the module graph
|
|
67
|
+
* that built the project names one (carrick#1260). Supplied for a project
|
|
68
|
+
* whose resolution went through a graph rather than through `node_modules`;
|
|
69
|
+
* absent otherwise, and the path itself is then the only thing to read.
|
|
70
|
+
*/
|
|
71
|
+
packageOf?: (filePath: string) => string | undefined;
|
|
65
72
|
}
|
|
66
73
|
/**
|
|
67
74
|
* TypeInferrer - Extracts types from source code, both explicit and inferred
|
|
@@ -72,6 +79,7 @@ export interface TypeInferrerOptions {
|
|
|
72
79
|
*/
|
|
73
80
|
export declare class TypeInferrer {
|
|
74
81
|
private readonly project;
|
|
82
|
+
private readonly packageOf;
|
|
75
83
|
constructor(options: TypeInferrerOptions);
|
|
76
84
|
/**
|
|
77
85
|
* Infer types for the given requests
|
|
@@ -727,14 +735,25 @@ export declare class TypeInferrer {
|
|
|
727
735
|
*/
|
|
728
736
|
private inferReceiverType;
|
|
729
737
|
/**
|
|
730
|
-
* The npm package name that declares a type
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
+
* The npm package name that declares a type. `undefined` when the type has
|
|
739
|
+
* no declaration to read (a top type, a primitive, an anonymous object
|
|
740
|
+
* literal) or when nothing owns its declaration but the workspace itself.
|
|
741
|
+
*
|
|
742
|
+
* The module graph is asked first, where there is one, because it is the
|
|
743
|
+
* only thing that can answer for a project whose resolution does not go
|
|
744
|
+
* through `node_modules`. Deno resolves an npm dependency's types straight
|
|
745
|
+
* out of its own cache
|
|
746
|
+
* (`$DENO_DIR/npm/<registry-host>/<name>/<version>/…`), a path with no
|
|
747
|
+
* `node_modules` segment anywhere in it, so the scan below found no package
|
|
748
|
+
* for ANY dependency-declared type on such a repo and every receiver the
|
|
749
|
+
* compiler had typed correctly went unclassified (carrick#1260). It runs
|
|
750
|
+
* first rather than second because a mixed checkout has both, and the graph
|
|
751
|
+
* is what actually resolved the module.
|
|
752
|
+
*
|
|
753
|
+
* The path scan is the Node answer: the LAST `node_modules` segment wins,
|
|
754
|
+
* which is what a nested or content-addressed store
|
|
755
|
+
* (`node_modules/.store/pkg@1.0.0/node_modules/pkg`) requires. Scoped names
|
|
756
|
+
* keep both segments.
|
|
738
757
|
*/
|
|
739
758
|
private declaringPackageOf;
|
|
740
759
|
/**
|
|
@@ -249,8 +249,10 @@ function typeText(type, enclosingNode) {
|
|
|
249
249
|
*/
|
|
250
250
|
export class TypeInferrer {
|
|
251
251
|
project;
|
|
252
|
+
packageOf;
|
|
252
253
|
constructor(options) {
|
|
253
254
|
this.project = options.project;
|
|
255
|
+
this.packageOf = options.packageOf;
|
|
254
256
|
}
|
|
255
257
|
/**
|
|
256
258
|
* Infer types for the given requests
|
|
@@ -2942,14 +2944,25 @@ export class TypeInferrer {
|
|
|
2942
2944
|
};
|
|
2943
2945
|
}
|
|
2944
2946
|
/**
|
|
2945
|
-
* The npm package name that declares a type
|
|
2946
|
-
*
|
|
2947
|
-
*
|
|
2948
|
-
* under a `node_modules` tree — a type the workspace itself declares.
|
|
2947
|
+
* The npm package name that declares a type. `undefined` when the type has
|
|
2948
|
+
* no declaration to read (a top type, a primitive, an anonymous object
|
|
2949
|
+
* literal) or when nothing owns its declaration but the workspace itself.
|
|
2949
2950
|
*
|
|
2950
|
-
* The
|
|
2951
|
-
*
|
|
2952
|
-
*
|
|
2951
|
+
* The module graph is asked first, where there is one, because it is the
|
|
2952
|
+
* only thing that can answer for a project whose resolution does not go
|
|
2953
|
+
* through `node_modules`. Deno resolves an npm dependency's types straight
|
|
2954
|
+
* out of its own cache
|
|
2955
|
+
* (`$DENO_DIR/npm/<registry-host>/<name>/<version>/…`), a path with no
|
|
2956
|
+
* `node_modules` segment anywhere in it, so the scan below found no package
|
|
2957
|
+
* for ANY dependency-declared type on such a repo and every receiver the
|
|
2958
|
+
* compiler had typed correctly went unclassified (carrick#1260). It runs
|
|
2959
|
+
* first rather than second because a mixed checkout has both, and the graph
|
|
2960
|
+
* is what actually resolved the module.
|
|
2961
|
+
*
|
|
2962
|
+
* The path scan is the Node answer: the LAST `node_modules` segment wins,
|
|
2963
|
+
* which is what a nested or content-addressed store
|
|
2964
|
+
* (`node_modules/.store/pkg@1.0.0/node_modules/pkg`) requires. Scoped names
|
|
2965
|
+
* keep both segments.
|
|
2953
2966
|
*/
|
|
2954
2967
|
declaringPackageOf(type) {
|
|
2955
2968
|
const symbol = type.getSymbol() ?? type.getAliasSymbol();
|
|
@@ -2958,6 +2971,10 @@ export class TypeInferrer {
|
|
|
2958
2971
|
return undefined;
|
|
2959
2972
|
}
|
|
2960
2973
|
const filePath = declaration.getSourceFile().getFilePath().replace(/\\/g, '/');
|
|
2974
|
+
const named = this.packageOf?.(filePath);
|
|
2975
|
+
if (named) {
|
|
2976
|
+
return named;
|
|
2977
|
+
}
|
|
2961
2978
|
const marker = '/node_modules/';
|
|
2962
2979
|
const index = filePath.lastIndexOf(marker);
|
|
2963
2980
|
if (index < 0) {
|