@recursica/adapter-tester 5.3.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/cli.cjs +12 -11
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +354 -212
- package/dist/cli.js.map +1 -1
- package/dist/devServer.d.ts +5 -2
- package/dist/devServer.d.ts.map +1 -1
- package/dist/fileConfig.d.ts +1 -1
- package/dist/harness/mantineSourceOfTruth.d.ts +1 -1
- package/dist/harness/mantineSourceOfTruth.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.html +226 -3
- package/dist/index.js +1 -1
- package/dist/{mantineSourceOfTruth-6KZlsQ67.cjs → mantineSourceOfTruth-DiQas6OS.cjs} +29 -16
- package/dist/mantineSourceOfTruth-DiQas6OS.cjs.map +1 -0
- package/dist/{mantineSourceOfTruth-CAKhcVCT.js → mantineSourceOfTruth-xUEi1k8U.js} +42 -29
- package/dist/mantineSourceOfTruth-xUEi1k8U.js.map +1 -0
- package/dist/runVisualRegression-CQk97Qkv.js +5051 -0
- package/dist/runVisualRegression-CQk97Qkv.js.map +1 -0
- package/dist/runVisualRegression-DNafR8Lb.cjs +13 -0
- package/dist/runVisualRegression-DNafR8Lb.cjs.map +1 -0
- package/dist/testing/runVisualRegression.d.ts +16 -2
- package/dist/testing/runVisualRegression.d.ts.map +1 -1
- package/dist/testing.cjs +1 -5
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +2 -380
- package/dist/testing.js.map +1 -1
- package/package.json +3 -2
- package/public/index.html +226 -3
- package/dist/index-C6uYPRmx.cjs +0 -9
- package/dist/index-C6uYPRmx.cjs.map +0 -1
- package/dist/index-DqQzFSAH.js +0 -4667
- package/dist/index-DqQzFSAH.js.map +0 -1
- package/dist/mantineSourceOfTruth-6KZlsQ67.cjs.map +0 -1
- package/dist/mantineSourceOfTruth-CAKhcVCT.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";const
|
|
1
|
+
"use strict";const n=require("node:fs"),t=require("node:path"),p=["recursica_variables_scoped.css","recursica_tokens.json","recursica_brand.json","recursica_ui-kit.json"],d="^8.0.0",a="^10.3.3",u="^19.0.0",l={"@storybook/addon-docs":a,"@storybook/addon-a11y":a,"storybook-dark-mode":"^5.0.0"},f={"react-markdown":"^10.1.0"};function y(r){return{name:"adapter-tester-mantine-source-of-truth-harness",private:!0,type:"module",scripts:{storybook:"storybook dev"},dependencies:{"@recursica/adapter-mantine-v8":r.mantineAdapterVersion,"@recursica/storybook-template":r.storybookTemplateVersion,"@recursica/adapter-common":"latest","@mantine/core":d,"@mantine/dates":d,react:u,"react-dom":u,storybook:a,"@storybook/react-vite":a,...l,...f}}}const h=`import { createMainConfig } from "@recursica/storybook-template/main";
|
|
2
2
|
|
|
3
3
|
const config = createMainConfig({
|
|
4
4
|
stories: [
|
|
@@ -20,7 +20,7 @@ export default config;
|
|
|
20
20
|
`;function g(){return`import type { Preview } from "@storybook/react-vite";
|
|
21
21
|
import { createPreviewConfig } from "@recursica/storybook-template/preview";
|
|
22
22
|
import { MantineProvider } from "@mantine/core";
|
|
23
|
-
import { Layer } from "@recursica/adapter-common";
|
|
23
|
+
import { Layer, RecursicaManifestContext } from "@recursica/adapter-common";
|
|
24
24
|
import "@mantine/core/styles.css";
|
|
25
25
|
import "@mantine/dates/styles.css";
|
|
26
26
|
import "@recursica/adapter-common/style.css";
|
|
@@ -28,6 +28,7 @@ import "../recursica_variables_scoped.css";
|
|
|
28
28
|
import recursicaTokens from "../recursica_tokens.json";
|
|
29
29
|
import recursicaBrand from "../recursica_brand.json";
|
|
30
30
|
import recursicaUIKit from "../recursica_ui-kit.json";
|
|
31
|
+
import recursicaManifest from "../recursica_manifest.json";
|
|
31
32
|
|
|
32
33
|
const basePreview = createPreviewConfig({
|
|
33
34
|
defaultTheme: "light",
|
|
@@ -54,13 +55,15 @@ const preview: Preview = {
|
|
|
54
55
|
const content = <Story />;
|
|
55
56
|
return (
|
|
56
57
|
<MantineProvider>
|
|
57
|
-
{
|
|
58
|
-
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
<RecursicaManifestContext.Provider value={recursicaManifest}>
|
|
59
|
+
{withLayer ? (
|
|
60
|
+
<Layer layer={layer as 0 | 1 | 2 | 3} style={{ padding: "48px" }}>
|
|
61
|
+
{content}
|
|
62
|
+
</Layer>
|
|
63
|
+
) : (
|
|
64
|
+
content
|
|
65
|
+
)}
|
|
66
|
+
</RecursicaManifestContext.Provider>
|
|
64
67
|
</MantineProvider>
|
|
65
68
|
);
|
|
66
69
|
},
|
|
@@ -69,21 +72,31 @@ const preview: Preview = {
|
|
|
69
72
|
};
|
|
70
73
|
|
|
71
74
|
export default preview;
|
|
72
|
-
`}function
|
|
75
|
+
`}function w(r,e,o){const s=r==="target"?o:t.join(e,"node_modules/@recursica/adapter-mantine-v8"),i=o??s;return`import { copyFileSync, existsSync, writeFileSync } from "node:fs";
|
|
73
76
|
import { join } from "node:path";
|
|
74
77
|
|
|
75
|
-
const sourceDir = ${JSON.stringify(
|
|
78
|
+
const sourceDir = ${JSON.stringify(s)};
|
|
76
79
|
const destDir = ${JSON.stringify(e)};
|
|
77
|
-
const files = ${JSON.stringify(
|
|
80
|
+
const files = ${JSON.stringify(p,null,2)};
|
|
81
|
+
const manifestDir = ${JSON.stringify(i)};
|
|
78
82
|
|
|
79
83
|
for (const file of files) {
|
|
80
84
|
copyFileSync(join(sourceDir, file), join(destDir, file));
|
|
81
85
|
}
|
|
86
|
+
const manifestSource = join(manifestDir, "recursica_manifest.json");
|
|
87
|
+
if (existsSync(manifestSource)) {
|
|
88
|
+
copyFileSync(manifestSource, join(destDir, "recursica_manifest.json"));
|
|
89
|
+
} else {
|
|
90
|
+
writeFileSync(join(destDir, "recursica_manifest.json"), "{}");
|
|
91
|
+
console.warn(
|
|
92
|
+
\`[adapter-tester] WARNING: no recursica_manifest.json at \${manifestSource} — using an empty manifest. Stories that read the manifest (e.g. Pagination) will fail on the Mantine side.\`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
82
95
|
|
|
83
96
|
console.log(\`[adapter-tester] copied Recursica tokens from \${sourceDir}\`);
|
|
84
|
-
`}function
|
|
85
|
-
`),
|
|
97
|
+
`}function m(r){const{dir:e,mantineAdapterVersion:o="latest",storybookTemplateVersion:s="latest",tokensSource:i="target",targetDir:c}=r;if(i==="target"&&!c)throw new Error(`mantineSourceOfTruthWebServer: tokensSource "target" (the default) requires targetDir — the target adapter's own repo root, source of its 4 committed Recursica token files.`);return n.mkdirSync(t.join(e,".storybook"),{recursive:!0}),n.writeFileSync(t.join(e,"package.json"),JSON.stringify(y({mantineAdapterVersion:o,storybookTemplateVersion:s}),null,2)+`
|
|
98
|
+
`),n.writeFileSync(t.join(e,".storybook/main.ts"),h),n.writeFileSync(t.join(e,".storybook/preview.tsx"),g()),n.writeFileSync(t.join(e,"copy-tokens.mjs"),w(i,e,c)),n.writeFileSync(t.join(e,".gitignore"),`node_modules
|
|
86
99
|
*.json
|
|
87
100
|
*.css
|
|
88
|
-
`),e}function v(r){const e=
|
|
89
|
-
//# sourceMappingURL=mantineSourceOfTruth-
|
|
101
|
+
`),e}function v(r){const e=m(r),{mantineAdapterVersion:o="latest",storybookTemplateVersion:s="latest"}=r;return{command:`npm install @recursica/adapter-mantine-v8@${o} @recursica/storybook-template@${s} --no-audit --no-fund && node copy-tokens.mjs && npm run storybook`,port:r.port,cwd:e,reuseExistingServer:!process.env.CI,cacheFile:t.join(e,"last-port.json"),timeout:180*1e3}}exports.mantineSourceOfTruthWebServer=v;exports.scaffoldMantineSourceOfTruthHarness=m;
|
|
102
|
+
//# sourceMappingURL=mantineSourceOfTruth-DiQas6OS.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mantineSourceOfTruth-DiQas6OS.cjs","sources":["../src/harness/mantineSourceOfTruth.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/** The 4 Recursica token files every real adapter commits at its own repo root. */\nconst TOKEN_FILES = [\n \"recursica_variables_scoped.css\",\n \"recursica_tokens.json\",\n \"recursica_brand.json\",\n \"recursica_ui-kit.json\",\n];\n\n/**\n * Generates a small, throwaway Storybook project that installs\n * `@recursica/adapter-mantine-v8` as a real npm dependency (not a workspace\n * link) and boots a real Storybook from its published `src/**\\/*.stories.tsx`\n * files, using `@recursica/storybook-template`'s exported factories.\n *\n * This lets any repo — including ones that never checked out the Recursica\n * monorepo — run adapter-tester's visual regression suite against Mantine\n * (Recursica's source-of-truth adapter) as one side of the comparison, while\n * the other side is that repo's own already-running local Storybook.\n *\n * See PROPOSAL-installed-package-harness.md for the verified prototype this\n * is built from, and the three upstream gaps it works around.\n */\n\n/**\n * Which Recursica token snapshot the harness's Mantine components render\n * with:\n *\n * - `\"target\"` (default): the target adapter's own committed\n * `recursica_variables_scoped.css`/`recursica_tokens.json`/\n * `recursica_brand.json`/`recursica_ui-kit.json` (read from `targetDir`,\n * copied into the harness once `npm install` finishes) — makes the\n * divergence check mean exactly \"given the *same* tokens this target\n * adapter is using, does it render the same as Mantine's own components,\"\n * isolating adapter-mapping correctness from any token-snapshot drift\n * between the two repos.\n * - `\"mantine-package\"`: `@recursica/adapter-mantine-v8`'s own bundled\n * token files (whatever it was last published with) — tests against\n * Mantine's own understanding of the tokens instead, which also (as a\n * side effect) flags a target repo whose own committed tokens have gone\n * stale relative to Mantine's.\n *\n * Never `@recursica/official-release` — confirmed live (not a theoretical\n * concern) to be a stale, retired, generic token snapshot unrelated to\n * either adapter's real ones: it resolves the brand's primary/secondary\n * fonts to Lexend/Bellota Text, not this design system's actual Dongle/\n * Nunito Sans. An earlier version of this harness imported from it\n * directly — this type/its two real options replace that entirely.\n */\nexport type MantineSourceOfTruthTokensSource = \"target\" | \"mantine-package\";\n\nexport interface MantineSourceOfTruthHarnessOptions {\n /**\n * Directory the harness project is scaffolded into. Regenerated on every\n * call — add it to your .gitignore rather than committing it.\n */\n dir: string;\n /** First-guess port, shown for `--dry-run` visibility only. The harness's\n * Storybook is never pinned to this — see `HarnessWebServerConfig.port`. */\n port: number;\n /** npm version/range for @recursica/adapter-mantine-v8. Defaults to \"latest\". */\n mantineAdapterVersion?: string;\n /** npm version/range for @recursica/storybook-template. Defaults to \"latest\". */\n storybookTemplateVersion?: string;\n /** See `MantineSourceOfTruthTokensSource`. Defaults to `\"target\"`. */\n tokensSource?: MantineSourceOfTruthTokensSource;\n /**\n * The target adapter's own repo root — required when `tokensSource` is\n * `\"target\"` (the default), the source the 4 token files are copied\n * from. Unused (and not required) for `\"mantine-package\"`.\n */\n targetDir?: string;\n}\n\nexport interface HarnessWebServerConfig {\n command: string;\n /** First-guess port, shown for `--dry-run` visibility only — not\n * authoritative. The real port is whatever this Storybook's own startup\n * banner reports once it's actually running (see portDiscovery.ts), since\n * Storybook silently falls back to an OS-assigned port whenever this one\n * is taken. */\n port: number;\n cwd: string;\n reuseExistingServer: boolean;\n /** File the real, detected port is cached in between runs, so a later\n * `reuseExistingServer` run can find this instance again. */\n cacheFile: string;\n timeout: number;\n}\n\n// Peer/dev ranges pinned to what @recursica/adapter-mantine-v8 and\n// @recursica/storybook-template themselves require, so the harness can't\n// drift onto an incompatible Mantine or Storybook major version.\nconst MANTINE_CORE_RANGE = \"^8.0.0\";\nconst STORYBOOK_RANGE = \"^10.3.3\";\nconst REACT_RANGE = \"^19.0.0\";\n\n// storybook-template's createMainConfig() defaults its addons list to these\n// three but doesn't declare them as peerDependencies (proposal gap 2) — a\n// harness that skips installing any of them gets a silent \"could not\n// resolve addon\" warning at boot, then a hard runtime crash later when Vite\n// pre-bundles preview.tsx's dependency graph. Installed explicitly here.\nconst DEFAULT_ADDON_DEPENDENCIES = {\n \"@storybook/addon-docs\": STORYBOOK_RANGE,\n \"@storybook/addon-a11y\": STORYBOOK_RANGE,\n \"storybook-dark-mode\": \"^5.0.0\",\n};\n\n// adapter-mantine-v8's Introduction.stories.tsx (Version.tsx/OverStyling.tsx)\n// needs react-markdown, but it's a devDependency there — Storybook-only,\n// never bundled into dist — so an external `npm install` of the published\n// package won't pull it in. The harness boots a real Storybook against\n// src/, so it must provide this itself. Installed explicitly here.\nconst WORKAROUND_DEPENDENCIES = {\n \"react-markdown\": \"^10.1.0\",\n};\n\nfunction harnessPackageJson(options: {\n mantineAdapterVersion: string;\n storybookTemplateVersion: string;\n}) {\n return {\n name: \"adapter-tester-mantine-source-of-truth-harness\",\n private: true,\n type: \"module\",\n scripts: {\n // No `-p` pin — Storybook silently falls back to an OS-assigned port\n // whenever its default is taken, so the caller detects the real port\n // from this process's own output rather than trusting a fixed one.\n storybook: `storybook dev`,\n },\n dependencies: {\n \"@recursica/adapter-mantine-v8\": options.mantineAdapterVersion,\n \"@recursica/storybook-template\": options.storybookTemplateVersion,\n \"@recursica/adapter-common\": \"latest\",\n \"@mantine/core\": MANTINE_CORE_RANGE,\n \"@mantine/dates\": MANTINE_CORE_RANGE,\n react: REACT_RANGE,\n \"react-dom\": REACT_RANGE,\n storybook: STORYBOOK_RANGE,\n \"@storybook/react-vite\": STORYBOOK_RANGE,\n ...DEFAULT_ADDON_DEPENDENCIES,\n ...WORKAROUND_DEPENDENCIES,\n },\n };\n}\n\nconst MAIN_TS = `import { createMainConfig } from \"@recursica/storybook-template/main\";\n\nconst config = createMainConfig({\n stories: [\n \"../node_modules/@recursica/adapter-mantine-v8/src/**/*.stories.@(js|jsx|mjs|ts|tsx)\",\n ],\n enableCORS: true,\n});\n\n// react-docgen-typescript can't resolve a TS project for a config file living\n// in .storybook/ when the component source it's docgen'ing lives three\n// directories down inside node_modules — it throws \"Cannot read properties\n// of undefined (reading 'fileExists')\", which surfaces as a plain 404 on\n// preview.tsx. Docgen only powers Storybook's Controls/Docs tables, which\n// this harness never renders, so disabling it is a safe workaround (see\n// PROPOSAL-installed-package-harness.md, gap 3).\nconfig.typescript = { ...config.typescript, reactDocgen: false };\n\nexport default config;\n`;\n\n// Both `tokensSource` modes copy the 4 token files into the harness's own\n// root (see `copyTokensScript()`) before Storybook boots, rather than\n// importing a package subpath directly — `@recursica/adapter-mantine-v8`'s\n// own `package.json` `exports` map only lists `\".\"`/`\"./style.css\"`, so a\n// bare `import \"@recursica/adapter-mantine-v8/recursica_tokens.json\"` would\n// fail to resolve under strict ESM exports-map enforcement even though the\n// file physically ships in the package (confirmed by reading that package's\n// real, installed `package.json` directly). Copying sidesteps that\n// entirely, and gives both modes the identical, simple `../recursica_*`\n// relative-import shape a real adapter's own `preview.tsx` already uses.\nfunction previewTsx(): string {\n return `import type { Preview } from \"@storybook/react-vite\";\nimport { createPreviewConfig } from \"@recursica/storybook-template/preview\";\nimport { MantineProvider } from \"@mantine/core\";\nimport { Layer, RecursicaManifestContext } from \"@recursica/adapter-common\";\nimport \"@mantine/core/styles.css\";\nimport \"@mantine/dates/styles.css\";\nimport \"@recursica/adapter-common/style.css\";\nimport \"../recursica_variables_scoped.css\";\nimport recursicaTokens from \"../recursica_tokens.json\";\nimport recursicaBrand from \"../recursica_brand.json\";\nimport recursicaUIKit from \"../recursica_ui-kit.json\";\nimport recursicaManifest from \"../recursica_manifest.json\";\n\nconst basePreview = createPreviewConfig({\n defaultTheme: \"light\",\n recursicaTokensJsonPath: recursicaTokens,\n recursicaBrandJsonPath: recursicaBrand,\n recursicaUIKitJsonPath: recursicaUIKit,\n});\n\n// Mirrors adapter-mantine-v8's own .storybook/preview.tsx decorator (every story defaults to\n// withLayer: true, layer: 0, wrapped with 48px padding) — every real adapter's own preview.tsx\n// applies this same wrapping, so a target adapter's story renders inside the same Layer\n// chrome/padding the source-of-truth side does. Without this, target screenshots come out\n// dramatically smaller/differently-positioned than the source of truth's (no Layer padding,\n// background, or border-radius at all), which alone can blow past the pixel-diff threshold\n// regardless of whether the actual Recursica tokens match — a false positive, not a real\n// component bug. ColorSchemeWrapper (adapter-mantine-v8's dark-mode-toggle sync helper) is\n// intentionally not replicated — it only matters for the interactive dev-mode UI, not automated\n// screenshot diffing, which always runs in a single theme.\nconst preview: Preview = {\n ...basePreview,\n decorators: [\n (Story, context) => {\n const { withLayer = true, layer = 0 } = context.args;\n const content = <Story />;\n return (\n <MantineProvider>\n <RecursicaManifestContext.Provider value={recursicaManifest}>\n {withLayer ? (\n <Layer layer={layer as 0 | 1 | 2 | 3} style={{ padding: \"48px\" }}>\n {content}\n </Layer>\n ) : (\n content\n )}\n </RecursicaManifestContext.Provider>\n </MantineProvider>\n );\n },\n ...(basePreview.decorators || []),\n ],\n};\n\nexport default preview;\n`;\n}\n\n/**\n * Generates `copy-tokens.mjs` — run as its own step between `npm install`\n * and `npm run storybook` (see `mantineSourceOfTruthWebServer`'s `command`),\n * not inlined into `scaffoldMantineSourceOfTruthHarness` itself: for\n * `\"mantine-package\"` mode, the source files live inside\n * `node_modules/@recursica/adapter-mantine-v8`, which doesn't exist yet at\n * scaffold time (scaffolding runs before `npm install`) — this script only\n * runs once the package is actually on disk. `\"target\"` mode's source files\n * are already on disk at scaffold time, but uses the same after-install\n * timing for one consistent code path rather than two.\n */\nfunction copyTokensScript(\n tokensSource: MantineSourceOfTruthTokensSource,\n dir: string,\n targetDir: string | undefined,\n): string {\n const sourceDir =\n tokensSource === \"target\"\n ? targetDir!\n : join(dir, \"node_modules/@recursica/adapter-mantine-v8\");\n\n // The mantine package doesn't publish recursica_manifest.json, so it\n // always comes from the target adapter (the Storybook being evaluated).\n // A target without one is tolerated with a warning: an empty manifest is\n // written so preview.tsx's import still resolves, and only stories that\n // actually read the manifest (e.g. Pagination) will fail.\n const manifestDir = targetDir ?? sourceDir;\n\n return `import { copyFileSync, existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst sourceDir = ${JSON.stringify(sourceDir)};\nconst destDir = ${JSON.stringify(dir)};\nconst files = ${JSON.stringify(TOKEN_FILES, null, 2)};\nconst manifestDir = ${JSON.stringify(manifestDir)};\n\nfor (const file of files) {\n copyFileSync(join(sourceDir, file), join(destDir, file));\n}\nconst manifestSource = join(manifestDir, \"recursica_manifest.json\");\nif (existsSync(manifestSource)) {\n copyFileSync(manifestSource, join(destDir, \"recursica_manifest.json\"));\n} else {\n writeFileSync(join(destDir, \"recursica_manifest.json\"), \"{}\");\n console.warn(\n \\`[adapter-tester] WARNING: no recursica_manifest.json at \\${manifestSource} — using an empty manifest. Stories that read the manifest (e.g. Pagination) will fail on the Mantine side.\\`,\n );\n}\n\nconsole.log(\\`[adapter-tester] copied Recursica tokens from \\${sourceDir}\\`);\n`;\n}\n\n/** Writes the harness project's files to `options.dir` without booting it. */\nexport function scaffoldMantineSourceOfTruthHarness(\n options: MantineSourceOfTruthHarnessOptions,\n): string {\n const {\n dir,\n mantineAdapterVersion = \"latest\",\n storybookTemplateVersion = \"latest\",\n tokensSource = \"target\",\n targetDir,\n } = options;\n\n if (tokensSource === \"target\" && !targetDir) {\n throw new Error(\n 'mantineSourceOfTruthWebServer: tokensSource \"target\" (the default) requires targetDir — the target adapter\\'s own repo root, source of its 4 committed Recursica token files.',\n );\n }\n\n mkdirSync(join(dir, \".storybook\"), { recursive: true });\n writeFileSync(\n join(dir, \"package.json\"),\n JSON.stringify(\n harnessPackageJson({\n mantineAdapterVersion,\n storybookTemplateVersion,\n }),\n null,\n 2,\n ) + \"\\n\",\n );\n writeFileSync(join(dir, \".storybook/main.ts\"), MAIN_TS);\n writeFileSync(join(dir, \".storybook/preview.tsx\"), previewTsx());\n writeFileSync(\n join(dir, \"copy-tokens.mjs\"),\n copyTokensScript(tokensSource, dir, targetDir),\n );\n writeFileSync(join(dir, \".gitignore\"), \"node_modules\\n*.json\\n*.css\\n\");\n\n return dir;\n}\n\n/**\n * Scaffolds the harness and returns a Playwright `webServer` entry for it.\n * Spread the result directly into `playwright.config.ts`'s `webServer` array.\n */\nexport function mantineSourceOfTruthWebServer(\n options: MantineSourceOfTruthHarnessOptions,\n): HarnessWebServerConfig {\n const dir = scaffoldMantineSourceOfTruthHarness(options);\n const {\n mantineAdapterVersion = \"latest\",\n storybookTemplateVersion = \"latest\",\n } = options;\n\n // A bare `npm install` is satisfied by a package-lock.json already sitting\n // in `dir` from a prior run and skips re-resolving against the registry\n // entirely — no network call — so a run can silently keep testing against\n // a stale @recursica/adapter-mantine-v8/storybook-template even after a newer\n // version is published. Naming the two version-pinned packages as explicit\n // `pkg@specifier` CLI args instead forces npm to re-check just those two\n // against the registry every run, while the rest of node_modules stays\n // cached. `copy-tokens.mjs` runs after install completes (see its own doc\n // comment for why) and before Storybook boots, so `preview.tsx`'s own\n // `../recursica_*` imports resolve correctly on first render.\n const command = `npm install @recursica/adapter-mantine-v8@${mantineAdapterVersion} @recursica/storybook-template@${storybookTemplateVersion} --no-audit --no-fund && node copy-tokens.mjs && npm run storybook`;\n\n return {\n command,\n port: options.port,\n cwd: dir,\n reuseExistingServer: !process.env.CI,\n cacheFile: join(dir, \"last-port.json\"),\n timeout: 180 * 1000,\n };\n}\n"],"names":["TOKEN_FILES","MANTINE_CORE_RANGE","STORYBOOK_RANGE","REACT_RANGE","DEFAULT_ADDON_DEPENDENCIES","WORKAROUND_DEPENDENCIES","harnessPackageJson","options","MAIN_TS","previewTsx","copyTokensScript","tokensSource","dir","targetDir","sourceDir","join","manifestDir","scaffoldMantineSourceOfTruthHarness","mantineAdapterVersion","storybookTemplateVersion","mkdirSync","writeFileSync","mantineSourceOfTruthWebServer"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { mkdirSync as
|
|
1
|
+
import { mkdirSync as u, writeFileSync as i } from "node:fs";
|
|
2
2
|
import { join as t } from "node:path";
|
|
3
|
-
const
|
|
3
|
+
const p = [
|
|
4
4
|
"recursica_variables_scoped.css",
|
|
5
5
|
"recursica_tokens.json",
|
|
6
6
|
"recursica_brand.json",
|
|
7
7
|
"recursica_ui-kit.json"
|
|
8
|
-
], d = "^8.0.0", a = "^10.3.3",
|
|
8
|
+
], d = "^8.0.0", a = "^10.3.3", m = "^19.0.0", l = {
|
|
9
9
|
"@storybook/addon-docs": a,
|
|
10
10
|
"@storybook/addon-a11y": a,
|
|
11
11
|
"storybook-dark-mode": "^5.0.0"
|
|
@@ -29,8 +29,8 @@ function y(r) {
|
|
|
29
29
|
"@recursica/adapter-common": "latest",
|
|
30
30
|
"@mantine/core": d,
|
|
31
31
|
"@mantine/dates": d,
|
|
32
|
-
react:
|
|
33
|
-
"react-dom":
|
|
32
|
+
react: m,
|
|
33
|
+
"react-dom": m,
|
|
34
34
|
storybook: a,
|
|
35
35
|
"@storybook/react-vite": a,
|
|
36
36
|
...l,
|
|
@@ -62,7 +62,7 @@ function g() {
|
|
|
62
62
|
return `import type { Preview } from "@storybook/react-vite";
|
|
63
63
|
import { createPreviewConfig } from "@recursica/storybook-template/preview";
|
|
64
64
|
import { MantineProvider } from "@mantine/core";
|
|
65
|
-
import { Layer } from "@recursica/adapter-common";
|
|
65
|
+
import { Layer, RecursicaManifestContext } from "@recursica/adapter-common";
|
|
66
66
|
import "@mantine/core/styles.css";
|
|
67
67
|
import "@mantine/dates/styles.css";
|
|
68
68
|
import "@recursica/adapter-common/style.css";
|
|
@@ -70,6 +70,7 @@ import "../recursica_variables_scoped.css";
|
|
|
70
70
|
import recursicaTokens from "../recursica_tokens.json";
|
|
71
71
|
import recursicaBrand from "../recursica_brand.json";
|
|
72
72
|
import recursicaUIKit from "../recursica_ui-kit.json";
|
|
73
|
+
import recursicaManifest from "../recursica_manifest.json";
|
|
73
74
|
|
|
74
75
|
const basePreview = createPreviewConfig({
|
|
75
76
|
defaultTheme: "light",
|
|
@@ -96,13 +97,15 @@ const preview: Preview = {
|
|
|
96
97
|
const content = <Story />;
|
|
97
98
|
return (
|
|
98
99
|
<MantineProvider>
|
|
99
|
-
{
|
|
100
|
-
|
|
101
|
-
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
<RecursicaManifestContext.Provider value={recursicaManifest}>
|
|
101
|
+
{withLayer ? (
|
|
102
|
+
<Layer layer={layer as 0 | 1 | 2 | 3} style={{ padding: "48px" }}>
|
|
103
|
+
{content}
|
|
104
|
+
</Layer>
|
|
105
|
+
) : (
|
|
106
|
+
content
|
|
107
|
+
)}
|
|
108
|
+
</RecursicaManifestContext.Provider>
|
|
106
109
|
</MantineProvider>
|
|
107
110
|
);
|
|
108
111
|
},
|
|
@@ -113,35 +116,45 @@ const preview: Preview = {
|
|
|
113
116
|
export default preview;
|
|
114
117
|
`;
|
|
115
118
|
}
|
|
116
|
-
function
|
|
117
|
-
const s = r === "target" ? o : t(e, "node_modules/@recursica/adapter-mantine-v8");
|
|
118
|
-
return `import { copyFileSync } from "node:fs";
|
|
119
|
+
function v(r, e, o) {
|
|
120
|
+
const s = r === "target" ? o : t(e, "node_modules/@recursica/adapter-mantine-v8"), n = o ?? s;
|
|
121
|
+
return `import { copyFileSync, existsSync, writeFileSync } from "node:fs";
|
|
119
122
|
import { join } from "node:path";
|
|
120
123
|
|
|
121
124
|
const sourceDir = ${JSON.stringify(s)};
|
|
122
125
|
const destDir = ${JSON.stringify(e)};
|
|
123
|
-
const files = ${JSON.stringify(
|
|
126
|
+
const files = ${JSON.stringify(p, null, 2)};
|
|
127
|
+
const manifestDir = ${JSON.stringify(n)};
|
|
124
128
|
|
|
125
129
|
for (const file of files) {
|
|
126
130
|
copyFileSync(join(sourceDir, file), join(destDir, file));
|
|
127
131
|
}
|
|
132
|
+
const manifestSource = join(manifestDir, "recursica_manifest.json");
|
|
133
|
+
if (existsSync(manifestSource)) {
|
|
134
|
+
copyFileSync(manifestSource, join(destDir, "recursica_manifest.json"));
|
|
135
|
+
} else {
|
|
136
|
+
writeFileSync(join(destDir, "recursica_manifest.json"), "{}");
|
|
137
|
+
console.warn(
|
|
138
|
+
\`[adapter-tester] WARNING: no recursica_manifest.json at \${manifestSource} — using an empty manifest. Stories that read the manifest (e.g. Pagination) will fail on the Mantine side.\`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
128
141
|
|
|
129
142
|
console.log(\`[adapter-tester] copied Recursica tokens from \${sourceDir}\`);
|
|
130
143
|
`;
|
|
131
144
|
}
|
|
132
|
-
function
|
|
145
|
+
function k(r) {
|
|
133
146
|
const {
|
|
134
147
|
dir: e,
|
|
135
148
|
mantineAdapterVersion: o = "latest",
|
|
136
149
|
storybookTemplateVersion: s = "latest",
|
|
137
|
-
tokensSource:
|
|
150
|
+
tokensSource: n = "target",
|
|
138
151
|
targetDir: c
|
|
139
152
|
} = r;
|
|
140
|
-
if (
|
|
153
|
+
if (n === "target" && !c)
|
|
141
154
|
throw new Error(
|
|
142
155
|
`mantineSourceOfTruthWebServer: tokensSource "target" (the default) requires targetDir — the target adapter's own repo root, source of its 4 committed Recursica token files.`
|
|
143
156
|
);
|
|
144
|
-
return
|
|
157
|
+
return u(t(e, ".storybook"), { recursive: !0 }), i(
|
|
145
158
|
t(e, "package.json"),
|
|
146
159
|
JSON.stringify(
|
|
147
160
|
y({
|
|
@@ -152,16 +165,16 @@ function v(r) {
|
|
|
152
165
|
2
|
|
153
166
|
) + `
|
|
154
167
|
`
|
|
155
|
-
),
|
|
168
|
+
), i(t(e, ".storybook/main.ts"), h), i(t(e, ".storybook/preview.tsx"), g()), i(
|
|
156
169
|
t(e, "copy-tokens.mjs"),
|
|
157
|
-
|
|
158
|
-
),
|
|
170
|
+
v(n, e, c)
|
|
171
|
+
), i(t(e, ".gitignore"), `node_modules
|
|
159
172
|
*.json
|
|
160
173
|
*.css
|
|
161
174
|
`), e;
|
|
162
175
|
}
|
|
163
|
-
function
|
|
164
|
-
const e =
|
|
176
|
+
function b(r) {
|
|
177
|
+
const e = k(r), {
|
|
165
178
|
mantineAdapterVersion: o = "latest",
|
|
166
179
|
storybookTemplateVersion: s = "latest"
|
|
167
180
|
} = r;
|
|
@@ -175,7 +188,7 @@ function S(r) {
|
|
|
175
188
|
};
|
|
176
189
|
}
|
|
177
190
|
export {
|
|
178
|
-
|
|
179
|
-
|
|
191
|
+
b as m,
|
|
192
|
+
k as s
|
|
180
193
|
};
|
|
181
|
-
//# sourceMappingURL=mantineSourceOfTruth-
|
|
194
|
+
//# sourceMappingURL=mantineSourceOfTruth-xUEi1k8U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mantineSourceOfTruth-xUEi1k8U.js","sources":["../src/harness/mantineSourceOfTruth.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/** The 4 Recursica token files every real adapter commits at its own repo root. */\nconst TOKEN_FILES = [\n \"recursica_variables_scoped.css\",\n \"recursica_tokens.json\",\n \"recursica_brand.json\",\n \"recursica_ui-kit.json\",\n];\n\n/**\n * Generates a small, throwaway Storybook project that installs\n * `@recursica/adapter-mantine-v8` as a real npm dependency (not a workspace\n * link) and boots a real Storybook from its published `src/**\\/*.stories.tsx`\n * files, using `@recursica/storybook-template`'s exported factories.\n *\n * This lets any repo — including ones that never checked out the Recursica\n * monorepo — run adapter-tester's visual regression suite against Mantine\n * (Recursica's source-of-truth adapter) as one side of the comparison, while\n * the other side is that repo's own already-running local Storybook.\n *\n * See PROPOSAL-installed-package-harness.md for the verified prototype this\n * is built from, and the three upstream gaps it works around.\n */\n\n/**\n * Which Recursica token snapshot the harness's Mantine components render\n * with:\n *\n * - `\"target\"` (default): the target adapter's own committed\n * `recursica_variables_scoped.css`/`recursica_tokens.json`/\n * `recursica_brand.json`/`recursica_ui-kit.json` (read from `targetDir`,\n * copied into the harness once `npm install` finishes) — makes the\n * divergence check mean exactly \"given the *same* tokens this target\n * adapter is using, does it render the same as Mantine's own components,\"\n * isolating adapter-mapping correctness from any token-snapshot drift\n * between the two repos.\n * - `\"mantine-package\"`: `@recursica/adapter-mantine-v8`'s own bundled\n * token files (whatever it was last published with) — tests against\n * Mantine's own understanding of the tokens instead, which also (as a\n * side effect) flags a target repo whose own committed tokens have gone\n * stale relative to Mantine's.\n *\n * Never `@recursica/official-release` — confirmed live (not a theoretical\n * concern) to be a stale, retired, generic token snapshot unrelated to\n * either adapter's real ones: it resolves the brand's primary/secondary\n * fonts to Lexend/Bellota Text, not this design system's actual Dongle/\n * Nunito Sans. An earlier version of this harness imported from it\n * directly — this type/its two real options replace that entirely.\n */\nexport type MantineSourceOfTruthTokensSource = \"target\" | \"mantine-package\";\n\nexport interface MantineSourceOfTruthHarnessOptions {\n /**\n * Directory the harness project is scaffolded into. Regenerated on every\n * call — add it to your .gitignore rather than committing it.\n */\n dir: string;\n /** First-guess port, shown for `--dry-run` visibility only. The harness's\n * Storybook is never pinned to this — see `HarnessWebServerConfig.port`. */\n port: number;\n /** npm version/range for @recursica/adapter-mantine-v8. Defaults to \"latest\". */\n mantineAdapterVersion?: string;\n /** npm version/range for @recursica/storybook-template. Defaults to \"latest\". */\n storybookTemplateVersion?: string;\n /** See `MantineSourceOfTruthTokensSource`. Defaults to `\"target\"`. */\n tokensSource?: MantineSourceOfTruthTokensSource;\n /**\n * The target adapter's own repo root — required when `tokensSource` is\n * `\"target\"` (the default), the source the 4 token files are copied\n * from. Unused (and not required) for `\"mantine-package\"`.\n */\n targetDir?: string;\n}\n\nexport interface HarnessWebServerConfig {\n command: string;\n /** First-guess port, shown for `--dry-run` visibility only — not\n * authoritative. The real port is whatever this Storybook's own startup\n * banner reports once it's actually running (see portDiscovery.ts), since\n * Storybook silently falls back to an OS-assigned port whenever this one\n * is taken. */\n port: number;\n cwd: string;\n reuseExistingServer: boolean;\n /** File the real, detected port is cached in between runs, so a later\n * `reuseExistingServer` run can find this instance again. */\n cacheFile: string;\n timeout: number;\n}\n\n// Peer/dev ranges pinned to what @recursica/adapter-mantine-v8 and\n// @recursica/storybook-template themselves require, so the harness can't\n// drift onto an incompatible Mantine or Storybook major version.\nconst MANTINE_CORE_RANGE = \"^8.0.0\";\nconst STORYBOOK_RANGE = \"^10.3.3\";\nconst REACT_RANGE = \"^19.0.0\";\n\n// storybook-template's createMainConfig() defaults its addons list to these\n// three but doesn't declare them as peerDependencies (proposal gap 2) — a\n// harness that skips installing any of them gets a silent \"could not\n// resolve addon\" warning at boot, then a hard runtime crash later when Vite\n// pre-bundles preview.tsx's dependency graph. Installed explicitly here.\nconst DEFAULT_ADDON_DEPENDENCIES = {\n \"@storybook/addon-docs\": STORYBOOK_RANGE,\n \"@storybook/addon-a11y\": STORYBOOK_RANGE,\n \"storybook-dark-mode\": \"^5.0.0\",\n};\n\n// adapter-mantine-v8's Introduction.stories.tsx (Version.tsx/OverStyling.tsx)\n// needs react-markdown, but it's a devDependency there — Storybook-only,\n// never bundled into dist — so an external `npm install` of the published\n// package won't pull it in. The harness boots a real Storybook against\n// src/, so it must provide this itself. Installed explicitly here.\nconst WORKAROUND_DEPENDENCIES = {\n \"react-markdown\": \"^10.1.0\",\n};\n\nfunction harnessPackageJson(options: {\n mantineAdapterVersion: string;\n storybookTemplateVersion: string;\n}) {\n return {\n name: \"adapter-tester-mantine-source-of-truth-harness\",\n private: true,\n type: \"module\",\n scripts: {\n // No `-p` pin — Storybook silently falls back to an OS-assigned port\n // whenever its default is taken, so the caller detects the real port\n // from this process's own output rather than trusting a fixed one.\n storybook: `storybook dev`,\n },\n dependencies: {\n \"@recursica/adapter-mantine-v8\": options.mantineAdapterVersion,\n \"@recursica/storybook-template\": options.storybookTemplateVersion,\n \"@recursica/adapter-common\": \"latest\",\n \"@mantine/core\": MANTINE_CORE_RANGE,\n \"@mantine/dates\": MANTINE_CORE_RANGE,\n react: REACT_RANGE,\n \"react-dom\": REACT_RANGE,\n storybook: STORYBOOK_RANGE,\n \"@storybook/react-vite\": STORYBOOK_RANGE,\n ...DEFAULT_ADDON_DEPENDENCIES,\n ...WORKAROUND_DEPENDENCIES,\n },\n };\n}\n\nconst MAIN_TS = `import { createMainConfig } from \"@recursica/storybook-template/main\";\n\nconst config = createMainConfig({\n stories: [\n \"../node_modules/@recursica/adapter-mantine-v8/src/**/*.stories.@(js|jsx|mjs|ts|tsx)\",\n ],\n enableCORS: true,\n});\n\n// react-docgen-typescript can't resolve a TS project for a config file living\n// in .storybook/ when the component source it's docgen'ing lives three\n// directories down inside node_modules — it throws \"Cannot read properties\n// of undefined (reading 'fileExists')\", which surfaces as a plain 404 on\n// preview.tsx. Docgen only powers Storybook's Controls/Docs tables, which\n// this harness never renders, so disabling it is a safe workaround (see\n// PROPOSAL-installed-package-harness.md, gap 3).\nconfig.typescript = { ...config.typescript, reactDocgen: false };\n\nexport default config;\n`;\n\n// Both `tokensSource` modes copy the 4 token files into the harness's own\n// root (see `copyTokensScript()`) before Storybook boots, rather than\n// importing a package subpath directly — `@recursica/adapter-mantine-v8`'s\n// own `package.json` `exports` map only lists `\".\"`/`\"./style.css\"`, so a\n// bare `import \"@recursica/adapter-mantine-v8/recursica_tokens.json\"` would\n// fail to resolve under strict ESM exports-map enforcement even though the\n// file physically ships in the package (confirmed by reading that package's\n// real, installed `package.json` directly). Copying sidesteps that\n// entirely, and gives both modes the identical, simple `../recursica_*`\n// relative-import shape a real adapter's own `preview.tsx` already uses.\nfunction previewTsx(): string {\n return `import type { Preview } from \"@storybook/react-vite\";\nimport { createPreviewConfig } from \"@recursica/storybook-template/preview\";\nimport { MantineProvider } from \"@mantine/core\";\nimport { Layer, RecursicaManifestContext } from \"@recursica/adapter-common\";\nimport \"@mantine/core/styles.css\";\nimport \"@mantine/dates/styles.css\";\nimport \"@recursica/adapter-common/style.css\";\nimport \"../recursica_variables_scoped.css\";\nimport recursicaTokens from \"../recursica_tokens.json\";\nimport recursicaBrand from \"../recursica_brand.json\";\nimport recursicaUIKit from \"../recursica_ui-kit.json\";\nimport recursicaManifest from \"../recursica_manifest.json\";\n\nconst basePreview = createPreviewConfig({\n defaultTheme: \"light\",\n recursicaTokensJsonPath: recursicaTokens,\n recursicaBrandJsonPath: recursicaBrand,\n recursicaUIKitJsonPath: recursicaUIKit,\n});\n\n// Mirrors adapter-mantine-v8's own .storybook/preview.tsx decorator (every story defaults to\n// withLayer: true, layer: 0, wrapped with 48px padding) — every real adapter's own preview.tsx\n// applies this same wrapping, so a target adapter's story renders inside the same Layer\n// chrome/padding the source-of-truth side does. Without this, target screenshots come out\n// dramatically smaller/differently-positioned than the source of truth's (no Layer padding,\n// background, or border-radius at all), which alone can blow past the pixel-diff threshold\n// regardless of whether the actual Recursica tokens match — a false positive, not a real\n// component bug. ColorSchemeWrapper (adapter-mantine-v8's dark-mode-toggle sync helper) is\n// intentionally not replicated — it only matters for the interactive dev-mode UI, not automated\n// screenshot diffing, which always runs in a single theme.\nconst preview: Preview = {\n ...basePreview,\n decorators: [\n (Story, context) => {\n const { withLayer = true, layer = 0 } = context.args;\n const content = <Story />;\n return (\n <MantineProvider>\n <RecursicaManifestContext.Provider value={recursicaManifest}>\n {withLayer ? (\n <Layer layer={layer as 0 | 1 | 2 | 3} style={{ padding: \"48px\" }}>\n {content}\n </Layer>\n ) : (\n content\n )}\n </RecursicaManifestContext.Provider>\n </MantineProvider>\n );\n },\n ...(basePreview.decorators || []),\n ],\n};\n\nexport default preview;\n`;\n}\n\n/**\n * Generates `copy-tokens.mjs` — run as its own step between `npm install`\n * and `npm run storybook` (see `mantineSourceOfTruthWebServer`'s `command`),\n * not inlined into `scaffoldMantineSourceOfTruthHarness` itself: for\n * `\"mantine-package\"` mode, the source files live inside\n * `node_modules/@recursica/adapter-mantine-v8`, which doesn't exist yet at\n * scaffold time (scaffolding runs before `npm install`) — this script only\n * runs once the package is actually on disk. `\"target\"` mode's source files\n * are already on disk at scaffold time, but uses the same after-install\n * timing for one consistent code path rather than two.\n */\nfunction copyTokensScript(\n tokensSource: MantineSourceOfTruthTokensSource,\n dir: string,\n targetDir: string | undefined,\n): string {\n const sourceDir =\n tokensSource === \"target\"\n ? targetDir!\n : join(dir, \"node_modules/@recursica/adapter-mantine-v8\");\n\n // The mantine package doesn't publish recursica_manifest.json, so it\n // always comes from the target adapter (the Storybook being evaluated).\n // A target without one is tolerated with a warning: an empty manifest is\n // written so preview.tsx's import still resolves, and only stories that\n // actually read the manifest (e.g. Pagination) will fail.\n const manifestDir = targetDir ?? sourceDir;\n\n return `import { copyFileSync, existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst sourceDir = ${JSON.stringify(sourceDir)};\nconst destDir = ${JSON.stringify(dir)};\nconst files = ${JSON.stringify(TOKEN_FILES, null, 2)};\nconst manifestDir = ${JSON.stringify(manifestDir)};\n\nfor (const file of files) {\n copyFileSync(join(sourceDir, file), join(destDir, file));\n}\nconst manifestSource = join(manifestDir, \"recursica_manifest.json\");\nif (existsSync(manifestSource)) {\n copyFileSync(manifestSource, join(destDir, \"recursica_manifest.json\"));\n} else {\n writeFileSync(join(destDir, \"recursica_manifest.json\"), \"{}\");\n console.warn(\n \\`[adapter-tester] WARNING: no recursica_manifest.json at \\${manifestSource} — using an empty manifest. Stories that read the manifest (e.g. Pagination) will fail on the Mantine side.\\`,\n );\n}\n\nconsole.log(\\`[adapter-tester] copied Recursica tokens from \\${sourceDir}\\`);\n`;\n}\n\n/** Writes the harness project's files to `options.dir` without booting it. */\nexport function scaffoldMantineSourceOfTruthHarness(\n options: MantineSourceOfTruthHarnessOptions,\n): string {\n const {\n dir,\n mantineAdapterVersion = \"latest\",\n storybookTemplateVersion = \"latest\",\n tokensSource = \"target\",\n targetDir,\n } = options;\n\n if (tokensSource === \"target\" && !targetDir) {\n throw new Error(\n 'mantineSourceOfTruthWebServer: tokensSource \"target\" (the default) requires targetDir — the target adapter\\'s own repo root, source of its 4 committed Recursica token files.',\n );\n }\n\n mkdirSync(join(dir, \".storybook\"), { recursive: true });\n writeFileSync(\n join(dir, \"package.json\"),\n JSON.stringify(\n harnessPackageJson({\n mantineAdapterVersion,\n storybookTemplateVersion,\n }),\n null,\n 2,\n ) + \"\\n\",\n );\n writeFileSync(join(dir, \".storybook/main.ts\"), MAIN_TS);\n writeFileSync(join(dir, \".storybook/preview.tsx\"), previewTsx());\n writeFileSync(\n join(dir, \"copy-tokens.mjs\"),\n copyTokensScript(tokensSource, dir, targetDir),\n );\n writeFileSync(join(dir, \".gitignore\"), \"node_modules\\n*.json\\n*.css\\n\");\n\n return dir;\n}\n\n/**\n * Scaffolds the harness and returns a Playwright `webServer` entry for it.\n * Spread the result directly into `playwright.config.ts`'s `webServer` array.\n */\nexport function mantineSourceOfTruthWebServer(\n options: MantineSourceOfTruthHarnessOptions,\n): HarnessWebServerConfig {\n const dir = scaffoldMantineSourceOfTruthHarness(options);\n const {\n mantineAdapterVersion = \"latest\",\n storybookTemplateVersion = \"latest\",\n } = options;\n\n // A bare `npm install` is satisfied by a package-lock.json already sitting\n // in `dir` from a prior run and skips re-resolving against the registry\n // entirely — no network call — so a run can silently keep testing against\n // a stale @recursica/adapter-mantine-v8/storybook-template even after a newer\n // version is published. Naming the two version-pinned packages as explicit\n // `pkg@specifier` CLI args instead forces npm to re-check just those two\n // against the registry every run, while the rest of node_modules stays\n // cached. `copy-tokens.mjs` runs after install completes (see its own doc\n // comment for why) and before Storybook boots, so `preview.tsx`'s own\n // `../recursica_*` imports resolve correctly on first render.\n const command = `npm install @recursica/adapter-mantine-v8@${mantineAdapterVersion} @recursica/storybook-template@${storybookTemplateVersion} --no-audit --no-fund && node copy-tokens.mjs && npm run storybook`;\n\n return {\n command,\n port: options.port,\n cwd: dir,\n reuseExistingServer: !process.env.CI,\n cacheFile: join(dir, \"last-port.json\"),\n timeout: 180 * 1000,\n };\n}\n"],"names":["TOKEN_FILES","MANTINE_CORE_RANGE","STORYBOOK_RANGE","REACT_RANGE","DEFAULT_ADDON_DEPENDENCIES","WORKAROUND_DEPENDENCIES","harnessPackageJson","options","MAIN_TS","previewTsx","copyTokensScript","tokensSource","dir","targetDir","sourceDir","join","manifestDir","scaffoldMantineSourceOfTruthHarness","mantineAdapterVersion","storybookTemplateVersion","mkdirSync","writeFileSync","mantineSourceOfTruthWebServer"],"mappings":"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"}
|