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