@fragments-sdk/cli 0.10.1 → 0.12.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/dist/ai-client-I6MDWNYA.js +21 -0
- package/dist/bin.js +292 -367
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-PW7QTQA6.js → chunk-4OC7FTJB.js} +2 -2
- package/dist/{chunk-HRFUSSZI.js → chunk-AM4MRTMN.js} +2 -2
- package/dist/{chunk-5G3VZH43.js → chunk-GVDSFQ4E.js} +281 -351
- package/dist/chunk-GVDSFQ4E.js.map +1 -0
- package/dist/chunk-JJ2VRTBU.js +626 -0
- package/dist/chunk-JJ2VRTBU.js.map +1 -0
- package/dist/{chunk-D5PYOXEI.js → chunk-LVWFOLUZ.js} +148 -13
- package/dist/{chunk-D5PYOXEI.js.map → chunk-LVWFOLUZ.js.map} +1 -1
- package/dist/{chunk-WXSR2II7.js → chunk-OQKMEFOS.js} +58 -6
- package/dist/chunk-OQKMEFOS.js.map +1 -0
- package/dist/chunk-SXTKFDCR.js +104 -0
- package/dist/chunk-SXTKFDCR.js.map +1 -0
- package/dist/chunk-T5OMVL7E.js +443 -0
- package/dist/chunk-T5OMVL7E.js.map +1 -0
- package/dist/{chunk-ZM4ZQZWZ.js → chunk-TPWGL2XS.js} +39 -37
- package/dist/chunk-TPWGL2XS.js.map +1 -0
- package/dist/{chunk-OQO55NKV.js → chunk-WFS63PCW.js} +85 -11
- package/dist/chunk-WFS63PCW.js.map +1 -0
- package/dist/core/index.js +9 -1
- package/dist/{discovery-NEOY4MPN.js → discovery-ZJQSXF56.js} +3 -3
- package/dist/{generate-FBHSXR3D.js → generate-RJFS2JWA.js} +4 -4
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/init-ZSX3NRCZ.js +636 -0
- package/dist/init-ZSX3NRCZ.js.map +1 -0
- package/dist/mcp-bin.js +2 -2
- package/dist/{scan-CJF2DOQW.js → scan-3PMCJ4RB.js} +6 -6
- package/dist/scan-generate-SYU4PYZD.js +1115 -0
- package/dist/scan-generate-SYU4PYZD.js.map +1 -0
- package/dist/{service-TQYWY65E.js → service-VMGNJZ42.js} +3 -3
- package/dist/snapshot-XOISO2IS.js +139 -0
- package/dist/snapshot-XOISO2IS.js.map +1 -0
- package/dist/{static-viewer-NUBFPKWH.js → static-viewer-5GXH2MGE.js} +3 -3
- package/dist/static-viewer-5GXH2MGE.js.map +1 -0
- package/dist/{test-Z5LVO724.js → test-SI4NSHQX.js} +4 -4
- package/dist/{tokens-CE46OTMD.js → tokens-T6SIVUT5.js} +5 -5
- package/dist/{viewer-DNMNC5VS.js → viewer-7ZEAFBVN.js} +80 -58
- package/dist/viewer-7ZEAFBVN.js.map +1 -0
- package/package.json +6 -14
- package/src/ai-client.ts +156 -0
- package/src/bin.ts +74 -2
- package/src/build.ts +95 -33
- package/src/commands/__tests__/drift-sync.test.ts +252 -0
- package/src/commands/__tests__/scan-generate.test.ts +497 -45
- package/src/commands/enhance.ts +11 -35
- package/src/commands/init.ts +296 -193
- package/src/commands/scan-generate.ts +740 -139
- package/src/commands/scan.ts +37 -32
- package/src/commands/setup.ts +143 -52
- package/src/commands/snapshot.ts +197 -0
- package/src/commands/sync.ts +357 -0
- package/src/commands/validate.ts +43 -1
- package/src/core/component-extractor.test.ts +282 -0
- package/src/core/component-extractor.ts +1030 -0
- package/src/core/discovery.ts +93 -7
- package/src/service/enhance/props-extractor.ts +235 -13
- package/src/validators.ts +236 -0
- package/src/viewer/__tests__/viewer-integration.test.ts +85 -74
- package/src/viewer/server.ts +37 -22
- package/src/viewer/vite-plugin.ts +25 -9
- package/dist/chunk-5G3VZH43.js.map +0 -1
- package/dist/chunk-OQO55NKV.js.map +0 -1
- package/dist/chunk-WXSR2II7.js.map +0 -1
- package/dist/chunk-ZM4ZQZWZ.js.map +0 -1
- package/dist/init-NDQXUWDU.js +0 -796
- package/dist/init-NDQXUWDU.js.map +0 -1
- package/dist/scan-generate-SJAN5MVI.js +0 -691
- package/dist/scan-generate-SJAN5MVI.js.map +0 -1
- package/dist/viewer-DNMNC5VS.js.map +0 -1
- package/src/ai.ts +0 -266
- package/src/commands/init-framework.ts +0 -414
- package/src/mcp/bin.ts +0 -36
- package/src/migrate/bin.ts +0 -114
- package/src/theme/index.ts +0 -77
- package/src/viewer/__tests__/a11y-fixes.test.ts +0 -358
- package/src/viewer/__tests__/jsx-parser.test.ts +0 -502
- package/src/viewer/__tests__/render-utils.test.ts +0 -232
- package/src/viewer/__tests__/style-utils.test.ts +0 -404
- package/src/viewer/assets/fragments-logo.ts +0 -4
- package/src/viewer/assets/fragments_logo.png +0 -0
- package/src/viewer/bin.ts +0 -86
- package/src/viewer/cli/health.ts +0 -256
- package/src/viewer/cli/index.ts +0 -33
- package/src/viewer/cli/scan.ts +0 -124
- package/src/viewer/cli/utils.ts +0 -174
- package/src/viewer/components/AccessibilityPanel.tsx +0 -1457
- package/src/viewer/components/ActionCapture.tsx +0 -172
- package/src/viewer/components/ActionsPanel.tsx +0 -332
- package/src/viewer/components/AllVariantsPreview.tsx +0 -78
- package/src/viewer/components/App.tsx +0 -582
- package/src/viewer/components/BottomPanel.tsx +0 -288
- package/src/viewer/components/CodePanel.naming.test.tsx +0 -59
- package/src/viewer/components/CodePanel.tsx +0 -118
- package/src/viewer/components/CommandPalette.tsx +0 -392
- package/src/viewer/components/ComponentDocView.tsx +0 -164
- package/src/viewer/components/ComponentGraph.tsx +0 -380
- package/src/viewer/components/ComponentHeader.tsx +0 -88
- package/src/viewer/components/ContractPanel.tsx +0 -241
- package/src/viewer/components/EmptyVariantMessage.tsx +0 -54
- package/src/viewer/components/ErrorBoundary.tsx +0 -97
- package/src/viewer/components/FigmaEmbed.tsx +0 -238
- package/src/viewer/components/FragmentEditor.tsx +0 -525
- package/src/viewer/components/FragmentRenderer.tsx +0 -61
- package/src/viewer/components/HeaderSearch.tsx +0 -24
- package/src/viewer/components/HealthDashboard.tsx +0 -441
- package/src/viewer/components/HmrStatusIndicator.tsx +0 -61
- package/src/viewer/components/Icons.tsx +0 -479
- package/src/viewer/components/InteractionsPanel.tsx +0 -757
- package/src/viewer/components/IsolatedPreviewFrame.tsx +0 -346
- package/src/viewer/components/IsolatedRender.tsx +0 -113
- package/src/viewer/components/KeyboardShortcutsHelp.tsx +0 -53
- package/src/viewer/components/LandingPage.tsx +0 -421
- package/src/viewer/components/Layout.tsx +0 -27
- package/src/viewer/components/LeftSidebar.tsx +0 -472
- package/src/viewer/components/LoadErrorMessage.tsx +0 -102
- package/src/viewer/components/MultiViewportPreview.tsx +0 -522
- package/src/viewer/components/NoVariantsMessage.tsx +0 -59
- package/src/viewer/components/PanelShell.tsx +0 -161
- package/src/viewer/components/PerformancePanel.tsx +0 -304
- package/src/viewer/components/PreviewArea.tsx +0 -472
- package/src/viewer/components/PreviewAside.tsx +0 -168
- package/src/viewer/components/PreviewFrameHost.tsx +0 -303
- package/src/viewer/components/PreviewPane.tsx +0 -149
- package/src/viewer/components/PreviewToolbar.tsx +0 -80
- package/src/viewer/components/PropsEditor.tsx +0 -506
- package/src/viewer/components/PropsTable.tsx +0 -111
- package/src/viewer/components/RelationsSection.tsx +0 -88
- package/src/viewer/components/ResizablePanel.tsx +0 -271
- package/src/viewer/components/RightSidebar.tsx +0 -102
- package/src/viewer/components/RuntimeToolsRegistrar.tsx +0 -17
- package/src/viewer/components/ScreenshotButton.tsx +0 -90
- package/src/viewer/components/Sidebar.tsx +0 -169
- package/src/viewer/components/SkeletonLoader.tsx +0 -161
- package/src/viewer/components/ThemeProvider.tsx +0 -42
- package/src/viewer/components/Toast.tsx +0 -3
- package/src/viewer/components/TokenStylePanel.tsx +0 -699
- package/src/viewer/components/TopToolbar.tsx +0 -159
- package/src/viewer/components/UsageSection.tsx +0 -95
- package/src/viewer/components/VariantMatrix.tsx +0 -388
- package/src/viewer/components/VariantRenderer.tsx +0 -131
- package/src/viewer/components/VariantTabs.tsx +0 -40
- package/src/viewer/components/ViewerHeader.tsx +0 -69
- package/src/viewer/components/ViewerStateSync.tsx +0 -52
- package/src/viewer/components/ViewportSelector.tsx +0 -172
- package/src/viewer/components/WebMCPDevTools.tsx +0 -503
- package/src/viewer/components/WebMCPIntegration.tsx +0 -47
- package/src/viewer/components/WebMCPStatusIndicator.tsx +0 -60
- package/src/viewer/components/_future/CreatePage.tsx +0 -836
- package/src/viewer/components/viewer-utils.ts +0 -16
- package/src/viewer/composition-renderer.ts +0 -381
- package/src/viewer/constants/index.ts +0 -1
- package/src/viewer/constants/ui.ts +0 -166
- package/src/viewer/entry.tsx +0 -335
- package/src/viewer/hooks/index.ts +0 -2
- package/src/viewer/hooks/useA11yCache.ts +0 -383
- package/src/viewer/hooks/useA11yService.ts +0 -364
- package/src/viewer/hooks/useActions.ts +0 -138
- package/src/viewer/hooks/useAppState.ts +0 -147
- package/src/viewer/hooks/useCompiledFragments.ts +0 -42
- package/src/viewer/hooks/useFigmaIntegration.ts +0 -132
- package/src/viewer/hooks/useHmrStatus.ts +0 -109
- package/src/viewer/hooks/useKeyboardShortcuts.ts +0 -270
- package/src/viewer/hooks/usePreviewBridge.ts +0 -347
- package/src/viewer/hooks/useScrollSpy.ts +0 -78
- package/src/viewer/hooks/useUrlState.ts +0 -318
- package/src/viewer/hooks/useViewSettings.ts +0 -111
- package/src/viewer/index.html +0 -28
- package/src/viewer/intelligence/healthReport.ts +0 -505
- package/src/viewer/intelligence/styleDrift.ts +0 -340
- package/src/viewer/intelligence/usageScanner.ts +0 -309
- package/src/viewer/jsx-parser.ts +0 -486
- package/src/viewer/preview-frame-entry.tsx +0 -25
- package/src/viewer/preview-frame.html +0 -125
- package/src/viewer/public/favicon.ico +0 -0
- package/src/viewer/render-template.html +0 -68
- package/src/viewer/styles/globals.css +0 -278
- package/src/viewer/types/a11y.ts +0 -197
- package/src/viewer/utils/a11y-fixes.ts +0 -509
- package/src/viewer/utils/actionExport.ts +0 -372
- package/src/viewer/utils/colorSchemes.ts +0 -201
- package/src/viewer/utils/detectRelationships.ts +0 -256
- package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss +0 -10
- package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss.d.ts +0 -2
- package/src/viewer/vendor/shared/src/ComponentDocContent.tsx +0 -274
- package/src/viewer/vendor/shared/src/DocsHeaderBar.tsx +0 -129
- package/src/viewer/vendor/shared/src/DocsPageAsideHost.tsx +0 -89
- package/src/viewer/vendor/shared/src/DocsPageShell.tsx +0 -124
- package/src/viewer/vendor/shared/src/DocsSearchCommand.tsx +0 -99
- package/src/viewer/vendor/shared/src/DocsSidebarNav.tsx +0 -66
- package/src/viewer/vendor/shared/src/PropsTable.module.scss +0 -68
- package/src/viewer/vendor/shared/src/PropsTable.module.scss.d.ts +0 -2
- package/src/viewer/vendor/shared/src/PropsTable.tsx +0 -76
- package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss +0 -114
- package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss.d.ts +0 -2
- package/src/viewer/vendor/shared/src/VariantPreviewCard.tsx +0 -137
- package/src/viewer/vendor/shared/src/docs-data/index.ts +0 -32
- package/src/viewer/vendor/shared/src/docs-data/mcp-configs.ts +0 -72
- package/src/viewer/vendor/shared/src/docs-data/palettes.ts +0 -75
- package/src/viewer/vendor/shared/src/docs-data/setup-examples.ts +0 -55
- package/src/viewer/vendor/shared/src/docs-layout.scss +0 -28
- package/src/viewer/vendor/shared/src/docs-layout.scss.d.ts +0 -2
- package/src/viewer/vendor/shared/src/index.ts +0 -34
- package/src/viewer/vendor/shared/src/types.ts +0 -53
- package/src/viewer/webmcp/__tests__/analytics.test.ts +0 -108
- package/src/viewer/webmcp/analytics.ts +0 -165
- package/src/viewer/webmcp/index.ts +0 -3
- package/src/viewer/webmcp/posthog-bridge.ts +0 -39
- package/src/viewer/webmcp/runtime-tools.ts +0 -152
- package/src/viewer/webmcp/scan-utils.ts +0 -135
- package/src/viewer/webmcp/use-tool-analytics.ts +0 -69
- package/src/viewer/webmcp/viewer-state.ts +0 -45
- /package/dist/{discovery-NEOY4MPN.js.map → ai-client-I6MDWNYA.js.map} +0 -0
- /package/dist/{chunk-PW7QTQA6.js.map → chunk-4OC7FTJB.js.map} +0 -0
- /package/dist/{chunk-HRFUSSZI.js.map → chunk-AM4MRTMN.js.map} +0 -0
- /package/dist/{scan-CJF2DOQW.js.map → discovery-ZJQSXF56.js.map} +0 -0
- /package/dist/{generate-FBHSXR3D.js.map → generate-RJFS2JWA.js.map} +0 -0
- /package/dist/{service-TQYWY65E.js.map → scan-3PMCJ4RB.js.map} +0 -0
- /package/dist/{static-viewer-NUBFPKWH.js.map → service-VMGNJZ42.js.map} +0 -0
- /package/dist/{test-Z5LVO724.js.map → test-SI4NSHQX.js.map} +0 -0
- /package/dist/{tokens-CE46OTMD.js.map → tokens-T6SIVUT5.js.map} +0 -0
|
@@ -7,63 +7,101 @@ import { tmpdir } from "node:os";
|
|
|
7
7
|
import { discoverInstalledFragments } from "../../core/discovery.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Integration tests for the
|
|
10
|
+
* Integration tests for the viewer architecture.
|
|
11
11
|
*
|
|
12
|
-
* After
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
12
|
+
* After the viewer extraction (Delivery A), viewer UI code lives in
|
|
13
|
+
* packages/viewer/ while CLI keeps the Vite server and plugin.
|
|
14
|
+
* These tests verify:
|
|
15
|
+
* - Viewer assets (HTML, TSX entry points) are found in packages/viewer/
|
|
16
|
+
* - The CLI server/plugin reference the viewer package correctly
|
|
17
|
+
* - The @fragments-sdk/cli/core alias resolves to consolidated core source
|
|
16
18
|
* - The virtual module generates valid import statements
|
|
17
|
-
* - The Vite config references correct file system locations
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
|
-
// Simulate the same path resolution used in server.ts and vite-plugin.ts
|
|
21
|
-
// At runtime, __dirname is dist/. In tests (vitest), it's the source dir.
|
|
22
21
|
const testDir = dirname(fileURLToPath(import.meta.url));
|
|
23
22
|
const viewerDir = resolve(testDir, "..");
|
|
24
23
|
const cliPackageRoot = resolve(viewerDir, "../..");
|
|
24
|
+
const packagesRoot = resolve(cliPackageRoot, "..");
|
|
25
|
+
const viewerPackageRoot = resolve(packagesRoot, "viewer");
|
|
26
|
+
const viewerSrc = resolve(viewerPackageRoot, "src");
|
|
25
27
|
|
|
26
|
-
describe("viewer path resolution", () => {
|
|
27
|
-
it("
|
|
28
|
-
|
|
29
|
-
const viewerRoot = resolve(cliPackageRoot, "src/viewer");
|
|
30
|
-
expect(existsSync(resolve(viewerRoot, "index.html"))).toBe(true);
|
|
28
|
+
describe("viewer package path resolution", () => {
|
|
29
|
+
it("viewer package root exists", () => {
|
|
30
|
+
expect(existsSync(viewerPackageRoot)).toBe(true);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
it("
|
|
34
|
-
|
|
35
|
-
expect(existsSync(resolve(viewerRoot, "entry.tsx"))).toBe(true);
|
|
33
|
+
it("viewer package contains index.html at root", () => {
|
|
34
|
+
expect(existsSync(resolve(viewerPackageRoot, "index.html"))).toBe(true);
|
|
36
35
|
});
|
|
37
36
|
|
|
38
|
-
it("
|
|
39
|
-
|
|
40
|
-
expect(existsSync(resolve(viewerRoot, "preview-frame.html"))).toBe(true);
|
|
37
|
+
it("viewer package contains entry.tsx", () => {
|
|
38
|
+
expect(existsSync(resolve(viewerSrc, "entry.tsx"))).toBe(true);
|
|
41
39
|
});
|
|
42
40
|
|
|
43
|
-
it("
|
|
44
|
-
|
|
45
|
-
expect(existsSync(resolve(viewerRoot, "preview-frame-entry.tsx"))).toBe(true);
|
|
41
|
+
it("viewer package contains preview-frame.html in src/", () => {
|
|
42
|
+
expect(existsSync(resolve(viewerSrc, "preview-frame.html"))).toBe(true);
|
|
46
43
|
});
|
|
47
44
|
|
|
48
|
-
it("
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
it("viewer package contains preview-frame-entry.tsx", () => {
|
|
46
|
+
expect(existsSync(resolve(viewerSrc, "preview-frame-entry.tsx"))).toBe(
|
|
47
|
+
true
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("viewer package contains render-template.html in src/", () => {
|
|
52
|
+
expect(existsSync(resolve(viewerSrc, "render-template.html"))).toBe(true);
|
|
51
53
|
});
|
|
52
54
|
|
|
53
|
-
it("
|
|
54
|
-
|
|
55
|
-
expect(existsSync(resolve(viewerRoot, "tailwind.config.js"))).toBe(false);
|
|
55
|
+
it("viewer package contains shared/index.ts barrel", () => {
|
|
56
|
+
expect(existsSync(resolve(viewerSrc, "shared/index.ts"))).toBe(true);
|
|
56
57
|
});
|
|
57
58
|
|
|
58
|
-
it("
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
it("viewer package contains app/index.ts barrel", () => {
|
|
60
|
+
expect(existsSync(resolve(viewerSrc, "app/index.ts"))).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("CLI viewer server references viewer package", () => {
|
|
65
|
+
it("server.ts has resolveViewerRoot function for monorepo and npm resolution", async () => {
|
|
66
|
+
const serverPath = resolve(viewerDir, "server.ts");
|
|
67
|
+
const content = await readFile(serverPath, "utf-8");
|
|
68
|
+
|
|
69
|
+
expect(content).toContain("function resolveViewerRoot(nodeModulesDir: string)");
|
|
70
|
+
// Checks monorepo path first
|
|
71
|
+
expect(content).toContain('resolve(packagesRoot, "viewer")');
|
|
72
|
+
// Falls back to npm-installed path
|
|
73
|
+
expect(content).toContain("@fragments-sdk/viewer");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("server.ts sets up viewer subpath aliases", async () => {
|
|
77
|
+
const serverPath = resolve(viewerDir, "server.ts");
|
|
78
|
+
const content = await readFile(serverPath, "utf-8");
|
|
79
|
+
|
|
80
|
+
expect(content).toContain("@fragments-sdk/viewer/shared");
|
|
81
|
+
expect(content).toContain("@fragments-sdk/viewer/app");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("server.ts does not reference old resolveFragmentsPackage for core", async () => {
|
|
85
|
+
const serverPath = resolve(viewerDir, "server.ts");
|
|
86
|
+
const content = await readFile(serverPath, "utf-8");
|
|
87
|
+
|
|
88
|
+
expect(content).not.toContain('resolveFragmentsPackage("core"');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("no source files import from @fragments-sdk/cli/core as a runtime dependency", async () => {
|
|
92
|
+
const serverPath = resolve(viewerDir, "server.ts");
|
|
93
|
+
const content = await readFile(serverPath, "utf-8");
|
|
94
|
+
|
|
95
|
+
const lines = content.split("\n");
|
|
96
|
+
const importLines = lines.filter(
|
|
97
|
+
(l) => l.startsWith("import") && l.includes("@fragments-sdk/cli/core")
|
|
98
|
+
);
|
|
99
|
+
expect(importLines).toHaveLength(0);
|
|
61
100
|
});
|
|
62
101
|
});
|
|
63
102
|
|
|
64
103
|
describe("@fragments-sdk/cli/core alias resolution", () => {
|
|
65
104
|
it("core/index.ts exists at the expected path", () => {
|
|
66
|
-
// server.ts: "@fragments-sdk/cli/core": resolve(cliPackageRoot, "src/core/index.ts")
|
|
67
105
|
const corePath = resolve(cliPackageRoot, "src/core/index.ts");
|
|
68
106
|
expect(existsSync(corePath)).toBe(true);
|
|
69
107
|
});
|
|
@@ -71,19 +109,15 @@ describe("@fragments-sdk/cli/core alias resolution", () => {
|
|
|
71
109
|
it("core/index.ts re-exports from @fragments-sdk/core", async () => {
|
|
72
110
|
const corePath = resolve(cliPackageRoot, "src/core/index.ts");
|
|
73
111
|
const content = await readFile(corePath, "utf-8");
|
|
74
|
-
// After core extraction, cli/core is a thin re-export shim
|
|
75
112
|
expect(content).toContain("@fragments-sdk/core");
|
|
76
113
|
});
|
|
77
114
|
});
|
|
78
115
|
|
|
79
116
|
describe("virtual module @fragments-sdk/cli/core import", () => {
|
|
80
117
|
it("vite-plugin generates import from @fragments-sdk/cli/core (resolved via alias)", async () => {
|
|
81
|
-
// The virtual module template in vite-plugin.ts must import from @fragments-sdk/cli/core
|
|
82
|
-
// which is resolved by the Vite alias to the consolidated core source
|
|
83
118
|
const pluginPath = resolve(viewerDir, "vite-plugin.ts");
|
|
84
119
|
const content = await readFile(pluginPath, "utf-8");
|
|
85
120
|
|
|
86
|
-
// The generated virtual module string should reference @fragments-sdk/cli/core
|
|
87
121
|
expect(content).toContain(
|
|
88
122
|
'import { storyModuleToFragment, setPreviewConfig, checkStoryExclusion, isForceIncluded, isConfigExcluded } from "@fragments-sdk/cli/core"'
|
|
89
123
|
);
|
|
@@ -93,43 +127,47 @@ describe("virtual module @fragments-sdk/cli/core import", () => {
|
|
|
93
127
|
const serverPath = resolve(viewerDir, "server.ts");
|
|
94
128
|
const content = await readFile(serverPath, "utf-8");
|
|
95
129
|
|
|
96
|
-
|
|
97
|
-
|
|
130
|
+
expect(content).toContain(
|
|
131
|
+
'"@fragments-sdk/cli/core": resolve(cliPackageRoot, "src/core/index.ts")'
|
|
132
|
+
);
|
|
98
133
|
});
|
|
99
134
|
|
|
100
135
|
it("vite-plugin merges authored variant code from metadata fragments", async () => {
|
|
101
136
|
const pluginPath = resolve(viewerDir, "vite-plugin.ts");
|
|
102
137
|
const content = await readFile(pluginPath, "utf-8");
|
|
103
138
|
|
|
104
|
-
expect(content).toContain(
|
|
139
|
+
expect(content).toContain(
|
|
140
|
+
"if (metaVariant.code && !fragmentVariant.code)"
|
|
141
|
+
);
|
|
105
142
|
expect(content).toContain("fragmentVariant.code = metaVariant.code;");
|
|
106
143
|
});
|
|
107
144
|
});
|
|
108
145
|
|
|
109
146
|
describe("viewer HTML templates", () => {
|
|
110
147
|
it("index.html contains entry.tsx script reference", async () => {
|
|
111
|
-
const htmlPath = resolve(
|
|
148
|
+
const htmlPath = resolve(viewerPackageRoot, "index.html");
|
|
112
149
|
const content = await readFile(htmlPath, "utf-8");
|
|
113
150
|
|
|
114
|
-
// The HTML references /src/entry.tsx which gets rewritten to an absolute path
|
|
115
151
|
expect(content).toContain('src="/src/entry.tsx"');
|
|
116
152
|
});
|
|
117
153
|
|
|
118
154
|
it("preview-frame.html contains preview-frame-entry.tsx reference", async () => {
|
|
119
|
-
const htmlPath = resolve(
|
|
155
|
+
const htmlPath = resolve(viewerSrc, "preview-frame.html");
|
|
120
156
|
const content = await readFile(htmlPath, "utf-8");
|
|
121
157
|
|
|
122
158
|
expect(content).toContain('src="/src/preview-frame-entry.tsx"');
|
|
123
159
|
});
|
|
124
160
|
|
|
125
|
-
it("vite-plugin
|
|
161
|
+
it("vite-plugin resolves viewerAssetsRoot with npm fallback", async () => {
|
|
126
162
|
const pluginPath = resolve(viewerDir, "vite-plugin.ts");
|
|
127
163
|
const content = await readFile(pluginPath, "utf-8");
|
|
128
164
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
expect(content).toContain(
|
|
165
|
+
// Tries monorepo path first
|
|
166
|
+
expect(content).toContain("monorepoViewerSrc");
|
|
167
|
+
// Falls back to npm-installed
|
|
168
|
+
expect(content).toContain("npmViewerSrc");
|
|
169
|
+
// Resolves to a final viewerAssetsRoot
|
|
170
|
+
expect(content).toContain("const viewerAssetsRoot =");
|
|
133
171
|
});
|
|
134
172
|
});
|
|
135
173
|
|
|
@@ -139,7 +177,6 @@ describe("discoverInstalledFragments", () => {
|
|
|
139
177
|
beforeAll(async () => {
|
|
140
178
|
tmpDir = await mkdtemp(resolve(tmpdir(), "fragments-test-"));
|
|
141
179
|
|
|
142
|
-
// Create a fake project with a dependency that has fragments
|
|
143
180
|
await writeFile(
|
|
144
181
|
resolve(tmpDir, "package.json"),
|
|
145
182
|
JSON.stringify({
|
|
@@ -147,7 +184,6 @@ describe("discoverInstalledFragments", () => {
|
|
|
147
184
|
})
|
|
148
185
|
);
|
|
149
186
|
|
|
150
|
-
// @acme/ui declares fragments
|
|
151
187
|
const acmeDir = resolve(tmpDir, "node_modules/@acme/ui");
|
|
152
188
|
await mkdir(resolve(acmeDir, "src/components"), { recursive: true });
|
|
153
189
|
await writeFile(
|
|
@@ -163,7 +199,6 @@ describe("discoverInstalledFragments", () => {
|
|
|
163
199
|
"export default {};"
|
|
164
200
|
);
|
|
165
201
|
|
|
166
|
-
// some-lib does NOT declare fragments
|
|
167
202
|
const someLibDir = resolve(tmpDir, "node_modules/some-lib");
|
|
168
203
|
await mkdir(resolve(someLibDir, "src"), { recursive: true });
|
|
169
204
|
await writeFile(
|
|
@@ -209,27 +244,3 @@ describe("discoverInstalledFragments", () => {
|
|
|
209
244
|
await rm(emptyDir, { recursive: true, force: true });
|
|
210
245
|
});
|
|
211
246
|
});
|
|
212
|
-
|
|
213
|
-
describe("no stale @fragments/* package references", () => {
|
|
214
|
-
it("server.ts does not reference old resolveFragmentsPackage for core", async () => {
|
|
215
|
-
const serverPath = resolve(viewerDir, "server.ts");
|
|
216
|
-
const content = await readFile(serverPath, "utf-8");
|
|
217
|
-
|
|
218
|
-
// Should NOT try to resolve @fragments-sdk/cli/core from node_modules
|
|
219
|
-
expect(content).not.toContain('resolveFragmentsPackage("core"');
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it("no source files import from @fragments-sdk/cli/core as a runtime dependency", async () => {
|
|
223
|
-
// All source-level imports should use relative paths (../core/).
|
|
224
|
-
// Only the generated virtual module string uses @fragments-sdk/cli/core (resolved via alias).
|
|
225
|
-
const serverPath = resolve(viewerDir, "server.ts");
|
|
226
|
-
const content = await readFile(serverPath, "utf-8");
|
|
227
|
-
|
|
228
|
-
// server.ts should import from relative paths, not @fragments-sdk/cli/core
|
|
229
|
-
const lines = content.split("\n");
|
|
230
|
-
const importLines = lines.filter(
|
|
231
|
-
(l) => l.startsWith("import") && l.includes("@fragments-sdk/cli/core")
|
|
232
|
-
);
|
|
233
|
-
expect(importLines).toHaveLength(0);
|
|
234
|
-
});
|
|
235
|
-
});
|
package/src/viewer/server.ts
CHANGED
|
@@ -26,16 +26,38 @@ import { loadConfig, discoverFragmentFiles, discoverInstalledFragments } from ".
|
|
|
26
26
|
import { fragmentsPlugin } from "./vite-plugin.js";
|
|
27
27
|
|
|
28
28
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
|
-
// At runtime, __dirname is dist/.
|
|
29
|
+
// At runtime, __dirname is dist/.
|
|
30
30
|
const cliPackageRoot = resolve(__dirname, "..");
|
|
31
|
-
const viewerRoot = resolve(cliPackageRoot, "src/viewer");
|
|
32
31
|
const packagesRoot = resolve(cliPackageRoot, "..");
|
|
33
32
|
const localUiLibRoot = resolve(packagesRoot, "../libs/ui/src");
|
|
34
|
-
const localSharedLibRoot = resolve(packagesRoot, "../libs/shared/src");
|
|
35
|
-
const vendoredSharedLibRoot = resolve(viewerRoot, "vendor/shared/src");
|
|
36
33
|
const localWebMCPRoot = resolve(packagesRoot, "webmcp/src");
|
|
37
34
|
const localContextRoot = resolve(packagesRoot, "context/src");
|
|
38
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the viewer package root.
|
|
38
|
+
* Monorepo: sibling under packages/.
|
|
39
|
+
* npm-installed: node_modules/@fragments-sdk/viewer.
|
|
40
|
+
*/
|
|
41
|
+
function resolveViewerRoot(nodeModulesDir: string): string {
|
|
42
|
+
// Prefer monorepo sibling (dev mode)
|
|
43
|
+
const monorepoPath = resolve(packagesRoot, "viewer");
|
|
44
|
+
if (existsSync(join(monorepoPath, "src/shared/index.ts"))) {
|
|
45
|
+
return monorepoPath;
|
|
46
|
+
}
|
|
47
|
+
// Installed via npm — resolve from node_modules
|
|
48
|
+
const npmPath = join(nodeModulesDir, "@fragments-sdk/viewer");
|
|
49
|
+
if (existsSync(npmPath)) {
|
|
50
|
+
return npmPath;
|
|
51
|
+
}
|
|
52
|
+
// CLI's own node_modules as last resort
|
|
53
|
+
const cliNpmPath = join(cliPackageRoot, "node_modules/@fragments-sdk/viewer");
|
|
54
|
+
if (existsSync(cliNpmPath)) {
|
|
55
|
+
return cliNpmPath;
|
|
56
|
+
}
|
|
57
|
+
// Fallback to monorepo path (will error later with a clear message)
|
|
58
|
+
return monorepoPath;
|
|
59
|
+
}
|
|
60
|
+
|
|
39
61
|
/**
|
|
40
62
|
* Resolve the @fragments/ui alias to the correct path.
|
|
41
63
|
* In external projects: use the installed @fragments-sdk/ui package.
|
|
@@ -99,21 +121,11 @@ function resolveContextLib(nodeModulesDir: string): string {
|
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
/**
|
|
102
|
-
* Resolve the @fragments-sdk/
|
|
103
|
-
* or vendored viewer fallback for npm installs.
|
|
124
|
+
* Resolve the @fragments-sdk/viewer src directory.
|
|
104
125
|
*/
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
return localSharedLibRoot;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const vendoredIndex = join(vendoredSharedLibRoot, "index.ts");
|
|
112
|
-
if (existsSync(vendoredIndex)) {
|
|
113
|
-
return vendoredSharedLibRoot;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return localSharedLibRoot;
|
|
126
|
+
function resolveViewerLib(nodeModulesDir: string): string {
|
|
127
|
+
const viewerRoot = resolveViewerRoot(nodeModulesDir);
|
|
128
|
+
return resolve(viewerRoot, "src");
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
/**
|
|
@@ -383,7 +395,8 @@ export async function createDevServer(
|
|
|
383
395
|
// Find node_modules (handles monorepo setups)
|
|
384
396
|
const nodeModulesPath = findNodeModules(projectRoot);
|
|
385
397
|
const uiLibRoot = resolveUiLib(nodeModulesPath);
|
|
386
|
-
const
|
|
398
|
+
const viewerRoot = resolveViewerRoot(nodeModulesPath);
|
|
399
|
+
const viewerLibRoot = resolveViewerLib(nodeModulesPath);
|
|
387
400
|
const webmcpLibRoot = resolveWebMCPLib(nodeModulesPath);
|
|
388
401
|
const contextLibRoot = resolveContextLib(nodeModulesPath);
|
|
389
402
|
// Detect whether resolved libs point to source (.ts) or dist (.js)
|
|
@@ -430,7 +443,7 @@ export async function createDevServer(
|
|
|
430
443
|
fs: {
|
|
431
444
|
// Allow serving files from viewer package, project, shared libs, node_modules root, and .storybook
|
|
432
445
|
allow: [
|
|
433
|
-
viewerRoot, uiLibRoot,
|
|
446
|
+
viewerRoot, uiLibRoot, viewerLibRoot, webmcpLibRoot, contextLibRoot,
|
|
434
447
|
projectRoot, configDir, dirname(nodeModulesPath),
|
|
435
448
|
...(hasStorybookDir ? [storybookDir] : []),
|
|
436
449
|
...installedPkgRoots,
|
|
@@ -489,8 +502,10 @@ export async function createDevServer(
|
|
|
489
502
|
...storybookAliases,
|
|
490
503
|
// Resolve @fragments-sdk/ui to local source or installed package
|
|
491
504
|
"@fragments-sdk/ui": uiLibRoot,
|
|
492
|
-
// Resolve @fragments-sdk/
|
|
493
|
-
"@fragments-sdk/shared":
|
|
505
|
+
// Resolve @fragments-sdk/viewer subpaths to viewer package source
|
|
506
|
+
"@fragments-sdk/viewer/shared": join(viewerLibRoot, "shared/index.ts"),
|
|
507
|
+
"@fragments-sdk/viewer/app": join(viewerLibRoot, "app/index.ts"),
|
|
508
|
+
"@fragments-sdk/viewer/docs-data": join(viewerLibRoot, "shared/docs-data/index.ts"),
|
|
494
509
|
// Resolve @fragments-sdk/webmcp subpaths to monorepo source or installed package
|
|
495
510
|
"@fragments-sdk/webmcp/react": isWebMCPSource
|
|
496
511
|
? join(webmcpLibRoot, "react/index.ts")
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import type { Plugin, ViteDevServer, ResolvedConfig } from "vite";
|
|
17
17
|
import { resolve, dirname } from "node:path";
|
|
18
18
|
import { fileURLToPath } from "node:url";
|
|
19
|
+
import { existsSync } from "node:fs";
|
|
19
20
|
import { readFile } from "node:fs/promises";
|
|
20
21
|
import { transform } from "esbuild";
|
|
21
22
|
import type { FragmentsConfig, CompiledFragment } from "../core/index.js";
|
|
@@ -101,8 +102,22 @@ interface CompareResponse {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
104
|
-
// At runtime, __dirname is dist/.
|
|
105
|
-
const
|
|
105
|
+
// At runtime, __dirname is dist/. Try monorepo sibling first, then npm-installed.
|
|
106
|
+
const monorepoViewerSrc = resolve(__dirname, "..", "..", "viewer", "src");
|
|
107
|
+
const npmViewerSrc = (() => {
|
|
108
|
+
// Check CLI's own node_modules
|
|
109
|
+
const cliNm = resolve(__dirname, "..", "node_modules", "@fragments-sdk", "viewer", "src");
|
|
110
|
+
if (existsSync(cliNm)) return cliNm;
|
|
111
|
+
// Walk up to find a node_modules with the viewer
|
|
112
|
+
let dir = resolve(__dirname, "..");
|
|
113
|
+
for (let i = 0; i < 5; i++) {
|
|
114
|
+
const candidate = resolve(dir, "node_modules", "@fragments-sdk", "viewer", "src");
|
|
115
|
+
if (existsSync(candidate)) return candidate;
|
|
116
|
+
dir = resolve(dir, "..");
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
})();
|
|
120
|
+
const viewerAssetsRoot = existsSync(monorepoViewerSrc) ? monorepoViewerSrc : (npmViewerSrc ?? monorepoViewerSrc);
|
|
106
121
|
|
|
107
122
|
// Store pending render requests (for internal render page to pick up)
|
|
108
123
|
const pendingRenders = new Map<
|
|
@@ -2138,12 +2153,13 @@ async function loadFragmentsForContext(
|
|
|
2138
2153
|
* Serve the viewer HTML page.
|
|
2139
2154
|
*/
|
|
2140
2155
|
async function serveViewerHTML(res: any, server: ViteDevServer): Promise<void> {
|
|
2141
|
-
const
|
|
2142
|
-
const
|
|
2156
|
+
const viewerSrc = viewerAssetsRoot;
|
|
2157
|
+
const viewerPkgRoot = resolve(viewerSrc, "..");
|
|
2158
|
+
const entryPath = resolve(viewerSrc, "entry.tsx");
|
|
2143
2159
|
|
|
2144
2160
|
try {
|
|
2145
|
-
// Read the viewer HTML template
|
|
2146
|
-
let html = await readFile(resolve(
|
|
2161
|
+
// Read the viewer HTML template (index.html is at package root, not src/)
|
|
2162
|
+
let html = await readFile(resolve(viewerPkgRoot, "index.html"), "utf-8");
|
|
2147
2163
|
|
|
2148
2164
|
// Rewrite the entry.tsx path to use absolute path to viewer package
|
|
2149
2165
|
html = html.replace("/src/entry.tsx", entryPath);
|
|
@@ -2165,12 +2181,12 @@ async function serveViewerHTML(res: any, server: ViteDevServer): Promise<void> {
|
|
|
2165
2181
|
* This is used for iframe-based component preview with CSS isolation.
|
|
2166
2182
|
*/
|
|
2167
2183
|
async function servePreviewFrameHTML(res: any, server: ViteDevServer): Promise<void> {
|
|
2168
|
-
const
|
|
2169
|
-
const entryPath = resolve(
|
|
2184
|
+
const viewerSrc = viewerAssetsRoot;
|
|
2185
|
+
const entryPath = resolve(viewerSrc, "preview-frame-entry.tsx");
|
|
2170
2186
|
|
|
2171
2187
|
try {
|
|
2172
2188
|
// Read the preview frame HTML template
|
|
2173
|
-
let html = await readFile(resolve(
|
|
2189
|
+
let html = await readFile(resolve(viewerSrc, "preview-frame.html"), "utf-8");
|
|
2174
2190
|
|
|
2175
2191
|
// Rewrite the entry path to use absolute path to viewer package
|
|
2176
2192
|
html = html.replace("/src/preview-frame-entry.tsx", entryPath);
|