@ijuantm/simpl-addon 2.6.3 → 2.6.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.
Files changed (2) hide show
  1. package/install.js +129 -185
  2. package/package.json +1 -1
package/install.js CHANGED
@@ -16,9 +16,18 @@ const COLORS = {
16
16
 
17
17
  const CDN_BASE = 'https://cdn.simpl.iwanvanderwal.nl/framework';
18
18
  const LOCAL_RELEASES_DIR = process.env.SIMPL_LOCAL_RELEASES || path.join(process.cwd(), 'local-releases');
19
+ const BOX_WIDTH = 62;
19
20
 
20
21
  const log = (message, color = 'reset') => console.log(`${COLORS[color]}${message}${COLORS.reset}`);
21
22
 
23
+ const box = (title) => {
24
+ log();
25
+ log(` ╭${'─'.repeat(BOX_WIDTH)}╮`);
26
+ log(` │ ${COLORS.bold}${title}${COLORS.reset}${' '.repeat(Math.max(0, BOX_WIDTH - title.length - 2))}│`);
27
+ log(` ╰${'─'.repeat(BOX_WIDTH)}╯`);
28
+ log();
29
+ };
30
+
22
31
  const fetchUrl = (url) => new Promise((resolve, reject) => {
23
32
  https.get(url, res => {
24
33
  if (res.statusCode === 302 || res.statusCode === 301) return fetchUrl(res.headers.location).then(resolve).catch(reject);
@@ -62,7 +71,6 @@ const downloadFile = (url, dest) => new Promise((resolve, reject) => {
62
71
  const promptUser = (question, defaultValue = '') => new Promise(resolve => {
63
72
  const rl = readline.createInterface({input: process.stdin, output: process.stdout});
64
73
  const prompt = defaultValue ? `${question} ${COLORS.dim}(${defaultValue})${COLORS.reset}: ` : `${question}: `;
65
-
66
74
  rl.question(prompt, answer => {
67
75
  rl.close();
68
76
  resolve(answer.trim() || defaultValue);
@@ -73,48 +81,22 @@ const printAnswer = (question, value) => console.log(`${question}: ${COLORS.cyan
73
81
 
74
82
  const getSimplVersion = () => {
75
83
  const simplFile = path.join(process.cwd(), '.simpl');
76
-
77
84
  if (!fs.existsSync(simplFile)) throw new Error('Not a Simpl project. Missing .simpl file in current directory.');
78
-
79
85
  const config = JSON.parse(fs.readFileSync(simplFile, 'utf8'));
80
-
81
86
  if (!config.version) throw new Error('Invalid .simpl file: missing version field');
82
-
83
87
  return config.version;
84
88
  };
85
89
 
86
- // --- Argument parsing ---
87
-
88
90
  const parseArgs = (args) => {
89
91
  const result = {addon: null, unknownFlags: [], help: false, list: false};
90
-
91
92
  for (const arg of args) {
92
- if (arg === '--help' || arg === '-h') {
93
- result.help = true;
94
- continue;
95
- }
96
- if (arg === '--list' || arg === '-l') {
97
- result.list = true;
98
- continue;
99
- }
100
-
101
- if (arg.startsWith('--addon=')) {
102
- result.addon = arg.slice(8).trim() || null;
103
- continue;
104
- }
105
- if (arg.startsWith('-a=')) {
106
- result.addon = arg.slice(3).trim() || null;
107
- continue;
108
- }
109
-
110
- if (arg.startsWith('-') && !arg.startsWith('--addon') && !arg.startsWith('-a')) {
111
- result.unknownFlags.push(arg);
112
- continue;
113
- }
114
-
115
- if (!arg.startsWith('-') && !result.addon) result.addon = arg;
93
+ if (arg === '--help' || arg === '-h') result.help = true;
94
+ else if (arg === '--list' || arg === '-l') result.list = true;
95
+ else if (arg.startsWith('--addon=')) result.addon = arg.slice(8).trim() || null;
96
+ else if (arg.startsWith('-a=')) result.addon = arg.slice(3).trim() || null;
97
+ else if (arg.startsWith('-') && !arg.startsWith('--addon') && !arg.startsWith('-a')) result.unknownFlags.push(arg);
98
+ else if (!arg.startsWith('-') && !result.addon) result.addon = arg;
116
99
  }
117
-
118
100
  return result;
119
101
  };
120
102
 
@@ -123,17 +105,12 @@ const KNOWN_FLAGS = ['--addon', '-a', '--help', '-h', '--list', '-l'];
123
105
  const levenshtein = (a, b) => {
124
106
  const m = a.length, n = b.length;
125
107
  const dp = Array.from({length: m + 1}, (_, i) => Array.from({length: n + 1}, (_, j) => i === 0 ? j : j === 0 ? i : 0));
126
-
127
- for (let i = 1; i <= m; i++)
128
- for (let j = 1; j <= n; j++)
129
- dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
130
-
108
+ for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
131
109
  return dp[m][n];
132
110
  };
133
111
 
134
112
  const closestMatch = (input, options) => {
135
113
  let best = null, bestDist = Infinity;
136
-
137
114
  for (const opt of options) {
138
115
  const dist = levenshtein(input.toLowerCase(), opt.toLowerCase());
139
116
  if (dist < bestDist) {
@@ -141,50 +118,43 @@ const closestMatch = (input, options) => {
141
118
  best = opt;
142
119
  }
143
120
  }
144
-
145
121
  return bestDist <= Math.max(3, Math.floor(input.length / 2)) ? best : null;
146
122
  };
147
123
 
148
- // --- Fuzzy addon resolution with interactive prompts ---
149
-
150
124
  const promptAddon = async (addons, firstInput = null) => {
151
125
  const askSuggestion = async (input) => {
152
126
  const suggestion = closestMatch(input, addons);
153
- console.log();
154
- log(` ${COLORS.red}✗${COLORS.reset} Add-on ${COLORS.bold}${input}${COLORS.reset} not found`, 'red');
127
+ log();
128
+ log(` ${COLORS.red}✗${COLORS.reset} Add-on ${COLORS.bold}${input}${COLORS.reset} not found`);
155
129
 
156
130
  if (suggestion) {
157
- log(` ${COLORS.yellow}Did you mean:${COLORS.reset} ${COLORS.cyan}${suggestion}${COLORS.reset}?`);
158
- console.log();
131
+ log(` Did you mean: ${COLORS.blue}${suggestion}${COLORS.reset}?`);
132
+ log();
159
133
 
160
134
  while (true) {
161
- const answer = await promptUser(` Use "${suggestion}"? ${COLORS.dim}(yes / no — no lists available add-ons)${COLORS.reset}`);
135
+ const answer = await promptUser(` Use "${suggestion}"? ${COLORS.dim}(yes / no (lists available add-ons))${COLORS.reset}`);
162
136
  const a = answer.toLowerCase();
163
-
164
137
  if (a === 'yes' || a === 'y') return suggestion;
165
138
  if (a === 'no' || a === 'n') break;
166
-
167
- log(` ${COLORS.dim}Please answer yes or no${COLORS.reset}`);
139
+ log(` ${COLORS.yellow}⚠${COLORS.reset} ${COLORS.dim}Please answer yes or no${COLORS.reset}`);
168
140
  }
169
141
  }
170
142
 
171
- console.log();
172
- log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
143
+ log();
144
+ log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
173
145
  listAddons(addons);
174
- console.log();
175
-
146
+ log();
176
147
  return null;
177
148
  };
178
149
 
179
150
  let pending = firstInput;
180
-
181
151
  while (true) {
182
- const input = pending || await promptUser(` Add-on to install ${COLORS.dim}(name or number)${COLORS.reset}`);
152
+ const input = pending || await promptUser(` Add-on to install ${COLORS.dim}(name or number)${COLORS.reset}`);
183
153
  pending = null;
184
154
 
185
155
  if (!input) {
186
- log(` ${COLORS.red}✗${COLORS.reset} Selection cannot be empty`, 'red');
187
- console.log();
156
+ log(` ${COLORS.yellow}⚠${COLORS.reset} ${COLORS.dim}Selection cannot be empty${COLORS.reset}`);
157
+ log();
188
158
  continue;
189
159
  }
190
160
 
@@ -197,42 +167,31 @@ const promptAddon = async (addons, firstInput = null) => {
197
167
  }
198
168
  };
199
169
 
200
- const listAddons = (addons) => addons.forEach((name, i) => log(` ${COLORS.cyan}${i + 1}.${COLORS.reset} ${name}`));
201
-
202
- // --- Help ---
170
+ const listAddons = (addons) => addons.forEach((name, i) => log(` ${COLORS.cyan}${i + 1}.${COLORS.reset} ${name}`));
203
171
 
204
172
  const showHelp = () => {
205
- console.log();
206
- log(` ╭${''.repeat(62)}╮`);
207
- log(`${COLORS.bold}Simpl Add-on Installer${COLORS.reset}${' '.repeat(38)}│`);
208
- log(` ╰${'─'.repeat(62)}╯`);
209
- console.log();
210
- log(` ${COLORS.bold}Usage:${COLORS.reset}`, 'blue');
211
- log(` ${COLORS.dim}npx @ijuantm/simpl-addon${COLORS.reset}`);
212
- log(` ${COLORS.dim}npx @ijuantm/simpl-addon --addon=<name>${COLORS.reset}`);
213
- log(` ${COLORS.dim}npx @ijuantm/simpl-addon --help${COLORS.reset}`);
214
- console.log();
215
- log(` ${COLORS.bold}Options:${COLORS.reset}`, 'blue');
216
- log(` ${COLORS.dim}--addon=<name>, -a=<name>${COLORS.reset} Add-on to install`);
217
- log(` ${COLORS.dim}--list, -l${COLORS.reset} List available add-ons`);
218
- log(` ${COLORS.dim}--help, -h${COLORS.reset} Show this help message`);
219
- console.log();
220
- log(` ${COLORS.bold}Note:${COLORS.reset}`, 'blue');
221
- log(` Run this command from the root of your Simpl project.`);
222
- log(` The add-on version will match your Simpl framework version.`);
223
- console.log();
173
+ box('Simpl Add-on Installer');
174
+ log(` ${COLORS.bold}Usage:${COLORS.reset}`, 'blue');
175
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon${COLORS.reset}`);
176
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon --addon=<name>${COLORS.reset}`);
177
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon --help${COLORS.reset}`);
178
+ log();
179
+ log(` ${COLORS.bold}Options:${COLORS.reset}`, 'blue');
180
+ log(` ${COLORS.dim}--addon=<name>, -a=<name>${COLORS.reset} Add-on to install`);
181
+ log(` ${COLORS.dim}--list, -l${COLORS.reset} List available add-ons`);
182
+ log(` ${COLORS.dim}--help, -h${COLORS.reset} Show this help message`);
183
+ log();
184
+ log(` ${COLORS.bold}Note:${COLORS.reset}`, 'blue');
185
+ log(` Run this command from the root of your Simpl project.`);
186
+ log(` The add-on version will match your Simpl framework version.`);
187
+ log();
224
188
  };
225
189
 
226
190
  const checkServerAvailability = () => new Promise(resolve => {
227
- const req = https.get(`${CDN_BASE}/versions.json`, {timeout: 5000}, res => {
191
+ https.get(`${CDN_BASE}/versions.json`, {timeout: 5000}, res => {
228
192
  res.resume();
229
193
  resolve(res.statusCode === 200);
230
- });
231
- req.on('error', () => resolve(false));
232
- req.on('timeout', () => {
233
- req.destroy();
234
- resolve(false);
235
- });
194
+ }).on('error', () => resolve(false)).on('timeout', () => resolve(false));
236
195
  });
237
196
 
238
197
  const getVersionsData = async () => {
@@ -254,11 +213,10 @@ const getAvailableAddons = async (version) => {
254
213
 
255
214
  const extractMarkers = (content) => {
256
215
  const markers = [];
257
-
258
216
  content.split('\n').forEach((line, i) => {
259
- const afterMatch = line.match(/@addon-insert:after\s*\(\s*(["'])(.+?)\1\s*\)/);
260
- const beforeMatch = line.match(/@addon-insert:before\s*\(\s*(["'])(.+?)\1\s*\)/);
261
- const replaceMatch = line.match(/@addon-insert:replace\s*\(\s*(["'])(.+?)\1\s*\)/);
217
+ const afterMatch = line.match(/@addon-insert:after\s*\(\s*(["'])(.*?)\1\s*\)/);
218
+ const beforeMatch = line.match(/@addon-insert:before\s*\(\s*(["'])(.*?)\1\s*\)/);
219
+ const replaceMatch = line.match(/@addon-insert:replace\s*\(\s*(["'])(.*?)\1\s*\)/);
262
220
 
263
221
  if (afterMatch) markers.push({type: 'after', lineIndex: i, searchText: afterMatch[2]});
264
222
  else if (beforeMatch) markers.push({type: 'before', lineIndex: i, searchText: beforeMatch[2]});
@@ -266,18 +224,15 @@ const extractMarkers = (content) => {
266
224
  else if (line.includes('@addon-insert:prepend')) markers.push({type: 'prepend', lineIndex: i});
267
225
  else if (line.includes('@addon-insert:append')) markers.push({type: 'append', lineIndex: i});
268
226
  });
269
-
270
227
  return markers;
271
228
  };
272
229
 
273
230
  const collectContentBetweenMarkers = (lines, startIndex) => {
274
231
  const content = [];
275
-
276
232
  for (let i = startIndex + 1; i < lines.length; i++) {
277
233
  if (lines[i].trim().includes('@addon-end')) break;
278
234
  content.push(lines[i]);
279
235
  }
280
-
281
236
  return content;
282
237
  };
283
238
 
@@ -285,10 +240,8 @@ const normalizeContent = (lines) => lines.map(l => l.trim()).filter(l => l && !l
285
240
 
286
241
  const processEnvContent = (content, targetContent) => {
287
242
  const envVarsToAdd = [], comments = [];
288
-
289
243
  content.forEach(line => {
290
244
  const trimmed = line.trim();
291
-
292
245
  if (trimmed.startsWith('#') || !trimmed) {
293
246
  comments.push(line);
294
247
  return;
@@ -297,7 +250,6 @@ const processEnvContent = (content, targetContent) => {
297
250
  const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
298
251
  if (match && !new RegExp(`^${match[1]}=`, 'm').test(targetContent)) envVarsToAdd.push(line);
299
252
  });
300
-
301
253
  return {content: [...comments, ...envVarsToAdd], count: envVarsToAdd.length};
302
254
  };
303
255
 
@@ -372,12 +324,11 @@ const mergeFile = (targetPath, addonContent, markers, isEnv = false) => {
372
324
  });
373
325
 
374
326
  if (newContent !== targetContent) fs.writeFileSync(targetPath, newContent, 'utf8');
375
-
376
327
  return {modified: newContent !== targetContent, operations};
377
328
  };
378
329
 
379
330
  const printMergeResults = (relativePath, isEnv, result) => {
380
- const indent = ' ';
331
+ const indent = ' ';
381
332
  const varText = isEnv ? 'environment variable' : 'line';
382
333
  let hasChanges = false;
383
334
 
@@ -400,18 +351,15 @@ const printMergeResults = (relativePath, isEnv, result) => {
400
351
 
401
352
  const extractZip = async (zipPath, destDir) => {
402
353
  fs.mkdirSync(destDir, {recursive: true});
403
-
404
- if (process.platform === 'win32') await execAsync(`powershell -command "Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force"`);
405
- else await execAsync(`unzip -q "${zipPath}" -d "${destDir}"`);
354
+ const cmd = process.platform === 'win32' ? `powershell -command "Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force"` : `unzip -q "${zipPath}" -d "${destDir}"`;
355
+ await execAsync(cmd);
406
356
 
407
357
  const entries = fs.readdirSync(destDir, {withFileTypes: true});
408
-
409
358
  if (entries.length === 1 && entries[0].isDirectory()) {
410
359
  const nestedDir = path.join(destDir, entries[0].name);
411
360
  fs.readdirSync(nestedDir).forEach(item => fs.renameSync(path.join(nestedDir, item), path.join(destDir, item)));
412
361
  fs.rmdirSync(nestedDir);
413
362
  }
414
-
415
363
  return destDir;
416
364
  };
417
365
 
@@ -443,7 +391,6 @@ const processAddonFiles = (addonDir, targetDir) => {
443
391
  });
444
392
 
445
393
  processDirectory(addonDir);
446
-
447
394
  return {copied, skipped, toMerge};
448
395
  };
449
396
 
@@ -453,8 +400,8 @@ const downloadAddon = async (addonName, version, targetDir) => {
453
400
 
454
401
  try {
455
402
  if (fs.existsSync(localZipPath)) {
456
- console.log();
457
- log(` 💻 Using local add-on files`, 'bold');
403
+ log();
404
+ log(` 💻 Using local add-on files`, 'bold');
458
405
  const sourceDir = await extractZip(localZipPath, tempExtract);
459
406
  const result = processAddonFiles(sourceDir, targetDir);
460
407
  fs.rmSync(tempExtract, {recursive: true, force: true});
@@ -483,14 +430,14 @@ const mergeFiles = (toMerge) => {
483
430
 
484
431
  toMerge.forEach(({content, destPath, relativePath, markers}) => {
485
432
  const isEnv = path.basename(destPath) === '.env';
486
- log(`\n ${COLORS.cyan}•${COLORS.reset} ${COLORS.dim}${relativePath}${COLORS.reset}`);
433
+ log(`\n ${COLORS.cyan}•${COLORS.reset} ${COLORS.dim}${relativePath}${COLORS.reset}`);
487
434
 
488
435
  try {
489
436
  const result = mergeFile(destPath, content, markers, isEnv);
490
437
  if (printMergeResults(relativePath, isEnv, result)) merged.push(relativePath);
491
438
  else unchanged.push(relativePath);
492
439
  } catch (error) {
493
- log(` ${COLORS.red}✗ Error:${COLORS.reset} ${error.message}`, 'red');
440
+ log(` ${COLORS.red}✗ Error:${COLORS.reset} ${error.message}`);
494
441
  failed.push(relativePath);
495
442
  }
496
443
  });
@@ -511,14 +458,14 @@ const main = async () => {
511
458
  for (const flag of parsed.unknownFlags) {
512
459
  const flagName = flag.includes('=') ? flag.slice(0, flag.indexOf('=')) : flag;
513
460
  const suggestion = closestMatch(flagName, KNOWN_FLAGS);
514
- console.log();
515
- log(` ${COLORS.yellow}⚠${COLORS.reset} Unknown option: ${COLORS.bold}${flag}${COLORS.reset}`, 'yellow');
516
- if (suggestion) log(` ${COLORS.dim}Did you mean ${COLORS.reset}${COLORS.cyan}${suggestion}${COLORS.reset}${COLORS.dim}?${COLORS.reset}`);
461
+ log();
462
+ log(` ${COLORS.yellow}⚠${COLORS.reset} Unknown option: ${COLORS.bold}${flag}${COLORS.reset}`, 'yellow');
463
+ if (suggestion) log(` ${COLORS.dim}Did you mean ${COLORS.reset}${COLORS.cyan}${suggestion}${COLORS.reset}${COLORS.dim}?${COLORS.reset}`);
517
464
  }
518
465
 
519
466
  if (parsed.unknownFlags.length > 0) {
520
- log(` ${COLORS.dim}Run with --help to see all available options.${COLORS.reset}`);
521
- console.log();
467
+ log(` ${COLORS.dim}Run with --help to see all available options.${COLORS.reset}`);
468
+ log();
522
469
  process.exit(1);
523
470
  }
524
471
 
@@ -527,59 +474,57 @@ const main = async () => {
527
474
  try {
528
475
  version = getSimplVersion();
529
476
  } catch (error) {
530
- console.log();
531
- log(` ${COLORS.red}✗${COLORS.reset} ${error.message}`, 'red');
532
- console.log();
477
+ log();
478
+ log(` ${COLORS.red}✗${COLORS.reset} ${error.message}`);
479
+ log();
533
480
  process.exit(1);
534
481
  }
535
482
 
536
- console.log();
537
- log(` ╭${'─'.repeat(62)}╮`);
538
- log(` │ ${COLORS.bold}Simpl Add-on Installer${COLORS.reset} ${COLORS.dim}(v${version})${COLORS.reset}${' '.repeat(34 - version.length)}│`);
539
- log(` ╰${'─'.repeat(62)}╯`);
483
+ log();
484
+ box(`Simpl Add-on Installer${COLORS.dim}(v${version})${COLORS.reset}`);
540
485
 
541
486
  let versionsData;
542
487
 
543
488
  try {
544
489
  versionsData = await getVersionsData();
545
490
  } catch (error) {
546
- console.log();
547
- log(` ${COLORS.red}✗${COLORS.reset} Failed to fetch version data`, 'red');
548
- if (error.message === 'CDN server is currently unreachable') log(` ${COLORS.dim}The CDN server is currently unavailable. Please try again later.${COLORS.reset}`);
549
- console.log();
491
+ log();
492
+ log(` ${COLORS.red}✗${COLORS.reset} Failed to fetch version data`);
493
+ if (error.message === 'CDN server is currently unreachable') log(` ${COLORS.dim}The CDN server is currently unavailable. Please try again later.${COLORS.reset}`);
494
+ log();
550
495
  process.exit(1);
551
496
  }
552
497
 
553
498
  const versionMeta = versionsData.versions[version];
554
499
  if (!versionMeta) {
555
- console.log();
556
- log(` ${COLORS.red}✗${COLORS.reset} Version ${COLORS.bold}${version}${COLORS.reset} not found`, 'red');
557
- console.log();
500
+ log();
501
+ log(` ${COLORS.red}✗${COLORS.reset} Version ${COLORS.bold}${version}${COLORS.reset} not found`);
502
+ log();
558
503
  process.exit(1);
559
504
  }
560
505
 
561
506
  if (versionMeta['script-compatible'] === false) {
562
- console.log();
563
- log(` ${COLORS.red}✗${COLORS.reset} Version ${COLORS.bold}${version}${COLORS.reset} is not compatible with this installer`, 'red');
564
- console.log();
565
- log(` ${COLORS.bold}Manual download:${COLORS.reset}`, 'blue');
566
- log(` ${COLORS.cyan}${CDN_BASE}/${version}/add-ons/`, 'cyan');
567
- console.log();
568
- log(` ${COLORS.bold}Available add-ons for this version:${COLORS.reset}`, 'blue');
507
+ log();
508
+ log(` ${COLORS.red}✗${COLORS.reset} Version ${COLORS.bold}${version}${COLORS.reset} is not compatible with this installer`);
509
+ log();
510
+ log(` ${COLORS.bold}Manual download:${COLORS.reset}`, 'blue');
511
+ log(` ${COLORS.cyan}${CDN_BASE}/${version}/add-ons/`, 'cyan');
512
+ log();
513
+ log(` ${COLORS.bold}Available add-ons for this version:${COLORS.reset}`, 'blue');
569
514
 
570
515
  const addons = versionMeta['add-ons'] || [];
571
- if (addons.length === 0) log(` ${COLORS.dim}No add-ons available${COLORS.reset}`);
516
+ if (addons.length === 0) log(` ${COLORS.dim}No add-ons available${COLORS.reset}`);
572
517
  else addons.forEach(name => {
573
- log(` ${COLORS.cyan}•${COLORS.reset} ${name}: ${COLORS.dim}${CDN_BASE}/${version}/add-ons/${name}.zip${COLORS.reset}`);
518
+ log(` ${COLORS.cyan}•${COLORS.reset} ${name}: ${COLORS.dim}${CDN_BASE}/${version}/add-ons/${name}.zip${COLORS.reset}`);
574
519
  });
575
520
 
576
- console.log();
521
+ log();
577
522
  process.exit(1);
578
523
  }
579
524
 
580
525
  if (!parsed.addon) {
581
- console.log();
582
- log(' 🗄️ Fetching available add-ons...', 'bold');
526
+ log();
527
+ log(' 🗄️ Fetching available add-ons...', 'bold');
583
528
  }
584
529
 
585
530
  let addons;
@@ -587,25 +532,25 @@ const main = async () => {
587
532
  try {
588
533
  addons = await getAvailableAddons(version);
589
534
  } catch (error) {
590
- console.log();
591
- log(` ${COLORS.red}✗${COLORS.reset} Failed to fetch add-ons`, 'red');
592
- if (error.message === 'CDN server is currently unreachable') log(` ${COLORS.dim}The CDN server is currently unavailable. Please try again later.${COLORS.reset}`);
593
- console.log();
535
+ log();
536
+ log(` ${COLORS.red}✗${COLORS.reset} Failed to fetch add-ons`);
537
+ if (error.message === 'CDN server is currently unreachable') log(` ${COLORS.dim}The CDN server is currently unavailable. Please try again later.${COLORS.reset}`);
538
+ log();
594
539
  process.exit(1);
595
540
  }
596
541
 
597
542
  if (addons.length === 0) {
598
- console.log();
599
- log(` ${COLORS.yellow}⚠${COLORS.reset} No add-ons available for this version`);
600
- console.log();
543
+ log();
544
+ log(` ${COLORS.yellow}⚠${COLORS.reset} No add-ons available for this version`);
545
+ log();
601
546
  process.exit(0);
602
547
  }
603
548
 
604
549
  if (parsed.list) {
605
- console.log();
606
- log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
550
+ log();
551
+ log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
607
552
  listAddons(addons);
608
- console.log();
553
+ log();
609
554
  process.exit(0);
610
555
  }
611
556
 
@@ -613,73 +558,72 @@ const main = async () => {
613
558
 
614
559
  if (parsed.addon) {
615
560
  addonName = await promptAddon(addons, parsed.addon);
616
- printAnswer(' Add-on to install', addonName);
561
+ printAnswer(' Add-on to install', addonName);
617
562
  } else {
618
- console.log();
619
- log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
563
+ log();
564
+ log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
620
565
  listAddons(addons);
621
- console.log();
566
+ log();
622
567
 
623
568
  addonName = await promptAddon(addons);
624
569
  }
625
570
 
626
- console.log();
627
- log(` ╭${'─'.repeat(62)}╮`);
628
- log(` │ ${COLORS.bold}Installing: ${COLORS.cyan}${addonName}${COLORS.reset} ${COLORS.dim}(v${version})${COLORS.reset}${' '.repeat(44 - addonName.length - version.length)}│`);
629
- log(` ╰${'─'.repeat(62)}╯`);
630
- console.log();
631
- log(` 📦 Downloading ${COLORS.cyan}${addonName}${COLORS.reset} add-on...`, 'bold');
571
+ log();
572
+ box(`Installing: ${COLORS.cyan}${addonName}${COLORS.reset} ${COLORS.dim}(v${version})${COLORS.reset}`);
573
+ log(` 📦 Downloading ${COLORS.cyan}${addonName}${COLORS.reset} add-on...`, 'bold');
632
574
 
633
575
  let copied, skipped, toMerge;
634
576
 
635
577
  try {
636
578
  ({copied, skipped, toMerge} = await downloadAddon(addonName, version, process.cwd()));
637
579
  } catch (error) {
638
- console.log();
639
- log(` ${COLORS.red}✗${COLORS.reset} Installation failed`, 'red');
640
- if (error.message === 'CDN server is currently unreachable') log(` ${COLORS.dim}The CDN server is currently unavailable. Please try again later.${COLORS.reset}`);
641
- else log(` ${COLORS.dim}Please verify the add-on exists and try again${COLORS.reset}`);
642
- console.log();
580
+ log();
581
+ log(` ${COLORS.red}✗${COLORS.reset} Installation failed`);
582
+ if (error.message === 'CDN server is currently unreachable') log(` ${COLORS.dim}The CDN server is currently unavailable. Please try again later.${COLORS.reset}`);
583
+ else log(` ${COLORS.dim}Please verify the add-on exists and try again${COLORS.reset}`);
584
+ log();
643
585
  process.exit(1);
644
586
  }
645
587
 
646
588
  if (copied.length > 0) {
647
- console.log();
648
- log(` ${COLORS.green}✓${COLORS.reset} Copied ${COLORS.bold}${copied.length}${COLORS.reset} new file${copied.length !== 1 ? 's' : ''}`);
589
+ log();
590
+ log(` ${COLORS.green}✓${COLORS.reset} Copied ${COLORS.bold}${copied.length}${COLORS.reset} new file${copied.length !== 1 ? 's' : ''}`);
649
591
  }
650
592
 
651
593
  if (skipped.length > 0) {
652
- console.log();
653
- log(` ${COLORS.gray}○${COLORS.reset} ${COLORS.dim}Skipped ${skipped.length} file${skipped.length !== 1 ? 's' : ''} (no merge markers):${COLORS.reset}`);
654
- skipped.forEach(file => log(` ${COLORS.dim}• ${file}${COLORS.reset}`));
594
+ log();
595
+ log(` ${COLORS.gray}○${COLORS.reset} ${COLORS.dim}Skipped ${skipped.length} file${skipped.length !== 1 ? 's' : ''} (no merge markers):${COLORS.reset}`);
596
+ skipped.forEach(file => log(` ${COLORS.dim}• ${file}${COLORS.reset}`));
655
597
  }
656
598
 
657
599
  if (toMerge.length > 0) {
658
- console.log();
659
- log(' 🔀 Merging existing files...', 'bold');
600
+ log();
601
+ log(' 🔀 Merging existing files...', 'bold');
660
602
  const {merged, failed, unchanged} = mergeFiles(toMerge);
661
603
 
662
- console.log();
663
- log(' ' + '─'.repeat(16), 'gray');
664
- console.log();
604
+ log();
605
+ log(' ' + '─'.repeat(16), 'gray');
606
+ log();
665
607
 
666
- if (merged.length > 0) log(` ${COLORS.green}✓${COLORS.reset} Successfully merged ${COLORS.bold}${merged.length}${COLORS.reset} file${merged.length !== 1 ? 's' : ''}`);
667
- if (unchanged.length > 0) log(` ${COLORS.gray}○${COLORS.reset} ${COLORS.dim}${unchanged.length} file${unchanged.length !== 1 ? 's' : ''} unchanged (content already exists)${COLORS.reset}`);
608
+ if (merged.length > 0) log(` ${COLORS.green}✓${COLORS.reset} Successfully merged ${COLORS.bold}${merged.length}${COLORS.reset} file${merged.length !== 1 ? 's' : ''}`);
609
+ if (unchanged.length > 0) log(` ${COLORS.gray}○${COLORS.reset} ${COLORS.dim}${unchanged.length} file${unchanged.length !== 1 ? 's' : ''} unchanged (content already exists)${COLORS.reset}`);
668
610
 
669
611
  if (failed.length > 0) {
670
- console.log();
671
- log(` ${COLORS.yellow}⚠${COLORS.reset} ${COLORS.yellow}${failed.length} file${failed.length !== 1 ? 's' : ''} failed to merge${COLORS.reset}`);
672
- log(` ${COLORS.yellow}Please review manually:${COLORS.reset}`);
673
- failed.forEach(file => log(` ${COLORS.cyan}• ${file}${COLORS.reset}`));
612
+ log();
613
+ log(` ${COLORS.yellow}⚠${COLORS.reset} ${COLORS.yellow}${failed.length} file${failed.length !== 1 ? 's' : ''} failed to merge${COLORS.reset}`);
614
+ log(` ${COLORS.yellow}Please review manually:${COLORS.reset}`);
615
+ failed.forEach(file => log(` ${COLORS.cyan}• ${file}${COLORS.reset}`));
674
616
  }
675
617
  }
676
618
 
677
- console.log();
678
- log(` ${COLORS.green}✓${COLORS.reset} ${COLORS.bold}${COLORS.green}Installation complete!${COLORS.reset}`, 'green');
679
- console.log();
619
+ log();
620
+ log(` ${COLORS.green}✓${COLORS.reset} ${COLORS.bold}${COLORS.green}Installation complete!${COLORS.reset}`, 'green');
621
+ log();
680
622
  };
681
623
 
682
624
  main().catch(() => {
683
- log(`\n ${COLORS.red}✗${COLORS.reset} Fatal error occurred\n`, 'red');
625
+ log();
626
+ log(` ${COLORS.red}✗${COLORS.reset} Fatal error occurred`);
627
+ log();
684
628
  process.exit(1);
685
629
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ijuantm/simpl-addon",
3
3
  "description": "CLI tool to install Simpl framework add-ons.",
4
- "version": "2.6.3",
4
+ "version": "2.6.4",
5
5
  "scripts": {
6
6
  "link": "npm link",
7
7
  "unlink": "npm unlink -g @ijuantm/simpl-addon"