vibe-design-system 2.5.32 → 2.5.35
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/bin/init.js
CHANGED
|
@@ -253,7 +253,7 @@ function addScripts(projectRoot) {
|
|
|
253
253
|
changed = true;
|
|
254
254
|
}
|
|
255
255
|
if (!scripts["vds:stories"]) {
|
|
256
|
-
scripts["vds:stories"] = "node vds-core/scan.mjs && node vds-core/story-generator.mjs && node vds-core/setup-storybook-providers.mjs";
|
|
256
|
+
scripts["vds:stories"] = "node vds-core/scan.mjs && node vds-core/story-generator.mjs && node vds-core/setup-storybook-providers.mjs && node vds-core/storybook-adapt.mjs";
|
|
257
257
|
changed = true;
|
|
258
258
|
}
|
|
259
259
|
if (!scripts["vds:watch"]) {
|
|
@@ -340,6 +340,18 @@ function runSetupStorybookProviders(projectRoot) {
|
|
|
340
340
|
if (r.status !== 0) process.exitCode = r.status ?? 1;
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
// ADIM 7c — Storybook adapt: mock problematic imports (server-only, next/*) so components load
|
|
344
|
+
function runStorybookAdapt(projectRoot) {
|
|
345
|
+
const adaptPath = path.join(projectRoot, "vds-core", "storybook-adapt.mjs");
|
|
346
|
+
if (!fs.existsSync(adaptPath)) return;
|
|
347
|
+
const r = spawnSync("node", [adaptPath], {
|
|
348
|
+
cwd: projectRoot,
|
|
349
|
+
stdio: "inherit",
|
|
350
|
+
shell: false,
|
|
351
|
+
});
|
|
352
|
+
if (r.status !== 0) process.exitCode = r.status ?? 1;
|
|
353
|
+
}
|
|
354
|
+
|
|
343
355
|
// ADIM 9 — Storybook örnek dosyalarını sil
|
|
344
356
|
function removeStorybookExamples(projectRoot) {
|
|
345
357
|
const storiesDir = path.join(projectRoot, "src", "stories");
|
|
@@ -394,6 +406,7 @@ removeStorybookExamples(projectRoot);
|
|
|
394
406
|
runScan(projectRoot);
|
|
395
407
|
runStoryGenerator(projectRoot);
|
|
396
408
|
runSetupStorybookProviders(projectRoot);
|
|
409
|
+
runStorybookAdapt(projectRoot);
|
|
397
410
|
|
|
398
411
|
// ADIM 8
|
|
399
412
|
console.log("\n✅ VDS kuruldu!");
|
package/package.json
CHANGED
|
@@ -51,7 +51,7 @@ To see **live renders** of components in the dashboard (isolated, no app chrome)
|
|
|
51
51
|
```bash
|
|
52
52
|
npm run vds:stories
|
|
53
53
|
```
|
|
54
|
-
Script
|
|
54
|
+
Script: `scan.mjs` → `story-generator.mjs` → `setup-storybook-providers.mjs` → **`storybook-adapt.mjs`** (dönüştürücü: sorunlu import'ları mock'lar, çözülemeyenleri uyarır).
|
|
55
55
|
|
|
56
56
|
- **Provider'lar:** `vds:stories` içinde zaten çalışır; ayrıca `node vds-core/setup-storybook-providers.mjs` çalıştırmanıza gerek yok. Hooks (useTimer, useSidebar, useCircles, useAuth, useSearch) and inject the matching providers into `.storybook/preview.ts`. Kalan "undefined (reading 'x')" hatalarında ilgili story'de args veya mock state ekleyin.
|
|
57
57
|
|
|
@@ -67,12 +67,24 @@ VDS, **tek komutla** projenizin design system'ını Storybook'ta stilleriyle eş
|
|
|
67
67
|
|
|
68
68
|
Kullanıcının her projede ayrı ayrı provider eklemesi, manuel story düzeltmesi veya birden fazla komut çalıştırması gerekmez. Nadir kalan hatalar (belirli bir component'ın özel context'i) story dosyasında args/mock ile giderilir.
|
|
69
69
|
|
|
70
|
-
**"Failed to fetch dynamically imported module"**
|
|
70
|
+
**"Failed to fetch dynamically imported module"** artık manuel adım gerektirmez: story'ler dinamik import ile üretilir; component yüklenemezse canvas'ta "Component could not be loaded (import error)." mesajı gösterilir, Storybook çökmez.
|
|
71
|
+
|
|
72
|
+
### Test projesinde çıkan hatalar (sorun giderme)
|
|
73
|
+
|
|
74
|
+
| Gördüğünüz mesaj | Ne yapmalı |
|
|
75
|
+
|------------------|------------|
|
|
76
|
+
| **Failed to fetch dynamically imported module: …/X.stories.tsx** | Story dosyası yüklenemiyor. En güncel VDS template’i kullanıp story’leri yeniden üretin: `npm run vds:stories`. Eski template’te statik import vardı; yeni sürümde dinamik import + catch kullanılıyor. |
|
|
77
|
+
| **Cannot read properties of undefined (reading 'dateRange')** (örn. TimeFilterPanel) | `filters` / `dateRange` varsayılanı generator’da var. `npm run vds:stories` tekrar çalıştırın; hâlâ olursa ilgili story’de `args.filters` veya `args.dateRange` manuel ekleyin. |
|
|
78
|
+
| **Cannot read properties of undefined (reading 'toString')** (örn. TaskEstimateInput) | `estimate` / sayısal proplar için varsayılan eklendi. `npm run vds:stories` ile story’leri yenileyin. |
|
|
79
|
+
| **Başlık/component boş** (örn. UnlockModuleModal) | Modal/drawer için `isOpen` veya `open: true` varsayılanı veriliyor. Story’leri yeniden üretin; gerekirse o story’de `args.open = true` veya `args.isOpen = true` kontrol edin. |
|
|
80
|
+
|
|
81
|
+
Genel adım: `vibe-design-system` güncel olsun, sonra proje kökünde **`npm run vds:stories`** çalıştırıp Storybook’u yeniden başlatın.
|
|
71
82
|
|
|
72
83
|
## Layout
|
|
73
84
|
|
|
74
85
|
- `vds-core/scan.mjs` — Projeyi tarar (src/components, CSS, Tailwind). `vds-output.json` ve `public/vds-output.json` yazar.
|
|
75
86
|
- `vds-core/story-generator.mjs` — `vds-output.json`'dan story'leri üretir; varsayılan args: filters/dateRange, sayı, tarih, modal/drawer için isOpen/open: true, onClose/onSave vb. no-op, circle/user/nav/allocation mock objeleri (visibility, path hatalarını önler).
|
|
76
87
|
- `vds-core/setup-storybook-providers.mjs` — Hook ve react-dnd kullanımını tespit eder, `.storybook/preview` decorator'larına provider ekler.
|
|
88
|
+
- `vds-core/storybook-adapt.mjs` — **Dönüştürücü:** src/ içindeki import'ları tarar; Storybook'ta yüklenmeyen paketleri (server-only, next/headers, next/navigation vb.) mock'lar, `.storybook/mocks/` yazar ve Vite alias'larını ekler. Göreli import'ları kontrol eder, çözülemeyenleri uyarır.
|
|
77
89
|
- `vds-core/VdsPreview.tsx` — İsteğe bağlı; `/vds-preview` ile dashboard canlı component önizlemesi yapar.
|
|
78
90
|
- Dashboard UI `/vds-output.json` okur; Foundations + Component Library gösterir.
|
|
@@ -676,13 +676,13 @@ function buildDefaultArgsForRequiredProps(props, usageFromPages = null, componen
|
|
|
676
676
|
} else if (/string/.test(type)) {
|
|
677
677
|
argLines.push(` ${name}: ${stringFallback(name)},`);
|
|
678
678
|
added.add(name);
|
|
679
|
-
} else if (/number/.test(type) || /^(value|amount|total|count|hours|minutes|progress|percent)$/.test(name)) {
|
|
679
|
+
} else if (/number/.test(type) || /^(value|amount|total|count|hours|minutes|progress|percent|estimate)$/.test(name)) {
|
|
680
680
|
argLines.push(` ${name}: 0,`);
|
|
681
681
|
added.add(name);
|
|
682
682
|
}
|
|
683
683
|
}
|
|
684
|
-
// Optional props that often cause "reading X of undefined" in Storybook if missing
|
|
685
|
-
const NUMBER_LIKE_OPTIONAL = new Set(["value", "amount", "total", "count", "hours", "minutes", "progress", "percent", "visibility"]);
|
|
684
|
+
// Optional props that often cause "reading X of undefined" or "reading 'toString'" in Storybook if missing
|
|
685
|
+
const NUMBER_LIKE_OPTIONAL = new Set(["value", "amount", "total", "count", "hours", "minutes", "progress", "percent", "visibility", "estimate"]);
|
|
686
686
|
const DATE_RANGE_DEFAULT = `{ dateRange: { from: new Date().toISOString(), to: new Date().toISOString() } }`;
|
|
687
687
|
for (const p of props) {
|
|
688
688
|
const type = String(p.type || "").trim();
|
|
@@ -715,6 +715,9 @@ function buildDefaultArgsForRequiredProps(props, usageFromPages = null, componen
|
|
|
715
715
|
} else if (name === "defaultProjectId") {
|
|
716
716
|
argLines.push(` ${name}: "1",`);
|
|
717
717
|
added.add(name);
|
|
718
|
+
} else if (name === "task" || /Task\b/.test(type)) {
|
|
719
|
+
argLines.push(` ${name}: { id: "1", title: "Example", estimate: 0 },`);
|
|
720
|
+
added.add(name);
|
|
718
721
|
}
|
|
719
722
|
}
|
|
720
723
|
}
|
|
@@ -992,32 +995,17 @@ function buildStoryFileContent(comp) {
|
|
|
992
995
|
|
|
993
996
|
const lines = [];
|
|
994
997
|
lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
|
|
995
|
-
|
|
996
|
-
lines.push(`import React from "react";`);
|
|
997
|
-
}
|
|
998
|
+
lines.push(`import React from "react";`);
|
|
998
999
|
if (lucideImports.length > 0) {
|
|
999
1000
|
lines.push(`import { ${lucideImports.join(", ")} } from "lucide-react";`);
|
|
1000
1001
|
}
|
|
1001
1002
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
lines.push(`import ${componentName} from "${importPath}";`);
|
|
1007
|
-
lines.push(`const ComponentRef = ${componentName};`);
|
|
1008
|
-
} else if (exportStyle === "named" || exportStyle === "unknown") {
|
|
1009
|
-
lines.push(`import { ${componentName} } from "${importPath}";`);
|
|
1010
|
-
lines.push(`const ComponentRef = ${componentName};`);
|
|
1011
|
-
} else {
|
|
1012
|
-
const defaultAlias = `${componentName}Default`;
|
|
1013
|
-
const namedAlias = `${componentName}Named`;
|
|
1014
|
-
lines.push(
|
|
1015
|
-
`import ${defaultAlias}, { ${componentName} as ${namedAlias} } from "${importPath}";`,
|
|
1016
|
-
);
|
|
1017
|
-
lines.push(`const ComponentRef = ${namedAlias} ?? ${defaultAlias};`);
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1003
|
+
// Dynamic import + catch so "Failed to fetch dynamically imported module" shows a fallback instead of breaking Storybook
|
|
1004
|
+
const loadFallback = `() => React.createElement('div', { style: { padding: 16, color: '#666', fontSize: 14 } }, 'Component could not be loaded (import error).')`;
|
|
1005
|
+
const getDefault = `(m) => ({ default: m["${componentName}"] ?? m.default })`;
|
|
1006
|
+
lines.push(`const ComponentRef = React.lazy(() => import(/* @vite-ignore */ "${importPath}").then(${getDefault}).catch(() => ({ default: ${loadFallback} })));`);
|
|
1020
1007
|
lines.push("");
|
|
1008
|
+
|
|
1021
1009
|
lines.push(`const meta = {`);
|
|
1022
1010
|
lines.push(` title: ${JSON.stringify(title)},`);
|
|
1023
1011
|
lines.push(` component: ComponentRef,`);
|
|
@@ -1042,10 +1030,10 @@ function buildStoryFileContent(comp) {
|
|
|
1042
1030
|
return lines.join("\n");
|
|
1043
1031
|
}
|
|
1044
1032
|
|
|
1045
|
-
//
|
|
1033
|
+
// Wrap in Suspense so lazy load errors render fallback instead of crashing
|
|
1046
1034
|
const renderLine = useReactNodeChildrenRender
|
|
1047
|
-
? ` render: (args) => React.createElement(ComponentRef, { ...args, children: args.children || React.createElement('span', null, 'Example') }),`
|
|
1048
|
-
: ` render: (args) =>
|
|
1035
|
+
? ` render: (args) => React.createElement(React.Suspense, { fallback: null }, React.createElement(ComponentRef, { ...args, children: args.children || React.createElement('span', null, 'Example') })),`
|
|
1036
|
+
: ` render: (args) => React.createElement(React.Suspense, { fallback: null }, React.createElement(ComponentRef, args)),`;
|
|
1049
1037
|
const childrenArgLine = (label) => (!omitChildren && !useReactNodeChildrenRender ? ` children: ${JSON.stringify(label)},` : null);
|
|
1050
1038
|
|
|
1051
1039
|
if (!variants.length) {
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* VDS — Storybook adapter: makes components load in Storybook by mocking
|
|
4
|
+
* problematic imports (server-only, next/*, etc.) and wiring Vite aliases.
|
|
5
|
+
*
|
|
6
|
+
* Run from project root: node vds-core/storybook-adapt.mjs
|
|
7
|
+
* Runs automatically as part of npm run vds:stories.
|
|
8
|
+
*/
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const PROJECT_ROOT = path.join(__dirname, "..");
|
|
15
|
+
const SRC_DIR = path.join(PROJECT_ROOT, "src");
|
|
16
|
+
const STORYBOOK_DIR = path.join(PROJECT_ROOT, ".storybook");
|
|
17
|
+
const MOCKS_DIR = path.join(STORYBOOK_DIR, "mocks");
|
|
18
|
+
|
|
19
|
+
const IGNORE_DIRS = new Set(["node_modules", "dist", ".next", "build", ".storybook", "stories"]);
|
|
20
|
+
|
|
21
|
+
// Packages that often break in Storybook (browser); we mock them so the component can load.
|
|
22
|
+
const KNOWN_PROBLEMATIC = new Set([
|
|
23
|
+
"server-only",
|
|
24
|
+
"next/headers",
|
|
25
|
+
"next/navigation",
|
|
26
|
+
"next/server",
|
|
27
|
+
"next/cache",
|
|
28
|
+
"next/dist/...",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
function getAllSourceFiles(dir, baseDir = dir) {
|
|
32
|
+
if (!fs.existsSync(dir)) return [];
|
|
33
|
+
const out = [];
|
|
34
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
35
|
+
for (const e of entries) {
|
|
36
|
+
const full = path.join(dir, e.name);
|
|
37
|
+
const rel = path.relative(baseDir, full).replace(/\\/g, "/");
|
|
38
|
+
if (e.isDirectory()) {
|
|
39
|
+
if (IGNORE_DIRS.has(e.name)) continue;
|
|
40
|
+
out.push(...getAllSourceFiles(full, baseDir));
|
|
41
|
+
} else if (/\.(tsx?|jsx?)$/i.test(e.name)) {
|
|
42
|
+
out.push(rel);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Extract import specifiers (package or path) from file content. */
|
|
49
|
+
function extractImports(content) {
|
|
50
|
+
const specifiers = new Set();
|
|
51
|
+
const re = /from\s+["']([^"']+)["']/g;
|
|
52
|
+
let m;
|
|
53
|
+
while ((m = re.exec(content)) !== null) {
|
|
54
|
+
specifiers.add(m[1]);
|
|
55
|
+
}
|
|
56
|
+
const re2 = /import\s+["']([^"']+)["']\s*;/g;
|
|
57
|
+
while ((m = re2.exec(content)) !== null) {
|
|
58
|
+
specifiers.add(m[1]);
|
|
59
|
+
}
|
|
60
|
+
return specifiers;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Check if this import is known to break in Storybook. */
|
|
64
|
+
function isProblematic(spec) {
|
|
65
|
+
if (spec.startsWith(".") || spec.startsWith("@/")) return false;
|
|
66
|
+
if (KNOWN_PROBLEMATIC.has(spec)) return true;
|
|
67
|
+
if (spec.startsWith("next/")) return true;
|
|
68
|
+
if (spec === "server-only") return true;
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function collectProblematicImports(projectRoot) {
|
|
73
|
+
const srcDir = path.join(projectRoot, "src");
|
|
74
|
+
if (!fs.existsSync(srcDir)) return new Set();
|
|
75
|
+
const files = getAllSourceFiles(srcDir, srcDir).map((r) => path.join(projectRoot, "src", r));
|
|
76
|
+
const found = new Set();
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
try {
|
|
79
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
80
|
+
for (const spec of extractImports(content)) {
|
|
81
|
+
if (isProblematic(spec)) found.add(spec);
|
|
82
|
+
}
|
|
83
|
+
} catch (_) {}
|
|
84
|
+
}
|
|
85
|
+
return found;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Check relative imports resolve to a file; report unresolved. */
|
|
89
|
+
function reportUnresolvedImports(projectRoot) {
|
|
90
|
+
const srcDir = path.join(projectRoot, "src");
|
|
91
|
+
if (!fs.existsSync(srcDir)) return;
|
|
92
|
+
const files = getAllSourceFiles(srcDir, srcDir).map((r) => path.join(projectRoot, "src", r));
|
|
93
|
+
for (const file of files) {
|
|
94
|
+
try {
|
|
95
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
96
|
+
const dir = path.dirname(file);
|
|
97
|
+
for (const spec of extractImports(content)) {
|
|
98
|
+
if (!spec.startsWith(".")) continue;
|
|
99
|
+
const resolved = path.resolve(dir, spec);
|
|
100
|
+
const exists =
|
|
101
|
+
fs.existsSync(resolved) ||
|
|
102
|
+
[".tsx", ".ts", ".jsx", ".js"].some((ext) => fs.existsSync(resolved + ext)) ||
|
|
103
|
+
["/index.tsx", "/index.ts", "/index.js"].some((ext) => fs.existsSync(resolved + ext));
|
|
104
|
+
if (!exists) {
|
|
105
|
+
const rel = path.relative(projectRoot, file);
|
|
106
|
+
console.warn("[VDS] Unresolved import in " + rel + ": " + spec);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (_) {}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Filename-safe alias for a specifier (e.g. next/headers -> next-headers). */
|
|
114
|
+
function mockFileName(spec) {
|
|
115
|
+
return spec.replace(/[@/\\]/g, "-") + ".js";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Generate mock module content for a given specifier. */
|
|
119
|
+
function getMockContent(spec) {
|
|
120
|
+
if (spec === "server-only") {
|
|
121
|
+
return "// Mock for Storybook: server-only has no runtime export.\nexport {};\n";
|
|
122
|
+
}
|
|
123
|
+
if (spec.startsWith("next/headers") || spec === "next/headers") {
|
|
124
|
+
return `// Mock for Storybook: next/headers
|
|
125
|
+
export function headers() { return new Headers(); }
|
|
126
|
+
export function cookies() { return { get: () => ({ value: '' }), getAll: () => [] }; }
|
|
127
|
+
export function draftMode() { return { isEnabled: false }; }
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
130
|
+
if (spec.startsWith("next/navigation") || spec === "next/navigation") {
|
|
131
|
+
return `// Mock for Storybook: next/navigation
|
|
132
|
+
export function useRouter() {
|
|
133
|
+
return { push: () => {}, replace: () => {}, back: () => {}, forward: () => {}, refresh: () => {},
|
|
134
|
+
prefetch: () => {}, pathname: '/', query: {}, asPath: '/' };
|
|
135
|
+
}
|
|
136
|
+
export function usePathname() { return '/'; }
|
|
137
|
+
export function useSearchParams() { return new URLSearchParams(); }
|
|
138
|
+
export function useParams() { return {}; }
|
|
139
|
+
export function redirect() {}
|
|
140
|
+
export function notFound() {}
|
|
141
|
+
export const permanentRedirect = redirect;
|
|
142
|
+
`;
|
|
143
|
+
}
|
|
144
|
+
if (spec.startsWith("next/server") || spec === "next/server") {
|
|
145
|
+
return `// Mock for Storybook: next/server
|
|
146
|
+
export function NextResponse() {}
|
|
147
|
+
NextResponse.json = (v) => ({ body: JSON.stringify(v), headers: {} });
|
|
148
|
+
NextResponse.redirect = () => ({});
|
|
149
|
+
export function NextRequest() {}
|
|
150
|
+
`;
|
|
151
|
+
}
|
|
152
|
+
if (spec.startsWith("next/cache") || spec === "next/cache") {
|
|
153
|
+
return `// Mock for Storybook: next/cache
|
|
154
|
+
export function unstable_cache(fn) { return fn; }
|
|
155
|
+
export function revalidateTag() {}
|
|
156
|
+
export function revalidatePath() {}
|
|
157
|
+
`;
|
|
158
|
+
}
|
|
159
|
+
return "// Mock for Storybook\nexport {};\nexport default {};\n";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function ensureMocksDir(projectRoot) {
|
|
163
|
+
const dir = path.join(projectRoot, ".storybook", "mocks");
|
|
164
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
165
|
+
return dir;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function writeMocks(projectRoot, specifiers) {
|
|
169
|
+
const dir = ensureMocksDir(projectRoot);
|
|
170
|
+
for (const spec of specifiers) {
|
|
171
|
+
const name = mockFileName(spec);
|
|
172
|
+
const filePath = path.join(dir, name);
|
|
173
|
+
fs.writeFileSync(filePath, getMockContent(spec), "utf-8");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function getMainPath(projectRoot) {
|
|
178
|
+
const sb = path.join(projectRoot, ".storybook");
|
|
179
|
+
for (const name of ["main.ts", "main.tsx", "main.js", "main.jsx"]) {
|
|
180
|
+
const p = path.join(sb, name);
|
|
181
|
+
if (fs.existsSync(p)) return p;
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Inject alias entries into .storybook/main.* viteFinal. */
|
|
187
|
+
function injectAliases(projectRoot, specifiers) {
|
|
188
|
+
const mainPath = getMainPath(projectRoot);
|
|
189
|
+
if (!mainPath) return;
|
|
190
|
+
let content = fs.readFileSync(mainPath, "utf-8");
|
|
191
|
+
const firstMock = mockFileName([...specifiers][0]);
|
|
192
|
+
if (content.includes(".storybook/mocks") && content.includes(firstMock)) return;
|
|
193
|
+
|
|
194
|
+
const aliasLines = [];
|
|
195
|
+
for (const spec of specifiers) {
|
|
196
|
+
const mockRel = `.storybook/mocks/${mockFileName(spec)}`;
|
|
197
|
+
aliasLines.push(`"${spec.replace(/"/g, '\\"')}": path.resolve(process.cwd(), "${mockRel}")`);
|
|
198
|
+
}
|
|
199
|
+
const newAliases = aliasLines.join(",\n ");
|
|
200
|
+
const pattern = /("@":\s*path\.resolve\(process\.cwd\(\),\s*"src"\))(\s*)(\})/;
|
|
201
|
+
if (pattern.test(content)) {
|
|
202
|
+
content = content.replace(pattern, `$1,\n ${newAliases}$2$3`);
|
|
203
|
+
fs.writeFileSync(mainPath, content, "utf-8");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function main() {
|
|
208
|
+
const projectRoot = PROJECT_ROOT;
|
|
209
|
+
if (!fs.existsSync(path.join(projectRoot, ".storybook"))) {
|
|
210
|
+
console.log("[VDS] .storybook not found; skip storybook-adapt.");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
reportUnresolvedImports(projectRoot);
|
|
214
|
+
const problematic = collectProblematicImports(projectRoot);
|
|
215
|
+
if (problematic.size === 0) return;
|
|
216
|
+
writeMocks(projectRoot, problematic);
|
|
217
|
+
injectAliases(projectRoot, problematic);
|
|
218
|
+
console.log("[VDS] Storybook adapt: mocked", [...problematic].join(", "));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
main();
|
|
@@ -14,6 +14,7 @@ function run() {
|
|
|
14
14
|
execSync('node vds-core/scan.mjs', { stdio: 'inherit', cwd: ROOT });
|
|
15
15
|
execSync('node vds-core/story-generator.mjs', { stdio: 'inherit', cwd: ROOT });
|
|
16
16
|
execSync('node vds-core/setup-storybook-providers.mjs', { stdio: 'inherit', cwd: ROOT });
|
|
17
|
+
execSync('node vds-core/storybook-adapt.mjs', { stdio: 'inherit', cwd: ROOT });
|
|
17
18
|
console.log(`[VDS ${ts}] ✅ Design system güncellendi.`);
|
|
18
19
|
} catch (e) {
|
|
19
20
|
console.error(`[VDS ${ts}] ❌ Hata:`, e.message);
|