@ijuantm/simpl-addon 2.3.0 → 2.4.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.
- package/install.js +56 -21
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -10,7 +10,8 @@ const {exec} = require('child_process');
|
|
|
10
10
|
const execAsync = promisify(exec);
|
|
11
11
|
|
|
12
12
|
const COLORS = {
|
|
13
|
-
reset: '\x1b[0m', green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m',
|
|
13
|
+
reset: '\x1b[0m', green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m',
|
|
14
|
+
cyan: '\x1b[36m', blue: '\x1b[34m', gray: '\x1b[90m', bold: '\x1b[1m', dim: '\x1b[2m'
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
const CDN_BASE = 'https://cdn.simpl.iwanvanderwal.nl/framework';
|
|
@@ -124,11 +125,11 @@ const getAvailableAddons = async (version) => {
|
|
|
124
125
|
|
|
125
126
|
if (fs.existsSync(localAddonsDir)) return fs.readdirSync(localAddonsDir, {withFileTypes: true})
|
|
126
127
|
.filter(entry => entry.isFile() && entry.name.endsWith('.zip'))
|
|
127
|
-
.map(entry => entry.name.replace('.zip', ''))
|
|
128
|
+
.map(entry => entry.name.replace('.zip', ''))
|
|
129
|
+
.sort();
|
|
128
130
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
return versionMeta?.['add-ons'] || [];
|
|
131
|
+
const versionMeta = (await getVersionsData()).versions[version];
|
|
132
|
+
return (versionMeta?.['add-ons'] || []).sort();
|
|
132
133
|
};
|
|
133
134
|
|
|
134
135
|
const extractMarkers = (content) => {
|
|
@@ -137,9 +138,11 @@ const extractMarkers = (content) => {
|
|
|
137
138
|
content.split('\n').forEach((line, i) => {
|
|
138
139
|
const afterMatch = line.match(/@addon-insert:after\s*\(\s*["'](.+?)["']\s*\)/);
|
|
139
140
|
const beforeMatch = line.match(/@addon-insert:before\s*\(\s*["'](.+?)["']\s*\)/);
|
|
141
|
+
const replaceMatch = line.match(/@addon-insert:replace\s*\(\s*["'](.+?)["']\s*\)/);
|
|
140
142
|
|
|
141
143
|
if (afterMatch) markers.push({type: 'after', lineIndex: i, searchText: afterMatch[1]});
|
|
142
144
|
else if (beforeMatch) markers.push({type: 'before', lineIndex: i, searchText: beforeMatch[1]});
|
|
145
|
+
else if (replaceMatch) markers.push({type: 'replace', lineIndex: i, markerName: replaceMatch[1]});
|
|
143
146
|
else if (line.includes('@addon-insert:prepend')) markers.push({type: 'prepend', lineIndex: i});
|
|
144
147
|
else if (line.includes('@addon-insert:append')) markers.push({type: 'append', lineIndex: i});
|
|
145
148
|
});
|
|
@@ -149,10 +152,12 @@ const extractMarkers = (content) => {
|
|
|
149
152
|
|
|
150
153
|
const collectContentBetweenMarkers = (lines, startIndex) => {
|
|
151
154
|
const content = [];
|
|
155
|
+
|
|
152
156
|
for (let i = startIndex + 1; i < lines.length; i++) {
|
|
153
157
|
if (lines[i].trim().includes('@addon-end')) break;
|
|
154
158
|
content.push(lines[i]);
|
|
155
159
|
}
|
|
160
|
+
|
|
156
161
|
return content;
|
|
157
162
|
};
|
|
158
163
|
|
|
@@ -181,6 +186,12 @@ const findInsertIndex = (lines, searchText, type) => {
|
|
|
181
186
|
return -1;
|
|
182
187
|
};
|
|
183
188
|
|
|
189
|
+
const findMarkerLine = (lines, markerName) => {
|
|
190
|
+
const markerPattern = new RegExp(`@addon-marker\\s*\\(\\s*["']${markerName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}["']\\s*\\)`);
|
|
191
|
+
for (let i = 0; i < lines.length; i++) if (markerPattern.test(lines[i])) return i;
|
|
192
|
+
return -1;
|
|
193
|
+
};
|
|
194
|
+
|
|
184
195
|
const mergeFile = (targetPath, addonContent, markers, isEnv = false) => {
|
|
185
196
|
const targetContent = fs.readFileSync(targetPath, 'utf8');
|
|
186
197
|
const addonLines = addonContent.split('\n');
|
|
@@ -207,7 +218,7 @@ const mergeFile = (targetPath, addonContent, markers, isEnv = false) => {
|
|
|
207
218
|
const targetSignature = normalizeContent(newContent.split('\n'));
|
|
208
219
|
|
|
209
220
|
if (signature && targetSignature.includes(signature)) {
|
|
210
|
-
operations.push({success: false, type: marker.type, lines: content.length, searchText: marker.searchText});
|
|
221
|
+
operations.push({success: false, type: marker.type, lines: content.length, searchText: marker.searchText || marker.markerName});
|
|
211
222
|
return;
|
|
212
223
|
}
|
|
213
224
|
}
|
|
@@ -219,6 +230,18 @@ const mergeFile = (targetPath, addonContent, markers, isEnv = false) => {
|
|
|
219
230
|
if (!newContent.endsWith('\n')) newContent += '\n';
|
|
220
231
|
newContent += '\n' + content.join('\n') + '\n';
|
|
221
232
|
operations.push({success: true, type: 'append', lines: lineCount});
|
|
233
|
+
} else if (marker.type === 'replace' && marker.markerName) {
|
|
234
|
+
const targetLines = newContent.split('\n');
|
|
235
|
+
const markerLine = findMarkerLine(targetLines, marker.markerName);
|
|
236
|
+
|
|
237
|
+
if (markerLine === -1) {
|
|
238
|
+
operations.push({success: false, type: 'notfound', markerName: marker.markerName});
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
targetLines.splice(markerLine, 1, ...content);
|
|
243
|
+
newContent = targetLines.join('\n');
|
|
244
|
+
operations.push({success: true, type: 'replace', lines: lineCount, markerName: marker.markerName});
|
|
222
245
|
} else if ((marker.type === 'after' || marker.type === 'before') && marker.searchText) {
|
|
223
246
|
const targetLines = newContent.split('\n');
|
|
224
247
|
const insertIndex = findInsertIndex(targetLines, marker.searchText, marker.type);
|
|
@@ -249,10 +272,13 @@ const printMergeResults = (relativePath, isEnv, result) => {
|
|
|
249
272
|
hasChanges = true;
|
|
250
273
|
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`);
|
|
251
274
|
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`);
|
|
252
|
-
else if (op.type === '
|
|
253
|
-
else if (op.type === '
|
|
254
|
-
|
|
255
|
-
|
|
275
|
+
else if (op.type === 'replace') log(`${indent}${COLORS.green}✓${COLORS.reset} Replaced marker ${COLORS.cyan}${op.markerName}${COLORS.reset} with ${COLORS.bold}${op.lines}${COLORS.reset} ${varText}${op.lines !== 1 ? 's' : ''}`);
|
|
276
|
+
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}`);
|
|
277
|
+
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}`);
|
|
278
|
+
} else if (op.type === 'notfound') {
|
|
279
|
+
const target = op.markerName ? `marker ${COLORS.dim}${op.markerName}${COLORS.reset}` : `${COLORS.dim}${op.searchText}${COLORS.reset}`;
|
|
280
|
+
log(`${indent}${COLORS.yellow}⚠${COLORS.reset} ${COLORS.yellow}Could not find target:${COLORS.reset} ${target}`);
|
|
281
|
+
} else log(`${indent}${COLORS.gray}○${COLORS.reset} ${COLORS.dim}Content already exists (${op.type})${COLORS.reset}`);
|
|
256
282
|
});
|
|
257
283
|
|
|
258
284
|
return hasChanges;
|
|
@@ -380,7 +406,7 @@ const main = async () => {
|
|
|
380
406
|
|
|
381
407
|
console.log();
|
|
382
408
|
log(` ╭${'─'.repeat(62)}╮`);
|
|
383
|
-
log(` │ ${COLORS.bold}Simpl Add-on Installer${COLORS.reset} ${COLORS.dim}(${version})${COLORS.reset}${' '.repeat(
|
|
409
|
+
log(` │ ${COLORS.bold}Simpl Add-on Installer${COLORS.reset} ${COLORS.dim}(v${version})${COLORS.reset}${' '.repeat(36 - version.length)}│`);
|
|
384
410
|
log(` ╰${'─'.repeat(62)}╯`);
|
|
385
411
|
console.log();
|
|
386
412
|
|
|
@@ -449,29 +475,38 @@ const main = async () => {
|
|
|
449
475
|
}
|
|
450
476
|
|
|
451
477
|
log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
|
|
452
|
-
addons.forEach(name => log(` ${COLORS.cyan}
|
|
478
|
+
addons.forEach((name, index) => log(` ${COLORS.cyan}${index + 1}.${COLORS.reset} ${name}`));
|
|
453
479
|
console.log();
|
|
454
480
|
|
|
455
481
|
let addonName;
|
|
456
482
|
|
|
457
483
|
while (true) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
484
|
+
const input = await promptUser(` Add-on to install ${COLORS.dim}(name or number)${COLORS.reset}`);
|
|
485
|
+
|
|
486
|
+
if (!input) {
|
|
487
|
+
log(` ${COLORS.red}✗${COLORS.reset} Selection cannot be empty`, 'red');
|
|
461
488
|
console.log();
|
|
462
489
|
continue;
|
|
463
490
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
491
|
+
|
|
492
|
+
const numInput = parseInt(input, 10);
|
|
493
|
+
if (!isNaN(numInput) && numInput >= 1 && numInput <= addons.length) {
|
|
494
|
+
addonName = addons[numInput - 1];
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (addons.includes(input)) {
|
|
499
|
+
addonName = input;
|
|
500
|
+
break;
|
|
468
501
|
}
|
|
469
|
-
|
|
502
|
+
|
|
503
|
+
log(` ${COLORS.red}✗${COLORS.reset} Invalid selection "${input}"`, 'red');
|
|
504
|
+
console.log();
|
|
470
505
|
}
|
|
471
506
|
|
|
472
507
|
console.log();
|
|
473
508
|
log(` ╭${'─'.repeat(62)}╮`);
|
|
474
|
-
log(` │ ${COLORS.bold}Installing: ${COLORS.cyan}${addonName}${COLORS.reset} ${COLORS.dim}(${version})${COLORS.reset}${' '.repeat(
|
|
509
|
+
log(` │ ${COLORS.bold}Installing: ${COLORS.cyan}${addonName}${COLORS.reset} ${COLORS.dim}(v${version})${COLORS.reset}${' '.repeat(45 - addonName.length - version.length)}│`);
|
|
475
510
|
log(` ╰${'─'.repeat(62)}╯`);
|
|
476
511
|
console.log();
|
|
477
512
|
log(' 📦 Downloading add-on...', 'bold');
|