@fuzdev/fuz_ui 0.194.0 → 0.195.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/dist/DeclarationDetail.svelte +139 -64
- package/dist/DeclarationDetail.svelte.d.ts +9 -0
- package/dist/DeclarationDetail.svelte.d.ts.map +1 -1
- package/dist/LibraryDetail.svelte +14 -10
- package/dist/LibraryDetail.svelte.d.ts +7 -0
- package/dist/LibraryDetail.svelte.d.ts.map +1 -1
- package/dist/declaration.svelte.d.ts +233 -25
- package/dist/declaration.svelte.d.ts.map +1 -1
- package/dist/declaration.svelte.js +71 -23
- package/dist/library.svelte.js +1 -1
- package/dist/library_gen.d.ts +24 -17
- package/dist/library_gen.d.ts.map +1 -1
- package/dist/library_gen.js +52 -32
- package/dist/library_output.d.ts +5 -4
- package/dist/library_output.d.ts.map +1 -1
- package/dist/library_output.js +11 -8
- package/dist/module.svelte.d.ts +21 -7
- package/dist/module.svelte.d.ts.map +1 -1
- package/dist/module.svelte.js +26 -11
- package/dist/tsdoc_mdz.d.ts +6 -1
- package/dist/tsdoc_mdz.d.ts.map +1 -1
- package/dist/tsdoc_mdz.js +23 -2
- package/package.json +10 -8
- package/src/lib/declaration.svelte.ts +90 -35
- package/src/lib/library.svelte.ts +1 -1
- package/src/lib/library_gen.ts +65 -42
- package/src/lib/library_output.ts +11 -8
- package/src/lib/module.svelte.ts +29 -16
- package/src/lib/tsdoc_mdz.ts +25 -2
- package/dist/analysis_context.d.ts +0 -199
- package/dist/analysis_context.d.ts.map +0 -1
- package/dist/analysis_context.js +0 -138
- package/dist/library_analysis.d.ts +0 -112
- package/dist/library_analysis.d.ts.map +0 -1
- package/dist/library_analysis.js +0 -106
- package/dist/library_generate.d.ts +0 -94
- package/dist/library_generate.d.ts.map +0 -1
- package/dist/library_generate.js +0 -147
- package/dist/library_pipeline.d.ts +0 -113
- package/dist/library_pipeline.d.ts.map +0 -1
- package/dist/library_pipeline.js +0 -160
- package/dist/module_helpers.d.ts +0 -334
- package/dist/module_helpers.d.ts.map +0 -1
- package/dist/module_helpers.js +0 -317
- package/dist/svelte_helpers.d.ts +0 -92
- package/dist/svelte_helpers.d.ts.map +0 -1
- package/dist/svelte_helpers.js +0 -367
- package/dist/ts_helpers.d.ts +0 -181
- package/dist/ts_helpers.d.ts.map +0 -1
- package/dist/ts_helpers.js +0 -674
- package/dist/tsdoc_helpers.d.ts +0 -119
- package/dist/tsdoc_helpers.d.ts.map +0 -1
- package/dist/tsdoc_helpers.js +0 -207
- package/src/lib/analysis_context.ts +0 -254
- package/src/lib/library_analysis.ts +0 -168
- package/src/lib/library_generate.ts +0 -215
- package/src/lib/library_pipeline.ts +0 -221
- package/src/lib/module_helpers.ts +0 -501
- package/src/lib/svelte_helpers.ts +0 -539
- package/src/lib/ts_helpers.ts +0 -862
- package/src/lib/tsdoc_helpers.ts +0 -246
|
@@ -1,20 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type {
|
|
2
|
+
DeclarationJson,
|
|
3
|
+
DeclarationJsonInput,
|
|
4
|
+
MemberJsonInput,
|
|
5
|
+
ParameterJsonInput,
|
|
6
|
+
ComponentPropJsonInput,
|
|
7
|
+
OverloadJsonInput,
|
|
8
|
+
} from 'svelte-docinfo/types.js';
|
|
9
|
+
import {generateImport, getDisplayName} from 'svelte-docinfo/declaration-helpers.js';
|
|
6
10
|
|
|
7
11
|
import type {Module} from './module.svelte.js';
|
|
8
12
|
import {url_github_file} from './package_helpers.js';
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
// `library.json` is serialized with svelte-docinfo's `compactReplacer`, which
|
|
15
|
+
// strips empty default arrays — so the on-disk data is the `*Input` shape
|
|
16
|
+
// (defaulted arrays optional), not the parsed `*Json` shape. Typing it as
|
|
17
|
+
// input makes TypeScript force a guard on every defaulted-array read.
|
|
18
|
+
//
|
|
19
|
+
// Helper to access kind-specific fields on the discriminated union.
|
|
20
|
+
// At runtime the field is present or undefined; TypeScript needs the cast.
|
|
21
|
+
const field = <T>(decl: DeclarationJsonInput, key: string): T | undefined =>
|
|
22
|
+
(decl as Record<string, unknown>)[key] as T | undefined;
|
|
11
23
|
|
|
12
24
|
/**
|
|
13
25
|
* Rich runtime representation of an exported declaration.
|
|
26
|
+
*
|
|
27
|
+
* Wraps svelte-docinfo's `DeclarationJson` discriminated union (on `kind`)
|
|
28
|
+
* with Svelte 5 reactive derivations and computed URLs.
|
|
29
|
+
* Kind-specific fields are accessed via the `field()` helper since
|
|
30
|
+
* not all fields exist on all variants.
|
|
31
|
+
*
|
|
32
|
+
* @see {@link https://github.com/ryanatkn/svelte-docinfo svelte-docinfo} for the analysis library
|
|
33
|
+
* @see `DeclarationDetail.svelte` for the rendering component
|
|
14
34
|
*/
|
|
15
35
|
export class Declaration {
|
|
16
36
|
readonly module: Module = $state.raw()!;
|
|
17
|
-
readonly declaration_json:
|
|
37
|
+
readonly declaration_json: DeclarationJsonInput = $state.raw()!;
|
|
18
38
|
|
|
19
39
|
library = $derived(this.module.library);
|
|
20
40
|
|
|
@@ -30,11 +50,11 @@ export class Declaration {
|
|
|
30
50
|
* GitHub source URL with line number.
|
|
31
51
|
*/
|
|
32
52
|
url_github = $derived(
|
|
33
|
-
this.library.repo_url && this.declaration_json.
|
|
53
|
+
this.library.repo_url && this.declaration_json.sourceLine
|
|
34
54
|
? url_github_file(
|
|
35
55
|
this.library.repo_url,
|
|
36
56
|
`src/lib/${this.module_path}`,
|
|
37
|
-
this.declaration_json.
|
|
57
|
+
this.declaration_json.sourceLine,
|
|
38
58
|
)
|
|
39
59
|
: undefined,
|
|
40
60
|
);
|
|
@@ -48,8 +68,10 @@ export class Declaration {
|
|
|
48
68
|
* Generated TypeScript import statement.
|
|
49
69
|
*/
|
|
50
70
|
import_statement = $derived(
|
|
51
|
-
|
|
52
|
-
|
|
71
|
+
// `generateImport` reads only `name`/`kind`/path, none of the defaulted
|
|
72
|
+
// arrays, so asserting the parsed shape here is sound.
|
|
73
|
+
generateImport(
|
|
74
|
+
this.declaration_json as DeclarationJson,
|
|
53
75
|
this.module_path,
|
|
54
76
|
this.library.package_json.name,
|
|
55
77
|
),
|
|
@@ -67,37 +89,70 @@ export class Declaration {
|
|
|
67
89
|
/**
|
|
68
90
|
* Display name with generic parameters.
|
|
69
91
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return_type = $derived(this.declaration_json.return_type);
|
|
78
|
-
return_description = $derived(this.declaration_json.return_description);
|
|
79
|
-
generic_params = $derived(this.declaration_json.generic_params);
|
|
80
|
-
extends = $derived(this.declaration_json.extends);
|
|
81
|
-
implements = $derived(this.declaration_json.implements);
|
|
82
|
-
throws = $derived(this.declaration_json.throws);
|
|
83
|
-
since = $derived(this.declaration_json.since);
|
|
84
|
-
examples = $derived(this.declaration_json.examples);
|
|
85
|
-
see_also = $derived(this.declaration_json.see_also);
|
|
86
|
-
members: Array<DeclarationJson> | undefined = $derived(
|
|
87
|
-
this.declaration_json.members as Array<DeclarationJson> | undefined,
|
|
88
|
-
);
|
|
89
|
-
properties: Array<DeclarationJson> | undefined = $derived(
|
|
90
|
-
this.declaration_json.properties as Array<DeclarationJson> | undefined,
|
|
92
|
+
// `getDisplayName` reads `genericParams` unguarded, so feed it the defaulted
|
|
93
|
+
// value rather than the raw (possibly-absent) input field.
|
|
94
|
+
display_name = $derived(
|
|
95
|
+
getDisplayName({
|
|
96
|
+
...this.declaration_json,
|
|
97
|
+
genericParams: this.declaration_json.genericParams ?? [],
|
|
98
|
+
} as DeclarationJson),
|
|
91
99
|
);
|
|
92
100
|
|
|
93
|
-
|
|
101
|
+
type_signature = $derived(this.declaration_json.typeSignature);
|
|
102
|
+
doc_comment = $derived(this.declaration_json.docComment);
|
|
103
|
+
deprecated_message = $derived(this.declaration_json.deprecatedMessage);
|
|
104
|
+
parameters = $derived(field<Array<ParameterJsonInput>>(this.declaration_json, 'parameters'));
|
|
105
|
+
props = $derived(field<Array<ComponentPropJsonInput>>(this.declaration_json, 'props'));
|
|
106
|
+
return_type = $derived(field<string>(this.declaration_json, 'returnType'));
|
|
107
|
+
return_description = $derived(field<string>(this.declaration_json, 'returnDescription'));
|
|
108
|
+
generic_params = $derived(this.declaration_json.genericParams ?? []);
|
|
109
|
+
extends_type = $derived(field<string | Array<string>>(this.declaration_json, 'extends'));
|
|
110
|
+
implements_types = $derived(field<Array<string>>(this.declaration_json, 'implements'));
|
|
111
|
+
throws = $derived(this.declaration_json.throws ?? []);
|
|
112
|
+
since = $derived(this.declaration_json.since);
|
|
113
|
+
examples = $derived(this.declaration_json.examples ?? []);
|
|
114
|
+
see_also = $derived(this.declaration_json.seeAlso ?? []);
|
|
115
|
+
/**
|
|
116
|
+
* Nested members for classes, interfaces, types, and enums.
|
|
117
|
+
*/
|
|
118
|
+
members = $derived(field<Array<MemberJsonInput>>(this.declaration_json, 'members'));
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Intersection types whose properties are external (filtered out of props/members).
|
|
122
|
+
* Present on `component` and `type` kinds.
|
|
123
|
+
*/
|
|
124
|
+
intersects = $derived(field<Array<string>>(this.declaration_json, 'intersects'));
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Whether a component accepts children via props or template usage.
|
|
128
|
+
* Present on `component` kind only.
|
|
129
|
+
*/
|
|
130
|
+
accepts_children = $derived(field<boolean>(this.declaration_json, 'acceptsChildren'));
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Function overload signatures when multiple public overloads exist.
|
|
134
|
+
* Present on `function` and `snippet` kinds, and on function/constructor members.
|
|
135
|
+
*/
|
|
136
|
+
overloads = $derived(field<Array<OverloadJsonInput>>(this.declaration_json, 'overloads'));
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Re-export alias info when this declaration is a renamed re-export.
|
|
140
|
+
*/
|
|
141
|
+
alias_of = $derived(this.declaration_json.aliasOf);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Mutation documentation from `@mutates` tags, mapping parameter names to descriptions.
|
|
145
|
+
*/
|
|
146
|
+
mutates = $derived(this.declaration_json.mutates);
|
|
147
|
+
|
|
148
|
+
has_examples = $derived(this.examples.length > 0);
|
|
94
149
|
is_deprecated = $derived(!!this.deprecated_message);
|
|
95
150
|
has_documentation = $derived(!!this.doc_comment);
|
|
96
151
|
has_parameters = $derived(!!(this.parameters && this.parameters.length > 0));
|
|
97
152
|
has_props = $derived(!!(this.props && this.props.length > 0));
|
|
98
|
-
has_generics = $derived(
|
|
153
|
+
has_generics = $derived(this.generic_params.length > 0);
|
|
99
154
|
|
|
100
|
-
constructor(module: Module, declaration_json:
|
|
155
|
+
constructor(module: Module, declaration_json: DeclarationJsonInput) {
|
|
101
156
|
this.module = module;
|
|
102
157
|
this.declaration_json = declaration_json;
|
|
103
158
|
}
|
|
@@ -64,7 +64,7 @@ export class Library {
|
|
|
64
64
|
*/
|
|
65
65
|
readonly modules = $derived(
|
|
66
66
|
this.source_json.modules
|
|
67
|
-
? this.source_json.modules.map((module_json) => new Module(this, module_json))
|
|
67
|
+
? this.source_json.modules.map((module_json) => new Module(this, module_json as any)) // TODO: remove cast when fuz_util SourceJson uses svelte-docinfo types
|
|
68
68
|
: [],
|
|
69
69
|
);
|
|
70
70
|
|
package/src/lib/library_gen.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gro-specific library metadata generation.
|
|
3
3
|
*
|
|
4
|
-
* This module provides Gro integration for library generation. It
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
4
|
+
* This module provides Gro integration for library generation. It uses svelte-docinfo's
|
|
5
|
+
* pure analysis (`analyze`) and wraps the results with fuz_ui's opinionated
|
|
6
|
+
* LibraryJson format (GitHub/npm metadata).
|
|
7
7
|
*
|
|
8
|
-
* For build-tool agnostic usage, see `
|
|
8
|
+
* For build-tool agnostic usage, see `svelte-docinfo`.
|
|
9
9
|
*
|
|
10
|
-
* @see
|
|
11
|
-
* @see
|
|
12
|
-
* @see
|
|
10
|
+
* @see svelte-docinfo/analyze.js for the generic analysis entry point
|
|
11
|
+
* @see svelte-docinfo/postprocess.js for post-processing helpers
|
|
12
|
+
* @see library_output.js for output file generation
|
|
13
13
|
*
|
|
14
14
|
* @module
|
|
15
15
|
*/
|
|
@@ -17,17 +17,18 @@
|
|
|
17
17
|
import type {Gen} from '@fuzdev/gro';
|
|
18
18
|
import {package_json_load} from '@fuzdev/gro/package_json.js';
|
|
19
19
|
import type {Disknode} from '@fuzdev/gro/disknode.js';
|
|
20
|
-
|
|
21
20
|
import {
|
|
22
|
-
|
|
21
|
+
analyze,
|
|
22
|
+
createSourceOptions,
|
|
23
23
|
type ModuleSourceOptions,
|
|
24
|
-
type
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from '
|
|
30
|
-
|
|
24
|
+
type OnDuplicatesCallback,
|
|
25
|
+
type SourceFileInfo,
|
|
26
|
+
type SourceOptionsDefaults,
|
|
27
|
+
} from 'svelte-docinfo';
|
|
28
|
+
import {normalizeSourceOptions, isSource, getSourceRoot} from 'svelte-docinfo/source-config.js';
|
|
29
|
+
import type {SourceJson} from '@fuzdev/fuz_util/source_json.js';
|
|
30
|
+
|
|
31
|
+
import {library_generate_output} from './library_output.js';
|
|
31
32
|
|
|
32
33
|
/** Options for Gro library generation. */
|
|
33
34
|
export interface LibraryGenOptions {
|
|
@@ -38,17 +39,17 @@ export interface LibraryGenOptions {
|
|
|
38
39
|
* merged with defaults. The `project_root` is automatically set to
|
|
39
40
|
* `process.cwd()` if not provided.
|
|
40
41
|
*/
|
|
41
|
-
source?: ModuleSourceOptions | Partial<
|
|
42
|
+
source?: ModuleSourceOptions | Partial<SourceOptionsDefaults>;
|
|
42
43
|
/**
|
|
43
44
|
* Callback invoked when duplicate declaration names are found.
|
|
44
45
|
*
|
|
45
46
|
* Consumers decide how to handle duplicates: throw, warn, or ignore.
|
|
46
|
-
* Use `
|
|
47
|
+
* Use `throwOnDuplicates` for strict flat namespace enforcement.
|
|
47
48
|
*
|
|
48
49
|
* @example
|
|
49
50
|
* ```ts
|
|
50
51
|
* // Throw on duplicates (strict flat namespace)
|
|
51
|
-
* library_gen({ on_duplicates:
|
|
52
|
+
* library_gen({ on_duplicates: throwOnDuplicates });
|
|
52
53
|
*
|
|
53
54
|
* // Warn but continue
|
|
54
55
|
* library_gen({
|
|
@@ -66,7 +67,13 @@ export interface LibraryGenOptions {
|
|
|
66
67
|
/**
|
|
67
68
|
* Convert Gro's `Disknode` to the build-tool agnostic `SourceFileInfo` interface.
|
|
68
69
|
*
|
|
69
|
-
* Use this when you want to analyze files using Gro's filer directly.
|
|
70
|
+
* Use this when you want to analyze files using Gro's filer directly. The
|
|
71
|
+
* `dependencies` field is populated from the filer's forward-edge graph — the
|
|
72
|
+
* svelte-docinfo session honors it as pre-resolved input and skips its own
|
|
73
|
+
* lex+resolve pass for these files, avoiding duplicate work the filer already did.
|
|
74
|
+
*
|
|
75
|
+
* Reverse edges (`dependents`) are not threaded through — svelte-docinfo
|
|
76
|
+
* computes them internally from the forward edges of the owned set.
|
|
70
77
|
*
|
|
71
78
|
* @throws Error if disknode has no content (should be loaded by Gro filer)
|
|
72
79
|
*/
|
|
@@ -80,7 +87,6 @@ export const source_file_from_disknode = (disknode: Disknode): SourceFileInfo =>
|
|
|
80
87
|
id: disknode.id,
|
|
81
88
|
content: disknode.contents,
|
|
82
89
|
dependencies: [...disknode.dependencies.keys()],
|
|
83
|
-
dependents: [...disknode.dependents.keys()],
|
|
84
90
|
};
|
|
85
91
|
};
|
|
86
92
|
|
|
@@ -88,7 +94,7 @@ export const source_file_from_disknode = (disknode: Disknode): SourceFileInfo =>
|
|
|
88
94
|
* Collect source files from Gro disknodes, filtering BEFORE conversion to `SourceFileInfo`.
|
|
89
95
|
*
|
|
90
96
|
* This avoids errors from files outside source directories (like test fixtures that may
|
|
91
|
-
* have malformed paths or missing content). The filtering uses `
|
|
97
|
+
* have malformed paths or missing content). The filtering uses `isSource` which
|
|
92
98
|
* checks `source_paths` to only include files in configured source directories.
|
|
93
99
|
*
|
|
94
100
|
* @param disknodes - iterator of Gro disknodes from filer
|
|
@@ -100,8 +106,10 @@ export const library_collect_source_files_from_disknodes = (
|
|
|
100
106
|
options: ModuleSourceOptions,
|
|
101
107
|
log?: {info: (...args: Array<unknown>) => void; warn: (...args: Array<unknown>) => void},
|
|
102
108
|
): Array<SourceFileInfo> => {
|
|
103
|
-
//
|
|
104
|
-
|
|
109
|
+
// Normalize options (throws on invalid config) and use the normalized form
|
|
110
|
+
// for downstream `isSource` / `getSourceRoot` calls, so callers that pass
|
|
111
|
+
// raw options (not via `createSourceOptions`) get consistent path handling.
|
|
112
|
+
const normalized_options = normalizeSourceOptions(options);
|
|
105
113
|
|
|
106
114
|
const all_disknodes = Array.from(disknodes);
|
|
107
115
|
log?.info(`received ${all_disknodes.length} files total from filer`);
|
|
@@ -110,7 +118,7 @@ export const library_collect_source_files_from_disknodes = (
|
|
|
110
118
|
for (const disknode of all_disknodes) {
|
|
111
119
|
// Filter by source_paths BEFORE trying to convert
|
|
112
120
|
// This avoids errors from test fixtures or other non-source files
|
|
113
|
-
if (!
|
|
121
|
+
if (!isSource(disknode.id, normalized_options)) {
|
|
114
122
|
continue;
|
|
115
123
|
}
|
|
116
124
|
source_files.push(source_file_from_disknode(disknode));
|
|
@@ -119,7 +127,7 @@ export const library_collect_source_files_from_disknodes = (
|
|
|
119
127
|
log?.info(`found ${source_files.length} source files to analyze`);
|
|
120
128
|
|
|
121
129
|
if (source_files.length === 0) {
|
|
122
|
-
const effective_root =
|
|
130
|
+
const effective_root = getSourceRoot(normalized_options);
|
|
123
131
|
log?.warn(`No source files found in ${effective_root} - generating empty library metadata`);
|
|
124
132
|
return [];
|
|
125
133
|
}
|
|
@@ -135,10 +143,12 @@ export const library_collect_source_files_from_disknodes = (
|
|
|
135
143
|
*
|
|
136
144
|
* This is the Gro-specific entry point. It handles:
|
|
137
145
|
* - Reading files from Gro's filer
|
|
138
|
-
* - Loading
|
|
139
|
-
* -
|
|
146
|
+
* - Loading package.json via Gro utilities
|
|
147
|
+
* - Analyzing source with svelte-docinfo (pure analysis)
|
|
148
|
+
* - Wrapping with LibraryJson (GitHub/npm metadata)
|
|
149
|
+
* - Returning output in Gro's Gen format
|
|
140
150
|
*
|
|
141
|
-
* For build-tool agnostic usage, use `
|
|
151
|
+
* For build-tool agnostic usage, use `analyze` directly.
|
|
142
152
|
*
|
|
143
153
|
* Usage in a `.gen.ts` file:
|
|
144
154
|
*
|
|
@@ -158,9 +168,9 @@ export const library_gen = (options?: LibraryGenOptions): Gen => {
|
|
|
158
168
|
|
|
159
169
|
// Build source options with project_root from cwd
|
|
160
170
|
const source_options: ModuleSourceOptions =
|
|
161
|
-
options?.source && '
|
|
171
|
+
options?.source && 'projectRoot' in options.source
|
|
162
172
|
? options.source
|
|
163
|
-
:
|
|
173
|
+
: createSourceOptions(process.cwd(), options?.source);
|
|
164
174
|
|
|
165
175
|
// Ensure filer is initialized
|
|
166
176
|
await filer.init();
|
|
@@ -175,22 +185,35 @@ export const library_gen = (options?: LibraryGenOptions): Gen => {
|
|
|
175
185
|
log,
|
|
176
186
|
);
|
|
177
187
|
|
|
178
|
-
//
|
|
179
|
-
const
|
|
180
|
-
source_files,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
log,
|
|
188
|
+
// Get pure analysis from svelte-docinfo (no package metadata).
|
|
189
|
+
const {modules} = await analyze({
|
|
190
|
+
sourceFiles: source_files,
|
|
191
|
+
sourceOptions: source_options,
|
|
192
|
+
onDuplicates: options?.on_duplicates,
|
|
193
|
+
log: log as any, // Type cast needed due to workspace dependency duplication
|
|
185
194
|
});
|
|
186
195
|
|
|
196
|
+
if (!package_json.version) {
|
|
197
|
+
throw new Error('package.json is missing required "version" field');
|
|
198
|
+
}
|
|
199
|
+
// Wrap modules with package metadata (fuz_ui's own SourceJson type)
|
|
200
|
+
const source_json: SourceJson = {
|
|
201
|
+
name: package_json.name,
|
|
202
|
+
version: package_json.version,
|
|
203
|
+
repository:
|
|
204
|
+
typeof package_json.repository === 'string'
|
|
205
|
+
? package_json.repository
|
|
206
|
+
: package_json.repository?.url,
|
|
207
|
+
modules: modules as any, // TODO: remove cast when fuz_util SourceJson uses svelte-docinfo types
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// Generate output files with fuz_ui's LibraryJson wrapper
|
|
211
|
+
const {json_content, ts_content} = library_generate_output(package_json, source_json);
|
|
212
|
+
|
|
187
213
|
log.info('library metadata generation complete');
|
|
188
214
|
|
|
189
215
|
// Return array of files in Gro's expected format
|
|
190
|
-
return [
|
|
191
|
-
{content: result.ts_content},
|
|
192
|
-
{content: result.json_content, filename: 'library.json'},
|
|
193
|
-
];
|
|
216
|
+
return [{content: ts_content}, {content: json_content, filename: 'library.json'}];
|
|
194
217
|
},
|
|
195
218
|
};
|
|
196
219
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Library output generation.
|
|
3
3
|
*
|
|
4
|
-
* Generates the
|
|
4
|
+
* Generates the library.json and library.ts files from analyzed metadata.
|
|
5
|
+
* Uses svelte-docinfo's `compactReplacer` to strip Zod default values
|
|
6
|
+
* (empty arrays, false booleans) for compact JSON output.
|
|
5
7
|
*
|
|
6
|
-
* @see `
|
|
7
|
-
* @see
|
|
8
|
-
* @see `library_gen.ts` for Gro-specific integration
|
|
8
|
+
* @see `library_gen.ts` for the main generation entry point
|
|
9
|
+
* @see {@link https://github.com/ryanatkn/svelte-docinfo svelte-docinfo} for the analysis library
|
|
9
10
|
*
|
|
10
11
|
* @module
|
|
11
12
|
*/
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
import type {PackageJson} from '@fuzdev/fuz_util/package_json.js';
|
|
14
15
|
import type {SourceJson} from '@fuzdev/fuz_util/source_json.js';
|
|
15
16
|
import {library_json_parse, type LibraryJson} from '@fuzdev/fuz_util/library_json.js';
|
|
17
|
+
import {compactReplacer} from 'svelte-docinfo';
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Result of generating library output files.
|
|
@@ -39,11 +41,12 @@ export const library_generate_output = (
|
|
|
39
41
|
package_json: PackageJson,
|
|
40
42
|
source_json: SourceJson,
|
|
41
43
|
): LibraryOutputResult => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
// Compact source_json (strips Zod default values like empty arrays and false booleans)
|
|
45
|
+
// Only applied to source_json, not the outer library_json package metadata
|
|
46
|
+
const compacted_source_json = JSON.parse(JSON.stringify(source_json, compactReplacer));
|
|
44
47
|
|
|
45
48
|
// Parse at generation time, not runtime
|
|
46
|
-
const library_json: LibraryJson = library_json_parse(package_json,
|
|
49
|
+
const library_json: LibraryJson = library_json_parse(package_json, compacted_source_json);
|
|
47
50
|
|
|
48
51
|
const json_content = JSON.stringify(library_json, null, '\t') + '\n';
|
|
49
52
|
|
|
@@ -51,7 +54,7 @@ export const library_generate_output = (
|
|
|
51
54
|
|
|
52
55
|
const ts_content = `${banner}
|
|
53
56
|
|
|
54
|
-
import type {LibraryJson} from '
|
|
57
|
+
import type {LibraryJson} from '@fuzdev/fuz_util/library_json.js';
|
|
55
58
|
|
|
56
59
|
import json from './library.json' with {type: 'json'};
|
|
57
60
|
|
package/src/lib/module.svelte.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {ModuleJsonInput} from 'svelte-docinfo/types.js';
|
|
2
2
|
|
|
3
3
|
import {Declaration} from './declaration.svelte.js';
|
|
4
4
|
import type {Library} from './library.svelte.js';
|
|
@@ -6,13 +6,30 @@ import {url_github_file} from './package_helpers.js';
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Rich runtime representation of a module with computed properties.
|
|
9
|
+
*
|
|
10
|
+
* Wraps svelte-docinfo's `ModuleJson` with reactive derivations,
|
|
11
|
+
* URL generation, and `Declaration` instances.
|
|
12
|
+
*
|
|
13
|
+
* @see {@link https://github.com/ryanatkn/svelte-docinfo svelte-docinfo} for the analysis library
|
|
14
|
+
* @see `declaration.svelte.ts` for the `Declaration` wrapper class
|
|
9
15
|
*/
|
|
10
16
|
export class Module {
|
|
11
17
|
readonly library: Library = $state.raw()!;
|
|
12
|
-
|
|
18
|
+
// `library.json` is compacted (svelte-docinfo's `compactReplacer` strips empty
|
|
19
|
+
// default arrays), so the on-disk data is the `*Input` shape. Typing it as
|
|
20
|
+
// input makes TypeScript force guards on defaulted-array reads.
|
|
21
|
+
readonly module_json: ModuleJsonInput = $state.raw()!;
|
|
13
22
|
|
|
14
23
|
/**
|
|
15
|
-
* Canonical module path
|
|
24
|
+
* Canonical module path — `src/lib/`-relative, with source extension
|
|
25
|
+
* (`.ts`, `.svelte`, etc.). Examples: `'Alert.ts'`, `'helpers/foo.ts'`,
|
|
26
|
+
* `'actions/composables.ts'`.
|
|
27
|
+
*
|
|
28
|
+
* This is the key `Library.module_by_path` indexes, so it's also the
|
|
29
|
+
* exact string TSDoc backtick references must use to auto-link to a
|
|
30
|
+
* module via `DocsLink.svelte` (e.g., `` `actions/composables.ts` ``).
|
|
31
|
+
* A leading `./` or a `.js` runtime extension will not match. Top-level
|
|
32
|
+
* files match by bare filename; nested files require the full sub-path.
|
|
16
33
|
*/
|
|
17
34
|
path = $derived(this.module_json.path);
|
|
18
35
|
|
|
@@ -21,17 +38,15 @@ export class Module {
|
|
|
21
38
|
*/
|
|
22
39
|
path_import = $derived('./' + this.path);
|
|
23
40
|
|
|
24
|
-
module_comment = $derived(this.module_json.
|
|
41
|
+
module_comment = $derived(this.module_json.moduleComment);
|
|
25
42
|
|
|
26
43
|
/**
|
|
27
44
|
* Array of `Declaration` instances. Filters out default exports.
|
|
28
45
|
*/
|
|
29
46
|
declarations = $derived(
|
|
30
|
-
this.module_json.declarations
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.map((declaration_json) => new Declaration(this, declaration_json))
|
|
34
|
-
: [],
|
|
47
|
+
(this.module_json.declarations ?? [])
|
|
48
|
+
.filter((declaration_json) => declaration_json.name !== 'default')
|
|
49
|
+
.map((declaration_json) => new Declaration(this, declaration_json)),
|
|
35
50
|
);
|
|
36
51
|
|
|
37
52
|
/**
|
|
@@ -48,23 +63,21 @@ export class Module {
|
|
|
48
63
|
: undefined,
|
|
49
64
|
);
|
|
50
65
|
|
|
51
|
-
has_declarations: boolean = $derived(
|
|
52
|
-
!!(this.module_json.declarations && this.module_json.declarations.length > 0),
|
|
53
|
-
);
|
|
66
|
+
has_declarations: boolean = $derived((this.module_json.declarations?.length ?? 0) > 0);
|
|
54
67
|
|
|
55
|
-
has_module_comment: boolean = $derived(!!this.
|
|
68
|
+
has_module_comment: boolean = $derived(!!this.module_comment);
|
|
56
69
|
|
|
57
70
|
/**
|
|
58
71
|
* Modules this imports (paths relative to src/lib).
|
|
59
72
|
*/
|
|
60
|
-
dependencies = $derived(this.module_json.dependencies);
|
|
73
|
+
dependencies = $derived(this.module_json.dependencies ?? []);
|
|
61
74
|
|
|
62
75
|
/**
|
|
63
76
|
* Modules that import this (paths relative to src/lib).
|
|
64
77
|
*/
|
|
65
|
-
dependents = $derived(this.module_json.dependents);
|
|
78
|
+
dependents = $derived(this.module_json.dependents ?? []);
|
|
66
79
|
|
|
67
|
-
constructor(library: Library, module_json:
|
|
80
|
+
constructor(library: Library, module_json: ModuleJsonInput) {
|
|
68
81
|
this.library = library;
|
|
69
82
|
this.module_json = module_json;
|
|
70
83
|
}
|
package/src/lib/tsdoc_mdz.ts
CHANGED
|
@@ -17,10 +17,12 @@ const format_reference = (ref: string): string => (mdz_is_url(ref) ? ref : `\`${
|
|
|
17
17
|
* Convert raw TSDoc `@see` content to mdz format for rendering.
|
|
18
18
|
*
|
|
19
19
|
* Handles TSDoc link syntax:
|
|
20
|
-
* - `{@link url|text}` → `[text](url)` (markdown link)
|
|
20
|
+
* - `{@link url|text}` → `[text](url)` (markdown link, TSDoc canonical form)
|
|
21
|
+
* - `{@link url text}` → `[text](url)` (TS-lenient space-separated form)
|
|
21
22
|
* - `{@link https://...}` → `https://...` (bare URL, auto-linked by mdz)
|
|
22
23
|
* - `{@link identifier}` → `` `identifier` `` (code formatting)
|
|
23
24
|
* - Bare URLs → returned as-is
|
|
25
|
+
* - Bare markdown links (`[text](url)` ...) → returned as-is
|
|
24
26
|
* - Bare identifiers → wrapped in backticks
|
|
25
27
|
* - `identifier description text` → `` `identifier` description text `` (first token is the reference)
|
|
26
28
|
*
|
|
@@ -38,6 +40,9 @@ const format_reference = (ref: string): string => (mdz_is_url(ref) ? ref : `\`${
|
|
|
38
40
|
* tsdoc_see_to_mdz('https://example.com')
|
|
39
41
|
* // → 'https://example.com'
|
|
40
42
|
*
|
|
43
|
+
* tsdoc_see_to_mdz('[svelte-docinfo](https://github.com/ryanatkn/svelte-docinfo) for the analysis library')
|
|
44
|
+
* // → '[svelte-docinfo](https://github.com/ryanatkn/svelte-docinfo) for the analysis library'
|
|
45
|
+
*
|
|
41
46
|
* tsdoc_see_to_mdz('library_gen.ts for Gro-specific integration')
|
|
42
47
|
* // → '`library_gen.ts` for Gro-specific integration'
|
|
43
48
|
* ```
|
|
@@ -51,7 +56,7 @@ export const tsdoc_see_to_mdz = (content: string): string => {
|
|
|
51
56
|
if (link_match) {
|
|
52
57
|
const inner = link_match[1]!.trim();
|
|
53
58
|
|
|
54
|
-
//
|
|
59
|
+
// Pipe separator takes precedence (TSDoc canonical form)
|
|
55
60
|
const pipe_index = inner.indexOf('|');
|
|
56
61
|
if (pipe_index !== -1) {
|
|
57
62
|
const reference = inner.slice(0, pipe_index).trim();
|
|
@@ -59,9 +64,27 @@ export const tsdoc_see_to_mdz = (content: string): string => {
|
|
|
59
64
|
return `[${display_text}](${reference})`;
|
|
60
65
|
}
|
|
61
66
|
|
|
67
|
+
// Space-separated form: TS accepts `{@link url text}` as equivalent to `{@link url|text}`.
|
|
68
|
+
// Only treat space as a separator when the first token looks like a link target (URL),
|
|
69
|
+
// so identifier-style references like `module.function` aren't split.
|
|
70
|
+
const space_index = inner.indexOf(' ');
|
|
71
|
+
if (space_index !== -1) {
|
|
72
|
+
const reference = inner.slice(0, space_index);
|
|
73
|
+
if (mdz_is_url(reference)) {
|
|
74
|
+
const display_text = inner.slice(space_index + 1).trim();
|
|
75
|
+
return `[${display_text}](${reference})`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
62
79
|
return format_reference(inner);
|
|
63
80
|
}
|
|
64
81
|
|
|
82
|
+
// Pass through bare markdown links (`[text](url)` optionally followed by description)
|
|
83
|
+
// so authors can write `@see [text](url) for context` directly.
|
|
84
|
+
if (trimmed.charCodeAt(0) === 91 /* [ */ && /^\[[^\]]+\]\([^)\s]+\)/.test(trimmed)) {
|
|
85
|
+
return trimmed;
|
|
86
|
+
}
|
|
87
|
+
|
|
65
88
|
// Split at first whitespace: first token is the reference, rest is description
|
|
66
89
|
const space_index = trimmed.indexOf(' ');
|
|
67
90
|
if (space_index === -1) {
|