@jsonpages/cli 2.0.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.
Files changed (3) hide show
  1. package/package.json +24 -0
  2. package/src/index.js +216 -0
  3. package/tsconfig.json +13 -0
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@jsonpages/cli",
3
+ "version": "2.0.0",
4
+ "description": "JsonPages CLI - Sovereign Projection Engine",
5
+ "type": "module",
6
+ "bin": {
7
+ "jsonpages": "./src/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -p ."
11
+ },
12
+ "dependencies": {
13
+ "chalk": "^5.3.0",
14
+ "commander": "^12.1.0",
15
+ "execa": "^9.0.2",
16
+ "fs-extra": "^11.2.0",
17
+ "ora": "^8.0.1"
18
+ },
19
+ "devDependencies": {
20
+ "@types/fs-extra": "^11.0.4",
21
+ "@types/node": "^22.13.1",
22
+ "typescript": "^5.7.3"
23
+ }
24
+ }
package/src/index.js ADDED
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs-extra';
5
+ import path from 'path';
6
+ import { execa } from 'execa';
7
+ import ora from 'ora';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ // šŸ›”ļø Risoluzione path per rendere la CLI shippable
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+
14
+ const program = new Command();
15
+
16
+ program
17
+ .name('jsonpages')
18
+ .description('JsonPages CLI - Sovereign Projection Engine')
19
+ .version('2.2.0');
20
+
21
+ program
22
+ .command('new')
23
+ .argument('<type>', 'Type of artifact (tenant)')
24
+ .argument('<name>', 'Name of the new tenant')
25
+ .option('--script <path>', 'Override default deterministic script path')
26
+ .action(async (type, name, options) => {
27
+ if (type !== 'tenant') {
28
+ console.log(chalk.red('āŒ Error: Only "tenant" type is supported.'));
29
+ return;
30
+ }
31
+
32
+ const targetDir = path.join(process.cwd(), name);
33
+
34
+ // šŸ” Logica Asset Interno:
35
+ // Se l'utente non fornisce uno script, usa quello dentro packages/cli/assets/
36
+ const defaultScriptPath = path.resolve(__dirname, '../assets/src_tenant_alpha.sh');
37
+ const scriptPath = options.script ? path.resolve(process.cwd(), options.script) : defaultScriptPath;
38
+
39
+ if (!fs.existsSync(scriptPath)) {
40
+ console.log(chalk.red(`āŒ Error: Deterministic script not found at ${scriptPath}`));
41
+ console.log(chalk.yellow(`Expected internal asset at: ${defaultScriptPath}`));
42
+ return;
43
+ }
44
+
45
+ console.log(chalk.blue.bold(`\nšŸš€ Projecting Sovereign Tenant: ${name}\n`));
46
+ const spinner = ora();
47
+
48
+ try {
49
+ // 1. SCAFFOLDING INFRA
50
+ spinner.start('Setting up environment (Vite + TS)...');
51
+ await fs.ensureDir(targetDir);
52
+ await execa('npm', ['create', 'vite@latest', '.', '--', '--template', 'react-ts'], { cwd: targetDir });
53
+ spinner.succeed('Environment scaffolded.');
54
+
55
+ // 2. CLEANUP (Piazza pulita per il determinismo)
56
+ spinner.start('Wiping default boilerplate...');
57
+ await fs.emptyDir(path.join(targetDir, 'src'));
58
+ const junk = ['App.css', 'App.tsx', 'main.tsx', 'vite-env.d.ts', 'favicon.ico', 'index.html'];
59
+ for (const file of junk) {
60
+ await fs.remove(path.join(targetDir, file)).catch(() => {});
61
+ await fs.remove(path.join(targetDir, 'src', file)).catch(() => {});
62
+ }
63
+ spinner.succeed('Clean slate achieved.');
64
+
65
+ // 3. INJECTION
66
+ spinner.start('Injecting Sovereign Configurations...');
67
+ await injectInfraFiles(targetDir, name);
68
+ spinner.succeed('Infrastructure configured.');
69
+
70
+ // 4. DETERMINISTIC SRC (Proiezione dal DNA interno)
71
+ spinner.start('Executing deterministic src projection...');
72
+ const localScript = path.join(targetDir, 'setup_src.sh');
73
+ await fs.copy(scriptPath, localScript);
74
+ await fs.chmod(localScript, '755');
75
+
76
+ // Esecuzione dello script (che ora crea anche index.html se incluso)
77
+ await execa('./setup_src.sh', [], { cwd: targetDir, shell: true });
78
+ await fs.remove(localScript);
79
+ spinner.succeed('Source code and assets projected successfully.');
80
+
81
+ // 5. DEPENDENCY RESOLUTION (Green Build Enforcement)
82
+ spinner.start('Installing dependencies (this may take a minute)...');
83
+
84
+ // 5a. Runtime Dependencies (Risolve Radix, CVA e Animations)
85
+ await execa('npm', ['install',
86
+ 'react',
87
+ 'react-dom',
88
+ 'zod',
89
+ 'react-router-dom',
90
+ 'lucide-react',
91
+ 'radix-ui', // šŸ›”ļø Risolve TS2307
92
+ '@base-ui/react', // Supporto componenti headless
93
+ 'class-variance-authority', // Supporto varianti componenti
94
+ 'tailwind-merge',
95
+ 'clsx',
96
+ 'tw-animate-css', // Supporto animazioni tenant
97
+ 'file-saver',
98
+ 'jszip'
99
+ ], { cwd: targetDir });
100
+
101
+ // 5b. Dev Dependencies
102
+ await execa('npm', ['install', '-D',
103
+ 'vite',
104
+ '@vitejs/plugin-react',
105
+ 'typescript',
106
+ '@tailwindcss/vite',
107
+ 'tailwindcss',
108
+ '@types/node',
109
+ '@types/react',
110
+ '@types/react-dom',
111
+ '@types/file-saver'
112
+ ], { cwd: targetDir });
113
+
114
+ // 5c. Linking Core via yalc
115
+ spinner.text = 'Linking @jsonpages/core via yalc...';
116
+ try {
117
+ await execa('yalc', ['add', '@jsonpages/core'], { cwd: targetDir });
118
+ } catch (e) {
119
+ spinner.warn(chalk.yellow('Yalc link failed. Ensure "@jsonpages/core" is published in yalc.'));
120
+ }
121
+
122
+ spinner.succeed(chalk.green.bold('✨ Tenant Ready!'));
123
+
124
+ console.log(`\n${chalk.white.bgBlue(' NEXT STEPS ')}`);
125
+ console.log(` ${chalk.cyan(`cd ${name}`)}`);
126
+ console.log(` ${chalk.cyan(`npm run dev`)} <- Start development`);
127
+ console.log(` ${chalk.cyan(`npm run build`)} <- Validate Green Build`);
128
+ console.log(`\nGovernance enforced. Build is now safe.\n`);
129
+
130
+ } catch (error) {
131
+ spinner.fail(chalk.red('Projection failed.'));
132
+ console.error(error);
133
+ }
134
+ });
135
+
136
+ async function injectInfraFiles(targetDir, name) {
137
+ const pkg = {
138
+ name: name,
139
+ private: true,
140
+ version: "1.0.0",
141
+ type: "module",
142
+ scripts: {
143
+ "dev": "vite",
144
+ "build": "tsc && vite build",
145
+ "preview": "vite preview"
146
+ }
147
+ };
148
+ await fs.writeJson(path.join(targetDir, 'package.json'), pkg, { spaces: 2 });
149
+
150
+ const viteConfig = `
151
+ import { defineConfig } from 'vite';
152
+ import react from '@vitejs/plugin-react';
153
+ import tailwindcss from '@tailwindcss/vite';
154
+ import path from 'path';
155
+
156
+ export default defineConfig({
157
+ plugins: [react(), tailwindcss()],
158
+ resolve: {
159
+ alias: {
160
+ '@': path.resolve(__dirname, './src'),
161
+ },
162
+ },
163
+ });`;
164
+ await fs.writeFile(path.join(targetDir, 'vite.config.ts'), viteConfig.trim());
165
+
166
+ const tsConfig = `
167
+ {
168
+ "compilerOptions": {
169
+ "target": "ES2020",
170
+ "useDefineForClassFields": true,
171
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
172
+ "module": "ESNext",
173
+ "skipLibCheck": true,
174
+ "moduleResolution": "bundler",
175
+ "allowImportingTsExtensions": true,
176
+ "resolveJsonModule": true,
177
+ "isolatedModules": true,
178
+ "noEmit": true,
179
+ "jsx": "react-jsx",
180
+ "strict": true,
181
+ "noUnusedLocals": true,
182
+ "noUnusedParameters": true,
183
+ "noFallthroughCasesInSwitch": true,
184
+ "baseUrl": ".",
185
+ "paths": {
186
+ "@/*": ["./src/*"]
187
+ }
188
+ },
189
+ "include": ["src"]
190
+ }`;
191
+ await fs.writeFile(path.join(targetDir, 'tsconfig.json'), tsConfig.trim());
192
+
193
+ const shadcnConfig = {
194
+ "$schema": "https://ui.shadcn.com/schema.json",
195
+ "style": "radix-nova",
196
+ "rsc": false,
197
+ "tsx": true,
198
+ "tailwind": {
199
+ "config": "",
200
+ "css": "src/index.css",
201
+ "baseColor": "zinc",
202
+ "cssVariables": true,
203
+ "prefix": ""
204
+ },
205
+ "aliases": {
206
+ "components": "@/components",
207
+ "utils": "@/lib/utils",
208
+ "ui": "@/components/ui",
209
+ "lib": "@/lib",
210
+ "hooks": "@/hooks"
211
+ }
212
+ };
213
+ await fs.writeJson(path.join(targetDir, 'components.json'), shadcnConfig, { spaces: 2 });
214
+ }
215
+
216
+ program.parse();
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "esModuleInterop": true,
9
+ "allowJs": true,
10
+ "noEmit": true
11
+ },
12
+ "include": ["src/**/*.ts", "src/**/*.js"]
13
+ }