@ijuantm/simpl-addon 2.5.0 → 2.6.0
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 +137 -20
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -81,6 +81,107 @@ const getSimplVersion = () => {
|
|
|
81
81
|
return config.version;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
// --- Argument parsing ---
|
|
85
|
+
|
|
86
|
+
const parseArgs = (args) => {
|
|
87
|
+
const result = {addon: null, unknownFlags: [], help: false, list: false};
|
|
88
|
+
|
|
89
|
+
for (const arg of args) {
|
|
90
|
+
if (arg === '--help' || arg === '-h') {
|
|
91
|
+
result.help = true;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (arg === '--list' || arg === '-l') {
|
|
95
|
+
result.list = true;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (arg.startsWith('--addon=')) {
|
|
100
|
+
result.addon = arg.slice(8).trim() || null;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (arg.startsWith('-a=')) {
|
|
104
|
+
result.addon = arg.slice(3).trim() || null;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (arg.startsWith('-') && !arg.startsWith('--addon') && !arg.startsWith('-a')) {
|
|
109
|
+
result.unknownFlags.push(arg);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!arg.startsWith('-') && !result.addon) result.addon = arg;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return result;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const KNOWN_FLAGS = ['--addon', '-a', '--help', '-h', '--list', '-l'];
|
|
120
|
+
|
|
121
|
+
const levenshtein = (a, b) => {
|
|
122
|
+
const m = a.length, n = b.length;
|
|
123
|
+
const dp = Array.from({length: m + 1}, (_, i) => Array.from({length: n + 1}, (_, j) => i === 0 ? j : j === 0 ? i : 0));
|
|
124
|
+
|
|
125
|
+
for (let i = 1; i <= m; i++)
|
|
126
|
+
for (let j = 1; j <= n; j++)
|
|
127
|
+
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]);
|
|
128
|
+
|
|
129
|
+
return dp[m][n];
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const closestMatch = (input, options) => {
|
|
133
|
+
let best = null, bestDist = Infinity;
|
|
134
|
+
|
|
135
|
+
for (const opt of options) {
|
|
136
|
+
const dist = levenshtein(input.toLowerCase(), opt.toLowerCase());
|
|
137
|
+
if (dist < bestDist) {
|
|
138
|
+
bestDist = dist;
|
|
139
|
+
best = opt;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return bestDist <= Math.max(3, Math.floor(input.length / 2)) ? best : null;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// --- Fuzzy addon resolution with interactive prompts ---
|
|
147
|
+
|
|
148
|
+
const resolveAddon = async (input, addons) => {
|
|
149
|
+
if (addons.includes(input)) return input;
|
|
150
|
+
|
|
151
|
+
const suggestion = closestMatch(input, addons);
|
|
152
|
+
console.log();
|
|
153
|
+
log(` ${COLORS.red}✗${COLORS.reset} Add-on ${COLORS.bold}${input}${COLORS.reset} not found`, 'red');
|
|
154
|
+
|
|
155
|
+
if (suggestion) {
|
|
156
|
+
log(` ${COLORS.yellow}Did you mean:${COLORS.reset} ${COLORS.cyan}${suggestion}${COLORS.reset}?`);
|
|
157
|
+
console.log();
|
|
158
|
+
|
|
159
|
+
while (true) {
|
|
160
|
+
const answer = await promptUser(` Use "${suggestion}"? ${COLORS.dim}(yes / no / list)${COLORS.reset}`);
|
|
161
|
+
const a = answer.toLowerCase();
|
|
162
|
+
|
|
163
|
+
if (a === 'yes' || a === 'y') return suggestion;
|
|
164
|
+
if (a === 'list') {
|
|
165
|
+
listAddons(addons);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
if (a === 'no' || a === 'n') break;
|
|
169
|
+
|
|
170
|
+
log(` ${COLORS.dim}Please answer yes, no, or list${COLORS.reset}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log();
|
|
175
|
+
log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
|
|
176
|
+
listAddons(addons);
|
|
177
|
+
console.log();
|
|
178
|
+
process.exit(1);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const listAddons = (addons) => addons.forEach((name, i) => log(` ${COLORS.cyan}${i + 1}.${COLORS.reset} ${name}`));
|
|
182
|
+
|
|
183
|
+
// --- Help ---
|
|
184
|
+
|
|
84
185
|
const showHelp = () => {
|
|
85
186
|
console.log();
|
|
86
187
|
log(` ╭${'─'.repeat(62)}╮`);
|
|
@@ -89,11 +190,13 @@ const showHelp = () => {
|
|
|
89
190
|
console.log();
|
|
90
191
|
log(` ${COLORS.bold}Usage:${COLORS.reset}`, 'blue');
|
|
91
192
|
log(` ${COLORS.dim}npx @ijuantm/simpl-addon${COLORS.reset}`);
|
|
92
|
-
log(` ${COLORS.dim}npx @ijuantm/simpl-addon
|
|
193
|
+
log(` ${COLORS.dim}npx @ijuantm/simpl-addon --addon=<name>${COLORS.reset}`);
|
|
93
194
|
log(` ${COLORS.dim}npx @ijuantm/simpl-addon --help${COLORS.reset}`);
|
|
94
195
|
console.log();
|
|
95
|
-
log(` ${COLORS.bold}
|
|
96
|
-
log(` ${COLORS.dim}--
|
|
196
|
+
log(` ${COLORS.bold}Options:${COLORS.reset}`, 'blue');
|
|
197
|
+
log(` ${COLORS.dim}--addon=<name>, -a=<name>${COLORS.reset} Add-on to install`);
|
|
198
|
+
log(` ${COLORS.dim}--list, -l${COLORS.reset} List available add-ons`);
|
|
199
|
+
log(` ${COLORS.dim}--help, -h${COLORS.reset} Show this help message`);
|
|
97
200
|
console.log();
|
|
98
201
|
log(` ${COLORS.bold}Note:${COLORS.reset}`, 'blue');
|
|
99
202
|
log(` Run this command from the root of your Simpl project.`);
|
|
@@ -378,14 +481,27 @@ const mergeFiles = (toMerge) => {
|
|
|
378
481
|
|
|
379
482
|
const main = async () => {
|
|
380
483
|
const args = process.argv.slice(2);
|
|
381
|
-
const
|
|
484
|
+
const parsed = parseArgs(args);
|
|
382
485
|
|
|
383
|
-
if (
|
|
486
|
+
if (parsed.help) {
|
|
384
487
|
showHelp();
|
|
385
488
|
process.exit(0);
|
|
386
489
|
}
|
|
387
490
|
|
|
388
|
-
|
|
491
|
+
// Warn about unknown flags and suggest closest known ones
|
|
492
|
+
for (const flag of parsed.unknownFlags) {
|
|
493
|
+
const flagName = flag.includes('=') ? flag.slice(0, flag.indexOf('=')) : flag;
|
|
494
|
+
const suggestion = closestMatch(flagName, KNOWN_FLAGS);
|
|
495
|
+
console.log();
|
|
496
|
+
log(` ${COLORS.yellow}⚠${COLORS.reset} Unknown option: ${COLORS.bold}${flag}${COLORS.reset}`, 'yellow');
|
|
497
|
+
if (suggestion) log(` ${COLORS.dim}Did you mean ${COLORS.reset}${COLORS.cyan}${suggestion}${COLORS.reset}${COLORS.dim}?${COLORS.reset}`);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (parsed.unknownFlags.length > 0) {
|
|
501
|
+
log(` ${COLORS.dim}Run with --help to see all available options.${COLORS.reset}`);
|
|
502
|
+
console.log();
|
|
503
|
+
process.exit(1);
|
|
504
|
+
}
|
|
389
505
|
|
|
390
506
|
let version;
|
|
391
507
|
|
|
@@ -442,7 +558,7 @@ const main = async () => {
|
|
|
442
558
|
process.exit(1);
|
|
443
559
|
}
|
|
444
560
|
|
|
445
|
-
if (!
|
|
561
|
+
if (!parsed.addon) {
|
|
446
562
|
console.log();
|
|
447
563
|
log(' 🗄️ Fetching available add-ons...', 'bold');
|
|
448
564
|
}
|
|
@@ -466,23 +582,22 @@ const main = async () => {
|
|
|
466
582
|
process.exit(0);
|
|
467
583
|
}
|
|
468
584
|
|
|
585
|
+
if (parsed.list) {
|
|
586
|
+
console.log();
|
|
587
|
+
log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
|
|
588
|
+
listAddons(addons);
|
|
589
|
+
console.log();
|
|
590
|
+
process.exit(0);
|
|
591
|
+
}
|
|
592
|
+
|
|
469
593
|
let addonName;
|
|
470
594
|
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
console.log();
|
|
474
|
-
log(` ${COLORS.red}✗${COLORS.reset} Add-on ${COLORS.bold}${directName}${COLORS.reset} not found`, 'red');
|
|
475
|
-
console.log();
|
|
476
|
-
log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
|
|
477
|
-
addons.forEach((name, index) => log(` ${COLORS.cyan}${index + 1}.${COLORS.reset} ${name}`));
|
|
478
|
-
console.log();
|
|
479
|
-
process.exit(1);
|
|
480
|
-
}
|
|
481
|
-
addonName = directName;
|
|
595
|
+
if (parsed.addon) {
|
|
596
|
+
addonName = await resolveAddon(parsed.addon, addons);
|
|
482
597
|
} else {
|
|
483
598
|
console.log();
|
|
484
599
|
log(` ${COLORS.bold}Available add-ons:${COLORS.reset}`, 'blue');
|
|
485
|
-
addons
|
|
600
|
+
listAddons(addons);
|
|
486
601
|
console.log();
|
|
487
602
|
|
|
488
603
|
while (true) {
|
|
@@ -505,7 +620,9 @@ const main = async () => {
|
|
|
505
620
|
break;
|
|
506
621
|
}
|
|
507
622
|
|
|
508
|
-
|
|
623
|
+
const suggestion = closestMatch(input, addons);
|
|
624
|
+
log(` ${COLORS.red}✗${COLORS.reset} Invalid selection ${COLORS.bold}${input}${COLORS.reset}`, 'red');
|
|
625
|
+
if (suggestion) log(` ${COLORS.dim}Did you mean ${COLORS.reset}${COLORS.cyan}${suggestion}${COLORS.reset}${COLORS.dim}?${COLORS.reset}`);
|
|
509
626
|
console.log();
|
|
510
627
|
}
|
|
511
628
|
}
|