svelte-docinfo 0.1.0
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/LICENSE +21 -0
- package/README.md +349 -0
- package/dist/analyze-core.d.ts +1386 -0
- package/dist/analyze-core.d.ts.map +1 -0
- package/dist/analyze-core.js +324 -0
- package/dist/analyze.d.ts +137 -0
- package/dist/analyze.d.ts.map +1 -0
- package/dist/analyze.js +148 -0
- package/dist/cli.d.ts +102 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +206 -0
- package/dist/concurrency.d.ts +38 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +57 -0
- package/dist/declaration-build.d.ts +164 -0
- package/dist/declaration-build.d.ts.map +1 -0
- package/dist/declaration-build.js +15 -0
- package/dist/declaration-helpers.d.ts +169 -0
- package/dist/declaration-helpers.d.ts.map +1 -0
- package/dist/declaration-helpers.js +239 -0
- package/dist/dep-resolver.d.ts +166 -0
- package/dist/dep-resolver.d.ts.map +1 -0
- package/dist/dep-resolver.js +144 -0
- package/dist/diagnostics.d.ts +650 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +377 -0
- package/dist/discovery.d.ts +115 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +126 -0
- package/dist/exports.d.ts +105 -0
- package/dist/exports.d.ts.map +1 -0
- package/dist/exports.js +274 -0
- package/dist/files.d.ts +77 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +95 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/log.d.ts +32 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +11 -0
- package/dist/logo.d.ts +8 -0
- package/dist/logo.d.ts.map +1 -0
- package/dist/logo.js +9 -0
- package/dist/main.d.ts +11 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +18 -0
- package/dist/paths.d.ts +35 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +34 -0
- package/dist/postprocess.d.ts +145 -0
- package/dist/postprocess.d.ts.map +1 -0
- package/dist/postprocess.js +305 -0
- package/dist/session.d.ts +248 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +496 -0
- package/dist/source-config.d.ts +330 -0
- package/dist/source-config.d.ts.map +1 -0
- package/dist/source-config.js +356 -0
- package/dist/source.d.ts +126 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +68 -0
- package/dist/svelte.d.ts +179 -0
- package/dist/svelte.d.ts.map +1 -0
- package/dist/svelte.js +898 -0
- package/dist/tsdoc.d.ts +145 -0
- package/dist/tsdoc.d.ts.map +1 -0
- package/dist/tsdoc.js +262 -0
- package/dist/types.d.ts +3381 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +588 -0
- package/dist/typescript-exports.d.ts +91 -0
- package/dist/typescript-exports.d.ts.map +1 -0
- package/dist/typescript-exports.js +656 -0
- package/dist/typescript-extract-class.d.ts +29 -0
- package/dist/typescript-extract-class.d.ts.map +1 -0
- package/dist/typescript-extract-class.js +251 -0
- package/dist/typescript-extract-function.d.ts +47 -0
- package/dist/typescript-extract-function.d.ts.map +1 -0
- package/dist/typescript-extract-function.js +108 -0
- package/dist/typescript-extract-shared.d.ts +166 -0
- package/dist/typescript-extract-shared.d.ts.map +1 -0
- package/dist/typescript-extract-shared.js +528 -0
- package/dist/typescript-extract-type-properties.d.ts +34 -0
- package/dist/typescript-extract-type-properties.d.ts.map +1 -0
- package/dist/typescript-extract-type-properties.js +241 -0
- package/dist/typescript-extract-type.d.ts +48 -0
- package/dist/typescript-extract-type.d.ts.map +1 -0
- package/dist/typescript-extract-type.js +238 -0
- package/dist/typescript-program.d.ts +211 -0
- package/dist/typescript-program.d.ts.map +1 -0
- package/dist/typescript-program.js +290 -0
- package/dist/vite.d.ts +116 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +418 -0
- package/package.json +131 -0
- package/virtual-svelte-docinfo.d.ts +49 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for working with declaration and member types.
|
|
3
|
+
*
|
|
4
|
+
* Display formatting, code generation, serialization, type narrowing,
|
|
5
|
+
* and type reference discovery for `DeclarationJson` and `MemberJson`.
|
|
6
|
+
*
|
|
7
|
+
* @see `types.ts` for `DeclarationJson`, `MemberJson` Zod schemas
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { DeclarationJson, MemberJson, DeclarationKind, MemberKind } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* JSON replacer that strips Zod default values for compact serialization.
|
|
14
|
+
*
|
|
15
|
+
* Strips empty arrays and `false` booleans — both are Zod `.default()` values
|
|
16
|
+
* restored on `.parse()`, so the round-trip is lossless for svelte-docinfo types.
|
|
17
|
+
* Assumes all boolean fields in the schema default to `false` — a `true`-defaulted
|
|
18
|
+
* boolean would need its `false` values preserved, breaking the round-trip.
|
|
19
|
+
*
|
|
20
|
+
* **Root-value caveat**: `JSON.stringify([], compactReplacer)` returns the JS
|
|
21
|
+
* `undefined` (not the string `'[]'`), and `JSON.stringify(false, compactReplacer)`
|
|
22
|
+
* returns the JS `undefined` too. Object-rooted callers (`AnalyzeResultJson`
|
|
23
|
+
* envelope, CLI output) don't hit this — empty inner arrays strip and
|
|
24
|
+
* `AnalyzeResultJson.parse` restores them on the consumer side. Array-rooted
|
|
25
|
+
* callers (Vite plugin, anyone splicing the JSON into a source template)
|
|
26
|
+
* must handle the empty case themselves before calling this; see
|
|
27
|
+
* `vite.ts:updateOutputFromQuery` for the pattern.
|
|
28
|
+
*
|
|
29
|
+
* Two guard tests in `declaration-helpers.test.ts` lock this in:
|
|
30
|
+
* - `every z.boolean().default in types.ts uses false` — source-regex check
|
|
31
|
+
* that fails on a new `z.boolean().default(true)`.
|
|
32
|
+
* - `parse → stringify(compactReplacer) → parse is a faithful round-trip
|
|
33
|
+
* across every variant` — exercises every variant and member through a
|
|
34
|
+
* full round-trip, catching regressions where a `.default(false)` or
|
|
35
|
+
* `.default([])` is removed (or a new field is added that the replacer
|
|
36
|
+
* drops but Zod doesn't restore).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const result = await analyze({sourceFiles, sourceOptions});
|
|
41
|
+
* const json = JSON.stringify(result, compactReplacer);
|
|
42
|
+
* // On the consumer side, restore Zod defaults:
|
|
43
|
+
* const restored = AnalyzeResultJson.parse(JSON.parse(json));
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const compactReplacer: (_key: string, value: unknown) => unknown;
|
|
47
|
+
/**
|
|
48
|
+
* Format declaration or member name with generic parameters for display.
|
|
49
|
+
*
|
|
50
|
+
* Default-slot entries return the literal `'default'` (the symbol's actual
|
|
51
|
+
* name in JS). Renderers that want a richer label (PascalCased module path,
|
|
52
|
+
* an explicit "default export" header) should branch on `name === 'default'`
|
|
53
|
+
* themselves before calling this.
|
|
54
|
+
*
|
|
55
|
+
* @see `generateImport` for the divergent default-slot fallback used in
|
|
56
|
+
* import-statement generation (PascalCased module path, since an import
|
|
57
|
+
* needs a JS identifier binding, not a label).
|
|
58
|
+
*
|
|
59
|
+
* @param declaration - the `DeclarationJson` or `MemberJson` to format
|
|
60
|
+
* @returns name with generic parameters appended (e.g., `Map<K, V>`)
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* getDisplayName({name: 'Map', kind: 'type', genericParams: [{name: 'K'}, {name: 'V'}]})
|
|
65
|
+
* // => 'Map<K, V>'
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare const getDisplayName: (declaration: DeclarationJson | MemberJson) => string;
|
|
69
|
+
/**
|
|
70
|
+
* Generate TypeScript import statement for a declaration.
|
|
71
|
+
*
|
|
72
|
+
* Produces `import type` for type/interface declarations, `import` for values.
|
|
73
|
+
*
|
|
74
|
+
* **Default export handling**: when `declaration.name === 'default'`, emits
|
|
75
|
+
* `import X from '...'` with the binding derived by PascalCasing the module
|
|
76
|
+
* path. (`'default'` is the symbol's actual name in JS — `import X from 'mod'`
|
|
77
|
+
* is sugar for `import {default as X} from 'mod'`.)
|
|
78
|
+
*
|
|
79
|
+
* @see `getDisplayName` for the divergent default-slot fallback used as a
|
|
80
|
+
* display label (the literal `'default'`, since a label has no use for a
|
|
81
|
+
* synthesized JS binding).
|
|
82
|
+
*
|
|
83
|
+
* @param declaration - the `DeclarationJson` to generate an import for
|
|
84
|
+
* @param modulePath - module path relative to source root (e.g., `foo.ts`)
|
|
85
|
+
* @param libraryName - package name for the import specifier (e.g., `@pkg/lib`)
|
|
86
|
+
* @returns formatted import statement string
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* generateImport({name: 'Foo', kind: 'type'}, 'foo.ts', '@pkg/lib')
|
|
91
|
+
* // => "import type {Foo} from '@pkg/lib/foo.js';"
|
|
92
|
+
*
|
|
93
|
+
* generateImport({name: 'default', kind: 'function'}, 'foo-bar.ts', '@pkg/lib')
|
|
94
|
+
* // => "import FooBar from '@pkg/lib/foo-bar.js';"
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare const generateImport: (declaration: DeclarationJson, modulePath: string, libraryName: string) => string;
|
|
98
|
+
/**
|
|
99
|
+
* Pre-compile identifier-boundary patterns for a set of declaration names.
|
|
100
|
+
*
|
|
101
|
+
* When scanning many type strings against the same declaration set,
|
|
102
|
+
* call this once and pass the result to `findTypeReferences`
|
|
103
|
+
* to avoid recompiling regexes on every call.
|
|
104
|
+
*
|
|
105
|
+
* @param declarationNames - set of known in-project declaration names
|
|
106
|
+
* @returns array of `[name, pattern]` pairs for use with `findTypeReferences`
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const names = new Set(modules.flatMap(m => m.declarations.map(d => d.name)));
|
|
111
|
+
* const patterns = buildTypeReferencePatterns(names);
|
|
112
|
+
* for (const decl of declarations) {
|
|
113
|
+
* const refs = findTypeReferences(decl.typeSignature, patterns);
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare const buildTypeReferencePatterns: (declarationNames: ReadonlySet<string>) => Array<[string, RegExp]>;
|
|
118
|
+
/**
|
|
119
|
+
* Find in-project declaration names referenced in a type string.
|
|
120
|
+
*
|
|
121
|
+
* Uses identifier-boundary matching to find which known declaration names appear
|
|
122
|
+
* in an opaque type string (e.g., `typeSignature`, `returnType`, parameter `type`).
|
|
123
|
+
* Enables consumers to render clickable type links without needing access to
|
|
124
|
+
* the TypeScript type checker.
|
|
125
|
+
*
|
|
126
|
+
* Handles identifiers starting with `$` (e.g., `$state`) which `\b` does not
|
|
127
|
+
* recognize as word boundaries.
|
|
128
|
+
*
|
|
129
|
+
* Accepts either a `ReadonlySet<string>` (convenience) or pre-compiled patterns
|
|
130
|
+
* from `buildTypeReferencePatterns` (performance). Use pre-compiled patterns
|
|
131
|
+
* when scanning many type strings against the same declaration set.
|
|
132
|
+
*
|
|
133
|
+
* **Known limitations**: Identifier-boundary matching can produce false positives
|
|
134
|
+
* when a declaration name appears as a property key in an object literal type
|
|
135
|
+
* (e.g., `{ Foo: string }` when `Foo` is a declaration). This is rare in practice.
|
|
136
|
+
*
|
|
137
|
+
* @param typeString - opaque type string from analysis output
|
|
138
|
+
* @param declarationNames - set of names or pre-compiled patterns from `buildTypeReferencePatterns`
|
|
139
|
+
* @returns array of declaration names found in the type string
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* const names = new Set(modules.flatMap(m => m.declarations.map(d => d.name)));
|
|
144
|
+
* findTypeReferences('Map<string, ModuleJson[]>', names)
|
|
145
|
+
* // => ['ModuleJson']
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export declare const findTypeReferences: (typeString: string, declarationNames: ReadonlySet<string> | Array<[string, RegExp]>) => Array<string>;
|
|
149
|
+
/**
|
|
150
|
+
* Narrow a declaration by kind for type-safe field access.
|
|
151
|
+
*
|
|
152
|
+
* Works with both `DeclarationJson` (top-level) and `MemberJson` (nested).
|
|
153
|
+
* Accepts `DeclarationKind | MemberKind` so `isKind(member, 'constructor')` compiles.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* if (isKind(declaration, 'function')) {
|
|
158
|
+
* declaration.parameters; // FunctionDeclarationJson — has parameters
|
|
159
|
+
* declaration.returnType; // has returnType
|
|
160
|
+
* }
|
|
161
|
+
* if (isKind(member, 'constructor')) {
|
|
162
|
+
* member.parameters; // ConstructorMemberJson — has parameters
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export declare const isKind: <K extends DeclarationKind | MemberKind>(declaration: DeclarationJson | MemberJson, kind: K) => declaration is Extract<DeclarationJson | MemberJson, {
|
|
167
|
+
kind: K;
|
|
168
|
+
}>;
|
|
169
|
+
//# sourceMappingURL=declaration-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration-helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/declaration-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAC,MAAM,YAAY,CAAC;AAIzF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,OAAO,OAAO,KAAG,OACqB,CAAC;AAIrF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,cAAc,GAAI,aAAa,eAAe,GAAG,UAAU,KAAG,MAS1E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,cAAc,GAC1B,aAAa,eAAe,EAC5B,YAAY,MAAM,EAClB,aAAa,MAAM,KACjB,MAuBF,CAAC;AA6BF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,0BAA0B,GACtC,kBAAkB,WAAW,CAAC,MAAM,CAAC,KACnC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,kBAAkB,GAC9B,YAAY,MAAM,EAClB,kBAAkB,WAAW,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAC7D,KAAK,CAAC,MAAM,CAYd,CAAC;AAIF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,eAAe,GAAG,UAAU,EAC5D,aAAa,eAAe,GAAG,UAAU,EACzC,MAAM,CAAC,KACL,WAAW,IAAI,OAAO,CAAC,eAAe,GAAG,UAAU,EAAE;IAAC,IAAI,EAAE,CAAC,CAAA;CAAC,CAA8B,CAAC"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for working with declaration and member types.
|
|
3
|
+
*
|
|
4
|
+
* Display formatting, code generation, serialization, type narrowing,
|
|
5
|
+
* and type reference discovery for `DeclarationJson` and `MemberJson`.
|
|
6
|
+
*
|
|
7
|
+
* @see `types.ts` for `DeclarationJson`, `MemberJson` Zod schemas
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
// ── Serialization ───────────────────────────────────────────────────────────
|
|
12
|
+
/**
|
|
13
|
+
* JSON replacer that strips Zod default values for compact serialization.
|
|
14
|
+
*
|
|
15
|
+
* Strips empty arrays and `false` booleans — both are Zod `.default()` values
|
|
16
|
+
* restored on `.parse()`, so the round-trip is lossless for svelte-docinfo types.
|
|
17
|
+
* Assumes all boolean fields in the schema default to `false` — a `true`-defaulted
|
|
18
|
+
* boolean would need its `false` values preserved, breaking the round-trip.
|
|
19
|
+
*
|
|
20
|
+
* **Root-value caveat**: `JSON.stringify([], compactReplacer)` returns the JS
|
|
21
|
+
* `undefined` (not the string `'[]'`), and `JSON.stringify(false, compactReplacer)`
|
|
22
|
+
* returns the JS `undefined` too. Object-rooted callers (`AnalyzeResultJson`
|
|
23
|
+
* envelope, CLI output) don't hit this — empty inner arrays strip and
|
|
24
|
+
* `AnalyzeResultJson.parse` restores them on the consumer side. Array-rooted
|
|
25
|
+
* callers (Vite plugin, anyone splicing the JSON into a source template)
|
|
26
|
+
* must handle the empty case themselves before calling this; see
|
|
27
|
+
* `vite.ts:updateOutputFromQuery` for the pattern.
|
|
28
|
+
*
|
|
29
|
+
* Two guard tests in `declaration-helpers.test.ts` lock this in:
|
|
30
|
+
* - `every z.boolean().default in types.ts uses false` — source-regex check
|
|
31
|
+
* that fails on a new `z.boolean().default(true)`.
|
|
32
|
+
* - `parse → stringify(compactReplacer) → parse is a faithful round-trip
|
|
33
|
+
* across every variant` — exercises every variant and member through a
|
|
34
|
+
* full round-trip, catching regressions where a `.default(false)` or
|
|
35
|
+
* `.default([])` is removed (or a new field is added that the replacer
|
|
36
|
+
* drops but Zod doesn't restore).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const result = await analyze({sourceFiles, sourceOptions});
|
|
41
|
+
* const json = JSON.stringify(result, compactReplacer);
|
|
42
|
+
* // On the consumer side, restore Zod defaults:
|
|
43
|
+
* const restored = AnalyzeResultJson.parse(JSON.parse(json));
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export const compactReplacer = (_key, value) => (Array.isArray(value) && value.length === 0) || value === false ? undefined : value;
|
|
47
|
+
// ── Display Helpers ─────────────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Format declaration or member name with generic parameters for display.
|
|
50
|
+
*
|
|
51
|
+
* Default-slot entries return the literal `'default'` (the symbol's actual
|
|
52
|
+
* name in JS). Renderers that want a richer label (PascalCased module path,
|
|
53
|
+
* an explicit "default export" header) should branch on `name === 'default'`
|
|
54
|
+
* themselves before calling this.
|
|
55
|
+
*
|
|
56
|
+
* @see `generateImport` for the divergent default-slot fallback used in
|
|
57
|
+
* import-statement generation (PascalCased module path, since an import
|
|
58
|
+
* needs a JS identifier binding, not a label).
|
|
59
|
+
*
|
|
60
|
+
* @param declaration - the `DeclarationJson` or `MemberJson` to format
|
|
61
|
+
* @returns name with generic parameters appended (e.g., `Map<K, V>`)
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* getDisplayName({name: 'Map', kind: 'type', genericParams: [{name: 'K'}, {name: 'V'}]})
|
|
66
|
+
* // => 'Map<K, V>'
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export const getDisplayName = (declaration) => {
|
|
70
|
+
if (!declaration.genericParams.length)
|
|
71
|
+
return declaration.name;
|
|
72
|
+
const params = declaration.genericParams.map((p) => {
|
|
73
|
+
let param = p.name;
|
|
74
|
+
if (p.constraint)
|
|
75
|
+
param += ` extends ${p.constraint}`;
|
|
76
|
+
if (p.defaultType)
|
|
77
|
+
param += ` = ${p.defaultType}`;
|
|
78
|
+
return param;
|
|
79
|
+
});
|
|
80
|
+
return `${declaration.name}<${params.join(', ')}>`;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Generate TypeScript import statement for a declaration.
|
|
84
|
+
*
|
|
85
|
+
* Produces `import type` for type/interface declarations, `import` for values.
|
|
86
|
+
*
|
|
87
|
+
* **Default export handling**: when `declaration.name === 'default'`, emits
|
|
88
|
+
* `import X from '...'` with the binding derived by PascalCasing the module
|
|
89
|
+
* path. (`'default'` is the symbol's actual name in JS — `import X from 'mod'`
|
|
90
|
+
* is sugar for `import {default as X} from 'mod'`.)
|
|
91
|
+
*
|
|
92
|
+
* @see `getDisplayName` for the divergent default-slot fallback used as a
|
|
93
|
+
* display label (the literal `'default'`, since a label has no use for a
|
|
94
|
+
* synthesized JS binding).
|
|
95
|
+
*
|
|
96
|
+
* @param declaration - the `DeclarationJson` to generate an import for
|
|
97
|
+
* @param modulePath - module path relative to source root (e.g., `foo.ts`)
|
|
98
|
+
* @param libraryName - package name for the import specifier (e.g., `@pkg/lib`)
|
|
99
|
+
* @returns formatted import statement string
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* generateImport({name: 'Foo', kind: 'type'}, 'foo.ts', '@pkg/lib')
|
|
104
|
+
* // => "import type {Foo} from '@pkg/lib/foo.js';"
|
|
105
|
+
*
|
|
106
|
+
* generateImport({name: 'default', kind: 'function'}, 'foo-bar.ts', '@pkg/lib')
|
|
107
|
+
* // => "import FooBar from '@pkg/lib/foo-bar.js';"
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export const generateImport = (declaration, modulePath, libraryName) => {
|
|
111
|
+
const jsPath = modulePath.replace(/\.ts$/, '.js');
|
|
112
|
+
const specifier = `${libraryName}/${jsPath}`;
|
|
113
|
+
// Default-slot entries — derive the import binding from the module path.
|
|
114
|
+
if (declaration.name === 'default') {
|
|
115
|
+
return `import ${pascalCaseFromModulePath(modulePath)} from '${specifier}';`;
|
|
116
|
+
}
|
|
117
|
+
// Components are default exports in Svelte
|
|
118
|
+
if (declaration.kind === 'component') {
|
|
119
|
+
return `import ${declaration.name} from '${specifier}';`;
|
|
120
|
+
}
|
|
121
|
+
// Namespace re-export: `export * as ns from './x'` in the source becomes
|
|
122
|
+
// `import * as ns from '<package>/<re-exporter>.js'` for consumers.
|
|
123
|
+
if (declaration.kind === 'namespace') {
|
|
124
|
+
return `import * as ${declaration.name} from '${specifier}';`;
|
|
125
|
+
}
|
|
126
|
+
const importKeyword = declaration.kind === 'type' || declaration.kind === 'interface' ? 'import type' : 'import';
|
|
127
|
+
return `${importKeyword} {${declaration.name}} from '${specifier}';`;
|
|
128
|
+
};
|
|
129
|
+
const pascalCaseFromModulePath = (modulePath) => {
|
|
130
|
+
const moduleName = modulePath.replace(/\.(js|ts|svelte)$/, '');
|
|
131
|
+
return moduleName
|
|
132
|
+
.split(/[-_/]/)
|
|
133
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
134
|
+
.join('');
|
|
135
|
+
};
|
|
136
|
+
// ── Type Reference Helpers ─────────────────────────────────────────────────
|
|
137
|
+
/**
|
|
138
|
+
* Escape special regex characters in a string.
|
|
139
|
+
*/
|
|
140
|
+
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
141
|
+
/** Matches TypeScript identifier characters (letters, digits, `_`, `$`). */
|
|
142
|
+
const ID_CHAR = '[a-zA-Z0-9_$]';
|
|
143
|
+
/**
|
|
144
|
+
* Build a regex that matches `name` only at identifier boundaries.
|
|
145
|
+
*
|
|
146
|
+
* Uses lookaround for `[a-zA-Z0-9_$]` instead of `\b` so that
|
|
147
|
+
* `$`-prefixed identifiers like `$state` are matched correctly.
|
|
148
|
+
*/
|
|
149
|
+
const buildIdentifierPattern = (name) => new RegExp('(?<!' + ID_CHAR + ')' + escapeRegex(name) + '(?!' + ID_CHAR + ')');
|
|
150
|
+
/**
|
|
151
|
+
* Pre-compile identifier-boundary patterns for a set of declaration names.
|
|
152
|
+
*
|
|
153
|
+
* When scanning many type strings against the same declaration set,
|
|
154
|
+
* call this once and pass the result to `findTypeReferences`
|
|
155
|
+
* to avoid recompiling regexes on every call.
|
|
156
|
+
*
|
|
157
|
+
* @param declarationNames - set of known in-project declaration names
|
|
158
|
+
* @returns array of `[name, pattern]` pairs for use with `findTypeReferences`
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* const names = new Set(modules.flatMap(m => m.declarations.map(d => d.name)));
|
|
163
|
+
* const patterns = buildTypeReferencePatterns(names);
|
|
164
|
+
* for (const decl of declarations) {
|
|
165
|
+
* const refs = findTypeReferences(decl.typeSignature, patterns);
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
export const buildTypeReferencePatterns = (declarationNames) => {
|
|
170
|
+
const patterns = [];
|
|
171
|
+
for (const name of declarationNames) {
|
|
172
|
+
if (name)
|
|
173
|
+
patterns.push([name, buildIdentifierPattern(name)]);
|
|
174
|
+
}
|
|
175
|
+
return patterns;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Find in-project declaration names referenced in a type string.
|
|
179
|
+
*
|
|
180
|
+
* Uses identifier-boundary matching to find which known declaration names appear
|
|
181
|
+
* in an opaque type string (e.g., `typeSignature`, `returnType`, parameter `type`).
|
|
182
|
+
* Enables consumers to render clickable type links without needing access to
|
|
183
|
+
* the TypeScript type checker.
|
|
184
|
+
*
|
|
185
|
+
* Handles identifiers starting with `$` (e.g., `$state`) which `\b` does not
|
|
186
|
+
* recognize as word boundaries.
|
|
187
|
+
*
|
|
188
|
+
* Accepts either a `ReadonlySet<string>` (convenience) or pre-compiled patterns
|
|
189
|
+
* from `buildTypeReferencePatterns` (performance). Use pre-compiled patterns
|
|
190
|
+
* when scanning many type strings against the same declaration set.
|
|
191
|
+
*
|
|
192
|
+
* **Known limitations**: Identifier-boundary matching can produce false positives
|
|
193
|
+
* when a declaration name appears as a property key in an object literal type
|
|
194
|
+
* (e.g., `{ Foo: string }` when `Foo` is a declaration). This is rare in practice.
|
|
195
|
+
*
|
|
196
|
+
* @param typeString - opaque type string from analysis output
|
|
197
|
+
* @param declarationNames - set of names or pre-compiled patterns from `buildTypeReferencePatterns`
|
|
198
|
+
* @returns array of declaration names found in the type string
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* const names = new Set(modules.flatMap(m => m.declarations.map(d => d.name)));
|
|
203
|
+
* findTypeReferences('Map<string, ModuleJson[]>', names)
|
|
204
|
+
* // => ['ModuleJson']
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
export const findTypeReferences = (typeString, declarationNames) => {
|
|
208
|
+
if (!typeString)
|
|
209
|
+
return [];
|
|
210
|
+
const patterns = Array.isArray(declarationNames)
|
|
211
|
+
? declarationNames
|
|
212
|
+
: buildTypeReferencePatterns(declarationNames);
|
|
213
|
+
const refs = [];
|
|
214
|
+
for (const [name, pattern] of patterns) {
|
|
215
|
+
if (pattern.test(typeString)) {
|
|
216
|
+
refs.push(name);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return refs;
|
|
220
|
+
};
|
|
221
|
+
// ── Narrowed Declaration Types ──────────────────────────────────────────────
|
|
222
|
+
/**
|
|
223
|
+
* Narrow a declaration by kind for type-safe field access.
|
|
224
|
+
*
|
|
225
|
+
* Works with both `DeclarationJson` (top-level) and `MemberJson` (nested).
|
|
226
|
+
* Accepts `DeclarationKind | MemberKind` so `isKind(member, 'constructor')` compiles.
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```ts
|
|
230
|
+
* if (isKind(declaration, 'function')) {
|
|
231
|
+
* declaration.parameters; // FunctionDeclarationJson — has parameters
|
|
232
|
+
* declaration.returnType; // has returnType
|
|
233
|
+
* }
|
|
234
|
+
* if (isKind(member, 'constructor')) {
|
|
235
|
+
* member.parameters; // ConstructorMemberJson — has parameters
|
|
236
|
+
* }
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
export const isKind = (declaration, kind) => declaration.kind === kind;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import resolver primitives for the analysis session.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the `ImportResolver` token contract (`{resolve, identity}`) plus
|
|
5
|
+
* building blocks the session uses inside its three-phase setFiles pipeline:
|
|
6
|
+
*
|
|
7
|
+
* - `ensureLexerReady` — one-time wasm init for `es-module-lexer`. Phase 1 is
|
|
8
|
+
* sync per-file; the session awaits this once before the loop starts.
|
|
9
|
+
* - `lexImports` — sync specifier extraction from already-prepared content
|
|
10
|
+
* (raw TS/JS, or svelte2tsx virtual content for `.svelte` files).
|
|
11
|
+
* - `createDefaultResolver` — the TS + tsconfig fallback used when neither
|
|
12
|
+
* `AnalysisSessionOptions.resolveImport` nor a per-call override is provided.
|
|
13
|
+
* Carries a fresh symbol identity per session (cache-key-safe).
|
|
14
|
+
* - `normalizeResolveImport` — coerces the public `ResolveImport` union (bare
|
|
15
|
+
* function or token-paired resolver) to an `ImportResolver` at each boundary.
|
|
16
|
+
* - `wrapResolveImport` — the fn→token primitive behind `normalizeResolveImport`:
|
|
17
|
+
* wraps a bare function in an `ImportResolver`, synthesizing a throwaway
|
|
18
|
+
* identity unless a stable one is passed.
|
|
19
|
+
*
|
|
20
|
+
* @internal — subpath-importable for power users who want to drive resolution
|
|
21
|
+
* outside the session, but not part of the stable barrel surface.
|
|
22
|
+
*
|
|
23
|
+
* @see `session.ts` for the three-phase ingestion pipeline that consumes these
|
|
24
|
+
* @see `loadTsconfig` in `typescript-program.ts` for the TS module-resolution
|
|
25
|
+
* compiler-options shortcut used by the default resolver
|
|
26
|
+
*
|
|
27
|
+
* @module
|
|
28
|
+
*/
|
|
29
|
+
import ts from 'typescript';
|
|
30
|
+
/**
|
|
31
|
+
* Bare import-resolver function — the convenience form.
|
|
32
|
+
*
|
|
33
|
+
* Resolve an import specifier to an absolute file path, or `null` if the
|
|
34
|
+
* specifier is unresolvable (external package, missing file, etc.). May return
|
|
35
|
+
* synchronously or asynchronously; sync returns are awaited harmlessly in the
|
|
36
|
+
* session's parallel resolve phase.
|
|
37
|
+
*
|
|
38
|
+
* @param specifier - import specifier from source code
|
|
39
|
+
* @param fromFile - absolute path of the importing file
|
|
40
|
+
*/
|
|
41
|
+
export type ResolveImportFn = (specifier: string, fromFile: string) => string | null | Promise<string | null>;
|
|
42
|
+
/**
|
|
43
|
+
* Token-paired import resolver.
|
|
44
|
+
*
|
|
45
|
+
* `identity` is a stable opaque token that keys the session's resolve cache
|
|
46
|
+
* alongside content. Cache hits require both (a) byte-for-byte identical
|
|
47
|
+
* source content and (b) identity equality. Naive function-reference keys
|
|
48
|
+
* would silently destroy cache reuse when callers wrap the resolver in fresh
|
|
49
|
+
* closures (a very common pattern in Vite/Rollup plugins) — opaque tokens
|
|
50
|
+
* lift the responsibility to the caller, where it can be done correctly.
|
|
51
|
+
*/
|
|
52
|
+
export interface ImportResolver {
|
|
53
|
+
/** Resolve an import specifier to an absolute file path, or `null`. */
|
|
54
|
+
resolve: ResolveImportFn;
|
|
55
|
+
/**
|
|
56
|
+
* Stable opaque token identifying this resolver's cache scope.
|
|
57
|
+
*
|
|
58
|
+
* Two `ImportResolver`s with `identity` `===` to each other are treated
|
|
59
|
+
* as cache-equivalent. `string` for human-readable identities (e.g.,
|
|
60
|
+
* `'vite-plugin-container'`); `symbol` for generated sentinels.
|
|
61
|
+
*/
|
|
62
|
+
identity: string | symbol;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Public resolver shape accepted across the API — a bare `ResolveImportFn` or
|
|
66
|
+
* the token-paired `ImportResolver`.
|
|
67
|
+
*
|
|
68
|
+
* Every entry point that accepts `resolveImport` (`analyze`, `analyzeFromFiles`,
|
|
69
|
+
* `createAnalysisSession`, and the session's `setFile`/`setFiles` per-call
|
|
70
|
+
* override) takes this union, so the same value copy-pastes between them. Pass:
|
|
71
|
+
*
|
|
72
|
+
* - a **bare function** for the common case — a fresh cache identity is
|
|
73
|
+
* synthesized at the boundary. Correct for one-shot use (`analyze`,
|
|
74
|
+
* `analyzeFromFiles`) and for a session default (wrapped once at
|
|
75
|
+
* construction, so identity is stable for the session's lifetime).
|
|
76
|
+
* - an **`ImportResolver`** with a stable `identity` when you need the session
|
|
77
|
+
* to reuse its resolve cache across calls where the same logical resolver is
|
|
78
|
+
* rebuilt as a fresh closure (Vite/Rollup plugins). A bare function handed to
|
|
79
|
+
* a *per-call* `setFile`/`setFiles` override is treated as a distinct
|
|
80
|
+
* resolver each call (fresh identity → touched files re-resolve), which is
|
|
81
|
+
* the expected behavior for a deliberate one-off override.
|
|
82
|
+
*/
|
|
83
|
+
export type ResolveImport = ResolveImportFn | ImportResolver;
|
|
84
|
+
/**
|
|
85
|
+
* Normalize the public `ResolveImport` union to an `ImportResolver`.
|
|
86
|
+
*
|
|
87
|
+
* Wraps a bare function via `wrapResolveImport` (fresh synthesized identity);
|
|
88
|
+
* passes a token-paired resolver through unchanged. `undefined` in, `undefined`
|
|
89
|
+
* out — callers fall back to the session default. Call once per logical
|
|
90
|
+
* resolver scope: at session construction for the default, per call for an
|
|
91
|
+
* override.
|
|
92
|
+
*/
|
|
93
|
+
export declare const normalizeResolveImport: (value: ResolveImport | undefined) => ImportResolver | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Ensure `es-module-lexer`'s wasm runtime is initialized.
|
|
96
|
+
*
|
|
97
|
+
* Idempotent and cheap after the first call. The session awaits this once at
|
|
98
|
+
* the top of `setFiles` so phase 1's per-file lex is purely synchronous.
|
|
99
|
+
*/
|
|
100
|
+
export declare const ensureLexerReady: () => Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Lex import specifiers from prepared content.
|
|
103
|
+
*
|
|
104
|
+
* Sync — caller must have awaited `ensureLexerReady` at least once before
|
|
105
|
+
* invoking. For `.svelte` files, pass the svelte2tsx-transformed virtual
|
|
106
|
+
* content, not the raw `.svelte` source (which isn't lex-able as JS/TS).
|
|
107
|
+
*
|
|
108
|
+
* Dynamic imports (`import(specifier)` with non-literal arg) are omitted.
|
|
109
|
+
*
|
|
110
|
+
* @throws Error if lexing fails (malformed source). Callers should catch and
|
|
111
|
+
* emit `import_parse_failed`.
|
|
112
|
+
*
|
|
113
|
+
* @param content - prepared file content (TS/JS, or svelte2tsx virtual)
|
|
114
|
+
* @param fileId - absolute file path (used for error messages)
|
|
115
|
+
* @returns specifiers in declaration order
|
|
116
|
+
*/
|
|
117
|
+
export declare const lexImports: (content: string, fileId: string) => Array<string>;
|
|
118
|
+
/**
|
|
119
|
+
* Create the default `ImportResolver` (TypeScript + tsconfig).
|
|
120
|
+
*
|
|
121
|
+
* Uses `ts.resolveModuleName` against `ts.sys` directly — no `ts.Program` is
|
|
122
|
+
* built. Identity is a fresh symbol per call, so each session that constructs
|
|
123
|
+
* its own default gets a unique cache scope. Multiple sessions sharing one
|
|
124
|
+
* resolver instance share the cache scope (correct, since resolver state is
|
|
125
|
+
* shared too).
|
|
126
|
+
*
|
|
127
|
+
* Falls back to appending `.svelte` when the bare specifier doesn't resolve —
|
|
128
|
+
* lets `.svelte` imports work without polluting the consumer's tsconfig.
|
|
129
|
+
*
|
|
130
|
+
* @param compilerOptions - parsed tsconfig (from `loadTsconfig`)
|
|
131
|
+
* @param projectRoot - absolute project root for the module-resolution cache
|
|
132
|
+
*/
|
|
133
|
+
export declare const createDefaultResolver: (compilerOptions: ts.CompilerOptions, projectRoot: string) => ImportResolver;
|
|
134
|
+
/**
|
|
135
|
+
* Wrap a bare `resolveImport` function into an `ImportResolver` token.
|
|
136
|
+
*
|
|
137
|
+
* `identity` is optional; when omitted, a fresh `Symbol('wrapped')` is
|
|
138
|
+
* synthesized per call. The synthesized default suits single-use scopes —
|
|
139
|
+
* `normalizeResolveImport` relies on it to wrap a bare function for a one-shot
|
|
140
|
+
* `analyze` call or for a session default (wrapped once at construction, so the
|
|
141
|
+
* identity stays stable for the session's lifetime).
|
|
142
|
+
*
|
|
143
|
+
* For a long-lived session that re-wraps the *same* logical resolver across
|
|
144
|
+
* calls (Vite plugin, LSP), a throwaway identity cache-misses every time — the
|
|
145
|
+
* fresh `Symbol('wrapped')` never compares equal. Pass a stable `identity`
|
|
146
|
+
* here, or — simpler — construct an `ImportResolver` (`{resolve, identity}`)
|
|
147
|
+
* directly and pass it through the `ResolveImport` union.
|
|
148
|
+
*/
|
|
149
|
+
export declare const wrapResolveImport: (resolveImport: ResolveImportFn, identity?: string | symbol) => ImportResolver;
|
|
150
|
+
/**
|
|
151
|
+
* Shared no-op `ImportResolver` for the "dependency resolution disabled" case.
|
|
152
|
+
*
|
|
153
|
+
* Stable string identity (`'no-deps'`) instead of a per-call symbol so that
|
|
154
|
+
* repeated ingests within a long-lived session cache-hit on identity. Each
|
|
155
|
+
* session still owns its own cache (entries live on the per-session `owned`
|
|
156
|
+
* map; sessions don't share state), but within one session every reference
|
|
157
|
+
* to `noDepsResolver` is `===` to every other — so a Vite re-save of
|
|
158
|
+
* byte-identical content with `resolveDependencies: false` exercises the
|
|
159
|
+
* cache-hit branch. The resolver always returns `null`, so any two calls
|
|
160
|
+
* with identical content under this identity produce identical resolution
|
|
161
|
+
* results — `string` identity correctly captures that. Used by both the
|
|
162
|
+
* one-shot `analyzeFromFiles` path and the long-lived Vite plugin
|
|
163
|
+
* (`resolveDependencies: false`).
|
|
164
|
+
*/
|
|
165
|
+
export declare const noDepsResolver: ImportResolver;
|
|
166
|
+
//# sourceMappingURL=dep-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dep-resolver.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/dep-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,GAAG,CAC7B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,KACZ,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC9B,uEAAuE;IACvE,OAAO,EAAE,eAAe,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,cAAc,CAAC;AAE7D;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAClC,OAAO,aAAa,GAAG,SAAS,KAC9B,cAAc,GAAG,SAC6E,CAAC;AAElG;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAAa,OAAO,CAAC,IAAI,CAErD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,QAAQ,MAAM,KAAG,KAAK,CAAC,MAAM,CAOxE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,GACjC,iBAAiB,EAAE,CAAC,eAAe,EACnC,aAAa,MAAM,KACjB,cAwBF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,GAC7B,eAAe,eAAe,EAC9B,WAAU,MAAM,GAAG,MAA0B,KAC3C,cAGD,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,EAAE,cAG5B,CAAC"}
|