@fuzdev/fuz_ui 0.195.0 → 0.196.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/LibraryDetail.svelte +1 -16
- package/dist/LibraryDetail.svelte.d.ts.map +1 -1
- package/dist/declaration.svelte.d.ts +8 -1
- package/dist/declaration.svelte.d.ts.map +1 -1
- package/dist/declaration.svelte.js +5 -4
- package/dist/library.svelte.d.ts +1 -76
- package/dist/library.svelte.d.ts.map +1 -1
- package/dist/module.svelte.d.ts.map +1 -1
- package/dist/module.svelte.js +4 -3
- package/dist/package_helpers.d.ts +0 -15
- package/dist/package_helpers.d.ts.map +1 -1
- package/dist/package_helpers.js +1 -18
- package/dist/tsdoc_mdz.d.ts +2 -2
- package/dist/tsdoc_mdz.js +2 -2
- package/package.json +6 -6
- package/src/lib/declaration.svelte.ts +5 -4
- package/src/lib/module.svelte.ts +4 -3
- package/src/lib/package_helpers.ts +1 -19
- package/src/lib/tsdoc_mdz.ts +2 -2
- package/dist/library_gen.d.ts +0 -104
- package/dist/library_gen.d.ts.map +0 -1
- package/dist/library_gen.js +0 -143
- package/dist/library_output.d.ts +0 -36
- package/dist/library_output.d.ts.map +0 -1
- package/dist/library_output.js +0 -44
- package/dist/vite_plugin_library_well_known.d.ts +0 -37
- package/dist/vite_plugin_library_well_known.d.ts.map +0 -1
- package/dist/vite_plugin_library_well_known.js +0 -144
- package/src/lib/library_gen.ts +0 -219
- package/src/lib/library_output.ts +0 -67
- package/src/lib/vite_plugin_library_well_known.ts +0 -189
package/dist/library_gen.js
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gro-specific library metadata generation.
|
|
3
|
-
*
|
|
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
|
-
*
|
|
8
|
-
* For build-tool agnostic usage, see `svelte-docinfo`.
|
|
9
|
-
*
|
|
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
|
-
*
|
|
14
|
-
* @module
|
|
15
|
-
*/
|
|
16
|
-
import { package_json_load } from '@fuzdev/gro/package_json.js';
|
|
17
|
-
import { analyze, createSourceOptions, } from 'svelte-docinfo';
|
|
18
|
-
import { normalizeSourceOptions, isSource, getSourceRoot } from 'svelte-docinfo/source-config.js';
|
|
19
|
-
import { library_generate_output } from './library_output.js';
|
|
20
|
-
/**
|
|
21
|
-
* Convert Gro's `Disknode` to the build-tool agnostic `SourceFileInfo` interface.
|
|
22
|
-
*
|
|
23
|
-
* Use this when you want to analyze files using Gro's filer directly. The
|
|
24
|
-
* `dependencies` field is populated from the filer's forward-edge graph — the
|
|
25
|
-
* svelte-docinfo session honors it as pre-resolved input and skips its own
|
|
26
|
-
* lex+resolve pass for these files, avoiding duplicate work the filer already did.
|
|
27
|
-
*
|
|
28
|
-
* Reverse edges (`dependents`) are not threaded through — svelte-docinfo
|
|
29
|
-
* computes them internally from the forward edges of the owned set.
|
|
30
|
-
*
|
|
31
|
-
* @throws Error if disknode has no content (should be loaded by Gro filer)
|
|
32
|
-
*/
|
|
33
|
-
export const source_file_from_disknode = (disknode) => {
|
|
34
|
-
if (disknode.contents == null) {
|
|
35
|
-
throw new Error(`Source file has no content: ${disknode.id} (ensure Gro filer loads file contents)`);
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
id: disknode.id,
|
|
39
|
-
content: disknode.contents,
|
|
40
|
-
dependencies: [...disknode.dependencies.keys()],
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* Collect source files from Gro disknodes, filtering BEFORE conversion to `SourceFileInfo`.
|
|
45
|
-
*
|
|
46
|
-
* This avoids errors from files outside source directories (like test fixtures that may
|
|
47
|
-
* have malformed paths or missing content). The filtering uses `isSource` which
|
|
48
|
-
* checks `source_paths` to only include files in configured source directories.
|
|
49
|
-
*
|
|
50
|
-
* @param disknodes - iterator of Gro disknodes from filer
|
|
51
|
-
* @param options - module source options for filtering
|
|
52
|
-
* @param log - optional logger for status messages
|
|
53
|
-
*/
|
|
54
|
-
export const library_collect_source_files_from_disknodes = (disknodes, options, log) => {
|
|
55
|
-
// Normalize options (throws on invalid config) and use the normalized form
|
|
56
|
-
// for downstream `isSource` / `getSourceRoot` calls, so callers that pass
|
|
57
|
-
// raw options (not via `createSourceOptions`) get consistent path handling.
|
|
58
|
-
const normalized_options = normalizeSourceOptions(options);
|
|
59
|
-
const all_disknodes = Array.from(disknodes);
|
|
60
|
-
log?.info(`received ${all_disknodes.length} files total from filer`);
|
|
61
|
-
const source_files = [];
|
|
62
|
-
for (const disknode of all_disknodes) {
|
|
63
|
-
// Filter by source_paths BEFORE trying to convert
|
|
64
|
-
// This avoids errors from test fixtures or other non-source files
|
|
65
|
-
if (!isSource(disknode.id, normalized_options)) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
source_files.push(source_file_from_disknode(disknode));
|
|
69
|
-
}
|
|
70
|
-
log?.info(`found ${source_files.length} source files to analyze`);
|
|
71
|
-
if (source_files.length === 0) {
|
|
72
|
-
const effective_root = getSourceRoot(normalized_options);
|
|
73
|
-
log?.warn(`No source files found in ${effective_root} - generating empty library metadata`);
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
// Sort for deterministic output (stable alphabetical module ordering)
|
|
77
|
-
source_files.sort((a, b) => a.id.localeCompare(b.id));
|
|
78
|
-
return source_files;
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* Creates a `Gen` object for generating library metadata with full TypeScript analysis.
|
|
82
|
-
*
|
|
83
|
-
* This is the Gro-specific entry point. It handles:
|
|
84
|
-
* - Reading files from Gro's filer
|
|
85
|
-
* - Loading package.json via Gro utilities
|
|
86
|
-
* - Analyzing source with svelte-docinfo (pure analysis)
|
|
87
|
-
* - Wrapping with LibraryJson (GitHub/npm metadata)
|
|
88
|
-
* - Returning output in Gro's Gen format
|
|
89
|
-
*
|
|
90
|
-
* For build-tool agnostic usage, use `analyze` directly.
|
|
91
|
-
*
|
|
92
|
-
* Usage in a `.gen.ts` file:
|
|
93
|
-
*
|
|
94
|
-
* ```ts
|
|
95
|
-
* import {library_gen} from './library_gen.js';
|
|
96
|
-
*
|
|
97
|
-
* export const gen = library_gen();
|
|
98
|
-
* ```
|
|
99
|
-
*
|
|
100
|
-
* @param options - optional generation options
|
|
101
|
-
*/
|
|
102
|
-
export const library_gen = (options) => {
|
|
103
|
-
return {
|
|
104
|
-
dependencies: 'all',
|
|
105
|
-
generate: async ({ log, filer }) => {
|
|
106
|
-
log.info('generating library metadata with full TypeScript analysis...');
|
|
107
|
-
// Build source options with project_root from cwd
|
|
108
|
-
const source_options = options?.source && 'projectRoot' in options.source
|
|
109
|
-
? options.source
|
|
110
|
-
: createSourceOptions(process.cwd(), options?.source);
|
|
111
|
-
// Ensure filer is initialized
|
|
112
|
-
await filer.init();
|
|
113
|
-
// Read package.json
|
|
114
|
-
const package_json = await package_json_load();
|
|
115
|
-
// Collect source files from Gro filer
|
|
116
|
-
const source_files = library_collect_source_files_from_disknodes(filer.files.values(), source_options, log);
|
|
117
|
-
// Get pure analysis from svelte-docinfo (no package metadata).
|
|
118
|
-
const { modules } = await analyze({
|
|
119
|
-
sourceFiles: source_files,
|
|
120
|
-
sourceOptions: source_options,
|
|
121
|
-
onDuplicates: options?.on_duplicates,
|
|
122
|
-
log: log, // Type cast needed due to workspace dependency duplication
|
|
123
|
-
});
|
|
124
|
-
if (!package_json.version) {
|
|
125
|
-
throw new Error('package.json is missing required "version" field');
|
|
126
|
-
}
|
|
127
|
-
// Wrap modules with package metadata (fuz_ui's own SourceJson type)
|
|
128
|
-
const source_json = {
|
|
129
|
-
name: package_json.name,
|
|
130
|
-
version: package_json.version,
|
|
131
|
-
repository: typeof package_json.repository === 'string'
|
|
132
|
-
? package_json.repository
|
|
133
|
-
: package_json.repository?.url,
|
|
134
|
-
modules: modules, // TODO: remove cast when fuz_util SourceJson uses svelte-docinfo types
|
|
135
|
-
};
|
|
136
|
-
// Generate output files with fuz_ui's LibraryJson wrapper
|
|
137
|
-
const { json_content, ts_content } = library_generate_output(package_json, source_json);
|
|
138
|
-
log.info('library metadata generation complete');
|
|
139
|
-
// Return array of files in Gro's expected format
|
|
140
|
-
return [{ content: ts_content }, { content: json_content, filename: 'library.json' }];
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
};
|
package/dist/library_output.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Library output generation.
|
|
3
|
-
*
|
|
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.
|
|
7
|
-
*
|
|
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
|
|
10
|
-
*
|
|
11
|
-
* @module
|
|
12
|
-
*/
|
|
13
|
-
import type { PackageJson } from '@fuzdev/fuz_util/package_json.js';
|
|
14
|
-
import type { SourceJson } from '@fuzdev/fuz_util/source_json.js';
|
|
15
|
-
/**
|
|
16
|
-
* Result of generating library output files.
|
|
17
|
-
* Contains both the JSON data and the TypeScript wrapper file.
|
|
18
|
-
*/
|
|
19
|
-
export interface LibraryOutputResult {
|
|
20
|
-
/** JSON content for `library.json`. */
|
|
21
|
-
json_content: string;
|
|
22
|
-
/** TypeScript wrapper content for `library.ts`. */
|
|
23
|
-
ts_content: string;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Generate the `library.json` and `library.ts` file contents.
|
|
27
|
-
* Parses at generation time so runtime only needs the pre-computed result.
|
|
28
|
-
*
|
|
29
|
-
* Returns JSON + .ts wrapper because:
|
|
30
|
-
* - JSON is natively importable by Node.js and Vite without TypeScript loaders
|
|
31
|
-
* - Works in CI environments that don't have TS compilation
|
|
32
|
-
* - The .ts wrapper validates with zod and exports with proper types
|
|
33
|
-
* (JSON imports get widened types like `string` instead of literal unions)
|
|
34
|
-
*/
|
|
35
|
-
export declare const library_generate_output: (package_json: PackageJson, source_json: SourceJson) => LibraryOutputResult;
|
|
36
|
-
//# sourceMappingURL=library_output.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"library_output.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/library_output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iCAAiC,CAAC;AAIhE;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,GACnC,cAAc,WAAW,EACzB,aAAa,UAAU,KACrB,mBAwBF,CAAC"}
|
package/dist/library_output.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Library output generation.
|
|
3
|
-
*
|
|
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.
|
|
7
|
-
*
|
|
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
|
|
10
|
-
*
|
|
11
|
-
* @module
|
|
12
|
-
*/
|
|
13
|
-
import { library_json_parse } from '@fuzdev/fuz_util/library_json.js';
|
|
14
|
-
import { compactReplacer } from 'svelte-docinfo';
|
|
15
|
-
/**
|
|
16
|
-
* Generate the `library.json` and `library.ts` file contents.
|
|
17
|
-
* Parses at generation time so runtime only needs the pre-computed result.
|
|
18
|
-
*
|
|
19
|
-
* Returns JSON + .ts wrapper because:
|
|
20
|
-
* - JSON is natively importable by Node.js and Vite without TypeScript loaders
|
|
21
|
-
* - Works in CI environments that don't have TS compilation
|
|
22
|
-
* - The .ts wrapper validates with zod and exports with proper types
|
|
23
|
-
* (JSON imports get widened types like `string` instead of literal unions)
|
|
24
|
-
*/
|
|
25
|
-
export const library_generate_output = (package_json, source_json) => {
|
|
26
|
-
// Compact source_json (strips Zod default values like empty arrays and false booleans)
|
|
27
|
-
// Only applied to source_json, not the outer library_json package metadata
|
|
28
|
-
const compacted_source_json = JSON.parse(JSON.stringify(source_json, compactReplacer));
|
|
29
|
-
// Parse at generation time, not runtime
|
|
30
|
-
const library_json = library_json_parse(package_json, compacted_source_json);
|
|
31
|
-
const json_content = JSON.stringify(library_json, null, '\t') + '\n';
|
|
32
|
-
const banner = '// generated by library.gen.ts - do not edit';
|
|
33
|
-
const ts_content = `${banner}
|
|
34
|
-
|
|
35
|
-
import type {LibraryJson} from '@fuzdev/fuz_util/library_json.js';
|
|
36
|
-
|
|
37
|
-
import json from './library.json' with {type: 'json'};
|
|
38
|
-
|
|
39
|
-
export const library_json: LibraryJson = json as LibraryJson;
|
|
40
|
-
|
|
41
|
-
${banner}
|
|
42
|
-
`;
|
|
43
|
-
return { json_content, ts_content };
|
|
44
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from 'vite';
|
|
2
|
-
export interface VitePluginLibraryWellKnownOptions {
|
|
3
|
-
/**
|
|
4
|
-
* Path to the `library.json` file (relative to `vite.config.ts`).
|
|
5
|
-
* @default './src/routes/library.json'
|
|
6
|
-
*/
|
|
7
|
-
library_path?: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Vite plugin that publishes `package.json` and `library.json` to `.well-known/`.
|
|
11
|
-
*
|
|
12
|
-
* Requires a generated `library.json` file (created by `library_gen` from `gro gen`).
|
|
13
|
-
* The plugin reads this JSON file and publishes its metadata to `.well-known/` for
|
|
14
|
-
* both dev and production builds.
|
|
15
|
-
*
|
|
16
|
-
* Note: This plugin respects SvelteKit's `base` path configuration, so `.well-known/`
|
|
17
|
-
* will be served at `{base}.well-known/` (e.g., `/my-app/.well-known/`). This deviates
|
|
18
|
-
* from RFC 8615 which specifies `.well-known` should be at the domain root. This tradeoff
|
|
19
|
-
* allows the plugin to work correctly when apps are deployed to non-root paths.
|
|
20
|
-
*
|
|
21
|
-
* Note: CORS headers are only set for the dev server. For production, configure
|
|
22
|
-
* CORS at the server level (nginx, Caddy, etc.) if cross-origin access is needed.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* // vite.config.ts
|
|
27
|
-
* import {defineConfig} from 'vite';
|
|
28
|
-
* import {sveltekit} from '@sveltejs/kit/vite';
|
|
29
|
-
* import {vite_plugin_library_well_known} from './vite_plugin_library_well_known.js';
|
|
30
|
-
*
|
|
31
|
-
* export default defineConfig({
|
|
32
|
-
* plugins: [sveltekit(), vite_plugin_library_well_known()],
|
|
33
|
-
* });
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export declare const vite_plugin_library_well_known: (options?: VitePluginLibraryWellKnownOptions) => Plugin;
|
|
37
|
-
//# sourceMappingURL=vite_plugin_library_well_known.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vite_plugin_library_well_known.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/vite_plugin_library_well_known.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,MAAM,CAAC;AAMjC,MAAM,WAAW,iCAAiC;IACjD;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,8BAA8B,GAC1C,UAAS,iCAAsC,KAC7C,MAqIF,CAAC"}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { isAbsolute, join } from 'node:path';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
const respond_json = (res, body) => {
|
|
4
|
-
res.setHeader('Content-Type', 'application/json');
|
|
5
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
6
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
7
|
-
res.end(body);
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Vite plugin that publishes `package.json` and `library.json` to `.well-known/`.
|
|
11
|
-
*
|
|
12
|
-
* Requires a generated `library.json` file (created by `library_gen` from `gro gen`).
|
|
13
|
-
* The plugin reads this JSON file and publishes its metadata to `.well-known/` for
|
|
14
|
-
* both dev and production builds.
|
|
15
|
-
*
|
|
16
|
-
* Note: This plugin respects SvelteKit's `base` path configuration, so `.well-known/`
|
|
17
|
-
* will be served at `{base}.well-known/` (e.g., `/my-app/.well-known/`). This deviates
|
|
18
|
-
* from RFC 8615 which specifies `.well-known` should be at the domain root. This tradeoff
|
|
19
|
-
* allows the plugin to work correctly when apps are deployed to non-root paths.
|
|
20
|
-
*
|
|
21
|
-
* Note: CORS headers are only set for the dev server. For production, configure
|
|
22
|
-
* CORS at the server level (nginx, Caddy, etc.) if cross-origin access is needed.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* // vite.config.ts
|
|
27
|
-
* import {defineConfig} from 'vite';
|
|
28
|
-
* import {sveltekit} from '@sveltejs/kit/vite';
|
|
29
|
-
* import {vite_plugin_library_well_known} from './vite_plugin_library_well_known.js';
|
|
30
|
-
*
|
|
31
|
-
* export default defineConfig({
|
|
32
|
-
* plugins: [sveltekit(), vite_plugin_library_well_known()],
|
|
33
|
-
* });
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export const vite_plugin_library_well_known = (options = {}) => {
|
|
37
|
-
const { library_path = './src/routes/library.json' } = options;
|
|
38
|
-
const content = {
|
|
39
|
-
package_json: null,
|
|
40
|
-
library_json: null,
|
|
41
|
-
};
|
|
42
|
-
// Set by configResolved
|
|
43
|
-
let root;
|
|
44
|
-
let base; // e.g., '/' or '/my-app/'
|
|
45
|
-
// Promise that resolves when library is loaded, used by middleware to avoid race condition
|
|
46
|
-
let ready_promise = null;
|
|
47
|
-
const load_library = async () => {
|
|
48
|
-
// Resolve path relative to project root
|
|
49
|
-
const resolved_path = isAbsolute(library_path) ? library_path : join(root, library_path);
|
|
50
|
-
let json_content;
|
|
51
|
-
try {
|
|
52
|
-
json_content = await readFile(resolved_path, 'utf-8');
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
throw new Error(`vite_plugin_library_well_known: failed to read library.json from "${library_path}"\n` +
|
|
56
|
-
`Resolved to: ${resolved_path}\n` +
|
|
57
|
-
`Make sure you've run \`gro gen\` to generate the library metadata.\n` +
|
|
58
|
-
`Error: ${error}`);
|
|
59
|
-
}
|
|
60
|
-
let raw;
|
|
61
|
-
try {
|
|
62
|
-
raw = JSON.parse(json_content);
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
throw new Error(`vite_plugin_library_well_known: failed to parse library.json from "${library_path}"\n` +
|
|
66
|
-
`Error: ${error}`);
|
|
67
|
-
}
|
|
68
|
-
// Basic structure validation (file is generated by library_gen)
|
|
69
|
-
if (raw == null || typeof raw !== 'object') {
|
|
70
|
-
throw new Error(`vite_plugin_library_well_known: invalid library.json at "${library_path}"\n` +
|
|
71
|
-
`Expected object, got ${typeof raw}`);
|
|
72
|
-
}
|
|
73
|
-
if (!('package_json' in raw) || !('source_json' in raw)) {
|
|
74
|
-
throw new Error(`vite_plugin_library_well_known: invalid library.json at "${library_path}"\n` +
|
|
75
|
-
`Expected object with package_json and source_json properties`);
|
|
76
|
-
}
|
|
77
|
-
const library_json = raw;
|
|
78
|
-
content.package_json = JSON.stringify(library_json.package_json, null, '\t') + '\n';
|
|
79
|
-
content.library_json = JSON.stringify(library_json, null, '\t') + '\n';
|
|
80
|
-
};
|
|
81
|
-
return {
|
|
82
|
-
name: 'vite_plugin_library_well_known',
|
|
83
|
-
configResolved(config) {
|
|
84
|
-
root = config.root;
|
|
85
|
-
base = config.base; // e.g., '/' or '/my-app/'
|
|
86
|
-
},
|
|
87
|
-
async buildStart() {
|
|
88
|
-
ready_promise = load_library();
|
|
89
|
-
await ready_promise;
|
|
90
|
-
},
|
|
91
|
-
configureServer(server) {
|
|
92
|
-
// TODO: add HMR support to reload library.json when it changes
|
|
93
|
-
const well_known_prefix = `${base}.well-known/`;
|
|
94
|
-
server.middlewares.use(async (req, res, next) => {
|
|
95
|
-
if (!req.url) {
|
|
96
|
-
next();
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const { pathname } = new URL(req.url, 'http://localhost');
|
|
100
|
-
if (!pathname.startsWith(well_known_prefix)) {
|
|
101
|
-
next();
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
// Wait for library to load before serving
|
|
105
|
-
try {
|
|
106
|
-
if (!ready_promise)
|
|
107
|
-
throw new Error('not initialized');
|
|
108
|
-
await ready_promise;
|
|
109
|
-
}
|
|
110
|
-
catch (_error) {
|
|
111
|
-
res.statusCode = 503;
|
|
112
|
-
respond_json(res, JSON.stringify({ error: 'Library not ready' }));
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const path = pathname.slice(well_known_prefix.length);
|
|
116
|
-
if (path === 'package.json' && content.package_json) {
|
|
117
|
-
respond_json(res, content.package_json);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (path === 'library.json' && content.library_json) {
|
|
121
|
-
respond_json(res, content.library_json);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
next();
|
|
125
|
-
});
|
|
126
|
-
},
|
|
127
|
-
generateBundle() {
|
|
128
|
-
if (content.package_json) {
|
|
129
|
-
this.emitFile({
|
|
130
|
-
type: 'asset',
|
|
131
|
-
fileName: '.well-known/package.json',
|
|
132
|
-
source: content.package_json,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
if (content.library_json) {
|
|
136
|
-
this.emitFile({
|
|
137
|
-
type: 'asset',
|
|
138
|
-
fileName: '.well-known/library.json',
|
|
139
|
-
source: content.library_json,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
};
|
package/src/lib/library_gen.ts
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gro-specific library metadata generation.
|
|
3
|
-
*
|
|
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
|
-
*
|
|
8
|
-
* For build-tool agnostic usage, see `svelte-docinfo`.
|
|
9
|
-
*
|
|
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
|
-
*
|
|
14
|
-
* @module
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import type {Gen} from '@fuzdev/gro';
|
|
18
|
-
import {package_json_load} from '@fuzdev/gro/package_json.js';
|
|
19
|
-
import type {Disknode} from '@fuzdev/gro/disknode.js';
|
|
20
|
-
import {
|
|
21
|
-
analyze,
|
|
22
|
-
createSourceOptions,
|
|
23
|
-
type ModuleSourceOptions,
|
|
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';
|
|
32
|
-
|
|
33
|
-
/** Options for Gro library generation. */
|
|
34
|
-
export interface LibraryGenOptions {
|
|
35
|
-
/**
|
|
36
|
-
* Module source options for filtering and path extraction.
|
|
37
|
-
*
|
|
38
|
-
* Can provide full `ModuleSourceOptions` or partial options that will be
|
|
39
|
-
* merged with defaults. The `project_root` is automatically set to
|
|
40
|
-
* `process.cwd()` if not provided.
|
|
41
|
-
*/
|
|
42
|
-
source?: ModuleSourceOptions | Partial<SourceOptionsDefaults>;
|
|
43
|
-
/**
|
|
44
|
-
* Callback invoked when duplicate declaration names are found.
|
|
45
|
-
*
|
|
46
|
-
* Consumers decide how to handle duplicates: throw, warn, or ignore.
|
|
47
|
-
* Use `throwOnDuplicates` for strict flat namespace enforcement.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```ts
|
|
51
|
-
* // Throw on duplicates (strict flat namespace)
|
|
52
|
-
* library_gen({ on_duplicates: throwOnDuplicates });
|
|
53
|
-
*
|
|
54
|
-
* // Warn but continue
|
|
55
|
-
* library_gen({
|
|
56
|
-
* on_duplicates: (dupes, log) => {
|
|
57
|
-
* for (const [name, locs] of dupes) {
|
|
58
|
-
* log.warn(`Duplicate: ${name} in ${locs.map(l => l.module).join(', ')}`);
|
|
59
|
-
* }
|
|
60
|
-
* }
|
|
61
|
-
* });
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
on_duplicates?: OnDuplicatesCallback;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Convert Gro's `Disknode` to the build-tool agnostic `SourceFileInfo` interface.
|
|
69
|
-
*
|
|
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.
|
|
77
|
-
*
|
|
78
|
-
* @throws Error if disknode has no content (should be loaded by Gro filer)
|
|
79
|
-
*/
|
|
80
|
-
export const source_file_from_disknode = (disknode: Disknode): SourceFileInfo => {
|
|
81
|
-
if (disknode.contents == null) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`Source file has no content: ${disknode.id} (ensure Gro filer loads file contents)`,
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
id: disknode.id,
|
|
88
|
-
content: disknode.contents,
|
|
89
|
-
dependencies: [...disknode.dependencies.keys()],
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Collect source files from Gro disknodes, filtering BEFORE conversion to `SourceFileInfo`.
|
|
95
|
-
*
|
|
96
|
-
* This avoids errors from files outside source directories (like test fixtures that may
|
|
97
|
-
* have malformed paths or missing content). The filtering uses `isSource` which
|
|
98
|
-
* checks `source_paths` to only include files in configured source directories.
|
|
99
|
-
*
|
|
100
|
-
* @param disknodes - iterator of Gro disknodes from filer
|
|
101
|
-
* @param options - module source options for filtering
|
|
102
|
-
* @param log - optional logger for status messages
|
|
103
|
-
*/
|
|
104
|
-
export const library_collect_source_files_from_disknodes = (
|
|
105
|
-
disknodes: Iterable<Disknode>,
|
|
106
|
-
options: ModuleSourceOptions,
|
|
107
|
-
log?: {info: (...args: Array<unknown>) => void; warn: (...args: Array<unknown>) => void},
|
|
108
|
-
): Array<SourceFileInfo> => {
|
|
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);
|
|
113
|
-
|
|
114
|
-
const all_disknodes = Array.from(disknodes);
|
|
115
|
-
log?.info(`received ${all_disknodes.length} files total from filer`);
|
|
116
|
-
|
|
117
|
-
const source_files: Array<SourceFileInfo> = [];
|
|
118
|
-
for (const disknode of all_disknodes) {
|
|
119
|
-
// Filter by source_paths BEFORE trying to convert
|
|
120
|
-
// This avoids errors from test fixtures or other non-source files
|
|
121
|
-
if (!isSource(disknode.id, normalized_options)) {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
source_files.push(source_file_from_disknode(disknode));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
log?.info(`found ${source_files.length} source files to analyze`);
|
|
128
|
-
|
|
129
|
-
if (source_files.length === 0) {
|
|
130
|
-
const effective_root = getSourceRoot(normalized_options);
|
|
131
|
-
log?.warn(`No source files found in ${effective_root} - generating empty library metadata`);
|
|
132
|
-
return [];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Sort for deterministic output (stable alphabetical module ordering)
|
|
136
|
-
source_files.sort((a, b) => a.id.localeCompare(b.id));
|
|
137
|
-
|
|
138
|
-
return source_files;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Creates a `Gen` object for generating library metadata with full TypeScript analysis.
|
|
143
|
-
*
|
|
144
|
-
* This is the Gro-specific entry point. It handles:
|
|
145
|
-
* - Reading files from Gro's filer
|
|
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
|
|
150
|
-
*
|
|
151
|
-
* For build-tool agnostic usage, use `analyze` directly.
|
|
152
|
-
*
|
|
153
|
-
* Usage in a `.gen.ts` file:
|
|
154
|
-
*
|
|
155
|
-
* ```ts
|
|
156
|
-
* import {library_gen} from '@fuzdev/fuz_ui/library_gen.js';
|
|
157
|
-
*
|
|
158
|
-
* export const gen = library_gen();
|
|
159
|
-
* ```
|
|
160
|
-
*
|
|
161
|
-
* @param options - optional generation options
|
|
162
|
-
*/
|
|
163
|
-
export const library_gen = (options?: LibraryGenOptions): Gen => {
|
|
164
|
-
return {
|
|
165
|
-
dependencies: 'all',
|
|
166
|
-
generate: async ({log, filer}) => {
|
|
167
|
-
log.info('generating library metadata with full TypeScript analysis...');
|
|
168
|
-
|
|
169
|
-
// Build source options with project_root from cwd
|
|
170
|
-
const source_options: ModuleSourceOptions =
|
|
171
|
-
options?.source && 'projectRoot' in options.source
|
|
172
|
-
? options.source
|
|
173
|
-
: createSourceOptions(process.cwd(), options?.source);
|
|
174
|
-
|
|
175
|
-
// Ensure filer is initialized
|
|
176
|
-
await filer.init();
|
|
177
|
-
|
|
178
|
-
// Read package.json
|
|
179
|
-
const package_json = await package_json_load();
|
|
180
|
-
|
|
181
|
-
// Collect source files from Gro filer
|
|
182
|
-
const source_files = library_collect_source_files_from_disknodes(
|
|
183
|
-
filer.files.values(),
|
|
184
|
-
source_options,
|
|
185
|
-
log,
|
|
186
|
-
);
|
|
187
|
-
|
|
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
|
|
194
|
-
});
|
|
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
|
-
|
|
213
|
-
log.info('library metadata generation complete');
|
|
214
|
-
|
|
215
|
-
// Return array of files in Gro's expected format
|
|
216
|
-
return [{content: ts_content}, {content: json_content, filename: 'library.json'}];
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
};
|