@wix/web50-cli 0.1.0 → 0.1.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/cjs/auth/deviceFlow.js +99 -13
- package/dist/cjs/auth/deviceFlow.js.map +1 -1
- package/dist/cjs/auth/index.js +65 -12
- package/dist/cjs/auth/index.js.map +1 -1
- package/dist/cjs/auth/secretStore.js.map +1 -1
- package/dist/cjs/cli.js +29 -1
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands/bundle.js +95 -0
- package/dist/cjs/commands/bundle.js.map +1 -0
- package/dist/cjs/commands/conversation.js +50 -0
- package/dist/cjs/commands/conversation.js.map +1 -0
- package/dist/cjs/commands/conversationWizard.js +526 -0
- package/dist/cjs/commands/conversationWizard.js.map +1 -0
- package/dist/cjs/commands/deploy.js +192 -0
- package/dist/cjs/commands/deploy.js.map +1 -0
- package/dist/cjs/commands/embed.js +118 -0
- package/dist/cjs/commands/embed.js.map +1 -0
- package/dist/cjs/commands/getClientId.js +60 -0
- package/dist/cjs/commands/getClientId.js.map +1 -0
- package/dist/cjs/commands/init.js +31 -26
- package/dist/cjs/commands/init.js.map +1 -1
- package/dist/cjs/commands/instructions.js +360 -0
- package/dist/cjs/commands/instructions.js.map +1 -0
- package/dist/cjs/commands/login.js +59 -4
- package/dist/cjs/commands/login.js.map +1 -1
- package/dist/cjs/commands/logout.js +16 -0
- package/dist/cjs/commands/logout.js.map +1 -0
- package/dist/cjs/commands/serve.js +122 -0
- package/dist/cjs/commands/serve.js.map +1 -0
- package/dist/cjs/commands/storybook.js +102 -0
- package/dist/cjs/commands/storybook.js.map +1 -0
- package/dist/cjs/commands/validate.js +266 -18
- package/dist/cjs/commands/validate.js.map +1 -1
- package/dist/cjs/commands/whoami.js +48 -0
- package/dist/cjs/commands/whoami.js.map +1 -0
- package/dist/cjs/utils/print.js +12 -0
- package/dist/cjs/utils/print.js.map +1 -1
- package/dist/cjs/utils/project.js +11 -0
- package/dist/cjs/utils/project.js.map +1 -1
- package/dist/cjs/utils/wixApi.js +55 -0
- package/dist/cjs/utils/wixApi.js.map +1 -0
- package/dist/esm/auth/deviceFlow.js +106 -13
- package/dist/esm/auth/deviceFlow.js.map +1 -1
- package/dist/esm/auth/index.js +71 -13
- package/dist/esm/auth/index.js.map +1 -1
- package/dist/esm/auth/secretStore.js.map +1 -1
- package/dist/esm/cli.js +29 -1
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/bundle.js +92 -0
- package/dist/esm/commands/bundle.js.map +1 -0
- package/dist/esm/commands/conversation.js +44 -0
- package/dist/esm/commands/conversation.js.map +1 -0
- package/dist/esm/commands/conversationWizard.js +527 -0
- package/dist/esm/commands/conversationWizard.js.map +1 -0
- package/dist/esm/commands/deploy.js +194 -0
- package/dist/esm/commands/deploy.js.map +1 -0
- package/dist/esm/commands/embed.js +112 -0
- package/dist/esm/commands/embed.js.map +1 -0
- package/dist/esm/commands/getClientId.js +56 -0
- package/dist/esm/commands/getClientId.js.map +1 -0
- package/dist/esm/commands/init.js +32 -27
- package/dist/esm/commands/init.js.map +1 -1
- package/dist/esm/commands/instructions.js +360 -0
- package/dist/esm/commands/instructions.js.map +1 -0
- package/dist/esm/commands/login.js +62 -6
- package/dist/esm/commands/login.js.map +1 -1
- package/dist/esm/commands/logout.js +12 -0
- package/dist/esm/commands/logout.js.map +1 -0
- package/dist/esm/commands/serve.js +117 -0
- package/dist/esm/commands/serve.js.map +1 -0
- package/dist/esm/commands/storybook.js +97 -0
- package/dist/esm/commands/storybook.js.map +1 -0
- package/dist/esm/commands/validate.js +269 -19
- package/dist/esm/commands/validate.js.map +1 -1
- package/dist/esm/commands/whoami.js +44 -0
- package/dist/esm/commands/whoami.js.map +1 -0
- package/dist/esm/utils/print.js +10 -0
- package/dist/esm/utils/print.js.map +1 -1
- package/dist/esm/utils/project.js +8 -0
- package/dist/esm/utils/project.js.map +1 -1
- package/dist/esm/utils/wixApi.js +51 -0
- package/dist/esm/utils/wixApi.js.map +1 -0
- package/dist/types/auth/deviceFlow.d.ts +3 -1
- package/dist/types/auth/deviceFlow.d.ts.map +1 -1
- package/dist/types/auth/index.d.ts +5 -1
- package/dist/types/auth/index.d.ts.map +1 -1
- package/dist/types/auth/secretStore.d.ts +2 -0
- package/dist/types/auth/secretStore.d.ts.map +1 -1
- package/dist/types/commands/bundle.d.ts +10 -0
- package/dist/types/commands/bundle.d.ts.map +1 -0
- package/dist/types/commands/conversation.d.ts +3 -0
- package/dist/types/commands/conversation.d.ts.map +1 -0
- package/dist/types/commands/conversationWizard.d.ts +3 -0
- package/dist/types/commands/conversationWizard.d.ts.map +1 -0
- package/dist/types/commands/deploy.d.ts +3 -0
- package/dist/types/commands/deploy.d.ts.map +1 -0
- package/dist/types/commands/embed.d.ts +3 -0
- package/dist/types/commands/embed.d.ts.map +1 -0
- package/dist/types/commands/getClientId.d.ts +3 -0
- package/dist/types/commands/getClientId.d.ts.map +1 -0
- package/dist/types/commands/init.d.ts.map +1 -1
- package/dist/types/commands/instructions.d.ts +3 -0
- package/dist/types/commands/instructions.d.ts.map +1 -0
- package/dist/types/commands/login.d.ts.map +1 -1
- package/dist/types/commands/logout.d.ts +3 -0
- package/dist/types/commands/logout.d.ts.map +1 -0
- package/dist/types/commands/serve.d.ts +3 -0
- package/dist/types/commands/serve.d.ts.map +1 -0
- package/dist/types/commands/storybook.d.ts +3 -0
- package/dist/types/commands/storybook.d.ts.map +1 -0
- package/dist/types/commands/validate.d.ts +5 -0
- package/dist/types/commands/validate.d.ts.map +1 -1
- package/dist/types/commands/whoami.d.ts +3 -0
- package/dist/types/commands/whoami.d.ts.map +1 -0
- package/dist/types/utils/print.d.ts +3 -0
- package/dist/types/utils/print.d.ts.map +1 -1
- package/dist/types/utils/project.d.ts +10 -0
- package/dist/types/utils/project.d.ts.map +1 -1
- package/dist/types/utils/wixApi.d.ts +9 -0
- package/dist/types/utils/wixApi.d.ts.map +1 -0
- package/package.json +5 -5
- package/defaults/package.json +0 -42
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Command","logout","error","logoutCommand","description","action","err_","Error","message","String","process","exit"],"sources":["../../../src/commands/logout.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { logout } from '../auth';\nimport { error } from '../utils/print';\n\nexport const logoutCommand = new Command('logout')\n .description('Sign out and remove stored credentials')\n .action(async () => {\n try {\n await logout();\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n"],"mappings":"AAAA,SAASA,OAAO,QAAQ,WAAW;AACnC,SAASC,MAAM,QAAQ,SAAS;AAChC,SAASC,KAAK,QAAQ,gBAAgB;AAEtC,OAAO,MAAMC,aAAa,GAAG,IAAIH,OAAO,CAAC,QAAQ,CAAC,CAC/CI,WAAW,CAAC,wCAAwC,CAAC,CACrDC,MAAM,CAAC,YAAY;EAClB,IAAI;IACF,MAAMJ,MAAM,CAAC,CAAC;EAChB,CAAC,CAAC,OAAOK,IAAI,EAAE;IACbJ,KAAK,CAACI,IAAI,YAAYC,KAAK,GAAGD,IAAI,CAACE,OAAO,GAAGC,MAAM,CAACH,IAAI,CAAC,CAAC;IAC1DI,OAAO,CAACC,IAAI,CAAC,CAAC,CAAC;EACjB;AACF,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as http from 'http';
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import { success, error, info, isJsonMode } from '../utils/print';
|
|
7
|
+
import { findProjectRoot } from '../utils/project';
|
|
8
|
+
import { runBundle } from './bundle';
|
|
9
|
+
const DEFAULT_PORT = 4001;
|
|
10
|
+
const MIME_TYPES = {
|
|
11
|
+
'.js': 'application/javascript',
|
|
12
|
+
'.css': 'text/css',
|
|
13
|
+
'.json': 'application/json',
|
|
14
|
+
'.map': 'application/json'
|
|
15
|
+
};
|
|
16
|
+
function startServer(distDir, corsOrigin) {
|
|
17
|
+
const server = http.createServer((req, res) => {
|
|
18
|
+
res.setHeader('Access-Control-Allow-Origin', corsOrigin);
|
|
19
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
20
|
+
res.setHeader('Access-Control-Allow-Headers', '*');
|
|
21
|
+
if (req.method === 'OPTIONS') {
|
|
22
|
+
res.writeHead(204);
|
|
23
|
+
res.end();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const urlPath = req.url === '/' ? '' : req.url ?? '';
|
|
27
|
+
const filePath = path.join(distDir, urlPath);
|
|
28
|
+
|
|
29
|
+
// Prevent path traversal outside distDir
|
|
30
|
+
if (!filePath.startsWith(distDir)) {
|
|
31
|
+
res.writeHead(403);
|
|
32
|
+
res.end('Forbidden');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
|
|
36
|
+
res.writeHead(404);
|
|
37
|
+
res.end('Not found');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const ext = path.extname(filePath);
|
|
41
|
+
const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';
|
|
42
|
+
res.setHeader('Content-Type', contentType);
|
|
43
|
+
res.writeHead(200);
|
|
44
|
+
fs.createReadStream(filePath).pipe(res);
|
|
45
|
+
});
|
|
46
|
+
return server;
|
|
47
|
+
}
|
|
48
|
+
export const serveCommand = new Command('serve').description('Bundle components and serve them on http://localhost:<port> with CORS enabled').option('--port <n>', 'Port to listen on', String(DEFAULT_PORT)).option('--no-bundle', 'Serve existing dist/cdn/ without rebuilding').option('--watch', 'Re-bundle on source changes (starts vite --watch alongside server)').option('--open', 'Open the served URL in your browser after start').option('--cors-origin <origin>', 'Restrict CORS Allow-Origin header', '*').action(async opts => {
|
|
49
|
+
try {
|
|
50
|
+
const projectRoot = findProjectRoot(process.cwd());
|
|
51
|
+
if (!projectRoot) {
|
|
52
|
+
error('No web5.config.json found. Run this command from within a Web5 project.');
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const port = parseInt(opts.port, 10);
|
|
56
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
57
|
+
error(`Invalid port: ${opts.port}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
const distDir = path.join(projectRoot, 'dist', 'cdn');
|
|
61
|
+
|
|
62
|
+
// ── Bundle (unless --no-bundle) ─────────────────────────────────────────
|
|
63
|
+
if (opts.bundle !== false) {
|
|
64
|
+
await runBundle(projectRoot);
|
|
65
|
+
}
|
|
66
|
+
if (!fs.existsSync(distDir)) {
|
|
67
|
+
error(`Bundle output not found at ${distDir}. Run \`web5 bundle\` first or remove --no-bundle.`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── Watch mode: spawn vite --watch in background ────────────────────────
|
|
72
|
+
if (opts.watch) {
|
|
73
|
+
const viteBin = path.join(projectRoot, 'node_modules', '.bin', 'vite');
|
|
74
|
+
if (!fs.existsSync(viteBin)) {
|
|
75
|
+
error('vite not found. Run `npm install` in your project first.');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
const watcher = spawn(`"${viteBin}"`, ['build', '--config', 'src/vite.cdn.config.ts', '--watch'], {
|
|
79
|
+
cwd: projectRoot,
|
|
80
|
+
shell: true,
|
|
81
|
+
stdio: 'inherit'
|
|
82
|
+
});
|
|
83
|
+
watcher.on('error', err_ => error(`Watch process error: ${err_.message}`));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Start HTTP server ───────────────────────────────────────────────────
|
|
87
|
+
const server = startServer(distDir, opts.corsOrigin);
|
|
88
|
+
const url = `http://localhost:${port}`;
|
|
89
|
+
server.listen(port, async () => {
|
|
90
|
+
const files = fs.readdirSync(distDir);
|
|
91
|
+
if (isJsonMode()) {
|
|
92
|
+
console.log(JSON.stringify({
|
|
93
|
+
url,
|
|
94
|
+
port,
|
|
95
|
+
files: files.map(f => `${url}/${f}`)
|
|
96
|
+
}));
|
|
97
|
+
} else {
|
|
98
|
+
success(`Serving on ${url}`);
|
|
99
|
+
for (const file of files) {
|
|
100
|
+
info(` ${url}/${file}`);
|
|
101
|
+
}
|
|
102
|
+
if (opts.watch) {
|
|
103
|
+
info('Watch mode active — rebuilds automatically on file changes.');
|
|
104
|
+
}
|
|
105
|
+
info('Press Ctrl+C to stop.');
|
|
106
|
+
}
|
|
107
|
+
if (opts.open) {
|
|
108
|
+
const openPkg = (await import('open')).default;
|
|
109
|
+
await openPkg(url);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
} catch (err_) {
|
|
113
|
+
error(err_ instanceof Error ? err_.message : String(err_));
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Command","path","fs","http","spawn","success","error","info","isJsonMode","findProjectRoot","runBundle","DEFAULT_PORT","MIME_TYPES","startServer","distDir","corsOrigin","server","createServer","req","res","setHeader","method","writeHead","end","urlPath","url","filePath","join","startsWith","existsSync","statSync","isDirectory","ext","extname","contentType","createReadStream","pipe","serveCommand","description","option","String","action","opts","projectRoot","process","cwd","exit","port","parseInt","isNaN","bundle","watch","viteBin","watcher","shell","stdio","on","err_","message","listen","files","readdirSync","console","log","JSON","stringify","map","f","file","open","openPkg","default","Error"],"sources":["../../../src/commands/serve.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport * as http from 'http';\nimport { spawn } from 'child_process';\nimport { success, error, info, isJsonMode } from '../utils/print';\nimport { findProjectRoot } from '../utils/project';\nimport { runBundle } from './bundle';\n\nconst DEFAULT_PORT = 4001;\n\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.map': 'application/json',\n};\n\nfunction startServer(\n distDir: string,\n corsOrigin: string,\n): http.Server {\n const server = http.createServer((req, res) => {\n res.setHeader('Access-Control-Allow-Origin', corsOrigin);\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', '*');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const urlPath = req.url === '/' ? '' : req.url ?? '';\n const filePath = path.join(distDir, urlPath);\n\n // Prevent path traversal outside distDir\n if (!filePath.startsWith(distDir)) {\n res.writeHead(403);\n res.end('Forbidden');\n return;\n }\n\n if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {\n res.writeHead(404);\n res.end('Not found');\n return;\n }\n\n const ext = path.extname(filePath);\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n res.setHeader('Content-Type', contentType);\n res.writeHead(200);\n fs.createReadStream(filePath).pipe(res);\n });\n\n return server;\n}\n\nexport const serveCommand = new Command('serve')\n .description('Bundle components and serve them on http://localhost:<port> with CORS enabled')\n .option('--port <n>', 'Port to listen on', String(DEFAULT_PORT))\n .option('--no-bundle', 'Serve existing dist/cdn/ without rebuilding')\n .option('--watch', 'Re-bundle on source changes (starts vite --watch alongside server)')\n .option('--open', 'Open the served URL in your browser after start')\n .option('--cors-origin <origin>', 'Restrict CORS Allow-Origin header', '*')\n .action(async (opts: {\n port: string;\n bundle: boolean;\n watch?: boolean;\n open?: boolean;\n corsOrigin: string;\n }) => {\n try {\n const projectRoot = findProjectRoot(process.cwd());\n if (!projectRoot) {\n error(\n 'No web5.config.json found. Run this command from within a Web5 project.',\n );\n process.exit(1);\n }\n\n const port = parseInt(opts.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n error(`Invalid port: ${opts.port}`);\n process.exit(1);\n }\n\n const distDir = path.join(projectRoot, 'dist', 'cdn');\n\n // ── Bundle (unless --no-bundle) ─────────────────────────────────────────\n if (opts.bundle !== false) {\n await runBundle(projectRoot);\n }\n\n if (!fs.existsSync(distDir)) {\n error(\n `Bundle output not found at ${distDir}. Run \\`web5 bundle\\` first or remove --no-bundle.`,\n );\n process.exit(1);\n }\n\n // ── Watch mode: spawn vite --watch in background ────────────────────────\n if (opts.watch) {\n const viteBin = path.join(projectRoot, 'node_modules', '.bin', 'vite');\n if (!fs.existsSync(viteBin)) {\n error('vite not found. Run `npm install` in your project first.');\n process.exit(1);\n }\n const watcher = spawn(\n `\"${viteBin}\"`,\n ['build', '--config', 'src/vite.cdn.config.ts', '--watch'],\n { cwd: projectRoot, shell: true, stdio: 'inherit' },\n );\n watcher.on('error', (err_) => error(`Watch process error: ${err_.message}`));\n }\n\n // ── Start HTTP server ───────────────────────────────────────────────────\n const server = startServer(distDir, opts.corsOrigin);\n const url = `http://localhost:${port}`;\n\n server.listen(port, async () => {\n const files = fs.readdirSync(distDir);\n\n if (isJsonMode()) {\n console.log(JSON.stringify({ url, port, files: files.map((f) => `${url}/${f}`) }));\n } else {\n success(`Serving on ${url}`);\n for (const file of files) {\n info(` ${url}/${file}`);\n }\n if (opts.watch) {\n info('Watch mode active — rebuilds automatically on file changes.');\n }\n info('Press Ctrl+C to stop.');\n }\n\n if (opts.open) {\n const openPkg = (await import('open')).default;\n await openPkg(url);\n }\n });\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { cp, readFile, writeFile } from 'fs/promises';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
import { success, error, info, warn } from '../utils/print';
|
|
7
|
+
import { findProjectRoot } from '../utils/project';
|
|
8
|
+
const DEFAULTS_DIR = path.join(__dirname, '../../../defaults');
|
|
9
|
+
const STORYBOOK_DEPS = {
|
|
10
|
+
storybook: '^8.0.0',
|
|
11
|
+
'@storybook/react-vite': '^8.0.0',
|
|
12
|
+
'@storybook/addon-essentials': '^8.0.0'
|
|
13
|
+
};
|
|
14
|
+
const STORYBOOK_SCRIPTS = {
|
|
15
|
+
storybook: 'storybook dev -p 6006',
|
|
16
|
+
'build-storybook': 'storybook build'
|
|
17
|
+
};
|
|
18
|
+
export const storybookCommand = new Command('storybook').description('Add Storybook configuration and stories to a Web5 project').action(async () => {
|
|
19
|
+
try {
|
|
20
|
+
const projectRoot = findProjectRoot(process.cwd());
|
|
21
|
+
if (!projectRoot) {
|
|
22
|
+
error('No web5.config.json found. Run this command from within a Web5 project.');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
info(`Adding Storybook to ${projectRoot}`);
|
|
26
|
+
|
|
27
|
+
// ── Copy .storybook/ config (overwrites on re-run — intentional) ──────
|
|
28
|
+
const storybookConfigSrc = path.join(DEFAULTS_DIR, '.storybook');
|
|
29
|
+
const storybookConfigDest = path.join(projectRoot, '.storybook');
|
|
30
|
+
await cp(storybookConfigSrc, storybookConfigDest, {
|
|
31
|
+
recursive: true
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// ── Copy stories folder (overwrites on re-run — intentional) ──────────
|
|
35
|
+
const storiesSrc = path.join(DEFAULTS_DIR, 'src', 'components', 'storybook');
|
|
36
|
+
const storiesDest = path.join(projectRoot, 'src', 'components', 'storybook');
|
|
37
|
+
await cp(storiesSrc, storiesDest, {
|
|
38
|
+
recursive: true
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ── Update package.json (idempotent) ───────────────────────────────────
|
|
42
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
43
|
+
if (!fs.existsSync(pkgPath)) {
|
|
44
|
+
error('No package.json found in project root.');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));
|
|
48
|
+
let pkgChanged = false;
|
|
49
|
+
|
|
50
|
+
// Scripts
|
|
51
|
+
pkg.scripts ??= {};
|
|
52
|
+
for (const [name, cmd] of Object.entries(STORYBOOK_SCRIPTS)) {
|
|
53
|
+
if (!pkg.scripts[name]) {
|
|
54
|
+
pkg.scripts[name] = cmd;
|
|
55
|
+
pkgChanged = true;
|
|
56
|
+
} else {
|
|
57
|
+
warn(`Script "${name}" already exists — skipping`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// devDependencies
|
|
62
|
+
pkg.devDependencies ??= {};
|
|
63
|
+
const missingDeps = [];
|
|
64
|
+
for (const [dep, version] of Object.entries(STORYBOOK_DEPS)) {
|
|
65
|
+
if (!pkg.devDependencies[dep]) {
|
|
66
|
+
pkg.devDependencies[dep] = version;
|
|
67
|
+
missingDeps.push(dep);
|
|
68
|
+
pkgChanged = true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (pkgChanged) {
|
|
72
|
+
await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
|
|
73
|
+
info('Updated package.json');
|
|
74
|
+
} else {
|
|
75
|
+
info('package.json already up to date');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Install dependencies ───────────────────────────────────────────────
|
|
79
|
+
if (missingDeps.length > 0) {
|
|
80
|
+
info(`Installing: ${missingDeps.join(', ')}`);
|
|
81
|
+
} else {
|
|
82
|
+
info('Running npm install to ensure dependencies are installed...');
|
|
83
|
+
}
|
|
84
|
+
execSync('npm install', {
|
|
85
|
+
cwd: projectRoot,
|
|
86
|
+
stdio: 'inherit'
|
|
87
|
+
});
|
|
88
|
+
success('Storybook is ready.');
|
|
89
|
+
console.log('');
|
|
90
|
+
info('Run it with:');
|
|
91
|
+
info(' npm run storybook');
|
|
92
|
+
} catch (err_) {
|
|
93
|
+
error(err_ instanceof Error ? err_.message : String(err_));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=storybook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Command","path","fs","cp","readFile","writeFile","execSync","success","error","info","warn","findProjectRoot","DEFAULTS_DIR","join","__dirname","STORYBOOK_DEPS","storybook","STORYBOOK_SCRIPTS","storybookCommand","description","action","projectRoot","process","cwd","exit","storybookConfigSrc","storybookConfigDest","recursive","storiesSrc","storiesDest","pkgPath","existsSync","pkg","JSON","parse","pkgChanged","scripts","name","cmd","Object","entries","devDependencies","missingDeps","dep","version","push","stringify","length","stdio","console","log","err_","Error","message","String"],"sources":["../../../src/commands/storybook.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport { cp, readFile, writeFile } from 'fs/promises';\nimport { execSync } from 'child_process';\nimport { success, error, info, warn } from '../utils/print';\nimport { findProjectRoot } from '../utils/project';\n\nconst DEFAULTS_DIR = path.join(__dirname, '../../../defaults');\n\nconst STORYBOOK_DEPS = {\n storybook: '^8.0.0',\n '@storybook/react-vite': '^8.0.0',\n '@storybook/addon-essentials': '^8.0.0',\n};\n\nconst STORYBOOK_SCRIPTS = {\n storybook: 'storybook dev -p 6006',\n 'build-storybook': 'storybook build',\n};\n\nexport const storybookCommand = new Command('storybook')\n .description('Add Storybook configuration and stories to a Web5 project')\n .action(async () => {\n try {\n const projectRoot = findProjectRoot(process.cwd());\n if (!projectRoot) {\n error(\n 'No web5.config.json found. Run this command from within a Web5 project.',\n );\n process.exit(1);\n }\n\n info(`Adding Storybook to ${projectRoot}`);\n\n // ── Copy .storybook/ config (overwrites on re-run — intentional) ──────\n const storybookConfigSrc = path.join(DEFAULTS_DIR, '.storybook');\n const storybookConfigDest = path.join(projectRoot, '.storybook');\n await cp(storybookConfigSrc, storybookConfigDest, { recursive: true });\n\n // ── Copy stories folder (overwrites on re-run — intentional) ──────────\n const storiesSrc = path.join(\n DEFAULTS_DIR,\n 'src',\n 'components',\n 'storybook',\n );\n const storiesDest = path.join(\n projectRoot,\n 'src',\n 'components',\n 'storybook',\n );\n await cp(storiesSrc, storiesDest, { recursive: true });\n\n // ── Update package.json (idempotent) ───────────────────────────────────\n const pkgPath = path.join(projectRoot, 'package.json');\n if (!fs.existsSync(pkgPath)) {\n error('No package.json found in project root.');\n process.exit(1);\n }\n\n const pkg = JSON.parse(await readFile(pkgPath, 'utf8')) as {\n scripts?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n let pkgChanged = false;\n\n // Scripts\n pkg.scripts ??= {};\n for (const [name, cmd] of Object.entries(STORYBOOK_SCRIPTS)) {\n if (!pkg.scripts[name]) {\n pkg.scripts[name] = cmd;\n pkgChanged = true;\n } else {\n warn(`Script \"${name}\" already exists — skipping`);\n }\n }\n\n // devDependencies\n pkg.devDependencies ??= {};\n const missingDeps: string[] = [];\n for (const [dep, version] of Object.entries(STORYBOOK_DEPS)) {\n if (!pkg.devDependencies[dep]) {\n pkg.devDependencies[dep] = version;\n missingDeps.push(dep);\n pkgChanged = true;\n }\n }\n\n if (pkgChanged) {\n await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\\n', 'utf8');\n info('Updated package.json');\n } else {\n info('package.json already up to date');\n }\n\n // ── Install dependencies ───────────────────────────────────────────────\n if (missingDeps.length > 0) {\n info(`Installing: ${missingDeps.join(', ')}`);\n } else {\n info('Running npm install to ensure dependencies are installed...');\n }\n\n execSync('npm install', { cwd: projectRoot, stdio: 'inherit' });\n\n success('Storybook is ready.');\n console.log('');\n info('Run it with:');\n info(' npm run storybook');\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import Ajv from 'ajv/dist/2020';
|
|
3
3
|
import { load as yamlLoad } from 'js-yaml';
|
|
4
|
-
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
4
|
+
import { readFileSync, existsSync, readdirSync, watch as fsWatch } from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import { error, info } from '../utils/print';
|
|
@@ -666,27 +666,21 @@ function buildActionsDomain(root) {
|
|
|
666
666
|
};
|
|
667
667
|
}
|
|
668
668
|
|
|
669
|
-
// ──
|
|
669
|
+
// ── Rendering ─────────────────────────────────────────────────────────────────
|
|
670
670
|
|
|
671
|
-
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
process.exit(1);
|
|
676
|
-
}
|
|
677
|
-
info(`Project root: ${root}`);
|
|
678
|
-
console.log('');
|
|
679
|
-
const domains = [buildAiInstructionsDomain(root), buildCmsSchemaDomain(root), buildActionsDomain(root)];
|
|
680
|
-
let hasErrors = false;
|
|
681
|
-
for (const domain of domains) {
|
|
671
|
+
function printDomain(domain, results, verbose) {
|
|
672
|
+
const failed = results.filter(r => !r.result.ok);
|
|
673
|
+
const domainOk = failed.length === 0;
|
|
674
|
+
if (verbose) {
|
|
682
675
|
console.log(domain.name);
|
|
683
|
-
for (const
|
|
684
|
-
|
|
676
|
+
for (const {
|
|
677
|
+
label,
|
|
678
|
+
result
|
|
679
|
+
} of results) {
|
|
685
680
|
if (result.ok) {
|
|
686
|
-
console.log(chalk.green(` \u2714 ${
|
|
681
|
+
console.log(chalk.green(` \u2714 ${label}`));
|
|
687
682
|
} else {
|
|
688
|
-
|
|
689
|
-
process.stderr.write(chalk.red(` \u2716 ${check.label}\n`));
|
|
683
|
+
process.stderr.write(chalk.red(` \u2716 ${label}\n`));
|
|
690
684
|
for (const e_ of result.errors) {
|
|
691
685
|
process.stderr.write(` ${e_.message}\n`);
|
|
692
686
|
if (e_.fix) {
|
|
@@ -696,9 +690,265 @@ export const validateCommand = new Command('validate').description('Validate pro
|
|
|
696
690
|
}
|
|
697
691
|
}
|
|
698
692
|
console.log('');
|
|
693
|
+
return domainOk;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Slim mode
|
|
697
|
+
if (domainOk) {
|
|
698
|
+
console.log(chalk.green(`\u2714 ${domain.name} — valid`));
|
|
699
|
+
return true;
|
|
700
|
+
}
|
|
701
|
+
console.log(domain.name);
|
|
702
|
+
for (const {
|
|
703
|
+
label,
|
|
704
|
+
result
|
|
705
|
+
} of failed) {
|
|
706
|
+
process.stderr.write(chalk.red(` \u2716 ${label}\n`));
|
|
707
|
+
for (const e_ of result.errors) {
|
|
708
|
+
process.stderr.write(` ${e_.message}\n`);
|
|
709
|
+
if (e_.fix) {
|
|
710
|
+
process.stderr.write(` Fix: ${e_.fix}\n`);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
console.log('');
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// ── JSON output ───────────────────────────────────────────────────────────────
|
|
719
|
+
|
|
720
|
+
function collectDomainJson(domain, results) {
|
|
721
|
+
return {
|
|
722
|
+
name: domain.name,
|
|
723
|
+
ok: results.every(r => r.result.ok),
|
|
724
|
+
checks: results.map(_ref => {
|
|
725
|
+
let {
|
|
726
|
+
label,
|
|
727
|
+
result
|
|
728
|
+
} = _ref;
|
|
729
|
+
return {
|
|
730
|
+
label,
|
|
731
|
+
ok: result.ok,
|
|
732
|
+
errors: result.errors
|
|
733
|
+
};
|
|
734
|
+
})
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// ── Build scripts domain ──────────────────────────────────────────────────────
|
|
739
|
+
|
|
740
|
+
function buildScriptsDomain(root) {
|
|
741
|
+
const pkgPath = path.join(root, 'package.json');
|
|
742
|
+
let pkg = {};
|
|
743
|
+
let fileExists = false;
|
|
744
|
+
return {
|
|
745
|
+
name: 'Build Scripts',
|
|
746
|
+
checks: [{
|
|
747
|
+
label: 'package.json — file exists',
|
|
748
|
+
run() {
|
|
749
|
+
fileExists = existsSync(pkgPath);
|
|
750
|
+
if (!fileExists) {
|
|
751
|
+
return {
|
|
752
|
+
ok: false,
|
|
753
|
+
errors: [{
|
|
754
|
+
message: `File not found: ${pkgPath}`,
|
|
755
|
+
fix: `Create a 'package.json' at the root of your project.`
|
|
756
|
+
}]
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
try {
|
|
760
|
+
pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
761
|
+
} catch (e) {
|
|
762
|
+
fileExists = false;
|
|
763
|
+
return {
|
|
764
|
+
ok: false,
|
|
765
|
+
errors: [{
|
|
766
|
+
message: `Failed to parse package.json: ${e instanceof Error ? e.message : String(e)}`,
|
|
767
|
+
fix: `Fix the JSON syntax in your package.json.`
|
|
768
|
+
}]
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
return {
|
|
772
|
+
ok: true,
|
|
773
|
+
errors: []
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
}, {
|
|
777
|
+
label: 'package.json — bundle script defined',
|
|
778
|
+
run() {
|
|
779
|
+
var _pkg$scripts;
|
|
780
|
+
if (!fileExists) {
|
|
781
|
+
return {
|
|
782
|
+
ok: false,
|
|
783
|
+
errors: [{
|
|
784
|
+
message: 'skipped — package.json not readable'
|
|
785
|
+
}]
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
if (typeof ((_pkg$scripts = pkg.scripts) == null ? void 0 : _pkg$scripts.bundle) === 'string' && pkg.scripts.bundle.length > 0) {
|
|
789
|
+
return {
|
|
790
|
+
ok: true,
|
|
791
|
+
errors: []
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
return {
|
|
795
|
+
ok: false,
|
|
796
|
+
errors: [{
|
|
797
|
+
message: `Missing 'bundle' script in package.json`,
|
|
798
|
+
fix: `Add a 'bundle' script to your package.json scripts, e.g.:\n "bundle": "vite build --config src/vite.cdn.config.ts"`
|
|
799
|
+
}]
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
}, {
|
|
803
|
+
label: 'package.json — build script defined',
|
|
804
|
+
run() {
|
|
805
|
+
var _pkg$scripts2;
|
|
806
|
+
if (!fileExists) {
|
|
807
|
+
return {
|
|
808
|
+
ok: false,
|
|
809
|
+
errors: [{
|
|
810
|
+
message: 'skipped — package.json not readable'
|
|
811
|
+
}]
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
if (typeof ((_pkg$scripts2 = pkg.scripts) == null ? void 0 : _pkg$scripts2.build) === 'string' && pkg.scripts.build.length > 0) {
|
|
815
|
+
return {
|
|
816
|
+
ok: true,
|
|
817
|
+
errors: []
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
return {
|
|
821
|
+
ok: false,
|
|
822
|
+
errors: [{
|
|
823
|
+
message: `Missing 'build' script in package.json`,
|
|
824
|
+
fix: `Add a 'build' script to your package.json scripts, e.g.:\n "build": "tsc"`
|
|
825
|
+
}]
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
}]
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// ── Domain selection ──────────────────────────────────────────────────────────
|
|
833
|
+
|
|
834
|
+
function selectDomains(root, filter) {
|
|
835
|
+
const all = [buildAiInstructionsDomain(root), buildCmsSchemaDomain(root), buildActionsDomain(root), buildScriptsDomain(root)];
|
|
836
|
+
if (!filter) return all;
|
|
837
|
+
const map = {
|
|
838
|
+
ai: 'AI Instructions',
|
|
839
|
+
cms: 'CMS Schema',
|
|
840
|
+
scripts: 'Build Scripts',
|
|
841
|
+
actions: 'Actions'
|
|
842
|
+
};
|
|
843
|
+
return all.filter(d => d.name === map[filter]);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// ── Core runner ───────────────────────────────────────────────────────────────
|
|
847
|
+
|
|
848
|
+
function runDomains(domains, verbose, format) {
|
|
849
|
+
let hasErrors = false;
|
|
850
|
+
const jsonResults = [];
|
|
851
|
+
for (const domain of domains) {
|
|
852
|
+
const results = domain.checks.map(check => ({
|
|
853
|
+
label: check.label,
|
|
854
|
+
result: check.run()
|
|
855
|
+
}));
|
|
856
|
+
let domainOk;
|
|
857
|
+
if (format === 'json') {
|
|
858
|
+
const jr = collectDomainJson(domain, results);
|
|
859
|
+
jsonResults.push(jr);
|
|
860
|
+
domainOk = jr.ok;
|
|
861
|
+
} else {
|
|
862
|
+
domainOk = printDomain(domain, results, verbose);
|
|
863
|
+
}
|
|
864
|
+
if (!domainOk) hasErrors = true;
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
867
|
+
ok: !hasErrors,
|
|
868
|
+
jsonResults
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// ── Programmatic API ─────────────────────────────────────────────────────────
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Runs all validation domains against the given project root.
|
|
876
|
+
* Prints results in slim mode and returns true if everything passes.
|
|
877
|
+
*/
|
|
878
|
+
export function runValidation(root) {
|
|
879
|
+
const domains = selectDomains(root);
|
|
880
|
+
const {
|
|
881
|
+
ok
|
|
882
|
+
} = runDomains(domains, false, 'text');
|
|
883
|
+
return ok;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// ── Watch mode ────────────────────────────────────────────────────────────────
|
|
887
|
+
|
|
888
|
+
function startWatch(root, run) {
|
|
889
|
+
const watchDirs = [path.join(root, 'src', 'configuration'), path.join(root, 'src', 'actions')].filter(d => existsSync(d));
|
|
890
|
+
if (watchDirs.length === 0) {
|
|
891
|
+
error('No directories to watch found.');
|
|
892
|
+
return;
|
|
699
893
|
}
|
|
700
|
-
|
|
894
|
+
let debounce = null;
|
|
895
|
+
const trigger = () => {
|
|
896
|
+
if (debounce) clearTimeout(debounce);
|
|
897
|
+
debounce = setTimeout(() => {
|
|
898
|
+
console.clear();
|
|
899
|
+
info(`[${new Date().toLocaleTimeString()}] Re-validating...`);
|
|
900
|
+
console.log('');
|
|
901
|
+
run();
|
|
902
|
+
}, 200);
|
|
903
|
+
};
|
|
904
|
+
for (const dir of watchDirs) {
|
|
905
|
+
fsWatch(dir, {
|
|
906
|
+
recursive: true
|
|
907
|
+
}, trigger);
|
|
908
|
+
}
|
|
909
|
+
info(`Watching for changes in ${watchDirs.map(d => path.relative(root, d)).join(', ')}...`);
|
|
910
|
+
info('Press Ctrl+C to stop.');
|
|
911
|
+
console.log('');
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// ── Command ───────────────────────────────────────────────────────────────────
|
|
915
|
+
|
|
916
|
+
export const validateCommand = new Command('validate').description('Validate project config files against their schemas').option('--verbose', 'Show all checks, including passing ones').option('--domain <domain>', 'Only validate one domain: ai, cms, actions, or scripts').option('--format <format>', 'Output format: text (default) or json', 'text').option('--watch', 'Re-validate on file changes (TTY only)').option('--strict', 'Exit with error even on warnings').option('--project <path>', 'Explicit project root (overrides cwd auto-detection)').action(opts => {
|
|
917
|
+
const verbose = Boolean(opts.verbose);
|
|
918
|
+
const format = opts.format ?? 'text';
|
|
919
|
+
const domainFilter = opts.domain;
|
|
920
|
+
const root = opts.project ? path.resolve(opts.project) : findProjectRoot(process.cwd());
|
|
921
|
+
if (!root) {
|
|
922
|
+
error('No web5.config.json found — run this command from inside a Web5 project');
|
|
701
923
|
process.exit(1);
|
|
702
924
|
}
|
|
925
|
+
if (format === 'text') {
|
|
926
|
+
info(`Project root: ${root}`);
|
|
927
|
+
console.log('');
|
|
928
|
+
}
|
|
929
|
+
const run = () => {
|
|
930
|
+
const domains = selectDomains(root, domainFilter);
|
|
931
|
+
const {
|
|
932
|
+
ok,
|
|
933
|
+
jsonResults
|
|
934
|
+
} = runDomains(domains, verbose, format);
|
|
935
|
+
if (format === 'json') {
|
|
936
|
+
console.log(JSON.stringify({
|
|
937
|
+
ok,
|
|
938
|
+
domains: jsonResults
|
|
939
|
+
}, null, 2));
|
|
940
|
+
}
|
|
941
|
+
if (!ok && !opts.watch) {
|
|
942
|
+
process.exit(1);
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
run();
|
|
946
|
+
if (opts.watch) {
|
|
947
|
+
if (!process.stdout.isTTY) {
|
|
948
|
+
error('--watch requires a TTY (interactive terminal).');
|
|
949
|
+
process.exit(1);
|
|
950
|
+
}
|
|
951
|
+
startWatch(root, run);
|
|
952
|
+
}
|
|
703
953
|
});
|
|
704
954
|
//# sourceMappingURL=validate.js.map
|