@jsonpages/cli 3.0.71 → 3.0.73

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 CHANGED
@@ -1,43 +1,45 @@
1
- {
2
- "name": "@jsonpages/cli",
3
- "version": "3.0.71",
4
- "description": "The Sovereign CLI Engine for JsonPages.",
5
- "type": "module",
6
- "bin": {
7
- "jsonpages": "./src/index.js"
8
- },
9
- "files": [
10
- "src",
11
- "assets/src_tenant_alpha.sh"
12
- ],
13
- "author": "JsonPages Team",
14
- "license": "MIT",
15
- "homepage": "https://github.com/jsonpages/npm-jpcore#readme",
16
- "repository": {
17
- "type": "git",
18
- "url": "git+https://github.com/jsonpages/npm-jpcore.git",
19
- "directory": "packages/core"
20
- },
21
- "bugs": {
22
- "url": "https://github.com/jsonpages/npm-jpcore/issues"
23
- },
24
- "publishConfig": {
25
- "access": "public"
26
- },
27
- "scripts": {
28
- "build": "tsc -p ."
29
- },
30
- "dependencies": {
31
- "@jsonpages/stack": "^1.0.0",
32
- "chalk": "^5.3.0",
33
- "commander": "^12.1.0",
34
- "execa": "^9.0.2",
35
- "fs-extra": "^11.2.0",
36
- "ora": "^8.0.1"
37
- },
38
- "devDependencies": {
39
- "@types/fs-extra": "^11.0.4",
40
- "@types/node": "^22.13.1",
41
- "typescript": "^5.7.3"
42
- }
43
- }
1
+ {
2
+ "name": "@jsonpages/cli",
3
+ "version": "3.0.73",
4
+ "description": "The Sovereign CLI Engine for JsonPages.",
5
+ "type": "module",
6
+ "bin": {
7
+ "jsonpages": "./src/index.js"
8
+ },
9
+ "files": [
10
+ "src",
11
+ "assets/src_tenant_alpha.sh",
12
+ "assets/templates"
13
+ ],
14
+ "author": "JsonPages Team",
15
+ "license": "MIT",
16
+ "homepage": "https://github.com/jsonpages/npm-jpcore#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/jsonpages/npm-jpcore.git",
20
+ "directory": "packages/cli"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/jsonpages/npm-jpcore/issues"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "scripts": {
29
+ "build": "tsc -p .",
30
+ "check:templates": "node ../../scripts/check-cli-templates.mjs"
31
+ },
32
+ "dependencies": {
33
+ "@jsonpages/stack": "^1.0.0",
34
+ "chalk": "^5.3.0",
35
+ "commander": "^12.1.0",
36
+ "execa": "^9.0.2",
37
+ "fs-extra": "^11.2.0",
38
+ "ora": "^8.0.1"
39
+ },
40
+ "devDependencies": {
41
+ "@types/fs-extra": "^11.0.4",
42
+ "@types/node": "^22.13.1",
43
+ "typescript": "^5.7.3"
44
+ }
45
+ }
package/src/index.js CHANGED
@@ -7,26 +7,23 @@ import { execa } from 'execa';
7
7
  import ora from 'ora';
8
8
  import { fileURLToPath } from 'url';
9
9
 
10
- // 🛡️ Risoluzione path ESM
11
10
  const __filename = fileURLToPath(import.meta.url);
12
11
  const __dirname = path.dirname(__filename);
12
+ const CLI_ASSETS_DIR = path.resolve(__dirname, '../assets');
13
+ const TEMPLATES_DIR = path.join(CLI_ASSETS_DIR, 'templates');
14
+ const LEGACY_ALPHA_DNA_PATH = path.join(CLI_ASSETS_DIR, 'src_tenant_alpha.sh');
13
15
 
14
16
  const program = new Command();
15
17
 
16
18
  program
17
19
  .name('jsonpages')
18
20
  .description('JsonPages CLI - Sovereign Projection Engine')
19
- .version('2.0.2'); // Bump version
21
+ .version('2.0.2');
20
22
 
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
23
  async function processScriptInNode(scriptPath, targetDir) {
27
24
  const content = await fs.readFile(scriptPath, 'utf-8');
28
25
  const lines = content.split('\n');
29
-
26
+
30
27
  let captureMode = false;
31
28
  let delimiter = '';
32
29
  let currentFile = '';
@@ -35,35 +32,25 @@ async function processScriptInNode(scriptPath, targetDir) {
35
32
  for (const line of lines) {
36
33
  const trimmed = line.trim();
37
34
 
38
- // 1. Modalità Cattura (Siamo dentro un cat << 'DELIMITER')
39
35
  if (captureMode) {
40
36
  if (trimmed === delimiter) {
41
- // Fine del blocco: Scriviamo su disco
42
37
  const filePath = path.join(targetDir, currentFile);
43
38
  await fs.outputFile(filePath, fileBuffer.join('\n'));
44
39
  captureMode = false;
45
40
  fileBuffer = [];
46
41
  } else {
47
- fileBuffer.push(line); // Preserva l'indentazione originale
42
+ fileBuffer.push(line);
48
43
  }
49
44
  continue;
50
45
  }
51
46
 
52
- // 2. Parsing Comandi Bash -> Node Operations
53
-
54
- // Rileva: mkdir -p "path"
55
47
  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
48
+ const match = trimmed.match(/"([^"]+)"/) || trimmed.match(/\s+([^\s]+)/);
58
49
  const dirPath = match ? match[1].replace(/"/g, '') : null;
59
50
  if (dirPath) {
60
51
  await fs.ensureDir(path.join(targetDir, dirPath));
61
52
  }
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
53
+ } else if (trimmed.startsWith('cat <<')) {
67
54
  const match = trimmed.match(/<<\s*'([^']+)'\s*>\s*"([^"]+)"/);
68
55
  if (match) {
69
56
  delimiter = match[1];
@@ -71,49 +58,69 @@ async function processScriptInNode(scriptPath, targetDir) {
71
58
  captureMode = true;
72
59
  }
73
60
  }
74
- // Ignora echo, set -e, commenti #, ecc.
75
61
  }
76
62
  }
77
63
 
64
+ function getAvailableTemplates() {
65
+ if (!fs.existsSync(TEMPLATES_DIR)) return [];
66
+ return fs
67
+ .readdirSync(TEMPLATES_DIR, { withFileTypes: true })
68
+ .filter((entry) => entry.isDirectory())
69
+ .map((entry) => entry.name)
70
+ .filter((name) => fs.existsSync(path.join(TEMPLATES_DIR, name, 'src_tenant.sh')))
71
+ .sort((a, b) => a.localeCompare(b));
72
+ }
73
+
74
+ function resolveTemplateScriptPath(templateName) {
75
+ const templatePath = path.join(TEMPLATES_DIR, templateName, 'src_tenant.sh');
76
+ if (fs.existsSync(templatePath)) return templatePath;
77
+ if (templateName === 'alpha' && fs.existsSync(LEGACY_ALPHA_DNA_PATH)) return LEGACY_ALPHA_DNA_PATH;
78
+ return templatePath;
79
+ }
80
+
78
81
  program
79
82
  .command('new')
80
83
  .argument('<type>', 'Type of artifact (tenant)')
81
84
  .argument('<name>', 'Name of the new tenant')
85
+ .option('--template <name>', 'Template profile (default: alpha)', 'alpha')
86
+ .option('--agritourism', 'Alias for --template agritourism')
82
87
  .option('--script <path>', 'Override default deterministic script path')
83
88
  .action(async (type, name, options) => {
84
89
  if (type !== 'tenant') {
85
- console.log(chalk.red('Error: Only "tenant" type is supported.'));
90
+ console.log(chalk.red('Error: Only "tenant" type is supported.'));
86
91
  return;
87
92
  }
88
93
 
89
94
  const targetDir = path.join(process.cwd(), name);
90
-
91
- // 🔍 Asset Resolution
92
- // Cerca lo script nella cartella assets installata col pacchetto
93
- const defaultScriptPath = path.resolve(__dirname, '../assets/src_tenant_alpha.sh');
94
- const scriptPath = options.script ? path.resolve(process.cwd(), options.script) : defaultScriptPath;
95
+ const availableTemplates = getAvailableTemplates();
96
+ const template = options.agritourism ? 'agritourism' : options.template;
97
+ const scriptPath = options.script
98
+ ? path.resolve(process.cwd(), options.script)
99
+ : resolveTemplateScriptPath(template);
100
+
101
+ if (!options.script && !availableTemplates.includes(template) && !(template === 'alpha' && fs.existsSync(LEGACY_ALPHA_DNA_PATH))) {
102
+ console.log(chalk.red(`Error: Unknown template "${template}".`));
103
+ console.log(chalk.yellow(`Available templates: ${availableTemplates.length ? availableTemplates.join(', ') : '(none found)'}`));
104
+ return;
105
+ }
95
106
 
96
107
  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}`));
108
+ console.log(chalk.red(`Error: DNA script not found at ${scriptPath}`));
109
+ console.log(chalk.yellow(`Debug info: template=${template}, assets=${CLI_ASSETS_DIR}`));
99
110
  return;
100
111
  }
101
112
 
102
- console.log(chalk.blue.bold(`\n🚀 Projecting Sovereign Tenant: ${name}\n`));
113
+ console.log(chalk.blue.bold(`\nProjecting Sovereign Tenant: ${name} (template: ${template})\n`));
103
114
  const spinner = ora();
104
115
 
105
116
  try {
106
- // 1. SCAFFOLDING INFRA
107
117
  spinner.start('Setting up environment (Vite + TS)...');
108
118
  await fs.ensureDir(targetDir);
109
-
110
- // Windows fix: npm.cmd invece di npm
119
+
111
120
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
112
-
113
121
  await execa(npmCmd, ['create', 'vite@latest', '.', '--', '--template', 'react-ts'], { cwd: targetDir });
114
122
  spinner.succeed('Environment scaffolded.');
115
123
 
116
- // 2. CLEANUP
117
124
  spinner.start('Wiping default boilerplate...');
118
125
  await fs.emptyDir(path.join(targetDir, 'src'));
119
126
  const junk = ['App.css', 'App.tsx', 'main.tsx', 'vite-env.d.ts', 'favicon.ico', 'index.html'];
@@ -123,28 +130,23 @@ program
123
130
  }
124
131
  spinner.succeed('Clean slate achieved.');
125
132
 
126
- // 3. INJECTION
127
133
  spinner.start('Injecting Sovereign Configurations...');
128
134
  await injectInfraFiles(targetDir, name);
129
135
  spinner.succeed('Infrastructure configured.');
130
136
 
131
- // 4. DETERMINISTIC PROJECTION (Node-based Interpreter)
132
137
  spinner.start('Executing deterministic src projection...');
133
- // Invece di execa('./script.sh'), usiamo il nostro interprete
134
138
  await processScriptInNode(scriptPath, targetDir);
135
139
  spinner.succeed('Source code and assets projected successfully.');
136
140
 
137
- // 5. Install dependencies (lo script .sh deve aver già scritto/copiato package.json in targetDir)
138
141
  spinner.start('Installing dependencies (this may take a minute)...');
139
142
  await execa(npmCmd, ['install'], { cwd: targetDir });
140
- spinner.succeed(chalk.green.bold('Tenant Ready!'));
143
+ spinner.succeed(chalk.green.bold('Tenant Ready.'));
141
144
 
142
145
  console.log(`\n${chalk.white.bgBlue(' NEXT STEPS ')}`);
143
146
  console.log(` ${chalk.cyan(`cd ${name}`)}`);
144
- console.log(` ${chalk.cyan(`npm run dev`)} <- Start development`);
145
- console.log(` ${chalk.cyan(`npm run build`)} <- Validate Green Build`);
146
- console.log(`\nGovernance enforced. Build is now safe.\n`);
147
-
147
+ console.log(` ${chalk.cyan('npm run dev')} <- Start development`);
148
+ console.log(` ${chalk.cyan('npm run build')} <- Validate Green Build`);
149
+ console.log(`\nTemplate used: ${template}\n`);
148
150
  } catch (error) {
149
151
  spinner.fail(chalk.red('Projection failed.'));
150
152
  console.error(error);
@@ -153,15 +155,15 @@ program
153
155
 
154
156
  async function injectInfraFiles(targetDir, name) {
155
157
  const pkg = {
156
- name: name,
158
+ name,
157
159
  private: true,
158
- version: "1.0.0",
159
- type: "module",
160
+ version: '1.0.0',
161
+ type: 'module',
160
162
  scripts: {
161
- "dev": "vite",
162
- "build": "tsc && vite build",
163
- "preview": "vite preview"
164
- }
163
+ dev: 'vite',
164
+ build: 'tsc && vite build',
165
+ preview: 'vite preview',
166
+ },
165
167
  };
166
168
  await fs.writeJson(path.join(targetDir, 'package.json'), pkg, { spaces: 2 });
167
169
 
@@ -197,26 +199,26 @@ async function injectInfraFiles(targetDir, name) {
197
199
  await fs.writeFile(path.join(targetDir, 'tsconfig.json'), tsConfig.trim());
198
200
 
199
201
  const shadcnConfig = {
200
- "$schema": "https://ui.shadcn.com/schema.json",
201
- "style": "radix-nova",
202
- "rsc": false,
203
- "tsx": true,
204
- "tailwind": {
205
- "config": "",
206
- "css": "src/index.css",
207
- "baseColor": "zinc",
208
- "cssVariables": true,
209
- "prefix": ""
202
+ $schema: 'https://ui.shadcn.com/schema.json',
203
+ style: 'radix-nova',
204
+ rsc: false,
205
+ tsx: true,
206
+ tailwind: {
207
+ config: '',
208
+ css: 'src/index.css',
209
+ baseColor: 'zinc',
210
+ cssVariables: true,
211
+ prefix: '',
212
+ },
213
+ aliases: {
214
+ components: '@/components',
215
+ utils: '@/lib/utils',
216
+ ui: '@/components/ui',
217
+ lib: '@/lib',
218
+ hooks: '@/hooks',
210
219
  },
211
- "aliases": {
212
- "components": "@/components",
213
- "utils": "@/lib/utils",
214
- "ui": "@/components/ui",
215
- "lib": "@/lib",
216
- "hooks": "@/hooks"
217
- }
218
220
  };
219
221
  await fs.writeJson(path.join(targetDir, 'components.json'), shadcnConfig, { spaces: 2 });
220
222
  }
221
223
 
222
- program.parse();
224
+ program.parse();