@fuzdev/fuz_ui 0.175.0 → 0.176.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/README.md +1 -1
- package/dist/Alert.svelte +2 -0
- package/dist/Alert.svelte.d.ts.map +1 -1
- package/dist/ApiModule.svelte +5 -6
- package/dist/ApiModule.svelte.d.ts.map +1 -1
- package/dist/DeclarationDetail.svelte +2 -1
- package/dist/DeclarationDetail.svelte.d.ts.map +1 -1
- package/dist/Details.svelte +2 -0
- package/dist/Details.svelte.d.ts.map +1 -1
- package/dist/Themed.svelte +2 -0
- package/dist/Themed.svelte.d.ts.map +1 -1
- package/dist/analysis_context.d.ts +195 -0
- package/dist/analysis_context.d.ts.map +1 -0
- package/dist/analysis_context.js +134 -0
- package/dist/library_analysis.d.ts +112 -0
- package/dist/library_analysis.d.ts.map +1 -0
- package/dist/library_analysis.js +106 -0
- package/dist/library_gen.d.ts +73 -5
- package/dist/library_gen.d.ts.map +1 -1
- package/dist/library_gen.js +130 -68
- package/dist/library_gen_helpers.d.ts +81 -72
- package/dist/library_gen_helpers.d.ts.map +1 -1
- package/dist/library_gen_helpers.js +115 -156
- package/dist/library_gen_output.d.ts +34 -0
- package/dist/library_gen_output.d.ts.map +1 -0
- package/dist/library_gen_output.js +40 -0
- package/dist/mdz.d.ts +3 -0
- package/dist/mdz.d.ts.map +1 -1
- package/dist/mdz.js +12 -3
- package/dist/module_helpers.d.ts +246 -24
- package/dist/module_helpers.d.ts.map +1 -1
- package/dist/module_helpers.js +250 -42
- package/dist/svelte_helpers.d.ts +65 -10
- package/dist/svelte_helpers.d.ts.map +1 -1
- package/dist/svelte_helpers.js +171 -49
- package/dist/ts_helpers.d.ts +132 -61
- package/dist/ts_helpers.d.ts.map +1 -1
- package/dist/ts_helpers.js +423 -282
- package/dist/tsdoc_helpers.d.ts +11 -0
- package/dist/tsdoc_helpers.d.ts.map +1 -1
- package/dist/tsdoc_helpers.js +22 -47
- package/dist/tsdoc_mdz.d.ts +36 -0
- package/dist/tsdoc_mdz.d.ts.map +1 -0
- package/dist/tsdoc_mdz.js +56 -0
- package/dist/vite_plugin_library_well_known.js +5 -5
- package/package.json +11 -6
- package/src/lib/analysis_context.ts +250 -0
- package/src/lib/library_analysis.ts +168 -0
- package/src/lib/library_gen.ts +199 -83
- package/src/lib/library_gen_helpers.ts +148 -215
- package/src/lib/library_gen_output.ts +63 -0
- package/src/lib/mdz.ts +13 -4
- package/src/lib/module_helpers.ts +392 -47
- package/src/lib/svelte_helpers.ts +291 -55
- package/src/lib/ts_helpers.ts +538 -338
- package/src/lib/tsdoc_helpers.ts +24 -49
- package/src/lib/tsdoc_mdz.ts +62 -0
- package/src/lib/vite_plugin_library_well_known.ts +5 -5
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library source analysis - unified entry point and shared types.
|
|
3
|
+
*
|
|
4
|
+
* Provides a single function for analyzing TypeScript and Svelte source files,
|
|
5
|
+
* dispatching to the appropriate domain-specific analyzer.
|
|
6
|
+
*
|
|
7
|
+
* This module also exports shared types used by both analyzers:
|
|
8
|
+
* - `DeclarationAnalysis` - A declaration with its nodocs flag
|
|
9
|
+
* - `ReExportInfo` - Information about a same-name re-export
|
|
10
|
+
* - `ModuleAnalysis` - Result of analyzing a module (unified structure)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import {library_analyze_module} from '@fuzdev/fuz_ui/library_analysis.js';
|
|
15
|
+
* import {ts_create_program} from '@fuzdev/fuz_ui/ts_helpers.js';
|
|
16
|
+
* import {module_create_source_options} from '@fuzdev/fuz_ui/module_helpers.js';
|
|
17
|
+
* import {AnalysisContext} from '@fuzdev/fuz_ui/analysis_context.js';
|
|
18
|
+
*
|
|
19
|
+
* const {program} = ts_create_program({root: './my-project'});
|
|
20
|
+
* const ctx = new AnalysisContext();
|
|
21
|
+
* const options = module_create_source_options('/my-project');
|
|
22
|
+
*
|
|
23
|
+
* const result = library_analyze_module(
|
|
24
|
+
* {id: '/my-project/src/lib/file.ts', content: '...'},
|
|
25
|
+
* program,
|
|
26
|
+
* options,
|
|
27
|
+
* ctx,
|
|
28
|
+
* );
|
|
29
|
+
*
|
|
30
|
+
* if (result) {
|
|
31
|
+
* // Filter out @nodocs declarations
|
|
32
|
+
* const declarations = result.declarations
|
|
33
|
+
* .filter(d => !d.nodocs)
|
|
34
|
+
* .map(d => d.declaration);
|
|
35
|
+
* console.log('Declarations:', declarations);
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @see ts_helpers.ts for TypeScript-specific analysis
|
|
40
|
+
* @see svelte_helpers.ts for Svelte component analysis
|
|
41
|
+
* @see module_helpers.ts for path utilities and SourceFileInfo
|
|
42
|
+
*
|
|
43
|
+
* @module
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import ts from 'typescript';
|
|
47
|
+
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
48
|
+
import type {DeclarationJson} from '@fuzdev/fuz_util/source_json.js';
|
|
49
|
+
|
|
50
|
+
import {ts_analyze_module} from './ts_helpers.js';
|
|
51
|
+
import {svelte_analyze_module} from './svelte_helpers.js';
|
|
52
|
+
import {
|
|
53
|
+
type SourceFileInfo,
|
|
54
|
+
type ModuleSourceOptions,
|
|
55
|
+
module_extract_path,
|
|
56
|
+
} from './module_helpers.js';
|
|
57
|
+
import type {AnalysisContext} from './analysis_context.js';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Result of analyzing a single declaration.
|
|
61
|
+
* Used by both TypeScript and Svelte analyzers for uniform handling.
|
|
62
|
+
*/
|
|
63
|
+
export interface DeclarationAnalysis {
|
|
64
|
+
/** The analyzed declaration metadata. */
|
|
65
|
+
declaration: DeclarationJson;
|
|
66
|
+
/** Whether the declaration is marked @nodocs (should be excluded from documentation). */
|
|
67
|
+
nodocs: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Information about a same-name re-export.
|
|
72
|
+
* Used for post-processing to build `also_exported_from` arrays.
|
|
73
|
+
*/
|
|
74
|
+
export interface ReExportInfo {
|
|
75
|
+
/** Name of the re-exported declaration. */
|
|
76
|
+
name: string;
|
|
77
|
+
/** Module path (relative to src/lib) where the declaration is originally declared. */
|
|
78
|
+
original_module: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Result of analyzing a module (TypeScript or Svelte).
|
|
83
|
+
* Both analyzers return this same structure for uniform handling.
|
|
84
|
+
*/
|
|
85
|
+
export interface ModuleAnalysis {
|
|
86
|
+
/** Module path relative to source root. */
|
|
87
|
+
path: string;
|
|
88
|
+
/** Module-level documentation comment. */
|
|
89
|
+
module_comment?: string;
|
|
90
|
+
/** All declarations with nodocs flags - consumer filters based on policy. */
|
|
91
|
+
declarations: Array<DeclarationAnalysis>;
|
|
92
|
+
/** Dependencies (other source modules this module imports). Empty if none. */
|
|
93
|
+
dependencies: Array<string>;
|
|
94
|
+
/** Dependents (other source modules that import this module). Empty if none. */
|
|
95
|
+
dependents: Array<string>;
|
|
96
|
+
/** Star exports (`export * from './module'`). Empty for Svelte components. */
|
|
97
|
+
star_exports: Array<string>;
|
|
98
|
+
/** Re-exports discovered during analysis. Empty for Svelte components. */
|
|
99
|
+
re_exports: Array<ReExportInfo>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Analyze a source file and extract module metadata.
|
|
104
|
+
*
|
|
105
|
+
* Unified entry point that dispatches to the appropriate analyzer based on file type:
|
|
106
|
+
* - TypeScript/JavaScript files → `ts_analyze_module`
|
|
107
|
+
* - Svelte components → `svelte_analyze_module`
|
|
108
|
+
*
|
|
109
|
+
* Returns raw analysis data including `nodocs` flags on declarations.
|
|
110
|
+
* Consumer is responsible for filtering based on their policy.
|
|
111
|
+
*
|
|
112
|
+
* This function can be called incrementally - consumers may cache results and
|
|
113
|
+
* only re-analyze changed files. The TypeScript program should include all files
|
|
114
|
+
* for accurate type resolution, but only changed files need re-analysis.
|
|
115
|
+
*
|
|
116
|
+
* @param source_file The source file info with content and optional dependency data
|
|
117
|
+
* @param program TypeScript program (used for type checking and source file lookup)
|
|
118
|
+
* @param options Module source options for path extraction
|
|
119
|
+
* @param ctx Analysis context for collecting diagnostics
|
|
120
|
+
* @param log Optional logger for warnings
|
|
121
|
+
* @returns Module metadata and re-exports, or undefined if source file not found in program
|
|
122
|
+
*/
|
|
123
|
+
export const library_analyze_module = (
|
|
124
|
+
source_file: SourceFileInfo,
|
|
125
|
+
program: ts.Program,
|
|
126
|
+
options: ModuleSourceOptions,
|
|
127
|
+
ctx: AnalysisContext,
|
|
128
|
+
log?: Logger,
|
|
129
|
+
): ModuleAnalysis | undefined => {
|
|
130
|
+
const checker = program.getTypeChecker();
|
|
131
|
+
const module_path = module_extract_path(source_file.id, options);
|
|
132
|
+
const analyzer_type = options.get_analyzer(source_file.id);
|
|
133
|
+
|
|
134
|
+
if (analyzer_type === 'svelte') {
|
|
135
|
+
return svelte_analyze_module(source_file, module_path, checker, options, ctx);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (analyzer_type === 'typescript') {
|
|
139
|
+
const ts_source_file = program.getSourceFile(source_file.id);
|
|
140
|
+
if (!ts_source_file) {
|
|
141
|
+
ctx.add({
|
|
142
|
+
kind: 'module_skipped',
|
|
143
|
+
file: module_path,
|
|
144
|
+
line: null,
|
|
145
|
+
column: null,
|
|
146
|
+
message: `Could not get source file from program: ${source_file.id}`,
|
|
147
|
+
severity: 'warning',
|
|
148
|
+
reason: 'not_in_program',
|
|
149
|
+
});
|
|
150
|
+
log?.warn(`Could not get source file from program: ${source_file.id}`);
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
return ts_analyze_module(source_file, ts_source_file, module_path, checker, options, ctx);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// analyzer_type is null - skip this file
|
|
157
|
+
ctx.add({
|
|
158
|
+
kind: 'module_skipped',
|
|
159
|
+
file: module_path,
|
|
160
|
+
line: null,
|
|
161
|
+
column: null,
|
|
162
|
+
message: `No analyzer for file type: ${source_file.id}`,
|
|
163
|
+
severity: 'warning',
|
|
164
|
+
reason: 'no_analyzer',
|
|
165
|
+
});
|
|
166
|
+
log?.warn(`No analyzer for file: ${source_file.id}`);
|
|
167
|
+
return undefined;
|
|
168
|
+
};
|
package/src/lib/library_gen.ts
CHANGED
|
@@ -11,27 +11,135 @@
|
|
|
11
11
|
* - Dependency graphs
|
|
12
12
|
* - Svelte component props
|
|
13
13
|
*
|
|
14
|
+
* This file contains Gro-specific integration. The actual analysis logic is in
|
|
15
|
+
* build-tool agnostic helpers that work with `SourceFileInfo`.
|
|
16
|
+
*
|
|
14
17
|
* @see @fuzdev/fuz_util/source_json.js for type definitions
|
|
15
|
-
* @see
|
|
16
|
-
* @see
|
|
17
|
-
* @see
|
|
18
|
-
* @see
|
|
18
|
+
* @see `library_analysis.ts` for the unified analysis entry point
|
|
19
|
+
* @see `library_gen_helpers.ts` for pipeline orchestration helpers
|
|
20
|
+
* @see `tsdoc_helpers.ts` for JSDoc/TSDoc parsing
|
|
21
|
+
* @see `ts_helpers.ts` for TypeScript analysis
|
|
22
|
+
* @see `svelte_helpers.ts` for Svelte component analysis
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
19
25
|
*/
|
|
20
26
|
|
|
21
27
|
import type {Gen} from '@ryanatkn/gro';
|
|
22
28
|
import {package_json_load} from '@ryanatkn/gro/package_json.js';
|
|
23
|
-
import type {
|
|
29
|
+
import type {Disknode} from '@ryanatkn/gro/disknode.js';
|
|
30
|
+
import type {SourceJson, ModuleJson} from '@fuzdev/fuz_util/source_json.js';
|
|
24
31
|
|
|
25
|
-
import {ts_create_program
|
|
26
|
-
import {
|
|
32
|
+
import {ts_create_program} from './ts_helpers.js';
|
|
33
|
+
import {
|
|
34
|
+
type SourceFileInfo,
|
|
35
|
+
type ModuleSourceOptions,
|
|
36
|
+
type ModuleSourcePartial,
|
|
37
|
+
module_create_source_options,
|
|
38
|
+
module_validate_source_options,
|
|
39
|
+
} from './module_helpers.js';
|
|
40
|
+
import {library_analyze_module} from './library_analysis.js';
|
|
27
41
|
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
} from './library_gen_helpers.
|
|
42
|
+
library_collect_source_files,
|
|
43
|
+
library_sort_modules,
|
|
44
|
+
library_find_duplicates,
|
|
45
|
+
library_merge_re_exports,
|
|
46
|
+
type CollectedReExport,
|
|
47
|
+
type DuplicateInfo,
|
|
48
|
+
} from './library_gen_helpers.js';
|
|
49
|
+
import {library_generate_json} from './library_gen_output.js';
|
|
50
|
+
import {AnalysisContext, format_diagnostic} from './analysis_context.js';
|
|
51
|
+
|
|
52
|
+
/** Options for library generation. */
|
|
53
|
+
export interface LibraryGenOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Module source options for filtering and path extraction.
|
|
56
|
+
*
|
|
57
|
+
* Can provide full `ModuleSourceOptions` or partial options that will be
|
|
58
|
+
* merged with defaults. The `project_root` is automatically set to
|
|
59
|
+
* `process.cwd()` if not provided.
|
|
60
|
+
*/
|
|
61
|
+
source?: ModuleSourceOptions | Partial<ModuleSourcePartial>;
|
|
62
|
+
/**
|
|
63
|
+
* Callback invoked when duplicate declaration names are found.
|
|
64
|
+
*
|
|
65
|
+
* Consumers decide how to handle duplicates: throw, warn, or ignore.
|
|
66
|
+
* Use `library_gen_throw_on_duplicates` for strict flat namespace enforcement.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // Throw on duplicates (strict flat namespace)
|
|
70
|
+
* library_gen({ on_duplicates: library_gen_throw_on_duplicates });
|
|
71
|
+
*
|
|
72
|
+
* // Warn but continue
|
|
73
|
+
* library_gen({
|
|
74
|
+
* on_duplicates: (dupes, log) => {
|
|
75
|
+
* for (const [name, locs] of dupes) {
|
|
76
|
+
* log.warn(`Duplicate: ${name} in ${locs.map(l => l.module).join(', ')}`);
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
* });
|
|
80
|
+
*/
|
|
81
|
+
on_duplicates?: OnDuplicatesCallback;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Callback for handling duplicate declaration names.
|
|
86
|
+
*
|
|
87
|
+
* @param duplicates Map of declaration names to their occurrences across modules
|
|
88
|
+
* @param log Logger for reporting
|
|
89
|
+
*/
|
|
90
|
+
export type OnDuplicatesCallback = (
|
|
91
|
+
duplicates: Map<string, Array<DuplicateInfo>>,
|
|
92
|
+
log: {error: (...args: Array<unknown>) => void},
|
|
93
|
+
) => void;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Strict duplicate handler that throws on any duplicate declaration names.
|
|
97
|
+
*
|
|
98
|
+
* Use this callback with `library_gen({ on_duplicates: library_gen_throw_on_duplicates })`
|
|
99
|
+
* to enforce a flat namespace where all declaration names must be unique.
|
|
100
|
+
*
|
|
101
|
+
* @throws Error if any duplicate declaration names are found
|
|
102
|
+
*/
|
|
103
|
+
export const library_gen_throw_on_duplicates: OnDuplicatesCallback = (duplicates, log) => {
|
|
104
|
+
if (duplicates.size === 0) return;
|
|
105
|
+
|
|
106
|
+
log.error('Duplicate declaration names detected in flat namespace:');
|
|
107
|
+
for (const [name, occurrences] of duplicates) {
|
|
108
|
+
log.error(` "${name}" found in:`);
|
|
109
|
+
for (const {declaration, module} of occurrences) {
|
|
110
|
+
const line_info = declaration.source_line !== undefined ? `:${declaration.source_line}` : '';
|
|
111
|
+
log.error(` - ${module}${line_info} (${declaration.kind})`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Found ${duplicates.size} duplicate declaration name${duplicates.size === 1 ? '' : 's'} across modules. ` +
|
|
116
|
+
'The flat namespace requires unique names. To resolve: ' +
|
|
117
|
+
'(1) rename one of the conflicting declarations, or ' +
|
|
118
|
+
'(2) add /** @nodocs */ to exclude from documentation. ' +
|
|
119
|
+
'See CLAUDE.md "Declaration namespacing" section for details.',
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Convert Gro's Disknode to the build-tool agnostic SourceFileInfo interface.
|
|
125
|
+
*
|
|
126
|
+
* Use this when you want to analyze files using Gro's filer directly.
|
|
127
|
+
*
|
|
128
|
+
* @throws Error if disknode has no content (should be loaded by Gro filer)
|
|
129
|
+
*/
|
|
130
|
+
export const source_file_from_disknode = (disknode: Disknode): SourceFileInfo => {
|
|
131
|
+
if (disknode.contents == null) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`Source file has no content: ${disknode.id} (ensure Gro filer loads file contents)`,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
id: disknode.id,
|
|
138
|
+
content: disknode.contents,
|
|
139
|
+
dependencies: [...disknode.dependencies.keys()],
|
|
140
|
+
dependents: [...disknode.dependents.keys()],
|
|
141
|
+
};
|
|
142
|
+
};
|
|
35
143
|
|
|
36
144
|
/**
|
|
37
145
|
* Creates a Gen object for generating library metadata with full TypeScript analysis.
|
|
@@ -43,12 +151,24 @@ import {
|
|
|
43
151
|
*
|
|
44
152
|
* export const gen = library_gen();
|
|
45
153
|
* ```
|
|
154
|
+
*
|
|
155
|
+
* @param options Optional generation options
|
|
46
156
|
*/
|
|
47
|
-
export const library_gen = (): Gen => {
|
|
157
|
+
export const library_gen = (options?: LibraryGenOptions): Gen => {
|
|
48
158
|
return {
|
|
49
159
|
generate: async ({log, filer}) => {
|
|
50
160
|
log.info('generating library metadata with full TypeScript analysis...');
|
|
51
161
|
|
|
162
|
+
// Build source options with project_root from cwd
|
|
163
|
+
const source_options: ModuleSourceOptions =
|
|
164
|
+
options?.source && 'project_root' in options.source
|
|
165
|
+
? options.source
|
|
166
|
+
: module_create_source_options(process.cwd(), options?.source);
|
|
167
|
+
|
|
168
|
+
// Validate options early to fail fast on misconfiguration
|
|
169
|
+
// (before expensive operations like program creation)
|
|
170
|
+
module_validate_source_options(source_options);
|
|
171
|
+
|
|
52
172
|
// Ensure filer is initialized
|
|
53
173
|
await filer.init();
|
|
54
174
|
|
|
@@ -56,100 +176,96 @@ export const library_gen = (): Gen => {
|
|
|
56
176
|
const package_json = await package_json_load();
|
|
57
177
|
|
|
58
178
|
// Create TypeScript program
|
|
59
|
-
const program = ts_create_program(log);
|
|
60
|
-
|
|
61
|
-
|
|
179
|
+
const {program} = ts_create_program(undefined, log);
|
|
180
|
+
|
|
181
|
+
// Create analysis context for collecting diagnostics
|
|
182
|
+
const ctx = new AnalysisContext();
|
|
183
|
+
|
|
184
|
+
// Convert Gro's filer files to build-tool agnostic SourceFileInfo
|
|
185
|
+
const all_source_files: Array<SourceFileInfo> = [];
|
|
186
|
+
for (const disknode of filer.files.values()) {
|
|
187
|
+
all_source_files.push(source_file_from_disknode(disknode));
|
|
62
188
|
}
|
|
63
189
|
|
|
64
|
-
|
|
190
|
+
// Collect and filter source files
|
|
191
|
+
const source_files = library_collect_source_files(all_source_files, source_options, log);
|
|
65
192
|
|
|
66
|
-
// Collect
|
|
67
|
-
const
|
|
193
|
+
// Collect modules (declared before source_json to include directly)
|
|
194
|
+
const modules: Array<ModuleJson> = [];
|
|
68
195
|
|
|
69
196
|
// Build source_json with array-based modules
|
|
70
197
|
// Phase 1: Analyze all modules and collect re-exports
|
|
71
198
|
const source_json: SourceJson = {
|
|
72
199
|
name: package_json.name,
|
|
73
200
|
version: package_json.version,
|
|
74
|
-
modules
|
|
201
|
+
modules,
|
|
75
202
|
};
|
|
76
203
|
|
|
77
|
-
// Collect
|
|
78
|
-
//
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
for (const disknode of source_disknodes) {
|
|
82
|
-
const source_id = disknode.id;
|
|
83
|
-
const module_path = module_extract_path(source_id);
|
|
84
|
-
const is_svelte = module_is_svelte(module_path);
|
|
85
|
-
|
|
86
|
-
// Handle Svelte files separately (before trying to get TypeScript source file)
|
|
87
|
-
if (is_svelte) {
|
|
88
|
-
const mod = library_gen_analyze_svelte_file(disknode, module_path, checker);
|
|
89
|
-
source_json.modules!.push(mod);
|
|
90
|
-
} else {
|
|
91
|
-
// For TypeScript/JS files, get the source file from the program
|
|
92
|
-
const source_file = program.getSourceFile(source_id);
|
|
93
|
-
if (!source_file) {
|
|
94
|
-
log.warn(`Could not get source file: ${source_id}`);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
204
|
+
// Collect re-exports for phase 2 merging
|
|
205
|
+
// See library_merge_re_exports for the two-phase resolution strategy
|
|
206
|
+
const collected_re_exports: Array<CollectedReExport> = [];
|
|
97
207
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
208
|
+
for (const source_file of source_files) {
|
|
209
|
+
// Use unified analyzer that dispatches based on file type
|
|
210
|
+
const result = library_analyze_module(source_file, program, source_options, ctx, log);
|
|
211
|
+
if (!result) continue;
|
|
212
|
+
|
|
213
|
+
// Build ModuleJson, filtering out @nodocs declarations
|
|
214
|
+
const module: ModuleJson = {
|
|
215
|
+
path: result.path,
|
|
216
|
+
declarations: result.declarations.filter((d) => !d.nodocs).map((d) => d.declaration),
|
|
217
|
+
};
|
|
218
|
+
if (result.module_comment) module.module_comment = result.module_comment;
|
|
219
|
+
if (result.dependencies.length > 0) module.dependencies = result.dependencies;
|
|
220
|
+
if (result.dependents.length > 0) module.dependents = result.dependents;
|
|
221
|
+
if (result.star_exports.length > 0) module.star_exports = result.star_exports;
|
|
222
|
+
|
|
223
|
+
modules.push(module);
|
|
224
|
+
|
|
225
|
+
// Collect re-exports for phase 2 merging
|
|
226
|
+
for (const re_export of result.re_exports) {
|
|
227
|
+
collected_re_exports.push({re_exporting_module: result.path, re_export});
|
|
111
228
|
}
|
|
112
229
|
}
|
|
113
230
|
|
|
114
231
|
// Phase 2: Build also_exported_from arrays from re-export data
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
for
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
if (
|
|
124
|
-
|
|
232
|
+
library_merge_re_exports(source_json, collected_re_exports);
|
|
233
|
+
|
|
234
|
+
// Sort modules alphabetically for deterministic output and cleaner diffs
|
|
235
|
+
source_json.modules = library_sort_modules(modules);
|
|
236
|
+
|
|
237
|
+
// Check for duplicate declaration names and invoke callback if provided
|
|
238
|
+
if (options?.on_duplicates) {
|
|
239
|
+
const duplicates = library_find_duplicates(source_json);
|
|
240
|
+
if (duplicates.size > 0) {
|
|
241
|
+
options.on_duplicates(duplicates, log);
|
|
125
242
|
}
|
|
126
|
-
module_map.get(name)!.push(re_exporting_module);
|
|
127
243
|
}
|
|
128
244
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
245
|
+
// Report any analysis diagnostics
|
|
246
|
+
if (ctx.diagnostics.length > 0) {
|
|
247
|
+
const errors = ctx.errors();
|
|
248
|
+
const warnings = ctx.warnings();
|
|
249
|
+
const format_options = {strip_base: process.cwd()};
|
|
133
250
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
251
|
+
if (errors.length > 0) {
|
|
252
|
+
log.error(`Analysis completed with ${errors.length} error(s):`);
|
|
253
|
+
for (const diagnostic of errors) {
|
|
254
|
+
log.error(` ${format_diagnostic(diagnostic, format_options)}`);
|
|
138
255
|
}
|
|
139
256
|
}
|
|
140
|
-
}
|
|
141
257
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
258
|
+
if (warnings.length > 0) {
|
|
259
|
+
log.warn(`Analysis completed with ${warnings.length} warning(s):`);
|
|
260
|
+
for (const diagnostic of warnings) {
|
|
261
|
+
log.warn(` ${format_diagnostic(diagnostic, format_options)}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
149
265
|
|
|
150
266
|
log.info('library metadata generation complete');
|
|
151
267
|
|
|
152
|
-
const {json_content, ts_content} =
|
|
268
|
+
const {json_content, ts_content} = library_generate_json(package_json, source_json);
|
|
153
269
|
|
|
154
270
|
// Return array of files:
|
|
155
271
|
// - library.json (default from .gen.json.ts naming)
|