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
package/dist/log.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal logger interface threaded through analysis functions.
|
|
3
|
+
*
|
|
4
|
+
* Separate from `diagnostics.ts` because logging and diagnostics are not the
|
|
5
|
+
* same concern: diagnostics are structured, schema-validated records of
|
|
6
|
+
* analysis-time failures; logs are unstructured progress/info messages the
|
|
7
|
+
* caller chooses how to display.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
package/dist/logo.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logo.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/logo.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB;;;;;;CAQb,CAAC"}
|
package/dist/logo.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const logo_svelte_docinfo = {
|
|
2
|
+
label: 'a cyan scroll with curling ends',
|
|
3
|
+
fill: '#1ec3d2',
|
|
4
|
+
paths: [
|
|
5
|
+
{
|
|
6
|
+
d: 'M 83,80.28 c -9.75,-34.41 2.18,-52.33 -3.76,-70 -2.31,-7.66 -48.25,-12 -70.25,-6 -12,6 -10,24 4,24 6,0 5.51,-13.67 6,-18 0,0 -1.43,59.52 5.13,80.21 1.2,3.8 2.91,5.28 4,5.92 3.93,2.31 63.48,3.74 68.01,0.54 1.18,-0.84 3.11,-5.38 2.63,-8.75 -0.42,-2.94 -3.27,-5.78 -5.28,-6.26 -1.74,-0.41 -0.62,-0.79 -5.37,-0.59 C 77.2,81.96 71.49,85.44 47.57,84.25 41.58,84.09 11.04,79.77 64.12,56.73 51.2,46.21 46.99,49.36 37.77,43.13 37.39,42.87 55,45.85 66.37,56.98 -10.84,93.94 82.99,80.29 82.99,80.29 Z',
|
|
7
|
+
},
|
|
8
|
+
],
|
|
9
|
+
};
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point for svelte-docinfo.
|
|
4
|
+
*
|
|
5
|
+
* This file is the bin script entry point. The actual CLI implementation
|
|
6
|
+
* is in `cli.ts` which exports `runCli()` for testing.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/main.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point for svelte-docinfo.
|
|
4
|
+
*
|
|
5
|
+
* This file is the bin script entry point. The actual CLI implementation
|
|
6
|
+
* is in `cli.ts` which exports `runCli()` for testing.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { runCli } from './cli.js';
|
|
11
|
+
try {
|
|
12
|
+
const exitCode = await runCli();
|
|
13
|
+
process.exit(exitCode);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error('Fatal error:', error);
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path normalization chokepoint.
|
|
3
|
+
*
|
|
4
|
+
* Internal contract: every path stored, compared, or used as a Map/Set key
|
|
5
|
+
* inside this library is in POSIX form (forward slashes). The library accepts
|
|
6
|
+
* native paths (backslash on Windows, forward slash elsewhere) at every public
|
|
7
|
+
* API boundary and at every `node:path` call site whose result flows into
|
|
8
|
+
* storage or comparison.
|
|
9
|
+
*
|
|
10
|
+
* `toPosixPath` is the only normalization primitive — anything that needs to
|
|
11
|
+
* convert a native path to the internal form goes through it. The function is
|
|
12
|
+
* idempotent: forward-slash inputs round-trip unchanged, so calls outside
|
|
13
|
+
* Windows are effectively a no-op.
|
|
14
|
+
*
|
|
15
|
+
* Drive-letter case (`C:` vs `c:`) and Windows long-path prefixes (`\\?\`) are
|
|
16
|
+
* deliberately out of scope — they don't arise from the path sources this
|
|
17
|
+
* library consumes (tsconfig roots, glob results, caller-supplied ids).
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Normalize a path to POSIX form (forward slashes).
|
|
23
|
+
*
|
|
24
|
+
* Replaces every backslash with a forward slash. Idempotent: forward-slash
|
|
25
|
+
* input returns unchanged. Empty string returns empty string.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* toPosixPath('C:\\proj\\src\\lib\\foo.ts') // => 'C:/proj/src/lib/foo.ts'
|
|
30
|
+
* toPosixPath('/home/user/proj/foo.ts') // => '/home/user/proj/foo.ts' (unchanged)
|
|
31
|
+
* toPosixPath('') // => ''
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare const toPosixPath: (p: string) => string;
|
|
35
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,KAAG,MAAwD,CAAC"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path normalization chokepoint.
|
|
3
|
+
*
|
|
4
|
+
* Internal contract: every path stored, compared, or used as a Map/Set key
|
|
5
|
+
* inside this library is in POSIX form (forward slashes). The library accepts
|
|
6
|
+
* native paths (backslash on Windows, forward slash elsewhere) at every public
|
|
7
|
+
* API boundary and at every `node:path` call site whose result flows into
|
|
8
|
+
* storage or comparison.
|
|
9
|
+
*
|
|
10
|
+
* `toPosixPath` is the only normalization primitive — anything that needs to
|
|
11
|
+
* convert a native path to the internal form goes through it. The function is
|
|
12
|
+
* idempotent: forward-slash inputs round-trip unchanged, so calls outside
|
|
13
|
+
* Windows are effectively a no-op.
|
|
14
|
+
*
|
|
15
|
+
* Drive-letter case (`C:` vs `c:`) and Windows long-path prefixes (`\\?\`) are
|
|
16
|
+
* deliberately out of scope — they don't arise from the path sources this
|
|
17
|
+
* library consumes (tsconfig roots, glob results, caller-supplied ids).
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Normalize a path to POSIX form (forward slashes).
|
|
23
|
+
*
|
|
24
|
+
* Replaces every backslash with a forward slash. Idempotent: forward-slash
|
|
25
|
+
* input returns unchanged. Empty string returns empty string.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* toPosixPath('C:\\proj\\src\\lib\\foo.ts') // => 'C:/proj/src/lib/foo.ts'
|
|
30
|
+
* toPosixPath('/home/user/proj/foo.ts') // => '/home/user/proj/foo.ts' (unchanged)
|
|
31
|
+
* toPosixPath('') // => ''
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export const toPosixPath = (p) => (p.includes('\\') ? p.replace(/\\/g, '/') : p);
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-processing for analyzed library metadata.
|
|
3
|
+
*
|
|
4
|
+
* These functions transform analysis results after module-level analysis is complete:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Validation** — `findDuplicates` checks flat namespace constraints
|
|
7
|
+
* 2. **Transformation** — `mergeReExports` resolves re-export relationships,
|
|
8
|
+
* `computeDependents` builds bidirectional dependency graphs
|
|
9
|
+
* 3. **Output** — `sortModules` prepares deterministic output
|
|
10
|
+
*
|
|
11
|
+
* @see `analyze.ts` for the main analysis entry point
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import type { DeclarationJson, ModuleJson } from './types.js';
|
|
16
|
+
import type { ReExportInfo } from './declaration-build.js';
|
|
17
|
+
import type { SourceFileInfo } from './source.js';
|
|
18
|
+
/**
|
|
19
|
+
* A duplicate declaration with its full metadata and module path.
|
|
20
|
+
*/
|
|
21
|
+
export interface DuplicateDeclaration {
|
|
22
|
+
/** The full declaration metadata. */
|
|
23
|
+
declaration: DeclarationJson;
|
|
24
|
+
/** Module path where this declaration is defined. */
|
|
25
|
+
module: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Find duplicate declaration names across modules.
|
|
29
|
+
*
|
|
30
|
+
* Callers can decide how to handle duplicates (throw, warn, ignore).
|
|
31
|
+
*
|
|
32
|
+
* @returns `Map` of declaration names to their `DuplicateDeclaration` occurrences (only includes duplicates)
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const duplicates = findDuplicates(modules);
|
|
37
|
+
* if (duplicates.size > 0) {
|
|
38
|
+
* for (const [name, occurrences] of duplicates) {
|
|
39
|
+
* console.error(`"${name}" found in:`);
|
|
40
|
+
* for (const {declaration, module} of occurrences) {
|
|
41
|
+
* console.error(` - ${module}:${declaration.sourceLine} (${declaration.kind})`);
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* throw new Error(`Found ${duplicates.size} duplicate declaration names`);
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare const findDuplicates: (modules: Array<ModuleJson>) => Map<string, Array<DuplicateDeclaration>>;
|
|
49
|
+
/**
|
|
50
|
+
* Sort modules alphabetically by path for deterministic output and cleaner diffs.
|
|
51
|
+
*
|
|
52
|
+
* @param modules - the modules to sort
|
|
53
|
+
* @returns a new sorted array (does not mutate input)
|
|
54
|
+
*/
|
|
55
|
+
export declare const sortModules: (modules: Array<ModuleJson>) => Array<ModuleJson>;
|
|
56
|
+
/**
|
|
57
|
+
* A collected re-export with its source module context.
|
|
58
|
+
*
|
|
59
|
+
* Used during the two-phase re-export resolution:
|
|
60
|
+
* 1. Phase 1: Collect re-exports from each module during analysis
|
|
61
|
+
* 2. Phase 2: Group by original module and merge into `alsoExportedFrom`
|
|
62
|
+
*/
|
|
63
|
+
export interface ReExportEntry {
|
|
64
|
+
/** The module that re-exports the declaration. */
|
|
65
|
+
reExportingModule: string;
|
|
66
|
+
/** The re-export info (name and original module). */
|
|
67
|
+
reExport: ReExportInfo;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build `alsoExportedFrom` arrays from collected re-export data.
|
|
71
|
+
*
|
|
72
|
+
* This function resolves the two-phase re-export problem:
|
|
73
|
+
*
|
|
74
|
+
* **Problem**: When module A re-exports from module B, we discover this while
|
|
75
|
+
* analyzing A, but need to update B's declarations. However, B may already be
|
|
76
|
+
* processed or may be processed later.
|
|
77
|
+
*
|
|
78
|
+
* **Solution**: Collect all re-exports in phase 1, then merge them in phase 2
|
|
79
|
+
* after all modules are analyzed.
|
|
80
|
+
*
|
|
81
|
+
* Component-only fields on renamed component aliases (`props`,
|
|
82
|
+
* `acceptsChildren`, etc.) are populated separately by `resolveComponentAliases`
|
|
83
|
+
* — call it after this function. They split because they touch disjoint fields
|
|
84
|
+
* and have different inputs.
|
|
85
|
+
*
|
|
86
|
+
* @param modules - the modules array with all modules (will be mutated)
|
|
87
|
+
* @param collectedReExports - array of re-exports collected during phase 1
|
|
88
|
+
* @mutates modules - unions new re-exporters into `declaration.alsoExportedFrom`
|
|
89
|
+
* (deduped + sorted), so a second call with the same inputs is a no-op
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* // helpers.ts exports: foo, bar
|
|
94
|
+
* // index.ts does: export {foo, bar} from './files.js'
|
|
95
|
+
* //
|
|
96
|
+
* // After processing:
|
|
97
|
+
* // - helpers.ts foo declaration gets: alsoExportedFrom: ['index.ts']
|
|
98
|
+
* // - helpers.ts bar declaration gets: alsoExportedFrom: ['index.ts']
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare const mergeReExports: (modules: Array<ModuleJson>, collectedReExports: Array<ReExportEntry>) => void;
|
|
102
|
+
/**
|
|
103
|
+
* Copy props/acceptsChildren/lang/etc. from canonical component declarations
|
|
104
|
+
* onto synthesized component-aliased declarations.
|
|
105
|
+
*
|
|
106
|
+
* Renamed Svelte component re-exports (`export {default as Foo} from './X.svelte'`)
|
|
107
|
+
* are emitted as `kind: 'component'` placeholders by `analyzeExports`, with `aliasOf`
|
|
108
|
+
* pointing at the canonical. The canonical's component-specific fields are only
|
|
109
|
+
* available after `analyzeSvelteModule` synthesizes the canonical declaration, so
|
|
110
|
+
* the copy happens here in phase 2 once all modules are analyzed.
|
|
111
|
+
*
|
|
112
|
+
* Call this *after* `mergeReExports` — both walk the same modules array but
|
|
113
|
+
* read/write disjoint fields, so order between them only matters for clarity.
|
|
114
|
+
*
|
|
115
|
+
* @mutates modules - fills component-only fields on aliased component declarations
|
|
116
|
+
*/
|
|
117
|
+
export declare const resolveComponentAliases: (modules: Array<ModuleJson>) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Compute bidirectional dependencies from source files.
|
|
120
|
+
*
|
|
121
|
+
* This function ensures that if file A has file B in its `dependencies`,
|
|
122
|
+
* then file B will have file A in its `dependents`. This provides consistent
|
|
123
|
+
* output regardless of whether callers provide one-directional or bidirectional
|
|
124
|
+
* dependency information.
|
|
125
|
+
*
|
|
126
|
+
* Returns new `SourceFileInfo` objects when computed dependents exist or when
|
|
127
|
+
* paths needed posixification; otherwise the original input objects flow
|
|
128
|
+
* through `===`-equal (fast path for session callers, who already pass POSIX
|
|
129
|
+
* paths and may have no inferable dependents for a given file).
|
|
130
|
+
*
|
|
131
|
+
* @param files - source files with optional dependency information
|
|
132
|
+
* @returns new array with bidirectional dependencies computed
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* // Input: Calculator.svelte has dependencies: [math.ts]
|
|
137
|
+
* // Output: Calculator.svelte has dependencies: [math.ts]
|
|
138
|
+
* // math.ts has dependents: [Calculator.svelte]
|
|
139
|
+
* const filesWithBidirectional = computeDependents(files);
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare const computeDependents: (files: ReadonlyArray<SourceFileInfo>) => Array<SourceFileInfo & {
|
|
143
|
+
dependents?: ReadonlyArray<string>;
|
|
144
|
+
}>;
|
|
145
|
+
//# sourceMappingURL=postprocess.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postprocess.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/postprocess.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAA2B,eAAe,EAAE,UAAU,EAAC,MAAM,YAAY,CAAC;AACtF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAuBhD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,qCAAqC;IACrC,WAAW,EAAE,eAAe,CAAC;IAC7B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,cAAc,GAC1B,SAAS,KAAK,CAAC,UAAU,CAAC,KACxB,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,oBAAoB,CAAC,CA4BzC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,KAAK,CAAC,UAAU,CAAC,KAAG,KAAK,CAAC,UAAU,CAExE,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,kDAAkD;IAClD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,QAAQ,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,cAAc,GAC1B,SAAS,KAAK,CAAC,UAAU,CAAC,EAC1B,oBAAoB,KAAK,CAAC,aAAa,CAAC,KACtC,IAkCF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS,KAAK,CAAC,UAAU,CAAC,KAAG,IAoDpE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,OAAO,aAAa,CAAC,cAAc,CAAC,KAClC,KAAK,CAAC,cAAc,GAAG;IAAC,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAC,CAwD7D,CAAC"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-processing for analyzed library metadata.
|
|
3
|
+
*
|
|
4
|
+
* These functions transform analysis results after module-level analysis is complete:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Validation** — `findDuplicates` checks flat namespace constraints
|
|
7
|
+
* 2. **Transformation** — `mergeReExports` resolves re-export relationships,
|
|
8
|
+
* `computeDependents` builds bidirectional dependency graphs
|
|
9
|
+
* 3. **Output** — `sortModules` prepares deterministic output
|
|
10
|
+
*
|
|
11
|
+
* @see `analyze.ts` for the main analysis entry point
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { toPosixPath } from './paths.js';
|
|
16
|
+
/**
|
|
17
|
+
* Posixify every entry in `arr`. Returns the same array reference when no
|
|
18
|
+
* entry needed normalization, so identity-equality short-circuits in
|
|
19
|
+
* `computeDependents`'s no-rewrite branch.
|
|
20
|
+
*/
|
|
21
|
+
const posixifyArray = (arr) => {
|
|
22
|
+
if (!arr)
|
|
23
|
+
return arr;
|
|
24
|
+
let changed = null;
|
|
25
|
+
for (let i = 0; i < arr.length; i++) {
|
|
26
|
+
const p = toPosixPath(arr[i]);
|
|
27
|
+
if (p !== arr[i]) {
|
|
28
|
+
if (!changed)
|
|
29
|
+
changed = arr.slice();
|
|
30
|
+
changed[i] = p;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return changed ?? arr;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Find duplicate declaration names across modules.
|
|
37
|
+
*
|
|
38
|
+
* Callers can decide how to handle duplicates (throw, warn, ignore).
|
|
39
|
+
*
|
|
40
|
+
* @returns `Map` of declaration names to their `DuplicateDeclaration` occurrences (only includes duplicates)
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const duplicates = findDuplicates(modules);
|
|
45
|
+
* if (duplicates.size > 0) {
|
|
46
|
+
* for (const [name, occurrences] of duplicates) {
|
|
47
|
+
* console.error(`"${name}" found in:`);
|
|
48
|
+
* for (const {declaration, module} of occurrences) {
|
|
49
|
+
* console.error(` - ${module}:${declaration.sourceLine} (${declaration.kind})`);
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* throw new Error(`Found ${duplicates.size} duplicate declaration names`);
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export const findDuplicates = (modules) => {
|
|
57
|
+
const allOccurrences = new Map();
|
|
58
|
+
// Collect declaration names. The default slot is module-scoped per the JS
|
|
59
|
+
// spec — every module can have its own `'default'` and they don't collide
|
|
60
|
+
// — so skip `name === 'default'` entries from this flat-namespace check.
|
|
61
|
+
for (const mod of modules) {
|
|
62
|
+
for (const declaration of mod.declarations) {
|
|
63
|
+
if (declaration.name === 'default')
|
|
64
|
+
continue;
|
|
65
|
+
if (!allOccurrences.has(declaration.name)) {
|
|
66
|
+
allOccurrences.set(declaration.name, []);
|
|
67
|
+
}
|
|
68
|
+
allOccurrences.get(declaration.name).push({
|
|
69
|
+
declaration,
|
|
70
|
+
module: mod.path,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Filter to only duplicates
|
|
75
|
+
const duplicates = new Map();
|
|
76
|
+
for (const [name, occurrences] of allOccurrences) {
|
|
77
|
+
if (occurrences.length > 1) {
|
|
78
|
+
duplicates.set(name, occurrences);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return duplicates;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Sort modules alphabetically by path for deterministic output and cleaner diffs.
|
|
85
|
+
*
|
|
86
|
+
* @param modules - the modules to sort
|
|
87
|
+
* @returns a new sorted array (does not mutate input)
|
|
88
|
+
*/
|
|
89
|
+
export const sortModules = (modules) => {
|
|
90
|
+
return modules.slice().sort((a, b) => a.path.localeCompare(b.path));
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Build `alsoExportedFrom` arrays from collected re-export data.
|
|
94
|
+
*
|
|
95
|
+
* This function resolves the two-phase re-export problem:
|
|
96
|
+
*
|
|
97
|
+
* **Problem**: When module A re-exports from module B, we discover this while
|
|
98
|
+
* analyzing A, but need to update B's declarations. However, B may already be
|
|
99
|
+
* processed or may be processed later.
|
|
100
|
+
*
|
|
101
|
+
* **Solution**: Collect all re-exports in phase 1, then merge them in phase 2
|
|
102
|
+
* after all modules are analyzed.
|
|
103
|
+
*
|
|
104
|
+
* Component-only fields on renamed component aliases (`props`,
|
|
105
|
+
* `acceptsChildren`, etc.) are populated separately by `resolveComponentAliases`
|
|
106
|
+
* — call it after this function. They split because they touch disjoint fields
|
|
107
|
+
* and have different inputs.
|
|
108
|
+
*
|
|
109
|
+
* @param modules - the modules array with all modules (will be mutated)
|
|
110
|
+
* @param collectedReExports - array of re-exports collected during phase 1
|
|
111
|
+
* @mutates modules - unions new re-exporters into `declaration.alsoExportedFrom`
|
|
112
|
+
* (deduped + sorted), so a second call with the same inputs is a no-op
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* // helpers.ts exports: foo, bar
|
|
117
|
+
* // index.ts does: export {foo, bar} from './files.js'
|
|
118
|
+
* //
|
|
119
|
+
* // After processing:
|
|
120
|
+
* // - helpers.ts foo declaration gets: alsoExportedFrom: ['index.ts']
|
|
121
|
+
* // - helpers.ts bar declaration gets: alsoExportedFrom: ['index.ts']
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export const mergeReExports = (modules, collectedReExports) => {
|
|
125
|
+
// Group re-exports by `(originalModule, name)`. The default slot keys as
|
|
126
|
+
// `'default'` like any other name — each module owns its own default slot,
|
|
127
|
+
// so the per-module map prevents cross-module collisions naturally.
|
|
128
|
+
const reExportMap = new Map();
|
|
129
|
+
for (const { reExportingModule, reExport } of collectedReExports) {
|
|
130
|
+
const { name, originalModule } = reExport;
|
|
131
|
+
if (!reExportMap.has(originalModule)) {
|
|
132
|
+
reExportMap.set(originalModule, new Map());
|
|
133
|
+
}
|
|
134
|
+
const moduleMap = reExportMap.get(originalModule);
|
|
135
|
+
if (!moduleMap.has(name)) {
|
|
136
|
+
moduleMap.set(name, []);
|
|
137
|
+
}
|
|
138
|
+
moduleMap.get(name).push(reExportingModule);
|
|
139
|
+
}
|
|
140
|
+
// Merge into original declarations
|
|
141
|
+
for (const mod of modules) {
|
|
142
|
+
const moduleReExports = reExportMap.get(mod.path);
|
|
143
|
+
if (!moduleReExports)
|
|
144
|
+
continue;
|
|
145
|
+
for (const declaration of mod.declarations) {
|
|
146
|
+
const reExporters = moduleReExports.get(declaration.name);
|
|
147
|
+
if (reExporters?.length) {
|
|
148
|
+
// Union with existing entries, dedupe, sort — keeps the function idempotent
|
|
149
|
+
// when re-run on already-merged modules
|
|
150
|
+
const merged = new Set(declaration.alsoExportedFrom);
|
|
151
|
+
for (const reExporter of reExporters)
|
|
152
|
+
merged.add(reExporter);
|
|
153
|
+
declaration.alsoExportedFrom = Array.from(merged).sort();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Copy props/acceptsChildren/lang/etc. from canonical component declarations
|
|
160
|
+
* onto synthesized component-aliased declarations.
|
|
161
|
+
*
|
|
162
|
+
* Renamed Svelte component re-exports (`export {default as Foo} from './X.svelte'`)
|
|
163
|
+
* are emitted as `kind: 'component'` placeholders by `analyzeExports`, with `aliasOf`
|
|
164
|
+
* pointing at the canonical. The canonical's component-specific fields are only
|
|
165
|
+
* available after `analyzeSvelteModule` synthesizes the canonical declaration, so
|
|
166
|
+
* the copy happens here in phase 2 once all modules are analyzed.
|
|
167
|
+
*
|
|
168
|
+
* Call this *after* `mergeReExports` — both walk the same modules array but
|
|
169
|
+
* read/write disjoint fields, so order between them only matters for clarity.
|
|
170
|
+
*
|
|
171
|
+
* @mutates modules - fills component-only fields on aliased component declarations
|
|
172
|
+
*/
|
|
173
|
+
export const resolveComponentAliases = (modules) => {
|
|
174
|
+
// Build {modulePath → {componentName → ComponentDeclarationJson}} for canonical lookups
|
|
175
|
+
const canonicalByModule = new Map();
|
|
176
|
+
for (const mod of modules) {
|
|
177
|
+
for (const decl of mod.declarations) {
|
|
178
|
+
if (decl.kind !== 'component' || decl.aliasOf)
|
|
179
|
+
continue;
|
|
180
|
+
let perModule = canonicalByModule.get(mod.path);
|
|
181
|
+
if (!perModule) {
|
|
182
|
+
perModule = new Map();
|
|
183
|
+
canonicalByModule.set(mod.path, perModule);
|
|
184
|
+
}
|
|
185
|
+
perModule.set(decl.name, decl);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
for (const mod of modules) {
|
|
189
|
+
for (const decl of mod.declarations) {
|
|
190
|
+
if (decl.kind !== 'component' || !decl.aliasOf)
|
|
191
|
+
continue;
|
|
192
|
+
const canonical = canonicalByModule.get(decl.aliasOf.module)?.get(decl.aliasOf.name);
|
|
193
|
+
if (!canonical)
|
|
194
|
+
continue;
|
|
195
|
+
decl.props = canonical.props;
|
|
196
|
+
decl.acceptsChildren = canonical.acceptsChildren;
|
|
197
|
+
decl.intersects = canonical.intersects;
|
|
198
|
+
decl.genericParams = canonical.genericParams;
|
|
199
|
+
if (canonical.lang !== undefined)
|
|
200
|
+
decl.lang = canonical.lang;
|
|
201
|
+
if (canonical.docComment !== undefined && decl.docComment === undefined) {
|
|
202
|
+
decl.docComment = canonical.docComment;
|
|
203
|
+
}
|
|
204
|
+
if (canonical.typeSignature !== undefined && decl.typeSignature === undefined) {
|
|
205
|
+
decl.typeSignature = canonical.typeSignature;
|
|
206
|
+
}
|
|
207
|
+
if (canonical.examples.length > 0 && decl.examples.length === 0) {
|
|
208
|
+
decl.examples = canonical.examples;
|
|
209
|
+
}
|
|
210
|
+
if (canonical.seeAlso.length > 0 && decl.seeAlso.length === 0) {
|
|
211
|
+
decl.seeAlso = canonical.seeAlso;
|
|
212
|
+
}
|
|
213
|
+
if (canonical.throws.length > 0 && decl.throws.length === 0) {
|
|
214
|
+
decl.throws = canonical.throws;
|
|
215
|
+
}
|
|
216
|
+
if (canonical.deprecatedMessage !== undefined && decl.deprecatedMessage === undefined) {
|
|
217
|
+
decl.deprecatedMessage = canonical.deprecatedMessage;
|
|
218
|
+
}
|
|
219
|
+
if (canonical.since !== undefined && decl.since === undefined) {
|
|
220
|
+
decl.since = canonical.since;
|
|
221
|
+
}
|
|
222
|
+
if (canonical.mutates !== undefined && decl.mutates === undefined) {
|
|
223
|
+
decl.mutates = canonical.mutates;
|
|
224
|
+
}
|
|
225
|
+
if (canonical.partial)
|
|
226
|
+
decl.partial = true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* Compute bidirectional dependencies from source files.
|
|
232
|
+
*
|
|
233
|
+
* This function ensures that if file A has file B in its `dependencies`,
|
|
234
|
+
* then file B will have file A in its `dependents`. This provides consistent
|
|
235
|
+
* output regardless of whether callers provide one-directional or bidirectional
|
|
236
|
+
* dependency information.
|
|
237
|
+
*
|
|
238
|
+
* Returns new `SourceFileInfo` objects when computed dependents exist or when
|
|
239
|
+
* paths needed posixification; otherwise the original input objects flow
|
|
240
|
+
* through `===`-equal (fast path for session callers, who already pass POSIX
|
|
241
|
+
* paths and may have no inferable dependents for a given file).
|
|
242
|
+
*
|
|
243
|
+
* @param files - source files with optional dependency information
|
|
244
|
+
* @returns new array with bidirectional dependencies computed
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* // Input: Calculator.svelte has dependencies: [math.ts]
|
|
249
|
+
* // Output: Calculator.svelte has dependencies: [math.ts]
|
|
250
|
+
* // math.ts has dependents: [Calculator.svelte]
|
|
251
|
+
* const filesWithBidirectional = computeDependents(files);
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
export const computeDependents = (files) => {
|
|
255
|
+
// Posixify ids and dependency lists at the boundary so a power user
|
|
256
|
+
// supplying a hand-built `SourceFileInfo[]` with mixed-shape paths still
|
|
257
|
+
// gets correct lookup behavior. Identity-preserving when no normalization
|
|
258
|
+
// is needed (session callers, who already pass POSIX): both arrays and the
|
|
259
|
+
// outer `SourceFileInfo` flow through `===`-equal.
|
|
260
|
+
const posixFiles = files.map((file) => {
|
|
261
|
+
const posixId = toPosixPath(file.id);
|
|
262
|
+
const posixDeps = posixifyArray(file.dependencies);
|
|
263
|
+
if (posixId === file.id && posixDeps === file.dependencies) {
|
|
264
|
+
return file;
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
...file,
|
|
268
|
+
id: posixId,
|
|
269
|
+
dependencies: posixDeps,
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
// Build a map of file id -> dependents (computed from dependencies)
|
|
273
|
+
const computedDependents = new Map();
|
|
274
|
+
// Initialize all files in the map
|
|
275
|
+
for (const file of posixFiles) {
|
|
276
|
+
computedDependents.set(file.id, new Set());
|
|
277
|
+
}
|
|
278
|
+
// Compute dependents from dependencies
|
|
279
|
+
for (const file of posixFiles) {
|
|
280
|
+
if (!file.dependencies)
|
|
281
|
+
continue;
|
|
282
|
+
for (const depId of file.dependencies) {
|
|
283
|
+
// Only add if the dependency is in our file set
|
|
284
|
+
if (computedDependents.has(depId)) {
|
|
285
|
+
computedDependents.get(depId).add(file.id);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Attach computed dependents to each file. Dependents are derived from
|
|
290
|
+
// forward edges in the owned set, not from caller input — the public
|
|
291
|
+
// `SourceFileInfo` carries no `dependents` field.
|
|
292
|
+
return posixFiles.map((file) => {
|
|
293
|
+
const computed = computedDependents.get(file.id);
|
|
294
|
+
if (!computed || computed.size === 0) {
|
|
295
|
+
// No computed dependents, return as-is
|
|
296
|
+
return file;
|
|
297
|
+
}
|
|
298
|
+
// Sort for deterministic output
|
|
299
|
+
const dependents = Array.from(computed).sort();
|
|
300
|
+
return {
|
|
301
|
+
...file,
|
|
302
|
+
dependents,
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
};
|