@weasel-js/forge 1.7.3 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/{FrameController-RdGggdGA.d.ts → FrameController-BH8xJHZ8.d.ts} +36 -1
- package/dist/{chunk-NYBMOSSR.js → chunk-5N4YP5HS.js} +166 -10
- package/dist/chunk-5N4YP5HS.js.map +1 -0
- package/dist/chunk-CJX3W5HY.js +151 -0
- package/dist/chunk-CJX3W5HY.js.map +1 -0
- package/dist/{chunk-SEK6EKHO.js → chunk-GHTVXHNJ.js} +72 -10
- package/dist/chunk-GHTVXHNJ.js.map +1 -0
- package/dist/{chunk-KIFCYY4F.js → chunk-JQD3MVUQ.js} +4 -4
- package/dist/{chunk-KIFCYY4F.js.map → chunk-JQD3MVUQ.js.map} +1 -1
- package/dist/chunk-KJGXJD3U.js +15 -0
- package/dist/chunk-KJGXJD3U.js.map +1 -0
- package/dist/chunk-L5XM5VKB.js +47 -0
- package/dist/chunk-L5XM5VKB.js.map +1 -0
- package/dist/{chunk-YKN3IAEX.js → chunk-MGQWCPYE.js} +4 -24
- package/dist/chunk-MGQWCPYE.js.map +1 -0
- package/dist/{chunk-JNJGIUYU.js → chunk-NI5FYQHW.js} +8 -5
- package/dist/chunk-NI5FYQHW.js.map +1 -0
- package/dist/{config-BJIgUhiI.d.ts → config-DoLWwEb2.d.ts} +5 -1
- package/dist/csf/preview-api.js +2 -1
- package/dist/csf/preview-api.js.map +1 -1
- package/dist/frame/index.css +1 -0
- package/dist/frame/index.css.map +1 -1
- package/dist/frame/index.d.ts +2 -2
- package/dist/frame/index.js +5 -4
- package/dist/frame/index.js.map +1 -1
- package/dist/index.d.ts +79 -4
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/shell/index.css +14 -0
- package/dist/shell/index.css.map +1 -1
- package/dist/shell/index.d.ts +2 -2
- package/dist/shell/index.js +225 -56
- package/dist/shell/index.js.map +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +6 -5
- package/dist/test/index.js.map +1 -1
- package/dist/vite/index.js +160 -16
- package/dist/vite/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-JNJGIUYU.js.map +0 -1
- package/dist/chunk-NYBMOSSR.js.map +0 -1
- package/dist/chunk-SEK6EKHO.js.map +0 -1
- package/dist/chunk-Y3WZ2EWR.js +0 -15
- package/dist/chunk-Y3WZ2EWR.js.map +0 -1
- package/dist/chunk-YKN3IAEX.js.map +0 -1
package/dist/test/index.d.ts
CHANGED
package/dist/test/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { StoryTrial } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import { loadStories } from '../chunk-
|
|
4
|
-
import '../chunk-
|
|
1
|
+
import { StoryTrial } from '../chunk-GHTVXHNJ.js';
|
|
2
|
+
import '../chunk-NI5FYQHW.js';
|
|
3
|
+
import { loadStories } from '../chunk-5N4YP5HS.js';
|
|
4
|
+
import '../chunk-L5XM5VKB.js';
|
|
5
5
|
import '../chunk-HRGPFQBW.js';
|
|
6
|
-
import '../chunk-
|
|
6
|
+
import '../chunk-MGQWCPYE.js';
|
|
7
|
+
import '../chunk-KJGXJD3U.js';
|
|
7
8
|
import { withValueAtPath } from '@weasel-js/labkit/config';
|
|
8
9
|
import { useState, useEffect } from 'react';
|
|
9
10
|
import { createRoot } from 'react-dom/client';
|
package/dist/test/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/test/runStory.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/test/runStory.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { withValueAtPath } from '@weasel-js/labkit/config';\nimport { type RefObject, useEffect, useState } from 'react';\nimport { createRoot, type Root } from 'react-dom/client';\nimport type { FrameSetup } from '../frame/FrameController';\nimport type { Viewport } from '../protocol/messages';\nimport { StoryTrial } from '../shell/StoryTrial';\nimport { loadStories } from '../story/load';\nimport type { LoadedStory } from '../story/types';\n\n/** Prefixes `error` with the phase it came from, keeping its stack. */\nfunction phased(phase: string, error: unknown): Error {\n const message = error instanceof Error ? error.message : String(error);\n const out = new Error(`${phase} fault: ${message}`, { cause: error });\n if (error instanceof Error && error.stack) out.stack = `${phase} fault: ${error.stack}`;\n return out;\n}\n\nconst settle = () =>\n new Promise<void>((resolve) => {\n requestAnimationFrame(() => setTimeout(resolve, 0));\n });\n\ninterface TestTrialProps {\n story: LoadedStory;\n setup: FrameSetup;\n hostRef: RefObject<HTMLElement | null>;\n /** The config in force after each commit, so `play` reads what the story last wrote. */\n onConfig: (config: unknown) => void;\n onRendered: () => void;\n onError: (error: unknown) => void;\n}\n\n/** The trial a story test runs in: its config and state, held the way a lab trial holds them. */\nfunction TestTrial({ story, setup, hostRef, onConfig, onRendered, onError }: TestTrialProps) {\n const [config, setConfigState] = useState<unknown>(() => story.config.defaults());\n const [state, setState] = useState<unknown>(null);\n useEffect(() => onConfig(config), [config, onConfig]);\n const ctx = {\n config,\n state,\n setConfig: (path: string, value: unknown) => setConfigState((prev: unknown) => withValueAtPath(prev, path, value)),\n setState,\n };\n return <StoryTrial story={story} setup={setup} ctx={ctx} hostRef={hostRef} onRendered={onRendered} onError={onError} />;\n}\n\n/** Options for `runStory`. */\nexport interface RunStoryOptions {\n /** The frame config (`frameConfig`). */\n setup?: FrameSetup;\n /** Resizes the page, for a story that names a viewport. Without it, stories run at whatever size the page is. */\n viewport?: (width: number, height: number) => Promise<void>;\n}\n\n/** Stops the story a timed-out test left mounted. */\nlet leftover: (() => unknown) | null = null;\n/** The page's size before any story resized it; a story with no viewport runs at this size. */\nlet pageSize: Viewport | null = null;\n\n/**\n * Renders one story in the test page the way the workshop does — defaults, no state, no globals — then plays it.\n * Throws on a render the story's boundary caught, or a play function that fails.\n */\nexport async function runStory(\n mod: Record<string, unknown>,\n exportName: string,\n file: string,\n autoTitle: string,\n { setup = {}, viewport }: RunStoryOptions = {},\n): Promise<void> {\n leftover?.();\n let story: LoadedStory | undefined;\n try {\n story = loadStories(mod, autoTitle, setup.parameters).find((s) => s.exportName === exportName);\n } catch (error) {\n throw phased('load', error);\n }\n if (!story) throw new Error(`load fault: ${file} has no story export \"${exportName}\"`);\n\n pageSize ??= { width: window.innerWidth, height: window.innerHeight };\n const size = story.viewport ?? pageSize;\n if (viewport && (window.innerWidth !== size.width || window.innerHeight !== size.height)) {\n await viewport(size.width, size.height);\n }\n\n const container = document.createElement('div');\n document.body.append(container);\n let root: Root | undefined;\n /** Returns what unmounting threw, having released everything else regardless. */\n const cleanup = (): { error: unknown } | null => {\n if (leftover === cleanup) leftover = null;\n let thrown: { error: unknown } | null = null;\n try {\n root?.unmount();\n } catch (error) {\n thrown = { error };\n } finally {\n root = undefined;\n container.remove();\n }\n return thrown;\n };\n leftover = cleanup;\n\n const hostRef: RefObject<HTMLElement | null> = { current: null };\n let config: unknown;\n let renderError: { error: unknown } | null = null;\n let markRendered: () => void = () => {};\n const rendered = new Promise<void>((resolve) => {\n markRendered = resolve;\n });\n const fail = (error: unknown) => {\n renderError ??= { error };\n // An error the boundary could not catch leaves nothing to announce `rendered`; the check below throws instead.\n markRendered();\n };\n const checkRender = () => {\n if (renderError) throw phased('render', renderError.error);\n };\n\n let failure: { error: unknown } | null = null;\n try {\n try {\n await setup.prepare?.(story);\n root = createRoot(container, { onUncaughtError: fail });\n root.render(\n <TestTrial\n story={story}\n setup={setup}\n hostRef={hostRef}\n onConfig={(next) => {\n config = next;\n }}\n onRendered={markRendered}\n onError={fail}\n />,\n );\n } catch (error) {\n throw phased('mount', error);\n }\n await rendered;\n await settle();\n checkRender();\n const host = hostRef.current;\n if (!host) throw new Error('render fault: the story host never mounted');\n if (story.play) {\n try {\n await story.play({ canvasElement: host, config, globals: {} });\n } catch (error) {\n throw phased('play', error);\n }\n await settle();\n checkRender();\n }\n } catch (error) {\n failure = { error };\n }\n const cleanupError = cleanup();\n if (failure) throw failure.error;\n if (cleanupError) throw phased('cleanup', cleanupError.error);\n}\n"]}
|
package/dist/vite/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isGallery } from '../chunk-WEQSLPKT.js';
|
|
2
2
|
import { storyNameFromExport, storyId } from '../chunk-HRGPFQBW.js';
|
|
3
|
-
import {
|
|
3
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, globSync, statSync } from 'fs';
|
|
4
4
|
import { resolve, sep, relative, matchesGlob, dirname, join, basename } from 'path';
|
|
5
5
|
import { parse } from '@babel/parser';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
@@ -344,17 +344,63 @@ function namesIn(node) {
|
|
|
344
344
|
walk(node);
|
|
345
345
|
return out;
|
|
346
346
|
}
|
|
347
|
-
function indexFile(code, file, autoTitle2) {
|
|
347
|
+
function indexFile(code, file, autoTitle2, wrappers = /* @__PURE__ */ new Set()) {
|
|
348
348
|
try {
|
|
349
|
-
|
|
350
|
-
return indexProgram(parse(code, { sourceType: "module", plugins }).program, file, autoTitle2);
|
|
349
|
+
return indexProgram(parseFile(code, file), file, autoTitle2, wrappers);
|
|
351
350
|
} catch (err) {
|
|
352
351
|
throw new Error(`${file}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
353
352
|
}
|
|
354
353
|
}
|
|
355
|
-
function
|
|
354
|
+
function foreignCallees(code, file) {
|
|
355
|
+
const program = parseFile(code, file);
|
|
356
|
+
const { bindings } = scan(program, /* @__PURE__ */ new Set());
|
|
357
|
+
const imported = /* @__PURE__ */ new Map();
|
|
358
|
+
const exported = [];
|
|
359
|
+
for (const stmt of program.body) {
|
|
360
|
+
if (stmt.type === "ImportDeclaration" && stmt.importKind !== "type" && stmt.source.value !== "@weasel-js/forge") {
|
|
361
|
+
for (const spec of stmt.specifiers) {
|
|
362
|
+
if (spec.type === "ImportNamespaceSpecifier" || spec.type === "ImportSpecifier" && spec.importKind === "type") continue;
|
|
363
|
+
const name = spec.type === "ImportDefaultSpecifier" ? "default" : exportedName(spec.imported);
|
|
364
|
+
imported.set(spec.local.name, { local: spec.local.name, spec: stmt.source.value, imported: name });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (stmt.type === "ExportDefaultDeclaration") exported.push(stmt.declaration);
|
|
368
|
+
if (stmt.type !== "ExportNamedDeclaration" || stmt.exportKind === "type") continue;
|
|
369
|
+
if (stmt.declaration?.type === "VariableDeclaration") exported.push(...stmt.declaration.declarations.map((d) => d.init));
|
|
370
|
+
if (stmt.source) continue;
|
|
371
|
+
for (const spec of stmt.specifiers) if (spec.type === "ExportSpecifier") exported.push(bindings.get(exportedName(spec.local)));
|
|
372
|
+
}
|
|
373
|
+
const found = /* @__PURE__ */ new Map();
|
|
374
|
+
for (const node of exported) {
|
|
375
|
+
const hit = imported.get(calleeOf(node ?? void 0, bindings) ?? "");
|
|
376
|
+
if (hit) found.set(hit.local, hit);
|
|
377
|
+
}
|
|
378
|
+
return [...found.values()];
|
|
379
|
+
}
|
|
380
|
+
function parseFile(code, file) {
|
|
381
|
+
const plugins = ["typescript", "decorators-legacy", .../\.[jt]sx$/.test(file) ? ["jsx"] : []];
|
|
382
|
+
return parse(code, { sourceType: "module", plugins }).program;
|
|
383
|
+
}
|
|
384
|
+
function calleeOf(node, bindings, depth = 0) {
|
|
385
|
+
if (!node || depth > 16) return void 0;
|
|
386
|
+
switch (node.type) {
|
|
387
|
+
case "TSSatisfiesExpression":
|
|
388
|
+
case "TSAsExpression":
|
|
389
|
+
case "TSTypeAssertion":
|
|
390
|
+
case "TSNonNullExpression":
|
|
391
|
+
case "ParenthesizedExpression":
|
|
392
|
+
return calleeOf(node.expression, bindings, depth + 1);
|
|
393
|
+
case "CallExpression":
|
|
394
|
+
return node.callee.type === "Identifier" ? node.callee.name : void 0;
|
|
395
|
+
case "Identifier":
|
|
396
|
+
return calleeOf(bindings.get(node.name), bindings, depth + 1);
|
|
397
|
+
default:
|
|
398
|
+
return void 0;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function scan(program, extra) {
|
|
356
402
|
const bindings = /* @__PURE__ */ new Map();
|
|
357
|
-
const wrappers =
|
|
403
|
+
const wrappers = new Set(extra);
|
|
358
404
|
for (const stmt of program.body) {
|
|
359
405
|
if (stmt.type === "ImportDeclaration" && stmt.source.value === "@weasel-js/forge") {
|
|
360
406
|
for (const spec of stmt.specifiers) {
|
|
@@ -368,6 +414,10 @@ function indexProgram(program, file, autoTitle2) {
|
|
|
368
414
|
for (const d of decl.declarations) if (d.id.type === "Identifier" && d.init) bindings.set(d.id.name, d.init);
|
|
369
415
|
}
|
|
370
416
|
}
|
|
417
|
+
return { bindings, wrappers };
|
|
418
|
+
}
|
|
419
|
+
function indexProgram(program, file, autoTitle2, extra) {
|
|
420
|
+
const { bindings, wrappers } = scan(program, extra);
|
|
371
421
|
let metaNode;
|
|
372
422
|
let metaDoc;
|
|
373
423
|
const exported = [];
|
|
@@ -536,6 +586,67 @@ function storybookShims() {
|
|
|
536
586
|
};
|
|
537
587
|
}
|
|
538
588
|
|
|
589
|
+
// src/vite/wrappers.ts
|
|
590
|
+
function createWrapperResolver(read) {
|
|
591
|
+
const modules = /* @__PURE__ */ new Map();
|
|
592
|
+
const info = (file) => {
|
|
593
|
+
if (!modules.has(file)) {
|
|
594
|
+
let parsed = null;
|
|
595
|
+
try {
|
|
596
|
+
parsed = moduleInfo(read(file), file);
|
|
597
|
+
} catch {
|
|
598
|
+
parsed = null;
|
|
599
|
+
}
|
|
600
|
+
modules.set(file, parsed);
|
|
601
|
+
}
|
|
602
|
+
return modules.get(file) ?? null;
|
|
603
|
+
};
|
|
604
|
+
return async (file, callees, resolve4) => {
|
|
605
|
+
const reads = /* @__PURE__ */ new Set();
|
|
606
|
+
const wrappers = /* @__PURE__ */ new Set();
|
|
607
|
+
if (callees.length === 0) return { wrappers, reads };
|
|
608
|
+
const target = async (spec, importer) => {
|
|
609
|
+
const id = (await resolve4(spec, importer).catch(() => null))?.split("?")[0];
|
|
610
|
+
return id && !id.startsWith("\0") ? id : null;
|
|
611
|
+
};
|
|
612
|
+
const declaring = async (at, name, depth = 0) => {
|
|
613
|
+
reads.add(at);
|
|
614
|
+
const mod = info(at);
|
|
615
|
+
if (!mod || depth > 32) return null;
|
|
616
|
+
const exp = mod.exports.get(name);
|
|
617
|
+
if (exp?.kind === "local") {
|
|
618
|
+
const imp = mod.imports.get(exp.local);
|
|
619
|
+
if (!imp) return `${at}#${exp.local}`;
|
|
620
|
+
if (imp.imported === "*") return null;
|
|
621
|
+
const next = await target(imp.spec, at);
|
|
622
|
+
return next ? declaring(next, imp.imported, depth + 1) : null;
|
|
623
|
+
}
|
|
624
|
+
if (exp?.kind === "from") {
|
|
625
|
+
const next = await target(exp.spec, at);
|
|
626
|
+
return next ? declaring(next, exp.imported, depth + 1) : null;
|
|
627
|
+
}
|
|
628
|
+
if (name === "default") return null;
|
|
629
|
+
for (const spec of mod.stars) {
|
|
630
|
+
const next = await target(spec, at);
|
|
631
|
+
const found = next ? await declaring(next, name, depth + 1) : null;
|
|
632
|
+
if (found) return found;
|
|
633
|
+
}
|
|
634
|
+
return null;
|
|
635
|
+
};
|
|
636
|
+
const forge2 = await target("@weasel-js/forge", file);
|
|
637
|
+
if (!forge2) return { wrappers, reads };
|
|
638
|
+
const own = new Set(
|
|
639
|
+
(await Promise.all(["meta", "story"].map((name) => declaring(forge2, name)))).filter((key) => key !== null)
|
|
640
|
+
);
|
|
641
|
+
for (const callee of callees) {
|
|
642
|
+
const from = await target(callee.spec, file);
|
|
643
|
+
const key = from ? await declaring(from, callee.imported) : null;
|
|
644
|
+
if (key && own.has(key)) wrappers.add(callee.local);
|
|
645
|
+
}
|
|
646
|
+
return { wrappers, reads };
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
|
|
539
650
|
// src/vite/plugin.ts
|
|
540
651
|
var PREFIX = "virtual:forge/";
|
|
541
652
|
var MODULES = /* @__PURE__ */ new Set(["index.js", "importers.js", "deps.js", "frame-config.js", "shell-config.js", "shell-entry.js", "frame-entry.js"]);
|
|
@@ -548,6 +659,8 @@ function forge(options) {
|
|
|
548
659
|
let deps = null;
|
|
549
660
|
let depsSent = null;
|
|
550
661
|
let depsPending = null;
|
|
662
|
+
const wrappersOf = /* @__PURE__ */ new Map();
|
|
663
|
+
let settledAll = null;
|
|
551
664
|
const glob = () => {
|
|
552
665
|
const files2 = options.stories.flatMap(
|
|
553
666
|
(pattern) => globSync(pattern, { cwd: root, exclude: (name) => basename(String(name)) === "node_modules" }).map((f) => resolve(root, f)).filter((f) => statSync(f).isFile()).sort()
|
|
@@ -558,7 +671,7 @@ function forge(options) {
|
|
|
558
671
|
const path = relative(root, file).split(sep).join("/");
|
|
559
672
|
return !path.split("/").includes("node_modules") && options.stories.some((pattern) => matchesGlob(path, pattern));
|
|
560
673
|
};
|
|
561
|
-
const read = (file) => indexFile(readFileSync(file, "utf8"), file, autoTitle(file, root, options.stories));
|
|
674
|
+
const read = (file) => indexFile(readFileSync(file, "utf8"), file, autoTitle(file, root, options.stories), wrappersOf.get(file)?.wrappers);
|
|
562
675
|
const logError = (err) => logger?.error(`[forge] ${err instanceof Error ? err.message : String(err)}`);
|
|
563
676
|
const files = () => {
|
|
564
677
|
byFile ??= new Map(
|
|
@@ -574,6 +687,27 @@ function forge(options) {
|
|
|
574
687
|
return byFile;
|
|
575
688
|
};
|
|
576
689
|
const index = () => [...files().values()].flat();
|
|
690
|
+
const settle = async (targets, resolveImport) => {
|
|
691
|
+
const decide = createWrapperResolver((file) => readFileSync(file, "utf8"));
|
|
692
|
+
const current = files();
|
|
693
|
+
for (const file of targets) {
|
|
694
|
+
if (!current.has(file)) continue;
|
|
695
|
+
let next;
|
|
696
|
+
try {
|
|
697
|
+
next = await decide(file, foreignCallees(readFileSync(file, "utf8"), file), resolveImport);
|
|
698
|
+
} catch {
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
const before = wrappersOf.get(file)?.wrappers ?? /* @__PURE__ */ new Set();
|
|
702
|
+
wrappersOf.set(file, next);
|
|
703
|
+
if (before.size === next.wrappers.size && [...before].every((name) => next.wrappers.has(name))) continue;
|
|
704
|
+
try {
|
|
705
|
+
current.set(file, read(file));
|
|
706
|
+
} catch (err) {
|
|
707
|
+
logError(err);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
};
|
|
577
711
|
const depGraph = () => deps ??= createDepGraph({ root, read: (file) => readFileSync(file, "utf8") });
|
|
578
712
|
const configModule = (path) => path ? `export { default } from ${JSON.stringify(resolve(root, path))};
|
|
579
713
|
` : "export default {};\n";
|
|
@@ -654,23 +788,26 @@ import.meta.hot?.accept('virtual:forge/importers.js', () => location.reload());
|
|
|
654
788
|
depsPending = null;
|
|
655
789
|
});
|
|
656
790
|
}
|
|
657
|
-
function reindex(server, file, event) {
|
|
791
|
+
async function reindex(server, file, event) {
|
|
658
792
|
const current = files();
|
|
659
793
|
if (event === "change" && current.has(file)) server.ws.send({ type: "custom", event: "forge:story", data: { file } });
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if (
|
|
794
|
+
const own = event === "add" ? matches(file) : current.has(file);
|
|
795
|
+
const through = [...wrappersOf].filter(([story, { reads }]) => story !== file && reads.has(file)).map(([story]) => story);
|
|
796
|
+
if (!own && through.length === 0) return false;
|
|
663
797
|
const before = JSON.stringify(index());
|
|
664
|
-
if (event === "unlink") {
|
|
798
|
+
if (own && event === "unlink") {
|
|
665
799
|
current.delete(file);
|
|
666
|
-
|
|
800
|
+
wrappersOf.delete(file);
|
|
801
|
+
} else if (own) {
|
|
667
802
|
try {
|
|
668
803
|
current.set(file, read(file));
|
|
669
804
|
} catch (err) {
|
|
670
805
|
logError(err);
|
|
671
|
-
return false;
|
|
806
|
+
if (through.length === 0) return false;
|
|
672
807
|
}
|
|
673
808
|
}
|
|
809
|
+
const resolveImport = async (spec, importer) => (await server.environments.client.pluginContainer.resolveId(spec, importer))?.id ?? null;
|
|
810
|
+
await settle([...own && event !== "unlink" ? [file] : [], ...through], resolveImport);
|
|
674
811
|
const next = index();
|
|
675
812
|
if (JSON.stringify(next) === before) return false;
|
|
676
813
|
invalidate(server, ["index.js", "importers.js"]);
|
|
@@ -703,6 +840,8 @@ import.meta.hot?.accept('virtual:forge/importers.js', () => location.reload());
|
|
|
703
840
|
base = config.base;
|
|
704
841
|
logger = config.logger;
|
|
705
842
|
byFile = null;
|
|
843
|
+
wrappersOf.clear();
|
|
844
|
+
settledAll = null;
|
|
706
845
|
deps = null;
|
|
707
846
|
depsSent = null;
|
|
708
847
|
},
|
|
@@ -712,6 +851,10 @@ import.meta.hot?.accept('virtual:forge/importers.js', () => location.reload());
|
|
|
712
851
|
async load(id) {
|
|
713
852
|
if (!id.startsWith(`\0${PREFIX}`)) return void 0;
|
|
714
853
|
const name = id.slice(PREFIX.length + 1);
|
|
854
|
+
if (name === "index.js") {
|
|
855
|
+
settledAll ??= settle([...files().keys()], async (spec, importer) => (await this.resolve(spec, importer))?.id ?? null);
|
|
856
|
+
await settledAll;
|
|
857
|
+
}
|
|
715
858
|
if (name !== "deps.js") return modules[name]?.();
|
|
716
859
|
const graph = await depGraph().build(index(), async (spec, importer) => (await this.resolve(spec, importer))?.id ?? null);
|
|
717
860
|
depsSent = JSON.stringify(graph);
|
|
@@ -723,11 +866,12 @@ import.meta.hot?.accept('virtual:forge/importers.js', () => location.reload());
|
|
|
723
866
|
for (const event of ["add", "change", "unlink"]) {
|
|
724
867
|
server.watcher.on(event, (path) => {
|
|
725
868
|
const file = resolve(path);
|
|
726
|
-
const indexed = reindex(server, file, event);
|
|
727
869
|
const added = event === "add" && /\.[cm]?[jt]sx?$/.test(file) && !file.split(sep).includes("node_modules");
|
|
728
870
|
if (added) depGraph().reset();
|
|
729
871
|
const read2 = added || event !== "add" && depGraph().invalidate(file);
|
|
730
|
-
|
|
872
|
+
reindex(server, file, event).then((indexed) => {
|
|
873
|
+
if (indexed || read2) redeps(server);
|
|
874
|
+
}, logError);
|
|
731
875
|
});
|
|
732
876
|
}
|
|
733
877
|
server.middlewares.use((req, res, next) => {
|