@ijuantm/simpl-addon 1.0.0 → 1.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.
Files changed (3) hide show
  1. package/.editorconfig +9 -0
  2. package/install.js +160 -81
  3. package/package.json +1 -1
package/.editorconfig ADDED
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ indent_style = space
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
package/install.js CHANGED
@@ -3,28 +3,22 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const https = require('https');
6
+ const {promisify} = require('util');
7
+ const {exec} = require('child_process');
8
+
9
+ const execAsync = promisify(exec);
6
10
 
7
11
  const COLORS = {
8
12
  reset: '\x1b[0m', green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m', cyan: '\x1b[36m', blue: '\x1b[34m', gray: '\x1b[90m', bold: '\x1b[1m', dim: '\x1b[2m'
9
13
  };
10
14
 
11
- const BRANCH = 'master';
12
- const REPO_BASE = 'https://api.github.com/repos/IJuanTM/simpl/contents/add-ons';
13
- const RAW_BASE = `https://raw.githubusercontent.com/IJuanTM/simpl/${BRANCH}/add-ons`;
15
+ const CDN_BASE = 'https://cdn.simpl.iwanvanderwal.nl/framework';
14
16
 
15
17
  const log = (message, color = 'reset') => console.log(`${COLORS[color]}${message}${COLORS.reset}`);
16
18
 
17
19
  const fetchUrl = (url) => new Promise((resolve, reject) => {
18
- const headers = {'User-Agent': 'simpl-installer'};
19
- if (process.env.GITHUB_TOKEN) headers['Authorization'] = `Bearer ${process.env.GITHUB_TOKEN}`;
20
-
21
- https.get(url, {headers}, res => {
20
+ https.get(url, res => {
22
21
  if (res.statusCode === 302 || res.statusCode === 301) return fetchUrl(res.headers.location).then(resolve).catch(reject);
23
- if (res.statusCode === 403) {
24
- const resetTime = res.headers['x-ratelimit-reset'];
25
- const resetDate = resetTime ? new Date(resetTime * 1000).toLocaleTimeString() : 'unknown';
26
- return reject(new Error(`GitHub API rate limit exceeded. Resets at ${resetDate}. ${process.env.GITHUB_TOKEN ? 'Token is set but may be invalid.' : 'Set GITHUB_TOKEN environment variable to increase limit.'}`));
27
- }
28
22
  if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage || 'Request failed'}`));
29
23
 
30
24
  let data = '';
@@ -33,51 +27,82 @@ const fetchUrl = (url) => new Promise((resolve, reject) => {
33
27
  }).on('error', reject);
34
28
  });
35
29
 
30
+ const downloadFile = (url, dest) => new Promise((resolve, reject) => {
31
+ const file = fs.createWriteStream(dest);
32
+
33
+ https.get(url, res => {
34
+ if (res.statusCode === 302 || res.statusCode === 301) {
35
+ fs.unlinkSync(dest);
36
+ return downloadFile(res.headers.location, dest).then(resolve).catch(reject);
37
+ }
38
+ if (res.statusCode !== 200) {
39
+ fs.unlinkSync(dest);
40
+ return reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage || 'Request failed'}`));
41
+ }
42
+
43
+ res.pipe(file);
44
+ file.on('finish', () => {
45
+ file.close();
46
+ resolve();
47
+ });
48
+ }).on('error', err => {
49
+ fs.unlinkSync(dest);
50
+ reject(err);
51
+ });
52
+
53
+ file.on('error', err => {
54
+ fs.unlinkSync(dest);
55
+ reject(err);
56
+ });
57
+ });
58
+
36
59
  const showHelp = () => {
37
60
  console.log();
38
61
  log(` ╭${'─'.repeat(62)}╮`);
39
62
  log(` │ ${COLORS.bold}Simpl Add-on Installer${COLORS.reset}${' '.repeat(38)}│`);
40
63
  log(` ╰${'─'.repeat(62)}╯`);
41
64
  console.log();
42
- log(' Usage:', 'cyan');
43
- log(' npx @ijuantm/simpl-addon <addon-name>');
44
- log(' npx @ijuantm/simpl-addon --list');
45
- log(' npx @ijuantm/simpl-addon --help');
65
+ log(` ${COLORS.bold}Usage:${COLORS.reset}`, 'blue');
66
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon <addon-name> [version]${COLORS.reset}`);
67
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon --list [version]${COLORS.reset}`);
68
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon --help${COLORS.reset}`);
46
69
  console.log();
47
- log(' Commands:', 'cyan');
48
- log(' <addon-name> Install the specified add-on');
49
- log(' --list, -l List all available add-ons');
50
- log(' --help, -h Show this help message');
70
+ log(` ${COLORS.bold}Arguments:${COLORS.reset}`, 'blue');
71
+ log(` ${COLORS.dim}addon-name${COLORS.reset} Name of the add-on to install`);
72
+ log(` ${COLORS.dim}version${COLORS.reset} Framework version (default: latest)`);
51
73
  console.log();
52
- log(' Examples:', 'cyan');
53
- log(' npx @ijuantm/simpl-addon auth');
54
- log(' npx @ijuantm/simpl-addon --list');
74
+ log(` ${COLORS.bold}Commands:${COLORS.reset}`, 'blue');
75
+ log(` ${COLORS.dim}--list, -l${COLORS.reset} List all available add-ons`);
76
+ log(` ${COLORS.dim}--help, -h${COLORS.reset} Show this help message`);
77
+ console.log();
78
+ log(` ${COLORS.bold}Examples:${COLORS.reset}`, 'blue');
79
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon auth${COLORS.reset}`);
80
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon auth 1.5.0${COLORS.reset}`);
81
+ log(` ${COLORS.dim}npx @ijuantm/simpl-addon --list${COLORS.reset}`);
55
82
  console.log();
56
83
  };
57
84
 
58
- const listAddons = async () => {
85
+ const listAddons = async (version) => {
59
86
  console.log();
60
87
  log(` ╭${'─'.repeat(62)}╮`);
61
- log(` │ ${COLORS.bold}Available Add-ons${COLORS.reset}${' '.repeat(43)}│`);
88
+ log(` │ ${COLORS.bold}Available Add-ons${COLORS.reset} ${COLORS.dim}(${version})${COLORS.reset}${' '.repeat(39 - version.length)}│`);
62
89
  log(` ╰${'─'.repeat(62)}╯`);
63
90
  console.log();
64
- log(' 📦 Fetching add-ons from GitHub...', 'bold');
91
+ log(' 📦 Fetching available add-ons...', 'bold');
65
92
 
66
93
  try {
67
- const response = await fetchUrl(`${REPO_BASE}?ref=${BRANCH}`);
68
- const addons = JSON.parse(response).filter(item => item.type === 'dir').map(item => item.name);
94
+ const response = await fetchUrl(`${CDN_BASE}/${version}/add-ons/list.json`);
95
+ const addons = JSON.parse(response)['add-ons'];
69
96
 
70
97
  console.log();
71
98
 
72
- if (addons.length === 0) {
73
- log(` ${COLORS.yellow}⚠${COLORS.reset} No add-ons available`);
74
- } else {
75
- addons.forEach(name => log(` ${COLORS.cyan}•${COLORS.reset} ${name}`));
76
- }
99
+ if (addons.length === 0) log(` ${COLORS.yellow}⚠${COLORS.reset} No add-ons available`);
100
+ else addons.forEach(name => log(` ${COLORS.cyan}•${COLORS.reset} ${name}`));
77
101
  } catch (error) {
78
102
  console.log();
79
103
  log(` ${COLORS.red}✗${COLORS.reset} Failed to fetch add-ons: ${error.message}`, 'red');
80
104
  console.log();
105
+
81
106
  process.exit(1);
82
107
  }
83
108
 
@@ -91,7 +116,10 @@ const extractMarkers = (content) => {
91
116
  const afterMatch = line.match(/@addon-insert:after\s*\(\s*["'](.+?)["']\s*\)/);
92
117
  const beforeMatch = line.match(/@addon-insert:before\s*\(\s*["'](.+?)["']\s*\)/);
93
118
 
94
- if (afterMatch) markers.push({type: 'after', lineIndex: i, searchText: afterMatch[1]}); else if (beforeMatch) markers.push({type: 'before', lineIndex: i, searchText: beforeMatch[1]}); else if (line.includes('@addon-insert:prepend')) markers.push({type: 'prepend', lineIndex: i}); else if (line.includes('@addon-insert:append')) markers.push({type: 'append', lineIndex: i});
119
+ if (afterMatch) markers.push({type: 'after', lineIndex: i, searchText: afterMatch[1]});
120
+ else if (beforeMatch) markers.push({type: 'before', lineIndex: i, searchText: beforeMatch[1]});
121
+ else if (line.includes('@addon-insert:prepend')) markers.push({type: 'prepend', lineIndex: i});
122
+ else if (line.includes('@addon-insert:append')) markers.push({type: 'append', lineIndex: i});
95
123
  });
96
124
 
97
125
  return markers;
@@ -102,15 +130,14 @@ const collectContentBetweenMarkers = (lines, startIndex) => {
102
130
 
103
131
  for (let i = startIndex + 1; i < lines.length; i++) {
104
132
  if (lines[i].trim().includes('@addon-end')) break;
133
+
105
134
  content.push(lines[i]);
106
135
  }
107
136
 
108
137
  return content;
109
138
  };
110
139
 
111
- const normalizeContent = (lines) => lines.map(l => l.trim())
112
- .filter(l => l && !l.startsWith('//') && !l.startsWith('#') && !l.startsWith('/*') && !l.startsWith('*'))
113
- .join('|');
140
+ const normalizeContent = (lines) => lines.map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('#') && !l.startsWith('/*') && !l.startsWith('*')).join('|');
114
141
 
115
142
  const processEnvContent = (content, targetContent) => {
116
143
  const envVarsToAdd = [], comments = [];
@@ -124,6 +151,7 @@ const processEnvContent = (content, targetContent) => {
124
151
  }
125
152
 
126
153
  const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
154
+
127
155
  if (match && !new RegExp(`^${match[1]}=`, 'm').test(targetContent)) envVarsToAdd.push(line);
128
156
  });
129
157
 
@@ -131,10 +159,7 @@ const processEnvContent = (content, targetContent) => {
131
159
  };
132
160
 
133
161
  const findInsertIndex = (lines, searchText, type) => {
134
- for (let i = 0; i < lines.length; i++) {
135
- if (lines[i].includes(searchText)) return type === 'before' ? i : i + 1;
136
- }
137
-
162
+ for (let i = 0; i < lines.length; i++) if (lines[i].includes(searchText)) return type === 'before' ? i : i + 1;
138
163
  return -1;
139
164
  };
140
165
 
@@ -142,16 +167,19 @@ const mergeFile = (targetPath, addonContent, markers, isEnv = false) => {
142
167
  const targetContent = fs.readFileSync(targetPath, 'utf8');
143
168
  const addonLines = addonContent.split('\n');
144
169
  const operations = [];
170
+
145
171
  let newContent = targetContent;
146
172
 
147
173
  markers.forEach(marker => {
148
174
  let content = collectContentBetweenMarkers(addonLines, marker.lineIndex);
175
+
149
176
  if (content.length === 0) return;
150
177
 
151
178
  let lineCount = content.length;
152
179
 
153
180
  if (isEnv) {
154
181
  const processed = processEnvContent(content, newContent);
182
+
155
183
  content = processed.content;
156
184
  lineCount = processed.count;
157
185
 
@@ -171,10 +199,13 @@ const mergeFile = (targetPath, addonContent, markers, isEnv = false) => {
171
199
 
172
200
  if (marker.type === 'prepend') {
173
201
  newContent = content.join('\n') + '\n' + newContent;
202
+
174
203
  operations.push({success: true, type: 'prepend', lines: lineCount});
175
204
  } else if (marker.type === 'append') {
176
205
  if (!newContent.endsWith('\n')) newContent += '\n';
206
+
177
207
  newContent += '\n' + content.join('\n') + '\n';
208
+
178
209
  operations.push({success: true, type: 'append', lines: lineCount});
179
210
  } else if ((marker.type === 'after' || marker.type === 'before') && marker.searchText) {
180
211
  const targetLines = newContent.split('\n');
@@ -186,74 +217,107 @@ const mergeFile = (targetPath, addonContent, markers, isEnv = false) => {
186
217
  }
187
218
 
188
219
  targetLines.splice(insertIndex, 0, ...content);
220
+
189
221
  newContent = targetLines.join('\n');
222
+
190
223
  operations.push({success: true, type: marker.type, lines: lineCount, searchText: marker.searchText});
191
224
  }
192
225
  });
193
226
 
194
227
  if (newContent !== targetContent) fs.writeFileSync(targetPath, newContent, 'utf8');
228
+
195
229
  return {modified: newContent !== targetContent, operations};
196
230
  };
197
231
 
198
232
  const printMergeResults = (relativePath, isEnv, result) => {
199
233
  const indent = ' ';
200
234
  const varText = isEnv ? 'environment variable' : 'line';
235
+
201
236
  let hasChanges = false;
202
237
 
203
238
  result.operations.forEach(op => {
204
239
  if (op.success) {
205
240
  hasChanges = true;
206
241
 
207
- if (op.type === 'prepend') log(`${indent}${COLORS.green}✓${COLORS.reset} Prepended ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} to file start`); else if (op.type === 'append') log(`${indent}${COLORS.green}✓${COLORS.reset} Appended ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} to file end`); else if (op.type === 'after') log(`${indent}${COLORS.green}✓${COLORS.reset} Inserted ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} ${COLORS.cyan}after${COLORS.reset} "${COLORS.dim}${op.searchText}${COLORS.reset}"`); else if (op.type === 'before') log(`${indent}${COLORS.green}✓${COLORS.reset} Inserted ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} ${COLORS.cyan}before${COLORS.reset} "${COLORS.dim}${op.searchText}${COLORS.reset}"`);
208
- } else if (op.type === 'notfound') log(`${indent}${COLORS.yellow}⚠${COLORS.reset} ${COLORS.yellow}Could not find target:${COLORS.reset} "${COLORS.dim}${op.searchText}${COLORS.reset}"`); else log(`${indent}${COLORS.gray}○${COLORS.reset} ${COLORS.dim}Content already exists (${op.type})${COLORS.reset}`);
242
+ if (op.type === 'prepend') log(`${indent}${COLORS.green}✓${COLORS.reset} Prepended ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} to file start`);
243
+ else if (op.type === 'append') log(`${indent}${COLORS.green}✓${COLORS.reset} Appended ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} to file end`);
244
+ else if (op.type === 'after') log(`${indent}${COLORS.green}✓${COLORS.reset} Inserted ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} ${COLORS.cyan}after${COLORS.reset} "${COLORS.dim}${op.searchText}${COLORS.reset}"`);
245
+ else if (op.type === 'before') log(`${indent}${COLORS.green}✓${COLORS.reset} Inserted ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''} ${COLORS.cyan}before${COLORS.reset} "${COLORS.dim}${op.searchText}${COLORS.reset}"`);
246
+ } else if (op.type === 'notfound') log(`${indent}${COLORS.yellow}⚠${COLORS.reset} ${COLORS.yellow}Could not find target:${COLORS.reset} "${COLORS.dim}${op.searchText}${COLORS.reset}"`);
247
+ else log(`${indent}${COLORS.gray}○${COLORS.reset} ${COLORS.dim}Content already exists (${op.type})${COLORS.reset}`);
209
248
  });
210
249
 
211
250
  return hasChanges;
212
251
  };
213
252
 
214
- const downloadAddonFiles = async (addonName, targetDir) => {
215
- const addonUrl = `${REPO_BASE}/${addonName}?ref=${BRANCH}`;
216
- let files;
253
+ const extractZip = async zipPath => {
254
+ const tempExtract = path.join(process.cwd(), '__temp_extract_addon__');
217
255
 
218
- try {
219
- files = JSON.parse(await fetchUrl(addonUrl));
220
- } catch (error) {
221
- throw new Error(`Add-on "${addonName}" not found`);
256
+ if (process.platform === 'win32') {
257
+ await execAsync(`powershell -command "Expand-Archive -Path '${zipPath}' -DestinationPath '${tempExtract}' -Force"`);
258
+ } else {
259
+ await execAsync(`unzip -q "${zipPath}" -d "${tempExtract}"`);
222
260
  }
223
261
 
262
+ const entries = fs.readdirSync(tempExtract, {withFileTypes: true});
263
+ const sourceDir = entries.length === 1 && entries[0].isDirectory() ? path.join(tempExtract, entries[0].name) : tempExtract;
264
+
265
+ return {sourceDir, tempExtract};
266
+ };
267
+
268
+ const processAddonFiles = (addonDir, targetDir) => {
224
269
  const copied = [], skipped = [], toMerge = [];
225
270
 
226
- const processFiles = async (fileList, basePath = '') => {
227
- for (const file of fileList) {
228
- if (file.name === 'README.md') continue;
271
+ const processDirectory = (dir, basePath = '') => fs.readdirSync(dir, {withFileTypes: true}).forEach(entry => {
272
+ if (entry.name === 'README.md') return;
229
273
 
230
- const relativePath = path.join(basePath, file.name).replace(/\\/g, '/');
231
- const destPath = path.join(targetDir, relativePath);
274
+ const srcPath = path.join(dir, entry.name);
275
+ const relativePath = path.join(basePath, entry.name).replace(/\\/g, '/');
276
+ const destPath = path.join(targetDir, relativePath);
232
277
 
233
- if (file.type === 'dir') {
234
- const subUrl = file.url.includes('?') ? `${file.url}&ref=${BRANCH}` : `${file.url}?ref=${BRANCH}`;
235
- const subFiles = JSON.parse(await fetchUrl(subUrl));
236
- await processFiles(subFiles, relativePath);
237
- } else {
238
- const content = await fetchUrl(`${RAW_BASE}/${addonName}/${relativePath}`);
278
+ if (entry.isDirectory()) processDirectory(srcPath, relativePath);
279
+ else {
280
+ const content = fs.readFileSync(srcPath, 'utf8');
239
281
 
240
- if (fs.existsSync(destPath)) {
241
- const markers = extractMarkers(content);
282
+ if (fs.existsSync(destPath)) {
283
+ const markers = extractMarkers(content);
284
+
285
+ if (markers.length > 0 || entry.name === '.env') toMerge.push({content, destPath, relativePath, markers});
286
+ else skipped.push(relativePath);
287
+ } else {
288
+ fs.mkdirSync(path.dirname(destPath), {recursive: true});
289
+ fs.copyFileSync(srcPath, destPath);
242
290
 
243
- if (markers.length > 0 || file.name === '.env') toMerge.push({content, destPath, relativePath, markers}); else skipped.push(relativePath);
244
- } else {
245
- fs.mkdirSync(path.dirname(destPath), {recursive: true});
246
- fs.writeFileSync(destPath, content, 'utf8');
247
- copied.push(relativePath);
248
- }
291
+ copied.push(relativePath);
249
292
  }
250
293
  }
251
- };
294
+ });
295
+
296
+ processDirectory(addonDir);
252
297
 
253
- await processFiles(files);
254
298
  return {copied, skipped, toMerge};
255
299
  };
256
300
 
301
+ const downloadAddon = async (addonName, version, targetDir) => {
302
+ const zipUrl = `${CDN_BASE}/${version}/add-ons/${addonName}.zip`;
303
+ const tempZip = path.join(process.cwd(), `temp-addon-${addonName}.zip`);
304
+
305
+ try {
306
+ await downloadFile(zipUrl, tempZip);
307
+
308
+ const {sourceDir, tempExtract} = await extractZip(tempZip);
309
+ const result = processAddonFiles(sourceDir, targetDir);
310
+
311
+ fs.unlinkSync(tempZip);
312
+ fs.rmSync(tempExtract, {recursive: true, force: true});
313
+
314
+ return result;
315
+ } catch (error) {
316
+ if (fs.existsSync(tempZip)) fs.unlinkSync(tempZip);
317
+ throw error;
318
+ }
319
+ };
320
+
257
321
  const mergeFiles = (toMerge) => {
258
322
  if (toMerge.length === 0) return {merged: [], failed: [], unchanged: []};
259
323
 
@@ -261,13 +325,17 @@ const mergeFiles = (toMerge) => {
261
325
 
262
326
  toMerge.forEach(({content, destPath, relativePath, markers}) => {
263
327
  const isEnv = path.basename(destPath) === '.env';
264
- log(`\n ${COLORS.cyan}•${COLORS.reset} ${COLORS.bold}${relativePath}${COLORS.reset}`);
328
+
329
+ log(`\n ${COLORS.cyan}•${COLORS.reset} ${COLORS.dim}${relativePath}${COLORS.reset}`);
265
330
 
266
331
  try {
267
332
  const result = mergeFile(destPath, content, markers, isEnv);
268
- if (printMergeResults(relativePath, isEnv, result)) merged.push(relativePath); else unchanged.push(relativePath);
333
+
334
+ if (printMergeResults(relativePath, isEnv, result)) merged.push(relativePath);
335
+ else unchanged.push(relativePath);
269
336
  } catch (error) {
270
337
  log(` ${COLORS.red}✗ Error:${COLORS.reset} ${error.message}`, 'red');
338
+
271
339
  failed.push(relativePath);
272
340
  }
273
341
  });
@@ -276,34 +344,42 @@ const mergeFiles = (toMerge) => {
276
344
  };
277
345
 
278
346
  const main = async () => {
279
- const command = process.argv[2];
347
+ const args = process.argv.slice(2);
348
+ const firstArg = args[0];
280
349
 
281
- if (!command || command === '--help' || command === '-h') {
350
+ if (!firstArg || firstArg === '--help' || firstArg === '-h') {
282
351
  showHelp();
352
+
283
353
  process.exit(0);
284
354
  }
285
355
 
286
- if (command === '--list' || command === '-l') {
287
- await listAddons();
356
+ if (firstArg === '--list' || firstArg === '-l') {
357
+ const version = args[1] || 'latest';
358
+ await listAddons(version);
359
+
288
360
  process.exit(0);
289
361
  }
290
362
 
363
+ const addonName = firstArg;
364
+ const version = args[1] || 'latest';
365
+
291
366
  console.log();
292
367
  log(` ╭${'─'.repeat(62)}╮`);
293
- log(` │ ${COLORS.bold}Installing add-on: ${COLORS.cyan}${command}${COLORS.reset}${' '.repeat(41 - command.length)}│`);
368
+ log(` │ ${COLORS.bold}Installing Add-on: ${COLORS.cyan}${addonName}${COLORS.reset} ${COLORS.dim}(${version})${COLORS.reset}${' '.repeat(37 - addonName.length - version.length)}│`);
294
369
  log(` ╰${'─'.repeat(62)}╯`);
295
370
  console.log();
296
- log(' 📦 Downloading add-on from GitHub...', 'bold');
371
+ log(' 📦 Downloading add-on...', 'bold');
297
372
 
298
373
  let copied, skipped, toMerge;
299
374
 
300
375
  try {
301
- ({copied, skipped, toMerge} = await downloadAddonFiles(command, process.cwd()));
376
+ ({copied, skipped, toMerge} = await downloadAddon(addonName, version, process.cwd()));
302
377
  } catch (error) {
303
378
  console.log();
304
379
  log(` ${COLORS.red}✗${COLORS.reset} ${error.message}`, 'red');
305
- log(` ${COLORS.dim}Run ${COLORS.cyan}npx @ijuantm/simpl-addon --list${COLORS.reset}${COLORS.dim} to see available add-ons${COLORS.reset}`);
380
+ log(` ${COLORS.dim}Run ${COLORS.dim}npx @ijuantm/simpl-addon --list${COLORS.reset} to see available add-ons`);
306
381
  console.log();
382
+
307
383
  process.exit(1);
308
384
  }
309
385
 
@@ -315,6 +391,7 @@ const main = async () => {
315
391
  if (skipped.length > 0) {
316
392
  console.log();
317
393
  log(` ${COLORS.gray}○${COLORS.reset} ${COLORS.dim}Skipped ${skipped.length} file${skipped.length !== 1 ? 's' : ''} (no merge markers):${COLORS.reset}`);
394
+
318
395
  skipped.forEach(file => log(` ${COLORS.dim}• ${file}${COLORS.reset}`));
319
396
  }
320
397
 
@@ -334,6 +411,7 @@ const main = async () => {
334
411
  console.log();
335
412
  log(` ${COLORS.yellow}⚠${COLORS.reset} ${COLORS.yellow}${failed.length} file${failed.length !== 1 ? 's' : ''} failed to merge${COLORS.reset}`);
336
413
  log(` ${COLORS.yellow}Please review manually:${COLORS.reset}`);
414
+
337
415
  failed.forEach(file => log(` ${COLORS.cyan}• ${file}${COLORS.reset}`));
338
416
  }
339
417
  }
@@ -345,5 +423,6 @@ const main = async () => {
345
423
 
346
424
  main().catch(err => {
347
425
  log(`\n ${COLORS.red}✗${COLORS.reset} Fatal error: ${err.message}\n`, 'red');
426
+
348
427
  process.exit(1);
349
428
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ijuantm/simpl-addon",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "CLI tool to install Simpl framework add-ons.",
5
5
  "main": "install.js",
6
6
  "bin": {