@jsonpages/cli 3.0.2 β 3.0.4
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/package.json +1 -1
- package/src/index.js +92 -70
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -6,24 +6,74 @@ import path from 'path';
|
|
|
6
6
|
import { execa } from 'execa';
|
|
7
7
|
import ora from 'ora';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { projectSrc } from './projection.js';
|
|
10
9
|
|
|
11
|
-
// π‘οΈ Risoluzione path
|
|
10
|
+
// π‘οΈ Risoluzione path ESM
|
|
12
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
12
|
const __dirname = path.dirname(__filename);
|
|
14
13
|
|
|
15
|
-
/** Cross-platform: on Windows, npm/yalc are .cmd; execa needs shell to resolve them. */
|
|
16
|
-
const execOpts = (cwd) => ({
|
|
17
|
-
cwd,
|
|
18
|
-
...(process.platform === 'win32' && { shell: true }),
|
|
19
|
-
});
|
|
20
|
-
|
|
21
14
|
const program = new Command();
|
|
22
15
|
|
|
23
16
|
program
|
|
24
17
|
.name('jsonpages')
|
|
25
18
|
.description('JsonPages CLI - Sovereign Projection Engine')
|
|
26
|
-
.version('2.2
|
|
19
|
+
.version('2.0.2'); // Bump version
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* π§ THE UNIVERSAL INTERPRETER
|
|
23
|
+
* Legge lo script bash "DNA" e lo esegue usando le API di Node.js.
|
|
24
|
+
* Rende la CLI compatibile con Windows (PowerShell/CMD) senza bisogno di Bash.
|
|
25
|
+
*/
|
|
26
|
+
async function processScriptInNode(scriptPath, targetDir) {
|
|
27
|
+
const content = await fs.readFile(scriptPath, 'utf-8');
|
|
28
|
+
const lines = content.split('\n');
|
|
29
|
+
|
|
30
|
+
let captureMode = false;
|
|
31
|
+
let delimiter = '';
|
|
32
|
+
let currentFile = '';
|
|
33
|
+
let fileBuffer = [];
|
|
34
|
+
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
const trimmed = line.trim();
|
|
37
|
+
|
|
38
|
+
// 1. ModalitΓ Cattura (Siamo dentro un cat << 'DELIMITER')
|
|
39
|
+
if (captureMode) {
|
|
40
|
+
if (trimmed === delimiter) {
|
|
41
|
+
// Fine del blocco: Scriviamo su disco
|
|
42
|
+
const filePath = path.join(targetDir, currentFile);
|
|
43
|
+
await fs.outputFile(filePath, fileBuffer.join('\n'));
|
|
44
|
+
captureMode = false;
|
|
45
|
+
fileBuffer = [];
|
|
46
|
+
} else {
|
|
47
|
+
fileBuffer.push(line); // Preserva l'indentazione originale
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 2. Parsing Comandi Bash -> Node Operations
|
|
53
|
+
|
|
54
|
+
// Rileva: mkdir -p "path"
|
|
55
|
+
if (trimmed.startsWith('mkdir -p')) {
|
|
56
|
+
const match = trimmed.match(/"([^"]+)"/) || trimmed.match(/\s+([^\s]+)/);
|
|
57
|
+
// Supporta sia mkdir -p "foo/bar" che mkdir -p foo/bar
|
|
58
|
+
const dirPath = match ? match[1].replace(/"/g, '') : null;
|
|
59
|
+
if (dirPath) {
|
|
60
|
+
await fs.ensureDir(path.join(targetDir, dirPath));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Rileva: cat << 'DELIMITER' > "path"
|
|
65
|
+
else if (trimmed.startsWith('cat <<')) {
|
|
66
|
+
// Regex robusta per catturare il delimitatore e il path del file
|
|
67
|
+
const match = trimmed.match(/<<\s*'([^']+)'\s*>\s*"([^"]+)"/);
|
|
68
|
+
if (match) {
|
|
69
|
+
delimiter = match[1];
|
|
70
|
+
currentFile = match[2];
|
|
71
|
+
captureMode = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Ignora echo, set -e, commenti #, ecc.
|
|
75
|
+
}
|
|
76
|
+
}
|
|
27
77
|
|
|
28
78
|
program
|
|
29
79
|
.command('new')
|
|
@@ -38,15 +88,14 @@ program
|
|
|
38
88
|
|
|
39
89
|
const targetDir = path.join(process.cwd(), name);
|
|
40
90
|
|
|
41
|
-
// π
|
|
42
|
-
//
|
|
91
|
+
// π Asset Resolution
|
|
92
|
+
// Cerca lo script nella cartella assets installata col pacchetto
|
|
43
93
|
const defaultScriptPath = path.resolve(__dirname, '../assets/src_tenant_alpha.sh');
|
|
44
94
|
const scriptPath = options.script ? path.resolve(process.cwd(), options.script) : defaultScriptPath;
|
|
45
95
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
console.log(chalk.
|
|
49
|
-
console.log(chalk.yellow(`Expected internal asset at: ${defaultScriptPath}`));
|
|
96
|
+
if (!fs.existsSync(scriptPath)) {
|
|
97
|
+
console.log(chalk.red(`β Error: DNA script not found at ${scriptPath}`));
|
|
98
|
+
console.log(chalk.yellow(`Debug info: __dirname is ${__dirname}`));
|
|
50
99
|
return;
|
|
51
100
|
}
|
|
52
101
|
|
|
@@ -57,10 +106,14 @@ program
|
|
|
57
106
|
// 1. SCAFFOLDING INFRA
|
|
58
107
|
spinner.start('Setting up environment (Vite + TS)...');
|
|
59
108
|
await fs.ensureDir(targetDir);
|
|
60
|
-
|
|
109
|
+
|
|
110
|
+
// Windows fix: npm.cmd invece di npm
|
|
111
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
112
|
+
|
|
113
|
+
await execa(npmCmd, ['create', 'vite@latest', '.', '--', '--template', 'react-ts'], { cwd: targetDir });
|
|
61
114
|
spinner.succeed('Environment scaffolded.');
|
|
62
115
|
|
|
63
|
-
// 2. CLEANUP
|
|
116
|
+
// 2. CLEANUP
|
|
64
117
|
spinner.start('Wiping default boilerplate...');
|
|
65
118
|
await fs.emptyDir(path.join(targetDir, 'src'));
|
|
66
119
|
const junk = ['App.css', 'App.tsx', 'main.tsx', 'vite-env.d.ts', 'favicon.ico', 'index.html'];
|
|
@@ -75,62 +128,31 @@ program
|
|
|
75
128
|
await injectInfraFiles(targetDir, name);
|
|
76
129
|
spinner.succeed('Infrastructure configured.');
|
|
77
130
|
|
|
78
|
-
// 4. DETERMINISTIC
|
|
79
|
-
spinner.start('
|
|
80
|
-
|
|
81
|
-
|
|
131
|
+
// 4. DETERMINISTIC PROJECTION (Node-based Interpreter)
|
|
132
|
+
spinner.start('Executing deterministic src projection...');
|
|
133
|
+
// Invece di execa('./script.sh'), usiamo il nostro interprete
|
|
134
|
+
await processScriptInNode(scriptPath, targetDir);
|
|
135
|
+
spinner.succeed('Source code and assets projected successfully.');
|
|
82
136
|
|
|
83
|
-
// 5. DEPENDENCY RESOLUTION
|
|
137
|
+
// 5. DEPENDENCY RESOLUTION
|
|
84
138
|
spinner.start('Installing dependencies (this may take a minute)...');
|
|
85
139
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
'
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
'file-saver',
|
|
103
|
-
'jszip',
|
|
104
|
-
],
|
|
105
|
-
execOpts(targetDir)
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
// 5b. Dev Dependencies
|
|
109
|
-
await execa(
|
|
110
|
-
'npm',
|
|
111
|
-
[
|
|
112
|
-
'install',
|
|
113
|
-
'-D',
|
|
114
|
-
'vite',
|
|
115
|
-
'@vitejs/plugin-react',
|
|
116
|
-
'typescript',
|
|
117
|
-
'@tailwindcss/vite',
|
|
118
|
-
'tailwindcss',
|
|
119
|
-
'@types/node',
|
|
120
|
-
'@types/react',
|
|
121
|
-
'@types/react-dom',
|
|
122
|
-
'@types/file-saver',
|
|
123
|
-
],
|
|
124
|
-
execOpts(targetDir)
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
// 5c. Linking Core via yalc
|
|
128
|
-
spinner.text = 'Linking @jsonpages/core via yalc...';
|
|
129
|
-
try {
|
|
130
|
-
await execa('yalc', ['add', '@jsonpages/core'], execOpts(targetDir));
|
|
131
|
-
} catch (e) {
|
|
132
|
-
spinner.warn(chalk.yellow('Yalc link failed. Ensure "@jsonpages/core" is published in yalc.'));
|
|
133
|
-
}
|
|
140
|
+
const deps = [
|
|
141
|
+
'react', 'react-dom', 'zod', 'react-router-dom',
|
|
142
|
+
'lucide-react', 'radix-ui',
|
|
143
|
+
'tailwind-merge', 'clsx',
|
|
144
|
+
'file-saver', 'jszip',
|
|
145
|
+
'@jsonpages/core' // Scarica dal registry pubblico
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
const devDeps = [
|
|
149
|
+
'vite', '@vitejs/plugin-react', 'typescript',
|
|
150
|
+
'@tailwindcss/vite', 'tailwindcss',
|
|
151
|
+
'@types/node', '@types/react', '@types/react-dom', '@types/file-saver'
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
await execa(npmCmd, ['install', ...deps], { cwd: targetDir });
|
|
155
|
+
await execa(npmCmd, ['install', '-D', ...devDeps], { cwd: targetDir });
|
|
134
156
|
|
|
135
157
|
spinner.succeed(chalk.green.bold('β¨ Tenant Ready!'));
|
|
136
158
|
|