@weasel-js/forge 1.5.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 (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/dist/FrameController-Ba3LaWfq.d.ts +196 -0
  4. package/dist/chunk-2GXKNXTJ.js +15 -0
  5. package/dist/chunk-2GXKNXTJ.js.map +1 -0
  6. package/dist/chunk-IOBG7GZQ.js +13 -0
  7. package/dist/chunk-IOBG7GZQ.js.map +1 -0
  8. package/dist/chunk-KKF7ZX5E.js +572 -0
  9. package/dist/chunk-KKF7ZX5E.js.map +1 -0
  10. package/dist/chunk-KKVTFMWV.js +59 -0
  11. package/dist/chunk-KKVTFMWV.js.map +1 -0
  12. package/dist/chunk-O5OQZQRZ.js +118 -0
  13. package/dist/chunk-O5OQZQRZ.js.map +1 -0
  14. package/dist/chunk-UZCXH724.js +24 -0
  15. package/dist/chunk-UZCXH724.js.map +1 -0
  16. package/dist/cli.js +107 -0
  17. package/dist/config-DdumOfyd.d.ts +28 -0
  18. package/dist/csf/preview-api.d.ts +9 -0
  19. package/dist/csf/preview-api.js +48 -0
  20. package/dist/csf/preview-api.js.map +1 -0
  21. package/dist/frame/index.css +35 -0
  22. package/dist/frame/index.css.map +1 -0
  23. package/dist/frame/index.d.ts +24 -0
  24. package/dist/frame/index.js +8 -0
  25. package/dist/frame/index.js.map +1 -0
  26. package/dist/index.d.ts +11 -0
  27. package/dist/index.js +14 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/shell/index.css +198 -0
  30. package/dist/shell/index.css.map +1 -0
  31. package/dist/shell/index.d.ts +51 -0
  32. package/dist/shell/index.js +836 -0
  33. package/dist/shell/index.js.map +1 -0
  34. package/dist/test/index.d.ts +17 -0
  35. package/dist/test/index.js +132 -0
  36. package/dist/test/index.js.map +1 -0
  37. package/dist/vite/index.d.ts +29 -0
  38. package/dist/vite/index.js +392 -0
  39. package/dist/vite/index.js.map +1 -0
  40. package/package.json +87 -0
@@ -0,0 +1,392 @@
1
+ import { titleFromFile, storyNameFromExport, storyId } from '../chunk-UZCXH724.js';
2
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, globSync } from 'fs';
3
+ import { resolve, relative, sep, matchesGlob, dirname, join, basename } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { parse } from '@babel/parser';
6
+
7
+ // src/vite/html.ts
8
+ function html(entry, mode = "serve") {
9
+ const src = `${mode === "serve" ? "/@id/" : ""}virtual:forge/${entry}`;
10
+ return `<!doctype html>
11
+ <html lang="en">
12
+ <head>
13
+ <meta charset="utf-8" />
14
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
15
+ <title>weaselforge</title>
16
+ </head>
17
+ <body>
18
+ <div id="root"></div>
19
+ <script type="module" src="${src}"></script>
20
+ </body>
21
+ </html>
22
+ `;
23
+ }
24
+
25
+ // src/vite/build.ts
26
+ var DIR = "node_modules/.forge";
27
+ var PAGES = { index: "shell-entry.js", frame: "frame-entry.js" };
28
+ function writePages(root) {
29
+ const dir = join(root, DIR);
30
+ mkdirSync(dir, { recursive: true });
31
+ return Object.fromEntries(
32
+ Object.entries(PAGES).map(([name, entry]) => {
33
+ const file = join(dir, `${name}.html`);
34
+ writeFileSync(file, html(entry, "build"));
35
+ return [name, file];
36
+ })
37
+ );
38
+ }
39
+ var up = (source) => (typeof source === "string" ? source : new TextDecoder().decode(source)).replace(/(\s(?:src|href)=")\.\.\/\.\.\//g, "$1./");
40
+ function hoistPages(bundle, emit) {
41
+ for (const name of Object.keys(PAGES)) {
42
+ const from = `${DIR}/${name}.html`;
43
+ const asset = bundle[from];
44
+ if (asset?.type !== "asset" || asset.source === void 0) continue;
45
+ delete bundle[from];
46
+ emit({ type: "asset", fileName: `${name}.html`, source: up(asset.source) });
47
+ }
48
+ }
49
+ function indexFile(code, file, root) {
50
+ try {
51
+ const plugins = ["typescript", "decorators-legacy", .../\.[jt]sx$/.test(file) ? ["jsx"] : []];
52
+ return indexProgram(parse(code, { sourceType: "module", plugins }).program, file, root);
53
+ } catch (err) {
54
+ throw new Error(`${file}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
55
+ }
56
+ }
57
+ function indexProgram(program, file, root) {
58
+ const bindings = /* @__PURE__ */ new Map();
59
+ const wrappers = /* @__PURE__ */ new Set();
60
+ for (const stmt of program.body) {
61
+ if (stmt.type === "ImportDeclaration" && stmt.source.value === "@weasel-js/forge") {
62
+ for (const spec of stmt.specifiers) {
63
+ if (spec.type === "ImportSpecifier" && ["meta", "story"].includes(exportedName(spec.imported))) {
64
+ wrappers.add(spec.local.name);
65
+ }
66
+ }
67
+ }
68
+ const decl = stmt.type === "ExportNamedDeclaration" ? stmt.declaration : stmt;
69
+ if (decl?.type === "VariableDeclaration") {
70
+ for (const d of decl.declarations) if (d.id.type === "Identifier" && d.init) bindings.set(d.id.name, d.init);
71
+ }
72
+ }
73
+ let metaNode;
74
+ const exported = [];
75
+ for (const stmt of program.body) {
76
+ if (stmt.type === "ExportDefaultDeclaration") metaNode = stmt.declaration;
77
+ if (stmt.type !== "ExportNamedDeclaration" || stmt.exportKind === "type") continue;
78
+ const decl = stmt.declaration;
79
+ if (decl?.type === "VariableDeclaration") {
80
+ for (const d of decl.declarations) {
81
+ if (d.id.type === "Identifier") exported.push({ name: d.id.name, node: d.init ?? void 0 });
82
+ }
83
+ } else if (decl?.type === "FunctionDeclaration" && decl.id) {
84
+ exported.push({ name: decl.id.name, node: void 0 });
85
+ }
86
+ for (const spec of stmt.specifiers) {
87
+ if (spec.type !== "ExportSpecifier" || spec.exportKind === "type") continue;
88
+ const name = exportedName(spec.exported);
89
+ const node = stmt.source ? void 0 : bindings.get(spec.local.name);
90
+ if (name === "default") metaNode = node;
91
+ else exported.push({ name, node });
92
+ }
93
+ }
94
+ if (!metaNode && !program.body.some(isDefaultExport)) return [];
95
+ const meta = objectOf(metaNode, bindings, wrappers);
96
+ const title = stringProp(meta, "title") ?? titleFromFile(file, root);
97
+ const include = storyFilter(meta, "includeStories");
98
+ const exclude = storyFilter(meta, "excludeStories");
99
+ return exported.filter(({ name }) => name !== "__namedExportsOrder").filter(({ name }) => (!include || include(name)) && (!exclude || !exclude(name))).map(({ name, node }) => {
100
+ const spec = objectOf(node, bindings, wrappers);
101
+ return {
102
+ id: storyId(title, name),
103
+ title,
104
+ name: stringProp(spec, "name") ?? stringProp(spec, "storyName") ?? storyNameFromExport(name),
105
+ exportName: name,
106
+ file
107
+ };
108
+ });
109
+ }
110
+ function isDefaultExport(stmt) {
111
+ if (stmt.type === "ExportDefaultDeclaration") return true;
112
+ return stmt.type === "ExportNamedDeclaration" && stmt.specifiers.some((s) => s.type === "ExportSpecifier" && exportedName(s.exported) === "default");
113
+ }
114
+ function exportedName(node) {
115
+ return node.type === "Identifier" ? node.name : node.value;
116
+ }
117
+ function objectOf(node, bindings, wrappers, depth = 0) {
118
+ if (!node || depth > 16) return null;
119
+ switch (node.type) {
120
+ case "ObjectExpression":
121
+ return node;
122
+ case "TSSatisfiesExpression":
123
+ case "TSAsExpression":
124
+ case "TSTypeAssertion":
125
+ case "TSNonNullExpression":
126
+ case "ParenthesizedExpression":
127
+ return objectOf(node.expression, bindings, wrappers, depth + 1);
128
+ case "CallExpression":
129
+ return node.callee.type === "Identifier" && wrappers.has(node.callee.name) ? objectOf(node.arguments[0], bindings, wrappers, depth + 1) : null;
130
+ case "Identifier":
131
+ return objectOf(bindings.get(node.name), bindings, wrappers, depth + 1);
132
+ default:
133
+ return null;
134
+ }
135
+ }
136
+ function prop(obj, key) {
137
+ for (const p of obj?.properties ?? []) {
138
+ if (p.type !== "ObjectProperty" || p.computed) continue;
139
+ const name = p.key.type === "Identifier" ? p.key.name : p.key.type === "StringLiteral" ? p.key.value : null;
140
+ if (name === key) return p.value;
141
+ }
142
+ return void 0;
143
+ }
144
+ function stringProp(obj, key) {
145
+ const value = prop(obj, key);
146
+ return value?.type === "StringLiteral" ? value.value : void 0;
147
+ }
148
+ function storyFilter(obj, key) {
149
+ const value = prop(obj, key);
150
+ if (value?.type === "RegExpLiteral") {
151
+ const re = new RegExp(value.pattern, value.flags.replace(/[gy]/g, ""));
152
+ return (name) => re.test(name);
153
+ }
154
+ if (value?.type === "ArrayExpression" && value.elements.every((e) => e?.type === "StringLiteral")) {
155
+ const names = new Set(value.elements.map((e) => e.value));
156
+ return (name) => names.has(name);
157
+ }
158
+ return null;
159
+ }
160
+ var PREVIEW_API = /^@?storybook\/preview-api$/;
161
+ function storybookShims() {
162
+ return {
163
+ name: "weaselforge:storybook-shims",
164
+ enforce: "pre",
165
+ resolveId(id) {
166
+ if (!PREVIEW_API.test(id)) return void 0;
167
+ return this.resolve("@weasel-js/forge/preview-api", fileURLToPath(import.meta.url), { skipSelf: true });
168
+ }
169
+ };
170
+ }
171
+
172
+ // src/vite/plugin.ts
173
+ var PREFIX = "virtual:forge/";
174
+ var MODULES = /* @__PURE__ */ new Set(["index.js", "importers.js", "frame-config.js", "shell-config.js", "shell-entry.js", "frame-entry.js"]);
175
+ var PAGES2 = { "/": "shell-entry.js", "/index.html": "shell-entry.js", "/frame.html": "frame-entry.js" };
176
+ function ownEntries() {
177
+ const here = fileURLToPath(import.meta.url);
178
+ for (let dir = dirname(here); dir !== dirname(dir); dir = dirname(dir)) {
179
+ const manifest = join(dir, "package.json");
180
+ if (!existsSync(manifest) || JSON.parse(readFileSync(manifest, "utf8")).name !== "@weasel-js/forge") {
181
+ continue;
182
+ }
183
+ const source = !relative(join(dir, "src"), here).startsWith("..");
184
+ return ["shell", "frame"].map((realm) => join(dir, source ? `src/${realm}/index.ts` : `dist/${realm}/index.js`));
185
+ }
186
+ return [];
187
+ }
188
+ function forge(options) {
189
+ let root = process.cwd();
190
+ let base = "/";
191
+ let byFile = null;
192
+ let logger;
193
+ const glob = () => {
194
+ const files2 = options.stories.flatMap(
195
+ (pattern) => globSync(pattern, { cwd: root, exclude: (name) => basename(String(name)) === "node_modules" }).map((f) => resolve(root, f)).sort()
196
+ );
197
+ return [...new Set(files2)];
198
+ };
199
+ const matches = (file) => {
200
+ const path = relative(root, file).split(sep).join("/");
201
+ return !path.split("/").includes("node_modules") && options.stories.some((pattern) => matchesGlob(path, pattern));
202
+ };
203
+ const read = (file) => indexFile(readFileSync(file, "utf8"), file, root);
204
+ const logError = (err) => logger?.error(`[forge] ${err instanceof Error ? err.message : String(err)}`);
205
+ const files = () => {
206
+ byFile ??= new Map(
207
+ glob().map((file) => {
208
+ try {
209
+ return [file, read(file)];
210
+ } catch (err) {
211
+ logError(err);
212
+ return [file, []];
213
+ }
214
+ })
215
+ );
216
+ return byFile;
217
+ };
218
+ const index = () => [...files().values()].flat();
219
+ const configModule = (path) => path ? `export { default } from ${JSON.stringify(resolve(root, path))};
220
+ ` : "export default {};\n";
221
+ const modules = {
222
+ "index.js": () => `export default ${JSON.stringify(index())};
223
+ `,
224
+ "importers.js": () => {
225
+ const lines = [...files()].filter(([, entries]) => entries.length > 0).map(([file]) => ` ${JSON.stringify(file)}: () => import(${JSON.stringify(file)}),`);
226
+ return `export default {
227
+ ${lines.join("\n")}
228
+ };
229
+ `;
230
+ },
231
+ "frame-config.js": () => configModule(options.frameConfig),
232
+ "shell-config.js": () => configModule(options.shellConfig),
233
+ "shell-entry.js": () => `import { mountWorkshop } from '@weasel-js/forge/shell';
234
+ import '@weasel-js/labkit/styles.css';
235
+ import '@weasel-js/forge/shell.css';
236
+ import index from 'virtual:forge/index.js';
237
+ import config from 'virtual:forge/shell-config.js';
238
+
239
+ const workshop = mountWorkshop({
240
+ index,
241
+ config,
242
+ frameUrl: ${JSON.stringify(`${base}frame.html`)},
243
+ stories: ${JSON.stringify(options.stories)},
244
+ });
245
+ import.meta.hot?.on('forge:index', (next) => workshop.setIndex(next));
246
+ `,
247
+ "frame-entry.js": () => `import { mountFrame } from '@weasel-js/forge/frame';
248
+ import '@weasel-js/forge/frame.css';
249
+ import index from 'virtual:forge/index.js';
250
+ import importers from 'virtual:forge/importers.js';
251
+ import setup from 'virtual:forge/frame-config.js';
252
+
253
+ mountFrame({ index, importers, root: ${JSON.stringify(root)}, setup });
254
+ `
255
+ };
256
+ function reindex(server, file, event) {
257
+ const current = files();
258
+ if (event === "change" && !current.has(file)) return;
259
+ if (event === "add" && !matches(file)) return;
260
+ if (event === "unlink" && !current.has(file)) return;
261
+ const before = JSON.stringify(index());
262
+ if (event === "unlink") {
263
+ current.delete(file);
264
+ } else {
265
+ try {
266
+ current.set(file, read(file));
267
+ } catch (err) {
268
+ logError(err);
269
+ return;
270
+ }
271
+ }
272
+ const next = index();
273
+ if (JSON.stringify(next) === before) return;
274
+ for (const env of Object.values(server.environments)) {
275
+ for (const name of ["index.js", "importers.js"]) {
276
+ const mod = env.moduleGraph.getModuleById(`\0${PREFIX}${name}`);
277
+ if (mod) env.moduleGraph.invalidateModule(mod);
278
+ }
279
+ }
280
+ server.ws.send({ type: "custom", event: "forge:index", data: next });
281
+ }
282
+ return [
283
+ ...options.storybookShims === false ? [] : [storybookShims()],
284
+ {
285
+ name: "weaselforge",
286
+ config(config, { command }) {
287
+ const at = resolve(config.root ?? process.cwd());
288
+ const entries = [
289
+ ...options.stories,
290
+ ...[options.frameConfig, options.shellConfig].flatMap((path) => path ? [resolve(at, path)] : []),
291
+ ...ownEntries()
292
+ ];
293
+ const optimizeDeps = { entries };
294
+ if (command !== "build") return { optimizeDeps };
295
+ return { optimizeDeps, build: { rolldownOptions: { input: writePages(at) } } };
296
+ },
297
+ generateBundle: {
298
+ order: "post",
299
+ handler(_, bundle) {
300
+ hoistPages(bundle, (file) => this.emitFile(file));
301
+ }
302
+ },
303
+ configResolved(config) {
304
+ root = config.root;
305
+ base = config.base;
306
+ logger = config.logger;
307
+ byFile = null;
308
+ },
309
+ resolveId(id) {
310
+ return id.startsWith(PREFIX) && MODULES.has(id.slice(PREFIX.length)) ? `\0${id}` : void 0;
311
+ },
312
+ load(id) {
313
+ if (!id.startsWith(`\0${PREFIX}`)) return void 0;
314
+ return modules[id.slice(PREFIX.length + 1)]?.();
315
+ },
316
+ configureServer(server) {
317
+ server.watcher.add([...files().keys()]);
318
+ for (const event of ["add", "change", "unlink"]) {
319
+ server.watcher.on(event, (file) => reindex(server, resolve(file), event));
320
+ }
321
+ server.middlewares.use((req, res, next) => {
322
+ const url = req.url ?? "/";
323
+ const path = url.split("?")[0] ?? "/";
324
+ const prefix = base.endsWith("/") ? base.slice(0, -1) : base;
325
+ const page = path === prefix ? "/" : path.startsWith(`${prefix}/`) ? path.slice(prefix.length) : null;
326
+ const entry = req.method === "GET" && page !== null ? PAGES2[page] : void 0;
327
+ if (!entry) return next();
328
+ server.transformIndexHtml(url, html(entry)).then(
329
+ (doc) => {
330
+ res.statusCode = 200;
331
+ res.setHeader("Content-Type", "text/html");
332
+ res.end(doc);
333
+ },
334
+ (err) => next(err)
335
+ );
336
+ });
337
+ }
338
+ }
339
+ ];
340
+ }
341
+ var TIMEOUT_MS = 15e3;
342
+ function forgeTest(options) {
343
+ let root = process.cwd();
344
+ const matches = (id) => {
345
+ if (id.startsWith("\0") || id.includes("?")) return false;
346
+ const path = relative(root, id).split(sep).join("/");
347
+ if (path.startsWith("../") || path.split("/").includes("node_modules")) return false;
348
+ return options.stories.some((pattern) => matchesGlob(path, pattern));
349
+ };
350
+ return [
351
+ ...options.storybookShims === false ? [] : [storybookShims()],
352
+ {
353
+ name: "weaselforge:test",
354
+ enforce: "pre",
355
+ configResolved(config) {
356
+ root = config.root;
357
+ },
358
+ transform(code, id) {
359
+ if (!matches(id)) return void 0;
360
+ const entries = indexFile(code, id, root);
361
+ if (entries.length === 0) return void 0;
362
+ const q = (value) => JSON.stringify(value);
363
+ const lines = [
364
+ "",
365
+ `import { test as __forge_test } from "vitest";`,
366
+ `import { page as __forge_page } from "vitest/browser";`,
367
+ `import { runStory as __forge_runStory } from "@weasel-js/forge/test";`,
368
+ `import "@weasel-js/forge/frame.css";`,
369
+ ...options.frameConfig ? [`import __forge_frame_config from ${q(resolve(root, options.frameConfig))};`] : [],
370
+ `const __forge_file = ${q(id)};`,
371
+ `const __forge_root = ${q(root)};`,
372
+ `const __forge_timeout = ${TIMEOUT_MS};`,
373
+ "const __forge_options = {",
374
+ ` setup: ${options.frameConfig ? "__forge_frame_config" : "undefined"},`,
375
+ " viewport: (width, height) => __forge_page.viewport(width, height),",
376
+ "};",
377
+ "const __forge_run = async (exportName) => __forge_runStory(await import(/* @vite-ignore */ import.meta.url), exportName, __forge_file, __forge_root, __forge_options);",
378
+ ...entries.map(
379
+ (entry) => `__forge_test(${q(entry.name)}, () => __forge_run(${q(entry.exportName)}), __forge_timeout);`
380
+ )
381
+ ];
382
+ return { code: `${code}
383
+ ${lines.join("\n")}
384
+ `, map: null };
385
+ }
386
+ }
387
+ ];
388
+ }
389
+
390
+ export { forge, forgeTest };
391
+ //# sourceMappingURL=index.js.map
392
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/vite/html.ts","../../src/vite/build.ts","../../src/vite/indexFile.ts","../../src/vite/storybookShims.ts","../../src/vite/plugin.ts","../../src/vite/forgeTest.ts"],"names":["PAGES","fileURLToPath","join","files","relative","sep","matchesGlob","resolve"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The document forge serves for `entry`, one of its `virtual:forge/*-entry.js` modules. A build hands the\n * bare id to its own resolver; the dev server needs the `/@id/` form a browser can request.\n */\nexport function html(entry: string, mode: 'serve' | 'build' = 'serve'): string {\n const src = `${mode === 'serve' ? '/@id/' : ''}virtual:forge/${entry}`;\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>weaselforge</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"${src}\"></script>\n </body>\n</html>\n`;\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { html } from './html';\n\nconst DIR = 'node_modules/.forge';\ntype Source = string | Uint8Array;\n\nconst PAGES: Record<string, string> = { index: 'shell-entry.js', frame: 'frame-entry.js' };\n\n/** Writes a build document per forge page under `<root>/node_modules/.forge`, returning them as build inputs. */\nexport function writePages(root: string): Record<string, string> {\n const dir = join(root, DIR);\n mkdirSync(dir, { recursive: true });\n return Object.fromEntries(\n Object.entries(PAGES).map(([name, entry]) => {\n const file = join(dir, `${name}.html`);\n writeFileSync(file, html(entry, 'build'));\n return [name, file];\n }),\n );\n}\n\n/** Vite wrote a relative base's urls from two directories down; the documents now sit at the output root. */\nconst up = (source: Source) =>\n (typeof source === 'string' ? source : new TextDecoder().decode(source)).replace(/(\\s(?:src|href)=\")\\.\\.\\/\\.\\.\\//g, '$1./');\n\n/** Replaces the documents vite emitted at their input path with copies at the output root. */\nexport function hoistPages(\n bundle: Record<string, { type: string; source?: Source }>,\n emit: (file: { type: 'asset'; fileName: string; source: Source }) => void,\n): void {\n for (const name of Object.keys(PAGES)) {\n const from = `${DIR}/${name}.html`;\n const asset = bundle[from];\n if (asset?.type !== 'asset' || asset.source === undefined) continue;\n delete bundle[from];\n emit({ type: 'asset', fileName: `${name}.html`, source: up(asset.source) });\n }\n}\n","import { type ParserPlugin, parse } from '@babel/parser';\nimport type * as t from '@babel/types';\nimport { storyId, storyNameFromExport, titleFromFile } from '../story/ids';\nimport type { IndexEntry } from '../story/types';\n\ntype Bindings = Map<string, t.Node>;\n\n/** The stories `code` declares, in source order, without running it. `file` is absolute. */\nexport function indexFile(code: string, file: string, root: string): IndexEntry[] {\n try {\n const plugins: ParserPlugin[] = ['typescript', 'decorators-legacy', ...(/\\.[jt]sx$/.test(file) ? (['jsx'] as const) : [])];\n return indexProgram(parse(code, { sourceType: 'module', plugins }).program, file, root);\n } catch (err) {\n throw new Error(`${file}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n }\n}\n\nfunction indexProgram(program: t.Program, file: string, root: string): IndexEntry[] {\n const bindings: Bindings = new Map();\n const wrappers = new Set<string>();\n for (const stmt of program.body) {\n if (stmt.type === 'ImportDeclaration' && stmt.source.value === '@weasel-js/forge') {\n for (const spec of stmt.specifiers) {\n if (spec.type === 'ImportSpecifier' && ['meta', 'story'].includes(exportedName(spec.imported))) {\n wrappers.add(spec.local.name);\n }\n }\n }\n const decl = stmt.type === 'ExportNamedDeclaration' ? stmt.declaration : stmt;\n if (decl?.type === 'VariableDeclaration') {\n for (const d of decl.declarations) if (d.id.type === 'Identifier' && d.init) bindings.set(d.id.name, d.init);\n }\n }\n\n let metaNode: t.Node | undefined;\n const exported: { name: string; node: t.Node | undefined }[] = [];\n for (const stmt of program.body) {\n if (stmt.type === 'ExportDefaultDeclaration') metaNode = stmt.declaration;\n if (stmt.type !== 'ExportNamedDeclaration' || stmt.exportKind === 'type') continue;\n const decl = stmt.declaration;\n if (decl?.type === 'VariableDeclaration') {\n for (const d of decl.declarations) {\n if (d.id.type === 'Identifier') exported.push({ name: d.id.name, node: d.init ?? undefined });\n }\n } else if (decl?.type === 'FunctionDeclaration' && decl.id) {\n exported.push({ name: decl.id.name, node: undefined });\n }\n for (const spec of stmt.specifiers) {\n if (spec.type !== 'ExportSpecifier' || spec.exportKind === 'type') continue;\n const name = exportedName(spec.exported);\n const node = stmt.source ? undefined : bindings.get(spec.local.name);\n if (name === 'default') metaNode = node;\n else exported.push({ name, node });\n }\n }\n if (!metaNode && !program.body.some(isDefaultExport)) return [];\n\n const meta = objectOf(metaNode, bindings, wrappers);\n const title = stringProp(meta, 'title') ?? titleFromFile(file, root);\n const include = storyFilter(meta, 'includeStories');\n const exclude = storyFilter(meta, 'excludeStories');\n\n return exported\n .filter(({ name }) => name !== '__namedExportsOrder')\n .filter(({ name }) => (!include || include(name)) && (!exclude || !exclude(name)))\n .map(({ name, node }) => {\n const spec = objectOf(node, bindings, wrappers);\n return {\n id: storyId(title, name),\n title,\n name: stringProp(spec, 'name') ?? stringProp(spec, 'storyName') ?? storyNameFromExport(name),\n exportName: name,\n file,\n };\n });\n}\n\nfunction isDefaultExport(stmt: t.Statement): boolean {\n if (stmt.type === 'ExportDefaultDeclaration') return true;\n return (\n stmt.type === 'ExportNamedDeclaration' &&\n stmt.specifiers.some((s) => s.type === 'ExportSpecifier' && exportedName(s.exported) === 'default')\n );\n}\n\nfunction exportedName(node: t.Identifier | t.StringLiteral): string {\n return node.type === 'Identifier' ? node.name : node.value;\n}\n\n/** The object literal `node` evaluates to, through casts, `meta(…)`/`story(…)` and top-level `const`s. */\nfunction objectOf(node: t.Node | undefined, bindings: Bindings, wrappers: Set<string>, depth = 0): t.ObjectExpression | null {\n if (!node || depth > 16) return null;\n switch (node.type) {\n case 'ObjectExpression':\n return node;\n case 'TSSatisfiesExpression':\n case 'TSAsExpression':\n case 'TSTypeAssertion':\n case 'TSNonNullExpression':\n case 'ParenthesizedExpression':\n return objectOf(node.expression, bindings, wrappers, depth + 1);\n case 'CallExpression':\n return node.callee.type === 'Identifier' && wrappers.has(node.callee.name)\n ? objectOf(node.arguments[0], bindings, wrappers, depth + 1)\n : null;\n case 'Identifier':\n return objectOf(bindings.get(node.name), bindings, wrappers, depth + 1);\n default:\n return null;\n }\n}\n\nfunction prop(obj: t.ObjectExpression | null, key: string): t.Node | undefined {\n for (const p of obj?.properties ?? []) {\n if (p.type !== 'ObjectProperty' || p.computed) continue;\n const name = p.key.type === 'Identifier' ? p.key.name : p.key.type === 'StringLiteral' ? p.key.value : null;\n if (name === key) return p.value;\n }\n return undefined;\n}\n\nfunction stringProp(obj: t.ObjectExpression | null, key: string): string | undefined {\n const value = prop(obj, key);\n return value?.type === 'StringLiteral' ? value.value : undefined;\n}\n\n/** `includeStories`/`excludeStories` as a predicate, when written as a string array or a regex literal. */\nfunction storyFilter(obj: t.ObjectExpression | null, key: string): ((name: string) => boolean) | null {\n const value = prop(obj, key);\n if (value?.type === 'RegExpLiteral') {\n const re = new RegExp(value.pattern, value.flags.replace(/[gy]/g, ''));\n return (name) => re.test(name);\n }\n if (value?.type === 'ArrayExpression' && value.elements.every((e) => e?.type === 'StringLiteral')) {\n const names = new Set(value.elements.map((e) => (e as t.StringLiteral).value));\n return (name) => names.has(name);\n }\n return null;\n}\n","import { fileURLToPath } from 'node:url';\nimport type { Plugin } from 'vite';\n\nconst PREVIEW_API = /^@?storybook\\/preview-api$/;\n\n/** Points `storybook/preview-api` and `@storybook/preview-api` at forge's shim. */\nexport function storybookShims(): Plugin {\n // Resolved from forge's own location, through the app's aliases, so a monorepo reaches source and an install reaches dist.\n return {\n name: 'weaselforge:storybook-shims',\n enforce: 'pre',\n resolveId(id) {\n if (!PREVIEW_API.test(id)) return undefined;\n return this.resolve('@weasel-js/forge/preview-api', fileURLToPath(import.meta.url), { skipSelf: true });\n },\n };\n}\n","import { existsSync, globSync, readFileSync } from 'node:fs';\nimport { basename, dirname, join, matchesGlob, relative, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Logger, Plugin, ViteDevServer } from 'vite';\nimport type { IndexEntry } from '../story/types';\nimport { hoistPages, writePages } from './build';\nimport { html } from './html';\nimport { indexFile } from './indexFile';\nimport { storybookShims } from './storybookShims';\n\nexport interface ForgeOptions {\n /** Globs of story files, relative to the vite root. */\n stories: string[];\n /** Path to the frame config module, relative to the vite root. Only frame documents import it. Optional. */\n frameConfig?: string;\n /** Path to the shell config module, relative to the vite root. Only the workshop page imports it. Optional. */\n shellConfig?: string;\n /** Alias Storybook's runtime modules to forge shims (Task 13). Default true. */\n storybookShims?: boolean;\n}\n\nconst PREFIX = 'virtual:forge/';\nconst MODULES = new Set(['index.js', 'importers.js', 'frame-config.js', 'shell-config.js', 'shell-entry.js', 'frame-entry.js']);\nconst PAGES: Record<string, string> = { '/': 'shell-entry.js', '/index.html': 'shell-entry.js', '/frame.html': 'frame-entry.js' };\n\n/** forge's shell and frame entry modules: source beside this file in a checkout, the built entries in an install. */\nfunction ownEntries(): string[] {\n const here = fileURLToPath(import.meta.url);\n for (let dir = dirname(here); dir !== dirname(dir); dir = dirname(dir)) {\n const manifest = join(dir, 'package.json');\n if (!existsSync(manifest) || (JSON.parse(readFileSync(manifest, 'utf8')) as { name?: string }).name !== '@weasel-js/forge') {\n continue;\n }\n const source = !relative(join(dir, 'src'), here).startsWith('..');\n return ['shell', 'frame'].map((realm) => join(dir, source ? `src/${realm}/index.ts` : `dist/${realm}/index.js`));\n }\n return [];\n}\n\nexport function forge(options: ForgeOptions): Plugin[] {\n let root = process.cwd();\n let base = '/';\n let byFile: Map<string, IndexEntry[]> | null = null;\n let logger: Logger | undefined;\n\n const glob = (): string[] => {\n const files = options.stories.flatMap((pattern) =>\n globSync(pattern, { cwd: root, exclude: (name) => basename(String(name)) === 'node_modules' })\n .map((f) => resolve(root, f))\n .sort(),\n );\n return [...new Set(files)];\n };\n const matches = (file: string): boolean => {\n const path = relative(root, file).split(sep).join('/');\n return !path.split('/').includes('node_modules') && options.stories.some((pattern) => matchesGlob(path, pattern));\n };\n const read = (file: string) => indexFile(readFileSync(file, 'utf8'), file, root);\n const logError = (err: unknown) => logger?.error(`[forge] ${err instanceof Error ? err.message : String(err)}`);\n /** A file that fails to parse stays in the map with no entries, so an edit that fixes it re-indexes it. */\n const files = (): Map<string, IndexEntry[]> => {\n byFile ??= new Map(\n glob().map((file) => {\n try {\n return [file, read(file)];\n } catch (err) {\n logError(err);\n return [file, []];\n }\n }),\n );\n return byFile;\n };\n const index = () => [...files().values()].flat();\n\n const configModule = (path: string | undefined) =>\n path ? `export { default } from ${JSON.stringify(resolve(root, path))};\\n` : 'export default {};\\n';\n\n const modules: Record<string, () => string> = {\n 'index.js': () => `export default ${JSON.stringify(index())};\\n`,\n 'importers.js': () => {\n const lines = [...files()]\n .filter(([, entries]) => entries.length > 0)\n .map(([file]) => ` ${JSON.stringify(file)}: () => import(${JSON.stringify(file)}),`);\n return `export default {\\n${lines.join('\\n')}\\n};\\n`;\n },\n 'frame-config.js': () => configModule(options.frameConfig),\n 'shell-config.js': () => configModule(options.shellConfig),\n 'shell-entry.js': () => `import { mountWorkshop } from '@weasel-js/forge/shell';\nimport '@weasel-js/labkit/styles.css';\nimport '@weasel-js/forge/shell.css';\nimport index from 'virtual:forge/index.js';\nimport config from 'virtual:forge/shell-config.js';\n\nconst workshop = mountWorkshop({\n index,\n config,\n frameUrl: ${JSON.stringify(`${base}frame.html`)},\n stories: ${JSON.stringify(options.stories)},\n});\nimport.meta.hot?.on('forge:index', (next) => workshop.setIndex(next));\n`,\n 'frame-entry.js': () => `import { mountFrame } from '@weasel-js/forge/frame';\nimport '@weasel-js/forge/frame.css';\nimport index from 'virtual:forge/index.js';\nimport importers from 'virtual:forge/importers.js';\nimport setup from 'virtual:forge/frame-config.js';\n\nmountFrame({ index, importers, root: ${JSON.stringify(root)}, setup });\n`,\n };\n\n function reindex(server: ViteDevServer, file: string, event: 'add' | 'change' | 'unlink'): void {\n const current = files();\n if (event === 'change' && !current.has(file)) return;\n if (event === 'add' && !matches(file)) return;\n if (event === 'unlink' && !current.has(file)) return;\n\n const before = JSON.stringify(index());\n if (event === 'unlink') {\n current.delete(file);\n } else {\n try {\n current.set(file, read(file));\n } catch (err) {\n logError(err);\n return;\n }\n }\n const next = index();\n if (JSON.stringify(next) === before) return;\n\n for (const env of Object.values(server.environments)) {\n for (const name of ['index.js', 'importers.js']) {\n const mod = env.moduleGraph.getModuleById(`\\0${PREFIX}${name}`);\n if (mod) env.moduleGraph.invalidateModule(mod);\n }\n }\n server.ws.send({ type: 'custom', event: 'forge:index', data: next });\n }\n\n return [\n ...(options.storybookShims === false ? [] : [storybookShims()]),\n {\n name: 'weaselforge',\n config(config, { command }) {\n const at = resolve(config.root ?? process.cwd());\n // The pages are virtual, so vite's scan finds no entry of its own to crawl for dependencies.\n const entries = [\n ...options.stories,\n ...[options.frameConfig, options.shellConfig].flatMap((path) => (path ? [resolve(at, path)] : [])),\n ...ownEntries(),\n ];\n const optimizeDeps = { entries };\n if (command !== 'build') return { optimizeDeps };\n return { optimizeDeps, build: { rolldownOptions: { input: writePages(at) } } };\n },\n generateBundle: {\n order: 'post',\n handler(_, bundle) {\n hoistPages(bundle, (file) => this.emitFile(file));\n },\n },\n configResolved(config) {\n root = config.root;\n base = config.base;\n logger = config.logger;\n byFile = null;\n },\n resolveId(id) {\n return id.startsWith(PREFIX) && MODULES.has(id.slice(PREFIX.length)) ? `\\0${id}` : undefined;\n },\n load(id) {\n if (!id.startsWith(`\\0${PREFIX}`)) return undefined;\n return modules[id.slice(PREFIX.length + 1)]?.();\n },\n configureServer(server) {\n server.watcher.add([...files().keys()]);\n for (const event of ['add', 'change', 'unlink'] as const) {\n server.watcher.on(event, (file) => reindex(server, resolve(file), event));\n }\n server.middlewares.use((req, res, next) => {\n const url = req.url ?? '/';\n const path = url.split('?')[0] ?? '/';\n const prefix = base.endsWith('/') ? base.slice(0, -1) : base;\n const page = path === prefix ? '/' : path.startsWith(`${prefix}/`) ? path.slice(prefix.length) : null;\n const entry = req.method === 'GET' && page !== null ? PAGES[page] : undefined;\n if (!entry) return next();\n server.transformIndexHtml(url, html(entry)).then(\n (doc) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(doc);\n },\n (err: unknown) => next(err),\n );\n });\n },\n },\n ];\n}\n","import { matchesGlob, relative, resolve, sep } from 'node:path';\nimport type { Plugin } from 'vite';\nimport { indexFile } from './indexFile';\nimport { storybookShims } from './storybookShims';\n\nexport interface ForgeTestOptions {\n /** Globs of story files, relative to the vite root. Each matching file becomes a test file. */\n stories: string[];\n /** Path to the frame config module, relative to the vite root; it sets up every story. Optional. */\n frameConfig?: string;\n /** Alias Storybook's runtime modules to forge shims. Default true. */\n storybookShims?: boolean;\n}\n\nconst TIMEOUT_MS = 15_000;\n\n/**\n * A vite plugin for vitest browser mode: every story in a matching file runs as one test, rendered and played\n * through forge's frame in the test page itself.\n */\nexport function forgeTest(options: ForgeTestOptions): Plugin[] {\n let root = process.cwd();\n\n const matches = (id: string): boolean => {\n if (id.startsWith('\\0') || id.includes('?')) return false;\n const path = relative(root, id).split(sep).join('/');\n if (path.startsWith('../') || path.split('/').includes('node_modules')) return false;\n return options.stories.some((pattern) => matchesGlob(path, pattern));\n };\n\n return [\n ...(options.storybookShims === false ? [] : [storybookShims()]),\n {\n name: 'weaselforge:test',\n enforce: 'pre',\n configResolved(config) {\n root = config.root;\n },\n transform(code, id) {\n if (!matches(id)) return undefined;\n const entries = indexFile(code, id, root);\n if (entries.length === 0) return undefined;\n const q = (value: string) => JSON.stringify(value);\n // The module comes from its own URL at test time: vitest imports a test file with a cache-busting query,\n // so a static self-import would evaluate the file a second time and register every test twice.\n const lines = [\n '',\n `import { test as __forge_test } from \"vitest\";`,\n `import { page as __forge_page } from \"vitest/browser\";`,\n `import { runStory as __forge_runStory } from \"@weasel-js/forge/test\";`,\n `import \"@weasel-js/forge/frame.css\";`,\n ...(options.frameConfig ? [`import __forge_frame_config from ${q(resolve(root, options.frameConfig))};`] : []),\n `const __forge_file = ${q(id)};`,\n `const __forge_root = ${q(root)};`,\n `const __forge_timeout = ${TIMEOUT_MS};`,\n 'const __forge_options = {',\n ` setup: ${options.frameConfig ? '__forge_frame_config' : 'undefined'},`,\n ' viewport: (width, height) => __forge_page.viewport(width, height),',\n '};',\n 'const __forge_run = async (exportName) => __forge_runStory(await import(/* @vite-ignore */ import.meta.url), exportName, __forge_file, __forge_root, __forge_options);',\n ...entries.map(\n (entry) => `__forge_test(${q(entry.name)}, () => __forge_run(${q(entry.exportName)}), __forge_timeout);`,\n ),\n ];\n return { code: `${code}\\n${lines.join('\\n')}\\n`, map: null };\n },\n },\n ];\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@weasel-js/forge",
3
+ "version": "1.5.0",
4
+ "description": "A component workshop on labkit: stories in isolated frames, controls and state in lab trials.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": [
8
+ "*.css"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./vite": {
16
+ "types": "./dist/vite/index.d.ts",
17
+ "import": "./dist/vite/index.js"
18
+ },
19
+ "./frame": {
20
+ "types": "./dist/frame/index.d.ts",
21
+ "import": "./dist/frame/index.js"
22
+ },
23
+ "./shell": {
24
+ "types": "./dist/shell/index.d.ts",
25
+ "import": "./dist/shell/index.js"
26
+ },
27
+ "./preview-api": {
28
+ "types": "./dist/csf/preview-api.d.ts",
29
+ "import": "./dist/csf/preview-api.js"
30
+ },
31
+ "./test": {
32
+ "types": "./dist/test/index.d.ts",
33
+ "import": "./dist/test/index.js"
34
+ },
35
+ "./shell.css": "./dist/shell/index.css",
36
+ "./frame.css": "./dist/frame/index.css",
37
+ "./package.json": "./package.json"
38
+ },
39
+ "bin": {
40
+ "weaselforge": "./dist/cli.js"
41
+ },
42
+ "author": "orochi235",
43
+ "homepage": "https://orochi235.github.io/weasel/",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/orochi235/weasel.git",
47
+ "directory": "packages/forge"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/orochi235/weasel/issues"
51
+ },
52
+ "engines": {
53
+ "node": ">=22"
54
+ },
55
+ "files": [
56
+ "dist",
57
+ "README.md",
58
+ "LICENSE"
59
+ ],
60
+ "scripts": {
61
+ "build": "tsup"
62
+ },
63
+ "dependencies": {
64
+ "@babel/parser": "^7.29.0",
65
+ "@weasel-js/theme": "1.5.0"
66
+ },
67
+ "devDependencies": {
68
+ "@babel/types": "^7.29.0"
69
+ },
70
+ "peerDependencies": {
71
+ "@weasel-js/core": "1.5.0",
72
+ "@weasel-js/labkit": "1.5.0",
73
+ "react": "^19.0.0",
74
+ "react-dom": "^19.0.0",
75
+ "vite": "^8.0.0",
76
+ "vitest": "^4.0.0"
77
+ },
78
+ "peerDependenciesMeta": {
79
+ "vitest": {
80
+ "optional": true
81
+ }
82
+ },
83
+ "publishConfig": {
84
+ "access": "public",
85
+ "provenance": true
86
+ }
87
+ }