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.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +349 -0
  3. package/dist/analyze-core.d.ts +1386 -0
  4. package/dist/analyze-core.d.ts.map +1 -0
  5. package/dist/analyze-core.js +324 -0
  6. package/dist/analyze.d.ts +137 -0
  7. package/dist/analyze.d.ts.map +1 -0
  8. package/dist/analyze.js +148 -0
  9. package/dist/cli.d.ts +102 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +206 -0
  12. package/dist/concurrency.d.ts +38 -0
  13. package/dist/concurrency.d.ts.map +1 -0
  14. package/dist/concurrency.js +57 -0
  15. package/dist/declaration-build.d.ts +164 -0
  16. package/dist/declaration-build.d.ts.map +1 -0
  17. package/dist/declaration-build.js +15 -0
  18. package/dist/declaration-helpers.d.ts +169 -0
  19. package/dist/declaration-helpers.d.ts.map +1 -0
  20. package/dist/declaration-helpers.js +239 -0
  21. package/dist/dep-resolver.d.ts +166 -0
  22. package/dist/dep-resolver.d.ts.map +1 -0
  23. package/dist/dep-resolver.js +144 -0
  24. package/dist/diagnostics.d.ts +650 -0
  25. package/dist/diagnostics.d.ts.map +1 -0
  26. package/dist/diagnostics.js +377 -0
  27. package/dist/discovery.d.ts +115 -0
  28. package/dist/discovery.d.ts.map +1 -0
  29. package/dist/discovery.js +126 -0
  30. package/dist/exports.d.ts +105 -0
  31. package/dist/exports.d.ts.map +1 -0
  32. package/dist/exports.js +274 -0
  33. package/dist/files.d.ts +77 -0
  34. package/dist/files.d.ts.map +1 -0
  35. package/dist/files.js +95 -0
  36. package/dist/index.d.ts +32 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +30 -0
  39. package/dist/log.d.ts +32 -0
  40. package/dist/log.d.ts.map +1 -0
  41. package/dist/log.js +11 -0
  42. package/dist/logo.d.ts +8 -0
  43. package/dist/logo.d.ts.map +1 -0
  44. package/dist/logo.js +9 -0
  45. package/dist/main.d.ts +11 -0
  46. package/dist/main.d.ts.map +1 -0
  47. package/dist/main.js +18 -0
  48. package/dist/paths.d.ts +35 -0
  49. package/dist/paths.d.ts.map +1 -0
  50. package/dist/paths.js +34 -0
  51. package/dist/postprocess.d.ts +145 -0
  52. package/dist/postprocess.d.ts.map +1 -0
  53. package/dist/postprocess.js +305 -0
  54. package/dist/session.d.ts +248 -0
  55. package/dist/session.d.ts.map +1 -0
  56. package/dist/session.js +496 -0
  57. package/dist/source-config.d.ts +330 -0
  58. package/dist/source-config.d.ts.map +1 -0
  59. package/dist/source-config.js +356 -0
  60. package/dist/source.d.ts +126 -0
  61. package/dist/source.d.ts.map +1 -0
  62. package/dist/source.js +68 -0
  63. package/dist/svelte.d.ts +179 -0
  64. package/dist/svelte.d.ts.map +1 -0
  65. package/dist/svelte.js +898 -0
  66. package/dist/tsdoc.d.ts +145 -0
  67. package/dist/tsdoc.d.ts.map +1 -0
  68. package/dist/tsdoc.js +262 -0
  69. package/dist/types.d.ts +3381 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +588 -0
  72. package/dist/typescript-exports.d.ts +91 -0
  73. package/dist/typescript-exports.d.ts.map +1 -0
  74. package/dist/typescript-exports.js +656 -0
  75. package/dist/typescript-extract-class.d.ts +29 -0
  76. package/dist/typescript-extract-class.d.ts.map +1 -0
  77. package/dist/typescript-extract-class.js +251 -0
  78. package/dist/typescript-extract-function.d.ts +47 -0
  79. package/dist/typescript-extract-function.d.ts.map +1 -0
  80. package/dist/typescript-extract-function.js +108 -0
  81. package/dist/typescript-extract-shared.d.ts +166 -0
  82. package/dist/typescript-extract-shared.d.ts.map +1 -0
  83. package/dist/typescript-extract-shared.js +528 -0
  84. package/dist/typescript-extract-type-properties.d.ts +34 -0
  85. package/dist/typescript-extract-type-properties.d.ts.map +1 -0
  86. package/dist/typescript-extract-type-properties.js +241 -0
  87. package/dist/typescript-extract-type.d.ts +48 -0
  88. package/dist/typescript-extract-type.d.ts.map +1 -0
  89. package/dist/typescript-extract-type.js +238 -0
  90. package/dist/typescript-program.d.ts +211 -0
  91. package/dist/typescript-program.d.ts.map +1 -0
  92. package/dist/typescript-program.js +290 -0
  93. package/dist/vite.d.ts +116 -0
  94. package/dist/vite.d.ts.map +1 -0
  95. package/dist/vite.js +418 -0
  96. package/package.json +131 -0
  97. package/virtual-svelte-docinfo.d.ts +49 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-core.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/analyze-core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Pure two-phase analysis orchestrator.
3
+ *
4
+ * Extracted from `analyze.ts` to break what would otherwise be a circular
5
+ * import: `session.ts → analyze.ts (for the orchestrator) → session.ts (for
6
+ * the wrappers)`. With the orchestrator here, both `session.ts` and
7
+ * `analyze.ts` import downward into this module without depending on each
8
+ * other.
9
+ *
10
+ * Public surface:
11
+ *
12
+ * - `analyzeCore` — runs phase 1 module dispatch + phase 2 re-export merge,
13
+ * returns `AnalyzeResultJson`. Caller supplies pre-prepared inputs (program,
14
+ * svelte virtuals, transform-failed IDs).
15
+ * - `analyzeModule` — the per-module dispatcher (TS / Svelte / CSS / JSON).
16
+ * `@internal`; exposed for tests and power users via the subpath.
17
+ * - `AnalyzeResultJson` / `OnDuplicates` / `OnDuplicatesCallback` — shared types
18
+ * surfaced through the main barrel directly from this module.
19
+ * - `throwOnDuplicates` — convenience callback paired with `OnDuplicates`.
20
+ * - `normalizeDiagnosticPaths` — boundary helper for build-tool integrations
21
+ * that bypass the session and collect their own diagnostics.
22
+ *
23
+ * @internal — module split is implementation detail; consumers go through
24
+ * `analyze.ts` / `session.ts` for the stable surface.
25
+ *
26
+ * @module
27
+ */
28
+ import ts from 'typescript';
29
+ import { z } from 'zod';
30
+ import { ModuleJson } from './types.js';
31
+ import { Diagnostic } from './diagnostics.js';
32
+ import { analyzeTypescriptModule } from './typescript-exports.js';
33
+ import { analyzeSvelteModule } from './svelte.js';
34
+ import { stripVirtualSuffix, getComponentName } from './source.js';
35
+ import { extractPath, extractDependencies } from './source-config.js';
36
+ import { toPosixPath } from './paths.js';
37
+ import { sortModules, findDuplicates, mergeReExports, resolveComponentAliases, } from './postprocess.js';
38
+ /**
39
+ * Convenience `OnDuplicatesCallback` that throws on any duplicate.
40
+ *
41
+ * @throws Error listing every duplicate name and module location
42
+ */
43
+ export const throwOnDuplicates = (duplicates) => {
44
+ if (duplicates.size === 0)
45
+ return;
46
+ throw new Error(formatDuplicates(duplicates));
47
+ };
48
+ const formatDuplicates = (duplicates) => {
49
+ const details = Array.from(duplicates)
50
+ .map(([name, occurrences]) => {
51
+ const locations = occurrences
52
+ .map(({ declaration, module }) => {
53
+ const lineInfo = declaration.sourceLine !== undefined ? `:${declaration.sourceLine}` : '';
54
+ return ` - ${module}${lineInfo} (${declaration.kind})`;
55
+ })
56
+ .join('\n');
57
+ return ` "${name}" found in:\n${locations}`;
58
+ })
59
+ .join('\n');
60
+ return (`Found ${duplicates.size} duplicate declaration name${duplicates.size === 1 ? '' : 's'} across modules. ` +
61
+ 'The flat namespace requires unique names. To resolve: ' +
62
+ '(1) rename one of the conflicting declarations, or ' +
63
+ '(2) add /** @nodocs */ to exclude from documentation.\n' +
64
+ details);
65
+ };
66
+ const emitDuplicateDiagnostics = (diagnostics, duplicates) => {
67
+ for (const [name, occurrences] of duplicates) {
68
+ const first = occurrences[0];
69
+ const modules = occurrences.map((o) => o.module);
70
+ diagnostics.push({
71
+ kind: 'duplicate_declaration',
72
+ file: first.module,
73
+ line: first.declaration.sourceLine,
74
+ message: `Duplicate declaration "${name}" defined in: ${modules.join(', ')}`,
75
+ severity: 'warning',
76
+ declarationName: name,
77
+ modules,
78
+ });
79
+ }
80
+ };
81
+ const dispatchOnDuplicates = (mode, duplicates, log) => {
82
+ if (duplicates.size === 0)
83
+ return;
84
+ if (mode === 'throw') {
85
+ throw new Error(formatDuplicates(duplicates));
86
+ }
87
+ const errorLog = log ?? { error: (msg) => console.error(msg) };
88
+ if (mode === 'warn') {
89
+ errorLog.error(formatDuplicates(duplicates));
90
+ return;
91
+ }
92
+ mode(duplicates, errorLog);
93
+ };
94
+ // ── Result types ─────────────────────────────────────────────────────────────
95
+ /**
96
+ * Result of `analyze`, `analyzeFromFiles`, and `AnalysisSession.query`.
97
+ *
98
+ * Modules sorted alphabetically by `path`. Diagnostics are query-time
99
+ * (analysis-pass) diagnostics only when produced by `session.query`; one-shot
100
+ * wrappers concatenate ingest + query diagnostics into this same array.
101
+ *
102
+ * ## Schema-validated round-trip
103
+ *
104
+ * The envelope is a Zod schema (`AnalyzeResultJson`) — both fields default to
105
+ * `[]`, so `JSON.stringify(result, compactReplacer)` strips empty arrays on
106
+ * the wire and `AnalyzeResultJson.parse(JSON.parse(json))` restores them.
107
+ * Consumers programmatically ingesting analysis JSON should parse through the
108
+ * schema to get defaults restored; raw-JSON consumers (e.g., `jq`) treat
109
+ * missing keys as null-equivalent (`jq '.diagnostics | length'` returns `0`
110
+ * on `{}`) and don't need the parse step.
111
+ *
112
+ * Construction sites (one-shot wrappers, `session.query`) hand back hand-built
113
+ * objects without re-running `.parse()` — the inner `modules` and
114
+ * `diagnostics` arrays are already Zod-validated upstream, and the envelope
115
+ * schema is the type contract, not a validation gate.
116
+ */
117
+ export const AnalyzeResultJson = z.strictObject({
118
+ modules: z.array(ModuleJson).default([]),
119
+ diagnostics: z.array(Diagnostic).default([]),
120
+ });
121
+ const toModuleAnalyzeResult = (raw) => {
122
+ const filtered = raw.declarations.filter((d) => !d.nodocs).map((d) => d.declaration);
123
+ const module = ModuleJson.parse({
124
+ path: raw.path,
125
+ declarations: filtered,
126
+ dependencies: raw.dependencies,
127
+ dependents: raw.dependents,
128
+ starExports: raw.starExports,
129
+ ...(raw.moduleComment ? { moduleComment: raw.moduleComment } : {}),
130
+ });
131
+ return { module, reExports: raw.reExports };
132
+ };
133
+ // ── Module dispatch ──────────────────────────────────────────────────────────
134
+ /**
135
+ * Analyze a single non-Svelte source file and extract module metadata.
136
+ *
137
+ * @internal Single-module dispatcher used internally by the two-phase
138
+ * orchestrator. Importable from `svelte-docinfo/analyze-core.js` for tests
139
+ * and power users — not part of the stable barrel API and not guaranteed
140
+ * across minor versions.
141
+ *
142
+ * Dispatches on file type:
143
+ * - TypeScript/JS → `analyzeTypescriptModule`
144
+ * - CSS/JSON → minimal module (no declarations, dependency tracking only)
145
+ * - Svelte → `module_skipped: requires_program` (callers using session API
146
+ * should not reach this path; the session pre-handles Svelte)
147
+ *
148
+ * Returns `undefined` when the file is skipped; the diagnostic is added to
149
+ * `diagnostics` so the caller can keep iterating.
150
+ */
151
+ export const analyzeModule = (sourceFile, program, options, diagnostics, log) => {
152
+ const checker = program.getTypeChecker();
153
+ const modulePath = extractPath(sourceFile.id, options);
154
+ const analyzerType = options.getAnalyzerType(sourceFile.id);
155
+ let raw;
156
+ if (analyzerType === 'svelte') {
157
+ diagnostics.push({
158
+ kind: 'module_skipped',
159
+ file: modulePath,
160
+ message: 'Svelte files require program integration. Use createAnalysisSession or analyze()/analyzeFromFiles() instead.',
161
+ severity: 'warning',
162
+ reason: 'requires_program',
163
+ });
164
+ log?.warn(`Svelte file skipped in analyzeModule: ${sourceFile.id}`);
165
+ return undefined;
166
+ }
167
+ else if (analyzerType === 'typescript') {
168
+ const tsSourceFile = program.getSourceFile(sourceFile.id);
169
+ if (!tsSourceFile) {
170
+ diagnostics.push({
171
+ kind: 'module_skipped',
172
+ file: modulePath,
173
+ message: `Could not get source file from program: ${sourceFile.id}`,
174
+ severity: 'warning',
175
+ reason: 'not_in_program',
176
+ });
177
+ log?.warn(`Could not get source file from program: ${sourceFile.id}`);
178
+ return undefined;
179
+ }
180
+ raw = analyzeTypescriptModule(sourceFile, tsSourceFile, modulePath, checker, options, diagnostics);
181
+ }
182
+ else if (analyzerType === 'css' || analyzerType === 'json') {
183
+ const { dependencies, dependents } = extractDependencies(sourceFile, options);
184
+ raw = {
185
+ path: modulePath,
186
+ declarations: [],
187
+ dependencies,
188
+ dependents,
189
+ starExports: [],
190
+ reExports: [],
191
+ };
192
+ }
193
+ else {
194
+ diagnostics.push({
195
+ kind: 'module_skipped',
196
+ file: modulePath,
197
+ message: `No analyzer for file type: ${sourceFile.id}`,
198
+ severity: 'warning',
199
+ reason: 'no_analyzer',
200
+ });
201
+ log?.warn(`No analyzer for file: ${sourceFile.id}`);
202
+ return undefined;
203
+ }
204
+ return toModuleAnalyzeResult(raw);
205
+ };
206
+ /**
207
+ * Run the two-phase analysis loop on pre-prepared inputs.
208
+ *
209
+ * @internal Shared two-phase orchestrator used internally by `session.query`
210
+ * and the one-shot wrappers. Importable from `svelte-docinfo/analyze-core.js`
211
+ * for tests and power users — not part of the stable barrel API and not
212
+ * guaranteed across minor versions.
213
+ *
214
+ * Phase 1: per-file dispatch (TS / Svelte / CSS / JSON / placeholder for
215
+ * transform-failed Svelte). Phase 2: re-export merge, component-alias fill,
216
+ * sort, duplicate detection. Diagnostic paths are normalized to
217
+ * project-root-relative form before return.
218
+ *
219
+ * Dependents are read from `sourceFile.dependents` (caller-supplied via
220
+ * `extractDependencies`); `analyzeCore` does not compute them. `session.query`
221
+ * runs `computeDependents` on the owned set before invoking this.
222
+ */
223
+ export const analyzeCore = (inputs) => {
224
+ const { sourceFiles, sourceOptions, program, svelteVirtualFiles, transformFailedIds, onDuplicates, log, } = inputs;
225
+ const checker = program.getTypeChecker();
226
+ const diagnostics = [];
227
+ const modules = [];
228
+ const collectedReExports = [];
229
+ // Phase 1: analyze every module, collect re-exports
230
+ for (const sourceFile of sourceFiles) {
231
+ // Failed-transform Svelte file: synthesize placeholder ModuleJson so
232
+ // the modules array reflects the full owned set. The originating
233
+ // transform_failed ingest diagnostic carries the cause; this slot
234
+ // is purely structural.
235
+ if (transformFailedIds?.has(sourceFile.id)) {
236
+ const modulePath = extractPath(sourceFile.id, sourceOptions);
237
+ const componentName = getComponentName(modulePath);
238
+ const { dependencies, dependents } = extractDependencies(sourceFile, sourceOptions);
239
+ modules.push(ModuleJson.parse({
240
+ path: modulePath,
241
+ declarations: [],
242
+ dependencies,
243
+ dependents,
244
+ starExports: [],
245
+ partial: true,
246
+ }));
247
+ log?.warn(`Svelte component ${componentName} marked partial (transform failed at ingest)`);
248
+ continue;
249
+ }
250
+ let result;
251
+ const virtualFile = svelteVirtualFiles.get(sourceFile.id);
252
+ if (virtualFile) {
253
+ const modulePath = extractPath(sourceFile.id, sourceOptions);
254
+ const raw = analyzeSvelteModule(sourceFile, modulePath, checker, sourceOptions, diagnostics, program, virtualFile);
255
+ if (raw) {
256
+ result = toModuleAnalyzeResult(raw);
257
+ }
258
+ else {
259
+ log?.error(`Svelte module analysis failed: ${sourceFile.id}`);
260
+ }
261
+ }
262
+ else {
263
+ result = analyzeModule(sourceFile, program, sourceOptions, diagnostics, log);
264
+ }
265
+ if (!result)
266
+ continue;
267
+ modules.push(result.module);
268
+ for (const reExport of result.reExports) {
269
+ collectedReExports.push({ reExportingModule: result.module.path, reExport });
270
+ }
271
+ }
272
+ // Phase 2a: build alsoExportedFrom arrays
273
+ mergeReExports(modules, collectedReExports);
274
+ // Phase 2b: fill component-only fields on renamed component aliases —
275
+ // canonical components are only fully populated after phase 1 finishes.
276
+ resolveComponentAliases(modules);
277
+ const sortedModules = sortModules(modules);
278
+ // Always run duplicate detection so a `duplicate_declaration` diagnostic
279
+ // reaches consumers regardless of `onDuplicates`. The `onDuplicates`
280
+ // callback/shortcut still fires for callers that want fail-fast or custom
281
+ // handling — diagnostics is the data, `onDuplicates` is the action.
282
+ const duplicates = findDuplicates(sortedModules);
283
+ emitDuplicateDiagnostics(diagnostics, duplicates);
284
+ if (onDuplicates) {
285
+ dispatchOnDuplicates(onDuplicates, duplicates, log);
286
+ }
287
+ normalizeDiagnosticPaths(diagnostics, sourceOptions.projectRoot);
288
+ return {
289
+ modules: sortedModules,
290
+ diagnostics,
291
+ };
292
+ };
293
+ /**
294
+ * Normalize `Diagnostic.file` to project-root-relative form, in place.
295
+ *
296
+ * Producers inside the analysis pipeline can write absolute paths or virtual
297
+ * paths (svelte2tsx output like `Foo.svelte.__svelte2tsx__.ts`). This pass
298
+ * collapses both to the public contract: a path relative to `projectRoot`
299
+ * with no leading slash and no `./` prefix.
300
+ *
301
+ * Exposed for build-tool integrations that bypass the session and collect
302
+ * their own discovery/dep diagnostics — they need the same normalization to
303
+ * match the public contract.
304
+ *
305
+ * @mutates diagnostics — rewrites each diagnostic's `file` field
306
+ */
307
+ export const normalizeDiagnosticPaths = (diagnostics, projectRoot) => {
308
+ const prefix = projectRoot.endsWith('/') ? projectRoot : projectRoot + '/';
309
+ for (const d of diagnostics) {
310
+ // Posixify so producers that emitted native-separator paths (e.g., a
311
+ // custom discovery layer building `path.relative` results on Windows)
312
+ // match the POSIX prefix derived from the normalized projectRoot.
313
+ let file = toPosixPath(stripVirtualSuffix(d.file));
314
+ if (file.startsWith(prefix)) {
315
+ file = file.slice(prefix.length);
316
+ }
317
+ else if (file.startsWith('/')) {
318
+ // Absolute path outside projectRoot — drop leading slash so display
319
+ // stays consistent.
320
+ file = file.slice(1);
321
+ }
322
+ d.file = file;
323
+ }
324
+ };
@@ -0,0 +1,137 @@
1
+ /**
2
+ * One-shot analysis wrappers — `analyze` and `analyzeFromFiles`.
3
+ *
4
+ * Both wrap a single-use `AnalysisSession`: `createSession → setFiles → query
5
+ * → dispose`. Incremental consumers (Vite plugin, LSP) should use
6
+ * `createAnalysisSession` directly so parsed ASTs and svelte2tsx output
7
+ * survive between calls.
8
+ *
9
+ * - `analyzeFromFiles` — high-level: file discovery from disk + dependency
10
+ * resolution + analysis. Recommended for CLI / build-time generation.
11
+ * - `analyze` — mid-level: caller supplies `SourceFileInfo[]`. For build-tool
12
+ * integrations that own discovery but don't run incrementally.
13
+ *
14
+ * @see `session.ts` for the persistent session API
15
+ * @see `analyze-core.ts` for the two-phase orchestrator
16
+ *
17
+ * @module
18
+ */
19
+ import type { AnalysisLog } from './log.js';
20
+ import { type ModuleSourceOptions, type SourceOptionsDefaults } from './source-config.js';
21
+ import { type Discovery } from './discovery.js';
22
+ import { type ResolveImport } from './dep-resolver.js';
23
+ import { type AnalyzeResultJson, type OnDuplicates } from './analyze-core.js';
24
+ import type { SourceFileInfo } from './source.js';
25
+ /**
26
+ * Options for `analyze`.
27
+ *
28
+ * Requires pre-loaded `SourceFileInfo` arrays — use `analyzeFromFiles` for
29
+ * automatic file discovery and loading from disk, or `createAnalysisSession`
30
+ * for incremental use.
31
+ */
32
+ export interface AnalyzeOptions {
33
+ /** Source files to analyze (must have content loaded). */
34
+ sourceFiles: ReadonlyArray<SourceFileInfo>;
35
+ /** Module source options for path extraction and source filtering. */
36
+ sourceOptions: ModuleSourceOptions;
37
+ /** Behavior when duplicate declaration names are found across modules. */
38
+ onDuplicates?: OnDuplicates;
39
+ /** Optional logger for status and diagnostic messages. */
40
+ log?: AnalysisLog;
41
+ /**
42
+ * Optional custom import resolver for the session default — a bare
43
+ * `ResolveImportFn` or a token-paired `ImportResolver` (see `ResolveImport`).
44
+ * For one-shot `analyze()` the session is single-use, so a bare function is
45
+ * the natural form; pass an `ImportResolver` with a stable `identity` only if
46
+ * you have a reason to control the cache scope.
47
+ */
48
+ resolveImport?: ResolveImport;
49
+ }
50
+ /**
51
+ * Analyze library source files and extract metadata (one-shot).
52
+ *
53
+ * Wraps a single-use `AnalysisSession`. For repeated analyses of the same
54
+ * source set (e.g., a Vite plugin reacting to file edits), use
55
+ * `createAnalysisSession` directly.
56
+ *
57
+ * @returns analyzed modules (sorted alphabetically) + concatenated ingest +
58
+ * query diagnostics
59
+ * @throws Error if `sourceOptions` validation fails or `tsconfig.json` is
60
+ * missing at `projectRoot`. Also propagates `onDuplicates: 'throw'` errors.
61
+ */
62
+ export declare const analyze: (options: AnalyzeOptions) => Promise<AnalyzeResultJson>;
63
+ /**
64
+ * Options for `analyzeFromFiles`.
65
+ *
66
+ * @see `AnalyzeOptions` for the build-tool-integration API where you supply
67
+ * `sourceFiles` and a fully-formed `sourceOptions: ModuleSourceOptions` directly.
68
+ */
69
+ export interface AnalyzeFromFilesOptions {
70
+ /** Absolute path to project root directory. */
71
+ projectRoot: string;
72
+ /** Partial overrides for default source options (SvelteKit `src/lib` layout). */
73
+ sourceOptions?: Partial<SourceOptionsDefaults>;
74
+ /** Behavior when duplicate declaration names are found across modules. */
75
+ onDuplicates?: OnDuplicates;
76
+ /** Optional logger for status and diagnostic messages. */
77
+ log?: AnalysisLog;
78
+ /**
79
+ * Glob patterns to include (relative to `projectRoot`).
80
+ *
81
+ * Filters glob-based discovery. Providing `include` under the default
82
+ * `discovery: 'auto'` collapses the chain to glob immediately; combining
83
+ * with `discovery: 'exports'` throws.
84
+ *
85
+ * When omitted, the glob fallback derives an include from
86
+ * `sourceOptions.sourcePaths` via `deriveIncludePatterns`, so custom
87
+ * `sourcePaths` (e.g., `['packages/foo']`) survive the fallback instead of
88
+ * silently defaulting to `src/lib`.
89
+ */
90
+ include?: Array<string>;
91
+ /** Glob patterns to exclude — fully replaces `sourceOptions.exclude` (no merge). */
92
+ exclude?: Array<string>;
93
+ /**
94
+ * Whether to resolve import dependencies (default `true`).
95
+ *
96
+ * When `false`, the session uses a no-op resolver that always returns
97
+ * `null`, so `ModuleJson.dependencies` / `dependents` stay empty.
98
+ * `analyzeFromFiles`'s discovery layer does not pre-populate
99
+ * `SourceFileInfo.dependencies`, so the session's pre-resolved fast path
100
+ * isn't reachable through this API — to exercise it, drive `analyze` or
101
+ * `createAnalysisSession` directly with files whose `dependencies` field
102
+ * is already filled in by your build tool.
103
+ *
104
+ * @default `true`
105
+ */
106
+ resolveDependencies?: boolean;
107
+ /**
108
+ * Optional custom import resolver — a bare `ResolveImportFn` or a
109
+ * token-paired `ImportResolver` (see `ResolveImport`). One-shot use doesn't
110
+ * benefit from a stable cache identity, so the bare function form is the
111
+ * natural choice here; for long-lived consumers (Vite plugin, LSP) construct
112
+ * an `ImportResolver` with a stable `identity` and pass it via
113
+ * `createAnalysisSession` so cache hits survive across calls.
114
+ *
115
+ * Cannot be combined with `resolveDependencies: false` — resolution is then
116
+ * off, so the resolver would never be consulted; passing both throws.
117
+ */
118
+ resolveImport?: ResolveImport;
119
+ /** Discovery strategy for source files. @default 'auto' */
120
+ discovery?: Discovery;
121
+ /** Dist directory name for exports-based discovery. @default 'dist' */
122
+ distDir?: string;
123
+ }
124
+ /**
125
+ * Analyze a library from files on disk with automatic file discovery.
126
+ *
127
+ * Recommended high-level API for one-shot use (CLI, build-time generation):
128
+ *
129
+ * 1. **Discovery** — `discoverSourceFiles` (exports-first, glob fallback)
130
+ * 2. **Ingest** — push discovered files into a single-use session
131
+ * 3. **Analysis** — `session.query()`
132
+ *
133
+ * @returns analyzed modules + concatenated ingest, discovery, and query diagnostics
134
+ * @throws Error if `sourceOptions` validation fails or `tsconfig.json` is missing
135
+ */
136
+ export declare const analyzeFromFiles: (options: AnalyzeFromFilesOptions) => Promise<AnalyzeResultJson>;
137
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/analyze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,UAAU,CAAC;AAE1C,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAsB,KAAK,SAAS,EAAC,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAiB,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAEN,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAIhD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC9B,0DAA0D;IAC1D,WAAW,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IAC3C,sEAAsE;IACtE,aAAa,EAAE,mBAAmB,CAAC;IACnC,0EAA0E;IAC1E,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,0DAA0D;IAC1D,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,GAAU,SAAS,cAAc,KAAG,OAAO,CAAC,iBAAiB,CAkBhF,CAAC;AAIF;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,aAAa,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC/C,0EAA0E;IAC1E,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,0DAA0D;IAC1D,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,oFAAoF;IACpF,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2DAA2D;IAC3D,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAC5B,SAAS,uBAAuB,KAC9B,OAAO,CAAC,iBAAiB,CAqG3B,CAAC"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * One-shot analysis wrappers — `analyze` and `analyzeFromFiles`.
3
+ *
4
+ * Both wrap a single-use `AnalysisSession`: `createSession → setFiles → query
5
+ * → dispose`. Incremental consumers (Vite plugin, LSP) should use
6
+ * `createAnalysisSession` directly so parsed ASTs and svelte2tsx output
7
+ * survive between calls.
8
+ *
9
+ * - `analyzeFromFiles` — high-level: file discovery from disk + dependency
10
+ * resolution + analysis. Recommended for CLI / build-time generation.
11
+ * - `analyze` — mid-level: caller supplies `SourceFileInfo[]`. For build-tool
12
+ * integrations that own discovery but don't run incrementally.
13
+ *
14
+ * @see `session.ts` for the persistent session API
15
+ * @see `analyze-core.ts` for the two-phase orchestrator
16
+ *
17
+ * @module
18
+ */
19
+ import { errorsOf, formatDiagnostic, warningsOf } from './diagnostics.js';
20
+ import { createAnalysisSession } from './session.js';
21
+ import { createSourceOptions, } from './source-config.js';
22
+ import { discoverSourceFiles } from './discovery.js';
23
+ import { noDepsResolver } from './dep-resolver.js';
24
+ import { normalizeDiagnosticPaths, } from './analyze-core.js';
25
+ /**
26
+ * Analyze library source files and extract metadata (one-shot).
27
+ *
28
+ * Wraps a single-use `AnalysisSession`. For repeated analyses of the same
29
+ * source set (e.g., a Vite plugin reacting to file edits), use
30
+ * `createAnalysisSession` directly.
31
+ *
32
+ * @returns analyzed modules (sorted alphabetically) + concatenated ingest +
33
+ * query diagnostics
34
+ * @throws Error if `sourceOptions` validation fails or `tsconfig.json` is
35
+ * missing at `projectRoot`. Also propagates `onDuplicates: 'throw'` errors.
36
+ */
37
+ export const analyze = async (options) => {
38
+ const session = createAnalysisSession({
39
+ sourceOptions: options.sourceOptions,
40
+ log: options.log,
41
+ resolveImport: options.resolveImport,
42
+ });
43
+ try {
44
+ const ingest = await session.setFiles(options.sourceFiles);
45
+ const query = session.query({ onDuplicates: options.onDuplicates, log: options.log });
46
+ // Concat is safe by spec — ingest diagnostics are paths-normalized in
47
+ // session.setFiles; query diagnostics are normalized in analyze-core.
48
+ return {
49
+ modules: query.modules,
50
+ diagnostics: [...ingest.diagnostics, ...query.diagnostics],
51
+ };
52
+ }
53
+ finally {
54
+ session.dispose();
55
+ }
56
+ };
57
+ /**
58
+ * Analyze a library from files on disk with automatic file discovery.
59
+ *
60
+ * Recommended high-level API for one-shot use (CLI, build-time generation):
61
+ *
62
+ * 1. **Discovery** — `discoverSourceFiles` (exports-first, glob fallback)
63
+ * 2. **Ingest** — push discovered files into a single-use session
64
+ * 3. **Analysis** — `session.query()`
65
+ *
66
+ * @returns analyzed modules + concatenated ingest, discovery, and query diagnostics
67
+ * @throws Error if `sourceOptions` validation fails or `tsconfig.json` is missing
68
+ */
69
+ export const analyzeFromFiles = async (options) => {
70
+ const { projectRoot, include, exclude, resolveDependencies: shouldResolveDependencies = true, resolveImport, sourceOptions, onDuplicates, log, discovery, distDir, } = options;
71
+ // A custom resolver with resolution turned off is a contradiction — the
72
+ // resolver would never be consulted. Fail fast rather than silently dropping
73
+ // it (mirrors the `discovery: 'exports'` + `include` config-error throw).
74
+ if (!shouldResolveDependencies && resolveImport !== undefined) {
75
+ throw new Error('`resolveImport` cannot be combined with `resolveDependencies: false` — ' +
76
+ 'dependency resolution is disabled, so the resolver would never be consulted. ' +
77
+ 'Remove `resolveImport`, or set `resolveDependencies: true` (the default).');
78
+ }
79
+ // Top-level `exclude` is an ergonomic shortcut that fully replaces
80
+ // `sourceOptions.exclude` (no array merge). Apply before
81
+ // `createSourceOptions` so the normalized options carry a single source
82
+ // of truth.
83
+ const mergedSourceOptions = exclude !== undefined ? { ...sourceOptions, exclude } : sourceOptions;
84
+ const resolvedSourceOptions = createSourceOptions(projectRoot, mergedSourceOptions);
85
+ const normalizedProjectRoot = resolvedSourceOptions.projectRoot;
86
+ // Step 1: discover files.
87
+ const { files: discoveredFiles, diagnostics: discoveryDiagnostics } = await discoverSourceFiles({
88
+ sourceOptions: resolvedSourceOptions,
89
+ include,
90
+ discovery,
91
+ distDir,
92
+ log,
93
+ });
94
+ // Step 2: build the session-default resolver. When dep-resolution is
95
+ // disabled, install the shared no-deps resolver so the session's lex+resolve
96
+ // passes surface no edges (faster than relying on the default resolver to
97
+ // return null for everything). Otherwise forward the caller's resolver — the
98
+ // session normalizes the `ResolveImport` union (bare fn or token-paired) and
99
+ // falls back to its TS+tsconfig default when undefined.
100
+ const sessionResolver = shouldResolveDependencies
101
+ ? resolveImport
102
+ : noDepsResolver;
103
+ // Step 3: ingest + analyze via single-use session.
104
+ const session = createAnalysisSession({
105
+ sourceOptions: resolvedSourceOptions,
106
+ log,
107
+ resolveImport: sessionResolver,
108
+ });
109
+ let result;
110
+ try {
111
+ const ingest = await session.setFiles(discoveredFiles);
112
+ const query = session.query({ onDuplicates, log });
113
+ result = {
114
+ modules: query.modules,
115
+ diagnostics: [...ingest.diagnostics, ...query.diagnostics],
116
+ };
117
+ }
118
+ finally {
119
+ session.dispose();
120
+ }
121
+ // Merge discovery diagnostics. `analyzeCore` and the session both already
122
+ // normalized their own; normalize discovery in place (idempotent for paths
123
+ // already project-relative) and append.
124
+ normalizeDiagnosticPaths(discoveryDiagnostics, normalizedProjectRoot);
125
+ for (const d of discoveryDiagnostics)
126
+ result.diagnostics.push(d);
127
+ if (log && shouldResolveDependencies) {
128
+ const totalDeps = result.modules.reduce((sum, m) => sum + m.dependencies.length, 0);
129
+ log.info(`Resolved ${totalDeps} module dependency edges`);
130
+ }
131
+ if (log && result.diagnostics.length > 0) {
132
+ const errors = errorsOf(result.diagnostics);
133
+ const warnings = warningsOf(result.diagnostics);
134
+ if (errors.length > 0) {
135
+ log.error(`Analysis completed with ${errors.length} error(s):`);
136
+ for (const diagnostic of errors) {
137
+ log.error(` ${formatDiagnostic(diagnostic)}`);
138
+ }
139
+ }
140
+ if (warnings.length > 0) {
141
+ log.warn(`Analysis completed with ${warnings.length} warning(s):`);
142
+ for (const diagnostic of warnings) {
143
+ log.warn(` ${formatDiagnostic(diagnostic)}`);
144
+ }
145
+ }
146
+ }
147
+ return result;
148
+ };