framer-export 4.3.10 → 4.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/dist/cli/index.js +898 -474
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "framer-export",
|
|
18
|
-
version: "4.
|
|
18
|
+
version: "4.4.1",
|
|
19
19
|
description: "Export any Framer, Webflow, or Wix site into a fully working local mirror. Downloads all assets, strips badges, rewrites URLs, and pretty-prints JS.",
|
|
20
20
|
type: "module",
|
|
21
21
|
main: "dist/cli/index.js",
|
|
@@ -204,6 +204,663 @@ var init_banner = __esm({
|
|
|
204
204
|
}
|
|
205
205
|
});
|
|
206
206
|
|
|
207
|
+
// src/cli/cooking.ts
|
|
208
|
+
import chalk2 from "chalk";
|
|
209
|
+
async function showLoadingIntro(version) {
|
|
210
|
+
if (!process.stdout.isTTY || process.env.CI) return;
|
|
211
|
+
await new Promise((resolve) => {
|
|
212
|
+
let frame = 0;
|
|
213
|
+
const draw = () => {
|
|
214
|
+
const spinner = SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
|
|
215
|
+
const title = renderShinyText(`Framer Export v${version}`, frame, {
|
|
216
|
+
baseColor: "#969696",
|
|
217
|
+
shineColor: "#ffffff",
|
|
218
|
+
shineWidth: 18
|
|
219
|
+
});
|
|
220
|
+
const dots = ".".repeat(frame % 4).padEnd(3, " ");
|
|
221
|
+
process.stdout.write(
|
|
222
|
+
`\r\x1B[2K ${ui.primary(spinner)} ${title} ${ui.muted(`Loading${dots}`)}`
|
|
223
|
+
);
|
|
224
|
+
frame++;
|
|
225
|
+
};
|
|
226
|
+
process.stdout.write("\x1B[?25l");
|
|
227
|
+
draw();
|
|
228
|
+
const interval = setInterval(draw, FRAME_INTERVAL);
|
|
229
|
+
setTimeout(() => {
|
|
230
|
+
clearInterval(interval);
|
|
231
|
+
process.stdout.write("\r\x1B[2K\x1B[?25h");
|
|
232
|
+
resolve();
|
|
233
|
+
}, INTRO_DURATION);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function renderShinyText(text, frame, options = {}) {
|
|
237
|
+
const baseColor = options.baseColor || "#808080";
|
|
238
|
+
const shineColor = options.shineColor || "#ffffff";
|
|
239
|
+
const shineWidth = options.shineWidth || SHINE_WIDTH;
|
|
240
|
+
const travel = text.length + shineWidth * 2;
|
|
241
|
+
const pos = frame * SHINE_SPEED % travel - shineWidth;
|
|
242
|
+
const base = hexToRgb(baseColor);
|
|
243
|
+
const shine = hexToRgb(shineColor);
|
|
244
|
+
let result = "";
|
|
245
|
+
for (let i = 0; i < text.length; i++) {
|
|
246
|
+
const dist = Math.abs(i - pos);
|
|
247
|
+
const intensity = smoothstep(0, 1, 1 - Math.min(1, dist / shineWidth));
|
|
248
|
+
const color = mixRgb(base, shine, intensity);
|
|
249
|
+
const paint = intensity > 0.82 ? chalk2.rgb(color.r, color.g, color.b).bold : chalk2.rgb(color.r, color.g, color.b);
|
|
250
|
+
result += paint(text[i]);
|
|
251
|
+
}
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
function smoothstep(edge0, edge1, value) {
|
|
255
|
+
const t = Math.max(0, Math.min(1, (value - edge0) / (edge1 - edge0)));
|
|
256
|
+
return t * t * (3 - 2 * t);
|
|
257
|
+
}
|
|
258
|
+
function hexToRgb(hex) {
|
|
259
|
+
const clean = hex.replace("#", "");
|
|
260
|
+
const normalized = clean.length === 3 ? clean.split("").map((char) => char + char).join("") : clean.padEnd(6, "0").slice(0, 6);
|
|
261
|
+
return {
|
|
262
|
+
r: Number.parseInt(normalized.slice(0, 2), 16),
|
|
263
|
+
g: Number.parseInt(normalized.slice(2, 4), 16),
|
|
264
|
+
b: Number.parseInt(normalized.slice(4, 6), 16)
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function mixRgb(from, to, amount) {
|
|
268
|
+
return {
|
|
269
|
+
r: Math.round(from.r + (to.r - from.r) * amount),
|
|
270
|
+
g: Math.round(from.g + (to.g - from.g) * amount),
|
|
271
|
+
b: Math.round(from.b + (to.b - from.b) * amount)
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
var SHINE_WIDTH, FRAME_INTERVAL, INTRO_DURATION, SHINE_SPEED, SPINNER_FRAMES, CookingSpinner;
|
|
275
|
+
var init_cooking = __esm({
|
|
276
|
+
"src/cli/cooking.ts"() {
|
|
277
|
+
"use strict";
|
|
278
|
+
init_theme();
|
|
279
|
+
SHINE_WIDTH = 14;
|
|
280
|
+
FRAME_INTERVAL = 70;
|
|
281
|
+
INTRO_DURATION = 1400;
|
|
282
|
+
SHINE_SPEED = 0.55;
|
|
283
|
+
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
284
|
+
CookingSpinner = class {
|
|
285
|
+
interval = null;
|
|
286
|
+
frame = 0;
|
|
287
|
+
phase = "";
|
|
288
|
+
active = false;
|
|
289
|
+
start(phase = "") {
|
|
290
|
+
this.phase = phase;
|
|
291
|
+
this.frame = 0;
|
|
292
|
+
this.active = true;
|
|
293
|
+
this.draw();
|
|
294
|
+
this.interval = setInterval(() => {
|
|
295
|
+
this.frame++;
|
|
296
|
+
this.draw();
|
|
297
|
+
}, FRAME_INTERVAL);
|
|
298
|
+
}
|
|
299
|
+
update(phase) {
|
|
300
|
+
this.phase = phase;
|
|
301
|
+
}
|
|
302
|
+
log(message) {
|
|
303
|
+
if (this.active) {
|
|
304
|
+
process.stdout.write("\r\x1B[2K");
|
|
305
|
+
}
|
|
306
|
+
process.stdout.write(message + "\n");
|
|
307
|
+
if (this.active) {
|
|
308
|
+
this.draw();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
stop() {
|
|
312
|
+
this.active = false;
|
|
313
|
+
if (this.interval) {
|
|
314
|
+
clearInterval(this.interval);
|
|
315
|
+
this.interval = null;
|
|
316
|
+
}
|
|
317
|
+
process.stdout.write("\r\x1B[2K");
|
|
318
|
+
}
|
|
319
|
+
draw() {
|
|
320
|
+
if (!this.active) return;
|
|
321
|
+
const spinner = SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length];
|
|
322
|
+
const shimmer = renderShinyText("Exporting", this.frame);
|
|
323
|
+
const frameStr = ui.primary(spinner);
|
|
324
|
+
const phaseStr = this.phase ? ` ${ui.muted(this.limitLen(this.phase, 52))}` : "";
|
|
325
|
+
process.stdout.write(`\r\x1B[2K ${frameStr} ${shimmer}${phaseStr}`);
|
|
326
|
+
}
|
|
327
|
+
limitLen(s, max) {
|
|
328
|
+
if (s.length <= max) return s;
|
|
329
|
+
return s.slice(0, max - 1) + "\u2026";
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// src/cli/box.ts
|
|
336
|
+
import chalk3 from "chalk";
|
|
337
|
+
function maxWidth() {
|
|
338
|
+
return Math.min(process.stdout.columns || 80, 76);
|
|
339
|
+
}
|
|
340
|
+
function padRight(text, w) {
|
|
341
|
+
const visible = stripAnsi(text).length;
|
|
342
|
+
if (visible >= w) return text;
|
|
343
|
+
return text + " ".repeat(w - visible);
|
|
344
|
+
}
|
|
345
|
+
function boxTop(w) {
|
|
346
|
+
const inner = w - 4;
|
|
347
|
+
return " " + ui.border("\u256D\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u256E");
|
|
348
|
+
}
|
|
349
|
+
function panelTop(w) {
|
|
350
|
+
const inner = w - 4;
|
|
351
|
+
return ui.border("\u256D\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u256E");
|
|
352
|
+
}
|
|
353
|
+
function boxBot(w) {
|
|
354
|
+
const inner = w - 4;
|
|
355
|
+
return " " + ui.border("\u2570\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u256F");
|
|
356
|
+
}
|
|
357
|
+
function panelBot(w) {
|
|
358
|
+
const inner = w - 4;
|
|
359
|
+
return ui.border("\u2570\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u256F");
|
|
360
|
+
}
|
|
361
|
+
function boxLine(w, text) {
|
|
362
|
+
const inner = w - 4;
|
|
363
|
+
const padded = padRight(text, inner);
|
|
364
|
+
return " " + ui.border("\u2502 ") + padded + ui.border(" \u2502");
|
|
365
|
+
}
|
|
366
|
+
function panelLine(w, text) {
|
|
367
|
+
const inner = w - 4;
|
|
368
|
+
const padded = padRight(text, inner);
|
|
369
|
+
return ui.border("\u2502 ") + padded + ui.border(" \u2502");
|
|
370
|
+
}
|
|
371
|
+
function boxSep(w) {
|
|
372
|
+
const inner = w - 4;
|
|
373
|
+
return " " + ui.border("\u251C\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u2524");
|
|
374
|
+
}
|
|
375
|
+
function panelSep(w) {
|
|
376
|
+
const inner = w - 4;
|
|
377
|
+
return ui.border("\u251C\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u2524");
|
|
378
|
+
}
|
|
379
|
+
function boxRow(w, label, value) {
|
|
380
|
+
const inner = w - 4;
|
|
381
|
+
const labelPlain = stripAnsi(chalk3.bold(label));
|
|
382
|
+
const visible = labelPlain.length + 1 + value.length;
|
|
383
|
+
if (visible > inner) {
|
|
384
|
+
const avail = inner - labelPlain.length - 2;
|
|
385
|
+
const truncated = value.length > avail ? value.slice(0, avail - 1) + ".." : value;
|
|
386
|
+
return " " + ui.border("\u2502 ") + chalk3.bold(label) + ": " + ui.primary(truncated) + " ".repeat(Math.max(0, inner - labelPlain.length - 1 - truncated.length)) + ui.border(" \u2502");
|
|
387
|
+
}
|
|
388
|
+
const right = inner - labelPlain.length - 1 - value.length;
|
|
389
|
+
return " " + ui.border("\u2502 ") + chalk3.bold(label) + ": " + ui.primary(value) + " ".repeat(right) + ui.border(" \u2502");
|
|
390
|
+
}
|
|
391
|
+
var init_box = __esm({
|
|
392
|
+
"src/cli/box.ts"() {
|
|
393
|
+
"use strict";
|
|
394
|
+
init_theme();
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// src/cli/select.ts
|
|
399
|
+
import readline from "readline";
|
|
400
|
+
import { stdin, stdout } from "process";
|
|
401
|
+
async function select(question, options, defaultIndex = 0, config = {}) {
|
|
402
|
+
const isTTY = stdin.isTTY && stdout.isTTY;
|
|
403
|
+
if (!isTTY) {
|
|
404
|
+
return fallbackPrompt(question, options, defaultIndex, config);
|
|
405
|
+
}
|
|
406
|
+
return arrowSelect(question, options, defaultIndex, config);
|
|
407
|
+
}
|
|
408
|
+
async function promptInput(question, defaultValue = "", config = {}) {
|
|
409
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
410
|
+
return fallbackInput(question, defaultValue);
|
|
411
|
+
}
|
|
412
|
+
return fullscreenInput(question, defaultValue, config);
|
|
413
|
+
}
|
|
414
|
+
async function arrowSelect(question, options, defaultIndex, config) {
|
|
415
|
+
const actions = config.actions ?? [];
|
|
416
|
+
const headerLines = config.headerLines ?? [];
|
|
417
|
+
const width = Math.max(44, Math.min(maxWidth(), 72));
|
|
418
|
+
const inner = width - 4;
|
|
419
|
+
const actionLineOffset = 2 + headerLines.length;
|
|
420
|
+
const hasActions = actions.length > 0;
|
|
421
|
+
const optionStartOffset = 3 + headerLines.length + (hasActions ? 1 : 0);
|
|
422
|
+
const lineCount = options.length + 4 + headerLines.length + (hasActions ? 1 : 0);
|
|
423
|
+
const rows = process.stdout.rows || 24;
|
|
424
|
+
const columns = process.stdout.columns || 80;
|
|
425
|
+
const panelTopRow = Math.max(2, Math.floor((rows - lineCount) / 2) + 1);
|
|
426
|
+
const panelLeftCol = Math.max(1, Math.floor((columns - width) / 2) + 1);
|
|
427
|
+
const footerRow = Math.min(rows, panelTopRow + lineCount + 1);
|
|
428
|
+
return new Promise((resolve) => {
|
|
429
|
+
const firstEnabled = options.findIndex((option) => !option.disabled);
|
|
430
|
+
let selected = options[defaultIndex]?.disabled ? firstEnabled : defaultIndex;
|
|
431
|
+
let selectedAction = null;
|
|
432
|
+
if (selected < 0) selected = 0;
|
|
433
|
+
const move = (direction) => {
|
|
434
|
+
let next = selected + direction;
|
|
435
|
+
while (next >= 0 && next < options.length) {
|
|
436
|
+
if (!options[next].disabled) {
|
|
437
|
+
selected = next;
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
next += direction;
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
const render = (initial = false) => {
|
|
444
|
+
if (!initial) {
|
|
445
|
+
stdout.write("\x1B[2J");
|
|
446
|
+
}
|
|
447
|
+
const lines = [];
|
|
448
|
+
lines.push(panelTop(width));
|
|
449
|
+
lines.push(
|
|
450
|
+
panelLine(width, centerText(`${ui.primary("\u25CF")} ${ui.text.bold(question)}`, inner))
|
|
451
|
+
);
|
|
452
|
+
for (const header of headerLines) {
|
|
453
|
+
lines.push(panelLine(width, centerText(ui.muted(header), inner)));
|
|
454
|
+
}
|
|
455
|
+
if (hasActions) {
|
|
456
|
+
lines.push(
|
|
457
|
+
panelLine(width, centerText(renderActions(actions, selectedAction, inner), inner))
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
lines.push(panelSep(width));
|
|
461
|
+
for (let i = 0; i < options.length; i++) {
|
|
462
|
+
lines.push(
|
|
463
|
+
panelLine(
|
|
464
|
+
width,
|
|
465
|
+
centerText(
|
|
466
|
+
renderOption(options[i], selectedAction === null && i === selected, inner),
|
|
467
|
+
inner
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
lines.push(panelBot(width));
|
|
473
|
+
lines.forEach((line, index) => writeAt(panelTopRow + index, panelLeftCol, line));
|
|
474
|
+
writeAt(
|
|
475
|
+
footerRow,
|
|
476
|
+
panelLeftCol,
|
|
477
|
+
centerText(
|
|
478
|
+
ui.muted(config.footer || "\u2191\u2193 move \xB7 enter select \xB7 mouse hover/click \xB7 esc close"),
|
|
479
|
+
width
|
|
480
|
+
)
|
|
481
|
+
);
|
|
482
|
+
};
|
|
483
|
+
const choose = (value = options[selected].value) => {
|
|
484
|
+
cleanup();
|
|
485
|
+
console.log(
|
|
486
|
+
` ${ui.success("\u2713")} ${ui.text.bold(question)} ${ui.primary(labelForValue(value, options, actions))}
|
|
487
|
+
`
|
|
488
|
+
);
|
|
489
|
+
resolve(value);
|
|
490
|
+
};
|
|
491
|
+
const onMouseData = (chunk) => {
|
|
492
|
+
const mouse = parseMouseEvent(chunk);
|
|
493
|
+
if (!mouse) return;
|
|
494
|
+
if (mouse.kind === "wheel-up") {
|
|
495
|
+
move(-1);
|
|
496
|
+
render();
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (mouse.kind === "wheel-down") {
|
|
500
|
+
move(1);
|
|
501
|
+
render();
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (hasActions && mouse.y === panelTopRow + actionLineOffset) {
|
|
505
|
+
const actionIdx = actionIndexAtX(actions, mouse.x, panelLeftCol, inner);
|
|
506
|
+
if (actionIdx === null || actions[actionIdx].disabled) return;
|
|
507
|
+
if (selectedAction !== actionIdx) {
|
|
508
|
+
selectedAction = actionIdx;
|
|
509
|
+
render();
|
|
510
|
+
}
|
|
511
|
+
if (mouse.kind === "click") choose(actions[actionIdx].value);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const idx = mouse.y - panelTopRow - optionStartOffset;
|
|
515
|
+
if (idx < 0 || idx >= options.length || options[idx].disabled) return;
|
|
516
|
+
if (selected !== idx) {
|
|
517
|
+
selected = idx;
|
|
518
|
+
selectedAction = null;
|
|
519
|
+
render();
|
|
520
|
+
}
|
|
521
|
+
if (mouse.kind === "click") {
|
|
522
|
+
choose();
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
const cleanup = () => {
|
|
526
|
+
leaveInteractiveScreen();
|
|
527
|
+
stdin.setRawMode(false);
|
|
528
|
+
stdin.removeListener("keypress", onKeypress);
|
|
529
|
+
stdin.removeListener("data", onMouseData);
|
|
530
|
+
stdin.pause();
|
|
531
|
+
};
|
|
532
|
+
readline.emitKeypressEvents(stdin);
|
|
533
|
+
stdin.setRawMode(true);
|
|
534
|
+
enterInteractiveScreen(true);
|
|
535
|
+
render(true);
|
|
536
|
+
const onKeypress = (_str, key) => {
|
|
537
|
+
if (!key) return;
|
|
538
|
+
if (key.name === "up" && selected > 0) {
|
|
539
|
+
move(-1);
|
|
540
|
+
selectedAction = null;
|
|
541
|
+
render();
|
|
542
|
+
} else if (key.name === "down" && selected < options.length - 1) {
|
|
543
|
+
move(1);
|
|
544
|
+
selectedAction = null;
|
|
545
|
+
render();
|
|
546
|
+
} else if (key.name === "tab" && hasActions) {
|
|
547
|
+
selectedAction = selectedAction === null ? 0 : null;
|
|
548
|
+
render();
|
|
549
|
+
} else if (key.name === "return") {
|
|
550
|
+
choose(selectedAction === null ? options[selected].value : actions[selectedAction].value);
|
|
551
|
+
} else if (key.ctrl && key.name === "c" || key.name === "escape") {
|
|
552
|
+
cleanup();
|
|
553
|
+
process.exit(0);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
stdin.resume();
|
|
557
|
+
stdin.on("data", onMouseData);
|
|
558
|
+
stdin.on("keypress", onKeypress);
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
async function fallbackPrompt(question, options, defaultIndex, config) {
|
|
562
|
+
if (!stdin.isTTY) {
|
|
563
|
+
const firstEnabled = options.findIndex((option) => !option.disabled);
|
|
564
|
+
const enabledDefault = options[defaultIndex]?.disabled ? firstEnabled : defaultIndex;
|
|
565
|
+
const def = String(enabledDefault + 1);
|
|
566
|
+
printFallbackOptions(question, options, enabledDefault, config);
|
|
567
|
+
while (true) {
|
|
568
|
+
const trimmed = (await readPipedLine()).trim();
|
|
569
|
+
if (trimmed.toLowerCase() === "a") {
|
|
570
|
+
const action = config.actions?.find((item) => !item.disabled);
|
|
571
|
+
if (action) return action.value;
|
|
572
|
+
}
|
|
573
|
+
if (!trimmed) {
|
|
574
|
+
const label = stripAnsi(options[enabledDefault].label);
|
|
575
|
+
console.log(` ${ui.success("\u2713")} ${ui.primary(label)}
|
|
576
|
+
`);
|
|
577
|
+
return options[enabledDefault].value;
|
|
578
|
+
}
|
|
579
|
+
const idx = parseInt(trimmed, 10);
|
|
580
|
+
if (idx >= 1 && idx <= options.length && !options[idx - 1].disabled) {
|
|
581
|
+
const label = stripAnsi(options[idx - 1].label);
|
|
582
|
+
console.log(` ${ui.success("\u2713")} ${ui.primary(label)}
|
|
583
|
+
`);
|
|
584
|
+
return options[idx - 1].value;
|
|
585
|
+
}
|
|
586
|
+
console.log(` ${ui.error("\u2717")} ${ui.warning(`Enter 1-${options.length} or ${def}`)}
|
|
587
|
+
`);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return new Promise((resolve) => {
|
|
591
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
592
|
+
const firstEnabled = options.findIndex((option) => !option.disabled);
|
|
593
|
+
const enabledDefault = options[defaultIndex]?.disabled ? firstEnabled : defaultIndex;
|
|
594
|
+
printFallbackOptions(question, options, enabledDefault, config);
|
|
595
|
+
const def = String(enabledDefault + 1);
|
|
596
|
+
const ask = () => {
|
|
597
|
+
rl.question(
|
|
598
|
+
` ${ui.primary(">")} ${ui.muted(`Choose [1-${options.length}] (${def})`)}: `,
|
|
599
|
+
(answer) => {
|
|
600
|
+
const trimmed = answer.trim();
|
|
601
|
+
if (trimmed.toLowerCase() === "a") {
|
|
602
|
+
const action = config.actions?.find((item) => !item.disabled);
|
|
603
|
+
if (action) {
|
|
604
|
+
rl.close();
|
|
605
|
+
resolve(action.value);
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
if (!trimmed) {
|
|
610
|
+
rl.close();
|
|
611
|
+
const label = stripAnsi(options[enabledDefault].label);
|
|
612
|
+
console.log(` ${ui.success("\u2713")} ${ui.primary(label)}
|
|
613
|
+
`);
|
|
614
|
+
resolve(options[enabledDefault].value);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
const idx = parseInt(trimmed, 10);
|
|
618
|
+
if (idx >= 1 && idx <= options.length && !options[idx - 1].disabled) {
|
|
619
|
+
rl.close();
|
|
620
|
+
const label = stripAnsi(options[idx - 1].label);
|
|
621
|
+
console.log(` ${ui.success("\u2713")} ${ui.primary(label)}
|
|
622
|
+
`);
|
|
623
|
+
resolve(options[idx - 1].value);
|
|
624
|
+
} else if (idx >= 1 && idx <= options.length && options[idx - 1].disabled) {
|
|
625
|
+
console.log(` ${ui.error("\u2717")} ${ui.warning("Option unavailable for now")}
|
|
626
|
+
`);
|
|
627
|
+
ask();
|
|
628
|
+
} else {
|
|
629
|
+
console.log(` ${ui.error("\u2717")} ${ui.warning(`Enter 1-${options.length}`)}
|
|
630
|
+
`);
|
|
631
|
+
ask();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
};
|
|
636
|
+
ask();
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
function fullscreenInput(question, defaultValue, config) {
|
|
640
|
+
const headerLines = config.headerLines ?? [];
|
|
641
|
+
const width = Math.max(44, Math.min(maxWidth(), 72));
|
|
642
|
+
const inner = width - 4;
|
|
643
|
+
const lineCount = 6 + headerLines.length;
|
|
644
|
+
const rows = process.stdout.rows || 24;
|
|
645
|
+
const columns = process.stdout.columns || 80;
|
|
646
|
+
const panelTopRow = Math.max(2, Math.floor((rows - lineCount) / 2) + 1);
|
|
647
|
+
const panelLeftCol = Math.max(1, Math.floor((columns - width) / 2) + 1);
|
|
648
|
+
const footerRow = Math.min(rows, panelTopRow + lineCount + 1);
|
|
649
|
+
return new Promise((resolve) => {
|
|
650
|
+
let value = defaultValue;
|
|
651
|
+
const render = () => {
|
|
652
|
+
stdout.write("\x1B[2J");
|
|
653
|
+
const shown = value || "";
|
|
654
|
+
const clipped = truncatePlain(shown, Math.max(12, inner - 10));
|
|
655
|
+
const input = `${ui.primary(">")} ${ui.text(clipped)}${ui.primary("\u258C")}`;
|
|
656
|
+
const lines = [];
|
|
657
|
+
lines.push(panelTop(width));
|
|
658
|
+
lines.push(
|
|
659
|
+
panelLine(width, centerText(`${ui.primary("\u25CF")} ${ui.text.bold(question)}`, inner))
|
|
660
|
+
);
|
|
661
|
+
for (const header of headerLines) {
|
|
662
|
+
lines.push(panelLine(width, centerText(ui.muted(header), inner)));
|
|
663
|
+
}
|
|
664
|
+
lines.push(panelSep(width));
|
|
665
|
+
lines.push(panelLine(width, centerText(input, inner)));
|
|
666
|
+
lines.push(panelBot(width));
|
|
667
|
+
lines.forEach((line, index) => writeAt(panelTopRow + index, panelLeftCol, line));
|
|
668
|
+
writeAt(
|
|
669
|
+
footerRow,
|
|
670
|
+
panelLeftCol,
|
|
671
|
+
centerText(ui.muted(config.footer || "type value \xB7 enter confirm \xB7 esc close"), width)
|
|
672
|
+
);
|
|
673
|
+
};
|
|
674
|
+
const cleanup = () => {
|
|
675
|
+
leaveInteractiveScreen();
|
|
676
|
+
stdin.setRawMode(false);
|
|
677
|
+
stdin.removeListener("keypress", onKeypress);
|
|
678
|
+
stdin.pause();
|
|
679
|
+
};
|
|
680
|
+
const submit = () => {
|
|
681
|
+
const output2 = cleanInputValue(value.trim() || defaultValue);
|
|
682
|
+
cleanup();
|
|
683
|
+
resolve(output2);
|
|
684
|
+
};
|
|
685
|
+
const onKeypress = (str, key) => {
|
|
686
|
+
if (key.ctrl && key.name === "c" || key.name === "escape") {
|
|
687
|
+
cleanup();
|
|
688
|
+
process.exit(0);
|
|
689
|
+
}
|
|
690
|
+
if (key.name === "return") {
|
|
691
|
+
submit();
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (key.name === "backspace") {
|
|
695
|
+
value = value.slice(0, -1);
|
|
696
|
+
render();
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
if (key.name === "delete") {
|
|
700
|
+
value = "";
|
|
701
|
+
render();
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
if (str && !key.ctrl && !key.meta && str >= " " && !isTerminalSequence(str, key)) {
|
|
705
|
+
value += cleanInputValue(str.replace(/[\r\n]/g, ""));
|
|
706
|
+
render();
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
readline.emitKeypressEvents(stdin);
|
|
710
|
+
stdin.setRawMode(true);
|
|
711
|
+
enterInteractiveScreen(false);
|
|
712
|
+
render();
|
|
713
|
+
stdin.resume();
|
|
714
|
+
stdin.on("keypress", onKeypress);
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
async function fallbackInput(question, defaultValue) {
|
|
718
|
+
if (!stdin.isTTY) {
|
|
719
|
+
const suffix = defaultValue ? ui.muted(` (${defaultValue})`) : "";
|
|
720
|
+
console.log(` ${ui.primary(">")} ${ui.text.bold(question)}${suffix}: `);
|
|
721
|
+
const answer = await readPipedLine();
|
|
722
|
+
return cleanInputValue(answer.trim() || defaultValue);
|
|
723
|
+
}
|
|
724
|
+
return new Promise((resolve) => {
|
|
725
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
726
|
+
const suffix = defaultValue ? ui.muted(` (${defaultValue})`) : "";
|
|
727
|
+
rl.question(` ${ui.primary(">")} ${ui.text.bold(question)}${suffix}: `, (answer) => {
|
|
728
|
+
rl.close();
|
|
729
|
+
resolve(cleanInputValue(answer.trim() || defaultValue));
|
|
730
|
+
});
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
function printFallbackOptions(question, options, enabledDefault, config) {
|
|
734
|
+
console.log(` ${ui.primary("\u25CF")} ${ui.text.bold(question)}
|
|
735
|
+
`);
|
|
736
|
+
for (const header of config.headerLines ?? []) {
|
|
737
|
+
console.log(` ${ui.muted(header)}`);
|
|
738
|
+
}
|
|
739
|
+
for (const action of config.actions ?? []) {
|
|
740
|
+
console.log(
|
|
741
|
+
` ${ui.muted("[A]")} ${action.disabled ? ui.muted(action.label) : ui.text(action.label)}`
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
if ((config.headerLines?.length || 0) > 0 || (config.actions?.length || 0) > 0) {
|
|
745
|
+
console.log("");
|
|
746
|
+
}
|
|
747
|
+
for (let i = 0; i < options.length; i++) {
|
|
748
|
+
const marker = i === enabledDefault ? ui.success(" \u25C6") : " ";
|
|
749
|
+
const label = options[i].disabled ? ui.muted(stripAnsi(options[i].label)) : ui.text(options[i].label);
|
|
750
|
+
console.log(` ${ui.muted(`[${i + 1}]`)}${marker} ${label}`);
|
|
751
|
+
}
|
|
752
|
+
console.log("");
|
|
753
|
+
}
|
|
754
|
+
function readPipedLine() {
|
|
755
|
+
if (!pipedLinesPromise) {
|
|
756
|
+
pipedLinesPromise = new Promise((resolve) => {
|
|
757
|
+
let data = "";
|
|
758
|
+
stdin.setEncoding("utf8");
|
|
759
|
+
stdin.on("data", (chunk) => {
|
|
760
|
+
data += chunk;
|
|
761
|
+
});
|
|
762
|
+
stdin.on("end", () => {
|
|
763
|
+
resolve(data.split(/\r?\n/));
|
|
764
|
+
});
|
|
765
|
+
stdin.on("error", () => {
|
|
766
|
+
resolve([]);
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
return pipedLinesPromise.then((lines) => lines[pipedLineIndex++] ?? "");
|
|
771
|
+
}
|
|
772
|
+
function renderActions(actions, active, width) {
|
|
773
|
+
return actions.map((action, index) => {
|
|
774
|
+
const label = truncatePlain(
|
|
775
|
+
stripAnsi(action.label),
|
|
776
|
+
Math.max(8, Math.floor(width / actions.length) - 8)
|
|
777
|
+
);
|
|
778
|
+
if (action.disabled) return `${ui.border("[")} ${ui.muted(label)} ${ui.border("]")}`;
|
|
779
|
+
if (active === index)
|
|
780
|
+
return `${ui.primary("\u203A")} ${ui.primary("[")} ${ui.text.bold(label)} ${ui.primary("]")} ${ui.primary("\u2039")}`;
|
|
781
|
+
return `${ui.border("[")} ${ui.primary(label)} ${ui.border("]")}`;
|
|
782
|
+
}).join(` ${ui.muted("\xB7")} `);
|
|
783
|
+
}
|
|
784
|
+
function actionIndexAtX(actions, mouseX, panelLeftCol, inner) {
|
|
785
|
+
if (actions.length === 0) return null;
|
|
786
|
+
const contentStart = panelLeftCol + 2;
|
|
787
|
+
const relative = mouseX - contentStart;
|
|
788
|
+
if (relative < 0 || relative > inner) return null;
|
|
789
|
+
return Math.min(actions.length - 1, Math.floor(relative / Math.max(1, inner) * actions.length));
|
|
790
|
+
}
|
|
791
|
+
function labelForValue(value, options, actions) {
|
|
792
|
+
return stripAnsi(
|
|
793
|
+
options.find((option) => option.value === value)?.label || actions.find((action) => action.value === value)?.label || value
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
function renderOption(option, selected, width) {
|
|
797
|
+
const plain = truncatePlain(stripAnsi(option.label), Math.max(10, width - 12));
|
|
798
|
+
if (option.disabled) {
|
|
799
|
+
return `${ui.border("[")} ${ui.muted(plain)} ${ui.border("]")}`;
|
|
800
|
+
}
|
|
801
|
+
if (selected) {
|
|
802
|
+
return `${ui.primary("\u203A")} ${ui.primary("[")} ${ui.text.bold(plain)} ${ui.primary("]")} ${ui.primary("\u2039")}`;
|
|
803
|
+
}
|
|
804
|
+
return `${ui.muted(" ")} ${ui.border("[")} ${ui.muted(plain)} ${ui.border("]")} ${ui.muted(" ")}`;
|
|
805
|
+
}
|
|
806
|
+
function enterInteractiveScreen(enableMouse) {
|
|
807
|
+
stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l");
|
|
808
|
+
if (enableMouse) {
|
|
809
|
+
stdout.write("\x1B[?1006h\x1B[?1000h\x1B[?1002h\x1B[?1003h");
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
function leaveInteractiveScreen() {
|
|
813
|
+
stdout.write(
|
|
814
|
+
"\x1B[?1003l\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?25h\x1B[?1049l"
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
function parseMouseEvent(chunk) {
|
|
818
|
+
const text = chunk.toString("utf-8");
|
|
819
|
+
const match = text.match(/\x1B\[<(\d+);(\d+);(\d+)([mM])/);
|
|
820
|
+
if (!match) return parseLegacyMouseEvent(text);
|
|
821
|
+
const code = Number(match[1]);
|
|
822
|
+
const x = Number(match[2]);
|
|
823
|
+
const y = Number(match[3]);
|
|
824
|
+
const state = match[4];
|
|
825
|
+
if (code === 64) return { kind: "wheel-up", x, y };
|
|
826
|
+
if (code === 65) return { kind: "wheel-down", x, y };
|
|
827
|
+
if (state === "m") return { kind: "click", x, y };
|
|
828
|
+
if ((code & 32) === 32 || code === 35) return { kind: "hover", x, y };
|
|
829
|
+
if ((code & 3) === 0) return { kind: "hover", x, y };
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
function parseLegacyMouseEvent(text) {
|
|
833
|
+
const match = text.match(/\x1B\[M([\s\S])([\s\S])([\s\S])/);
|
|
834
|
+
if (!match) return null;
|
|
835
|
+
const code = match[1].charCodeAt(0) - 32;
|
|
836
|
+
const x = match[2].charCodeAt(0) - 32;
|
|
837
|
+
const y = match[3].charCodeAt(0) - 32;
|
|
838
|
+
if (code === 64) return { kind: "wheel-up", x, y };
|
|
839
|
+
if (code === 65) return { kind: "wheel-down", x, y };
|
|
840
|
+
if ((code & 3) === 3) return { kind: "click", x, y };
|
|
841
|
+
if ((code & 32) === 32) return { kind: "hover", x, y };
|
|
842
|
+
return { kind: "hover", x, y };
|
|
843
|
+
}
|
|
844
|
+
function writeAt(row, col, text) {
|
|
845
|
+
stdout.write(`\x1B[${row};${col}H${text}`);
|
|
846
|
+
}
|
|
847
|
+
function isTerminalSequence(str, key) {
|
|
848
|
+
return str.includes("\x1B") || !!key.sequence?.includes("\x1B") || /^(?:\d+;){2}\d+[mM]$/.test(str);
|
|
849
|
+
}
|
|
850
|
+
function cleanInputValue(value) {
|
|
851
|
+
return value.replace(/\x1B\[<\d+;\d+;\d+[mM]/g, "").replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "").replace(/(?:\d+;){2}\d+[mM]/g, "").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
|
|
852
|
+
}
|
|
853
|
+
var pipedLinesPromise, pipedLineIndex;
|
|
854
|
+
var init_select = __esm({
|
|
855
|
+
"src/cli/select.ts"() {
|
|
856
|
+
"use strict";
|
|
857
|
+
init_box();
|
|
858
|
+
init_theme();
|
|
859
|
+
pipedLinesPromise = null;
|
|
860
|
+
pipedLineIndex = 0;
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
|
|
207
864
|
// src/assets/asset-map.ts
|
|
208
865
|
import path from "path";
|
|
209
866
|
import crypto from "crypto";
|
|
@@ -340,7 +997,7 @@ var init_download = __esm({
|
|
|
340
997
|
});
|
|
341
998
|
|
|
342
999
|
// src/logger/index.ts
|
|
343
|
-
import
|
|
1000
|
+
import chalk4 from "chalk";
|
|
344
1001
|
function setCooking(spinner) {
|
|
345
1002
|
_cooking = spinner;
|
|
346
1003
|
}
|
|
@@ -360,52 +1017,52 @@ var init_logger = __esm({
|
|
|
360
1017
|
_cooking = null;
|
|
361
1018
|
T = () => (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
|
|
362
1019
|
LOG_PALETTE = [
|
|
363
|
-
(s) =>
|
|
364
|
-
(s) =>
|
|
365
|
-
(s) =>
|
|
366
|
-
(s) =>
|
|
367
|
-
(s) =>
|
|
368
|
-
(s) =>
|
|
1020
|
+
(s) => chalk4.hex(THEME.primary)(s),
|
|
1021
|
+
(s) => chalk4.hex(THEME.primarySoft)(s),
|
|
1022
|
+
(s) => chalk4.hex(THEME.secondary)(s),
|
|
1023
|
+
(s) => chalk4.hex(THEME.accent)(s),
|
|
1024
|
+
(s) => chalk4.hex(THEME.info)(s),
|
|
1025
|
+
(s) => chalk4.hex(THEME.text)(s)
|
|
369
1026
|
];
|
|
370
1027
|
_li = 0;
|
|
371
1028
|
log = (m) => {
|
|
372
1029
|
_li++;
|
|
373
1030
|
const c = LOG_PALETTE[_li % LOG_PALETTE.length];
|
|
374
1031
|
output(
|
|
375
|
-
`${
|
|
1032
|
+
`${chalk4.hex(THEME.muted)(`[${T()}]`)} ${chalk4.hex(THEME.primary)("[log]")} ${c(trunc(m, 120))}`
|
|
376
1033
|
);
|
|
377
1034
|
};
|
|
378
1035
|
INFO_PALETTE = [
|
|
379
|
-
(s) =>
|
|
380
|
-
(s) =>
|
|
381
|
-
(s) =>
|
|
1036
|
+
(s) => chalk4.hex(THEME.info)(s),
|
|
1037
|
+
(s) => chalk4.hex(THEME.secondary)(s),
|
|
1038
|
+
(s) => chalk4.hex(THEME.primarySoft)(s)
|
|
382
1039
|
];
|
|
383
1040
|
_ii = 0;
|
|
384
1041
|
info = (m) => {
|
|
385
1042
|
_ii++;
|
|
386
1043
|
const c = INFO_PALETTE[_ii % INFO_PALETTE.length];
|
|
387
1044
|
output(
|
|
388
|
-
`${
|
|
1045
|
+
`${chalk4.hex(THEME.muted)(`[${T()}]`)} ${chalk4.hex(THEME.info).bold("[info]")} ${c(trunc(m, 120))}`
|
|
389
1046
|
);
|
|
390
1047
|
};
|
|
391
1048
|
warn = (m) => {
|
|
392
1049
|
const colors = [
|
|
393
|
-
(s) =>
|
|
394
|
-
(s) =>
|
|
1050
|
+
(s) => chalk4.hex(THEME.warning)(s),
|
|
1051
|
+
(s) => chalk4.hex(THEME.primary)(s)
|
|
395
1052
|
];
|
|
396
1053
|
const c = colors[Math.floor(Math.random() * colors.length)];
|
|
397
|
-
const line = `${
|
|
1054
|
+
const line = `${chalk4.hex(THEME.muted)(`[${T()}]`)} ${chalk4.hex(THEME.warning).bold("[warn]")} ${c(trunc(m, 120))}`;
|
|
398
1055
|
if (_cooking) _cooking.log(line);
|
|
399
1056
|
else console.warn(line);
|
|
400
1057
|
};
|
|
401
1058
|
success = (m) => {
|
|
402
1059
|
const colors = [
|
|
403
|
-
(s) =>
|
|
404
|
-
(s) =>
|
|
1060
|
+
(s) => chalk4.hex(THEME.success)(s),
|
|
1061
|
+
(s) => chalk4.hex(THEME.info)(s)
|
|
405
1062
|
];
|
|
406
1063
|
const c = colors[Math.floor(Math.random() * colors.length)];
|
|
407
1064
|
output(
|
|
408
|
-
`${
|
|
1065
|
+
`${chalk4.hex(THEME.muted)(`[${T()}]`)} ${chalk4.hex(THEME.success)("[ok]")} ${c(trunc(m, 120))}`
|
|
409
1066
|
);
|
|
410
1067
|
};
|
|
411
1068
|
}
|
|
@@ -1318,52 +1975,6 @@ var init_output = __esm({
|
|
|
1318
1975
|
}
|
|
1319
1976
|
});
|
|
1320
1977
|
|
|
1321
|
-
// src/cli/box.ts
|
|
1322
|
-
import chalk3 from "chalk";
|
|
1323
|
-
function maxWidth() {
|
|
1324
|
-
return Math.min(process.stdout.columns || 80, 76);
|
|
1325
|
-
}
|
|
1326
|
-
function padRight(text, w) {
|
|
1327
|
-
const visible = stripAnsi(text).length;
|
|
1328
|
-
if (visible >= w) return text;
|
|
1329
|
-
return text + " ".repeat(w - visible);
|
|
1330
|
-
}
|
|
1331
|
-
function boxTop(w) {
|
|
1332
|
-
const inner = w - 4;
|
|
1333
|
-
return " " + ui.border("\u256D\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u256E");
|
|
1334
|
-
}
|
|
1335
|
-
function boxBot(w) {
|
|
1336
|
-
const inner = w - 4;
|
|
1337
|
-
return " " + ui.border("\u2570\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u256F");
|
|
1338
|
-
}
|
|
1339
|
-
function boxLine(w, text) {
|
|
1340
|
-
const inner = w - 4;
|
|
1341
|
-
const padded = padRight(text, inner);
|
|
1342
|
-
return " " + ui.border("\u2502 ") + padded + ui.border(" \u2502");
|
|
1343
|
-
}
|
|
1344
|
-
function boxSep(w) {
|
|
1345
|
-
const inner = w - 4;
|
|
1346
|
-
return " " + ui.border("\u251C\u2500") + ui.border("\u2500".repeat(inner)) + ui.border("\u2500\u2524");
|
|
1347
|
-
}
|
|
1348
|
-
function boxRow(w, label, value) {
|
|
1349
|
-
const inner = w - 4;
|
|
1350
|
-
const labelPlain = stripAnsi(chalk3.bold(label));
|
|
1351
|
-
const visible = labelPlain.length + 1 + value.length;
|
|
1352
|
-
if (visible > inner) {
|
|
1353
|
-
const avail = inner - labelPlain.length - 2;
|
|
1354
|
-
const truncated = value.length > avail ? value.slice(0, avail - 1) + ".." : value;
|
|
1355
|
-
return " " + ui.border("\u2502 ") + chalk3.bold(label) + ": " + ui.primary(truncated) + " ".repeat(Math.max(0, inner - labelPlain.length - 1 - truncated.length)) + ui.border(" \u2502");
|
|
1356
|
-
}
|
|
1357
|
-
const right = inner - labelPlain.length - 1 - value.length;
|
|
1358
|
-
return " " + ui.border("\u2502 ") + chalk3.bold(label) + ": " + ui.primary(value) + " ".repeat(right) + ui.border(" \u2502");
|
|
1359
|
-
}
|
|
1360
|
-
var init_box = __esm({
|
|
1361
|
-
"src/cli/box.ts"() {
|
|
1362
|
-
"use strict";
|
|
1363
|
-
init_theme();
|
|
1364
|
-
}
|
|
1365
|
-
});
|
|
1366
|
-
|
|
1367
1978
|
// src/exporter/summary.ts
|
|
1368
1979
|
import fs3 from "fs/promises";
|
|
1369
1980
|
import path4 from "path";
|
|
@@ -1392,294 +2003,69 @@ async function printSummary(exporter) {
|
|
|
1392
2003
|
const G2 = ui.primarySoft;
|
|
1393
2004
|
const C2 = ui.secondary;
|
|
1394
2005
|
const Y = ui.accent;
|
|
1395
|
-
const O = ui.warning;
|
|
1396
|
-
const Br = ui.info;
|
|
1397
|
-
const Gr = ui.muted;
|
|
1398
|
-
const Gn = ui.success;
|
|
1399
|
-
const entries = [
|
|
1400
|
-
["styles/", styles, "CSS", G],
|
|
1401
|
-
["scripts/vendor/", vendor, "JS vendor", G2],
|
|
1402
|
-
["scripts/modules/", scripts, "JS modules", C2],
|
|
1403
|
-
["assets/images/", imgs, "images", Y],
|
|
1404
|
-
["assets/videos/", videos, "videos", O],
|
|
1405
|
-
["assets/fonts/", fonts, "fonts", Br],
|
|
1406
|
-
["assets/misc/", misc, "misc", Gr],
|
|
1407
|
-
["data/", data, "data", Gr],
|
|
1408
|
-
["subpages/", subpages, "pages", Gn]
|
|
1409
|
-
];
|
|
1410
|
-
console.log("");
|
|
1411
|
-
if (!isSmall) {
|
|
1412
|
-
console.log(boxTop(w));
|
|
1413
|
-
console.log(boxLine(w, `${ui.text.bold(" Export Summary")} ${chip("done")}`));
|
|
1414
|
-
console.log(boxSep(w));
|
|
1415
|
-
} else {
|
|
1416
|
-
console.log(ui.text.bold(" Export Summary:"));
|
|
1417
|
-
}
|
|
1418
|
-
for (const [label, cnt, type, color] of entries) {
|
|
1419
|
-
if (cnt === 0) continue;
|
|
1420
|
-
const inner = w - 4;
|
|
1421
|
-
const l = label.padEnd(16);
|
|
1422
|
-
const c = String(cnt).padStart(3);
|
|
1423
|
-
const rowText = `${color(l)}${ui.text(c)} ${ui.muted(type)}`;
|
|
1424
|
-
const visible = 16 + 3 + 2 + type.length;
|
|
1425
|
-
const pad = Math.max(0, inner - visible);
|
|
1426
|
-
if (isSmall) {
|
|
1427
|
-
console.log(` ${color(label)} ${ui.text(String(cnt))} ${ui.muted(type)}`);
|
|
1428
|
-
} else {
|
|
1429
|
-
console.log(" " + ui.border("\u2502 ") + rowText + " ".repeat(pad) + ui.border(" \u2502"));
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
if (!isSmall) {
|
|
1433
|
-
console.log(boxBot(w));
|
|
1434
|
-
}
|
|
1435
|
-
console.log("");
|
|
1436
|
-
const cdCmd = "cd " + path4.basename(exporter.outDir) + " && node serve.cjs";
|
|
1437
|
-
if (!isSmall) {
|
|
1438
|
-
console.log(boxTop(w));
|
|
1439
|
-
console.log(boxLine(w, ui.text.bold(" To serve locally")));
|
|
1440
|
-
console.log(boxSep(w));
|
|
1441
|
-
const inner = w - 6;
|
|
1442
|
-
const cmdLen = cdCmd.length;
|
|
1443
|
-
const pad = Math.max(0, inner - cmdLen);
|
|
1444
|
-
console.log(
|
|
1445
|
-
" " + ui.border("\u2502 ") + G(cdCmd) + " ".repeat(pad) + ui.muted(" copy") + ui.border(" \u2502")
|
|
1446
|
-
);
|
|
1447
|
-
console.log(boxBot(w));
|
|
1448
|
-
} else {
|
|
1449
|
-
console.log(ui.text.bold(" To serve locally:"));
|
|
1450
|
-
console.log(` ${G(cdCmd)}`);
|
|
1451
|
-
}
|
|
1452
|
-
console.log("");
|
|
1453
|
-
console.log(ui.muted(" note: must be served via HTTP for JS modules to work."));
|
|
1454
|
-
console.log("");
|
|
1455
|
-
}
|
|
1456
|
-
var init_summary = __esm({
|
|
1457
|
-
"src/exporter/summary.ts"() {
|
|
1458
|
-
"use strict";
|
|
1459
|
-
init_box();
|
|
1460
|
-
init_theme();
|
|
1461
|
-
}
|
|
1462
|
-
});
|
|
1463
|
-
|
|
1464
|
-
// src/cli/select.ts
|
|
1465
|
-
import readline from "readline";
|
|
1466
|
-
import { stdin, stdout } from "process";
|
|
1467
|
-
async function select(question, options, defaultIndex = 0) {
|
|
1468
|
-
const isTTY = stdin.isTTY && stdout.isTTY;
|
|
1469
|
-
if (!isTTY) {
|
|
1470
|
-
return fallbackPrompt(question, options, defaultIndex);
|
|
1471
|
-
}
|
|
1472
|
-
return arrowSelect(question, options, defaultIndex);
|
|
1473
|
-
}
|
|
1474
|
-
async function arrowSelect(question, options, defaultIndex) {
|
|
1475
|
-
const panelTopRow = await queryCursorRow();
|
|
1476
|
-
const width = Math.min(maxWidth(), 72);
|
|
1477
|
-
const inner = width - 4;
|
|
1478
|
-
const optionStartOffset = 3;
|
|
1479
|
-
const lineCount = options.length + 4;
|
|
1480
|
-
return new Promise((resolve) => {
|
|
1481
|
-
const firstEnabled = options.findIndex((option) => !option.disabled);
|
|
1482
|
-
let selected = options[defaultIndex]?.disabled ? firstEnabled : defaultIndex;
|
|
1483
|
-
if (selected < 0) selected = 0;
|
|
1484
|
-
const move = (direction) => {
|
|
1485
|
-
let next = selected + direction;
|
|
1486
|
-
while (next >= 0 && next < options.length) {
|
|
1487
|
-
if (!options[next].disabled) {
|
|
1488
|
-
selected = next;
|
|
1489
|
-
return;
|
|
1490
|
-
}
|
|
1491
|
-
next += direction;
|
|
1492
|
-
}
|
|
1493
|
-
};
|
|
1494
|
-
const render = (initial = false) => {
|
|
1495
|
-
if (!initial) {
|
|
1496
|
-
stdout.write(`\x1B[${lineCount}A`);
|
|
1497
|
-
stdout.write("\x1B[J");
|
|
1498
|
-
}
|
|
1499
|
-
console.log(boxTop(width));
|
|
1500
|
-
console.log(
|
|
1501
|
-
boxLine(width, centerText(`${ui.primary("\u25CF")} ${ui.text.bold(question)}`, inner))
|
|
1502
|
-
);
|
|
1503
|
-
console.log(boxSep(width));
|
|
1504
|
-
for (let i = 0; i < options.length; i++) {
|
|
1505
|
-
console.log(
|
|
1506
|
-
boxLine(width, centerText(renderOption(options[i], i === selected, inner), inner))
|
|
1507
|
-
);
|
|
1508
|
-
}
|
|
1509
|
-
console.log(boxBot(width));
|
|
1510
|
-
};
|
|
1511
|
-
const choose = () => {
|
|
1512
|
-
cleanup();
|
|
1513
|
-
stdout.write(`\x1B[${lineCount}A`);
|
|
1514
|
-
stdout.write("\x1B[J");
|
|
1515
|
-
console.log(
|
|
1516
|
-
` ${ui.success("\u2713")} ${ui.text.bold(question)} ${ui.primary(stripAnsi(options[selected].label))}
|
|
1517
|
-
`
|
|
1518
|
-
);
|
|
1519
|
-
resolve(options[selected].value);
|
|
1520
|
-
};
|
|
1521
|
-
const onMouseData = (chunk) => {
|
|
1522
|
-
const mouse = parseMouseEvent(chunk);
|
|
1523
|
-
if (!mouse) return;
|
|
1524
|
-
if (mouse.kind === "wheel-up") {
|
|
1525
|
-
move(-1);
|
|
1526
|
-
render();
|
|
1527
|
-
return;
|
|
1528
|
-
}
|
|
1529
|
-
if (mouse.kind === "wheel-down") {
|
|
1530
|
-
move(1);
|
|
1531
|
-
render();
|
|
1532
|
-
return;
|
|
1533
|
-
}
|
|
1534
|
-
if (panelTopRow === null) return;
|
|
1535
|
-
const idx = mouse.y - panelTopRow - optionStartOffset;
|
|
1536
|
-
if (idx < 0 || idx >= options.length || options[idx].disabled) return;
|
|
1537
|
-
if (selected !== idx) {
|
|
1538
|
-
selected = idx;
|
|
1539
|
-
render();
|
|
1540
|
-
}
|
|
1541
|
-
if (mouse.kind === "click") {
|
|
1542
|
-
choose();
|
|
1543
|
-
}
|
|
1544
|
-
};
|
|
1545
|
-
const cleanup = () => {
|
|
1546
|
-
disableMouse();
|
|
1547
|
-
stdin.setRawMode(false);
|
|
1548
|
-
stdin.removeListener("keypress", onKeypress);
|
|
1549
|
-
stdin.removeListener("data", onMouseData);
|
|
1550
|
-
stdin.pause();
|
|
1551
|
-
};
|
|
1552
|
-
render(true);
|
|
1553
|
-
readline.emitKeypressEvents(stdin);
|
|
1554
|
-
stdin.setRawMode(true);
|
|
1555
|
-
enableInteractiveInput();
|
|
1556
|
-
const onKeypress = (_str, key) => {
|
|
1557
|
-
if (!key) return;
|
|
1558
|
-
if (key.name === "up" && selected > 0) {
|
|
1559
|
-
move(-1);
|
|
1560
|
-
render();
|
|
1561
|
-
} else if (key.name === "down" && selected < options.length - 1) {
|
|
1562
|
-
move(1);
|
|
1563
|
-
render();
|
|
1564
|
-
} else if (key.name === "return") {
|
|
1565
|
-
choose();
|
|
1566
|
-
} else if (key.ctrl && key.name === "c" || key.name === "escape") {
|
|
1567
|
-
cleanup();
|
|
1568
|
-
process.exit(0);
|
|
1569
|
-
}
|
|
1570
|
-
};
|
|
1571
|
-
stdin.resume();
|
|
1572
|
-
stdin.on("data", onMouseData);
|
|
1573
|
-
stdin.on("keypress", onKeypress);
|
|
1574
|
-
});
|
|
1575
|
-
}
|
|
1576
|
-
async function fallbackPrompt(question, options, defaultIndex) {
|
|
1577
|
-
return new Promise((resolve) => {
|
|
1578
|
-
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
1579
|
-
const firstEnabled = options.findIndex((option) => !option.disabled);
|
|
1580
|
-
const enabledDefault = options[defaultIndex]?.disabled ? firstEnabled : defaultIndex;
|
|
1581
|
-
console.log(` ${ui.primary("\u25CF")} ${ui.text.bold(question)}
|
|
1582
|
-
`);
|
|
1583
|
-
for (let i = 0; i < options.length; i++) {
|
|
1584
|
-
const marker = i === enabledDefault ? ui.success(" \u25C6") : " ";
|
|
1585
|
-
const label = options[i].disabled ? ui.muted(stripAnsi(options[i].label)) : ui.text(options[i].label);
|
|
1586
|
-
console.log(` ${ui.muted(`[${i + 1}]`)}${marker} ${label}`);
|
|
2006
|
+
const O = ui.warning;
|
|
2007
|
+
const Br = ui.info;
|
|
2008
|
+
const Gr = ui.muted;
|
|
2009
|
+
const Gn = ui.success;
|
|
2010
|
+
const entries = [
|
|
2011
|
+
["styles/", styles, "CSS", G],
|
|
2012
|
+
["scripts/vendor/", vendor, "JS vendor", G2],
|
|
2013
|
+
["scripts/modules/", scripts, "JS modules", C2],
|
|
2014
|
+
["assets/images/", imgs, "images", Y],
|
|
2015
|
+
["assets/videos/", videos, "videos", O],
|
|
2016
|
+
["assets/fonts/", fonts, "fonts", Br],
|
|
2017
|
+
["assets/misc/", misc, "misc", Gr],
|
|
2018
|
+
["data/", data, "data", Gr],
|
|
2019
|
+
["subpages/", subpages, "pages", Gn]
|
|
2020
|
+
];
|
|
2021
|
+
console.log("");
|
|
2022
|
+
if (!isSmall) {
|
|
2023
|
+
console.log(boxTop(w));
|
|
2024
|
+
console.log(boxLine(w, `${ui.text.bold(" Export Summary")} ${chip("done")}`));
|
|
2025
|
+
console.log(boxSep(w));
|
|
2026
|
+
} else {
|
|
2027
|
+
console.log(ui.text.bold(" Export Summary:"));
|
|
2028
|
+
}
|
|
2029
|
+
for (const [label, cnt, type, color] of entries) {
|
|
2030
|
+
if (cnt === 0) continue;
|
|
2031
|
+
const inner = w - 4;
|
|
2032
|
+
const l = label.padEnd(16);
|
|
2033
|
+
const c = String(cnt).padStart(3);
|
|
2034
|
+
const rowText = `${color(l)}${ui.text(c)} ${ui.muted(type)}`;
|
|
2035
|
+
const visible = 16 + 3 + 2 + type.length;
|
|
2036
|
+
const pad = Math.max(0, inner - visible);
|
|
2037
|
+
if (isSmall) {
|
|
2038
|
+
console.log(` ${color(label)} ${ui.text(String(cnt))} ${ui.muted(type)}`);
|
|
2039
|
+
} else {
|
|
2040
|
+
console.log(" " + ui.border("\u2502 ") + rowText + " ".repeat(pad) + ui.border(" \u2502"));
|
|
1587
2041
|
}
|
|
1588
|
-
console.log("");
|
|
1589
|
-
const def = String(enabledDefault + 1);
|
|
1590
|
-
const ask = () => {
|
|
1591
|
-
rl.question(
|
|
1592
|
-
` ${ui.primary(">")} ${ui.muted(`Choose [1-${options.length}] (${def})`)}: `,
|
|
1593
|
-
(answer) => {
|
|
1594
|
-
const trimmed = answer.trim();
|
|
1595
|
-
if (!trimmed) {
|
|
1596
|
-
rl.close();
|
|
1597
|
-
const label = stripAnsi(options[enabledDefault].label);
|
|
1598
|
-
console.log(` ${ui.success("\u2713")} ${ui.primary(label)}
|
|
1599
|
-
`);
|
|
1600
|
-
resolve(options[enabledDefault].value);
|
|
1601
|
-
return;
|
|
1602
|
-
}
|
|
1603
|
-
const idx = parseInt(trimmed, 10);
|
|
1604
|
-
if (idx >= 1 && idx <= options.length && !options[idx - 1].disabled) {
|
|
1605
|
-
rl.close();
|
|
1606
|
-
const label = stripAnsi(options[idx - 1].label);
|
|
1607
|
-
console.log(` ${ui.success("\u2713")} ${ui.primary(label)}
|
|
1608
|
-
`);
|
|
1609
|
-
resolve(options[idx - 1].value);
|
|
1610
|
-
} else if (idx >= 1 && idx <= options.length && options[idx - 1].disabled) {
|
|
1611
|
-
console.log(` ${ui.error("\u2717")} ${ui.warning("Option unavailable for now")}
|
|
1612
|
-
`);
|
|
1613
|
-
ask();
|
|
1614
|
-
} else {
|
|
1615
|
-
console.log(` ${ui.error("\u2717")} ${ui.warning(`Enter 1-${options.length}`)}
|
|
1616
|
-
`);
|
|
1617
|
-
ask();
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
);
|
|
1621
|
-
};
|
|
1622
|
-
ask();
|
|
1623
|
-
});
|
|
1624
|
-
}
|
|
1625
|
-
function renderOption(option, selected, width) {
|
|
1626
|
-
const plain = truncatePlain(stripAnsi(option.label), Math.max(10, width - 12));
|
|
1627
|
-
if (option.disabled) {
|
|
1628
|
-
return `${ui.border("[")} ${ui.muted(plain)} ${ui.border("]")}`;
|
|
1629
2042
|
}
|
|
1630
|
-
if (
|
|
1631
|
-
|
|
2043
|
+
if (!isSmall) {
|
|
2044
|
+
console.log(boxBot(w));
|
|
1632
2045
|
}
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
if ((code & 3) === 0) return { kind: "hover", x, y };
|
|
1654
|
-
return null;
|
|
1655
|
-
}
|
|
1656
|
-
function queryCursorRow() {
|
|
1657
|
-
if (!stdin.isTTY || !stdout.isTTY) return Promise.resolve(null);
|
|
1658
|
-
return new Promise((resolve) => {
|
|
1659
|
-
const wasRaw = stdin.isRaw;
|
|
1660
|
-
let done = false;
|
|
1661
|
-
const finish = (row) => {
|
|
1662
|
-
if (done) return;
|
|
1663
|
-
done = true;
|
|
1664
|
-
clearTimeout(timer);
|
|
1665
|
-
stdin.removeListener("data", onData);
|
|
1666
|
-
if (!wasRaw) stdin.setRawMode(false);
|
|
1667
|
-
resolve(row);
|
|
1668
|
-
};
|
|
1669
|
-
const onData = (chunk) => {
|
|
1670
|
-
const match = chunk.toString("utf-8").match(/\x1B\[(\d+);\d+R/);
|
|
1671
|
-
if (!match) return;
|
|
1672
|
-
finish(Number(match[1]));
|
|
1673
|
-
};
|
|
1674
|
-
const timer = setTimeout(() => finish(null), 80);
|
|
1675
|
-
stdin.setRawMode(true);
|
|
1676
|
-
stdin.resume();
|
|
1677
|
-
stdin.on("data", onData);
|
|
1678
|
-
stdout.write("\x1B[6n");
|
|
1679
|
-
});
|
|
2046
|
+
console.log("");
|
|
2047
|
+
const cdCmd = "cd " + path4.basename(exporter.outDir) + " && node serve.cjs";
|
|
2048
|
+
if (!isSmall) {
|
|
2049
|
+
console.log(boxTop(w));
|
|
2050
|
+
console.log(boxLine(w, ui.text.bold(" To serve locally")));
|
|
2051
|
+
console.log(boxSep(w));
|
|
2052
|
+
const inner = w - 6;
|
|
2053
|
+
const cmdLen = cdCmd.length;
|
|
2054
|
+
const pad = Math.max(0, inner - cmdLen);
|
|
2055
|
+
console.log(
|
|
2056
|
+
" " + ui.border("\u2502 ") + G(cdCmd) + " ".repeat(pad) + ui.muted(" copy") + ui.border(" \u2502")
|
|
2057
|
+
);
|
|
2058
|
+
console.log(boxBot(w));
|
|
2059
|
+
} else {
|
|
2060
|
+
console.log(ui.text.bold(" To serve locally:"));
|
|
2061
|
+
console.log(` ${G(cdCmd)}`);
|
|
2062
|
+
}
|
|
2063
|
+
console.log("");
|
|
2064
|
+
console.log(ui.muted(" note: must be served via HTTP for JS modules to work."));
|
|
2065
|
+
console.log("");
|
|
1680
2066
|
}
|
|
1681
|
-
var
|
|
1682
|
-
"src/
|
|
2067
|
+
var init_summary = __esm({
|
|
2068
|
+
"src/exporter/summary.ts"() {
|
|
1683
2069
|
"use strict";
|
|
1684
2070
|
init_box();
|
|
1685
2071
|
init_theme();
|
|
@@ -2166,82 +2552,6 @@ var init_prompt_assistant = __esm({
|
|
|
2166
2552
|
}
|
|
2167
2553
|
});
|
|
2168
2554
|
|
|
2169
|
-
// src/cli/cooking.ts
|
|
2170
|
-
import chalk4 from "chalk";
|
|
2171
|
-
var SHINE_WIDTH, FRAME_INTERVAL, SPINNER_FRAMES, CookingSpinner;
|
|
2172
|
-
var init_cooking = __esm({
|
|
2173
|
-
"src/cli/cooking.ts"() {
|
|
2174
|
-
"use strict";
|
|
2175
|
-
init_theme();
|
|
2176
|
-
SHINE_WIDTH = 10;
|
|
2177
|
-
FRAME_INTERVAL = 80;
|
|
2178
|
-
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
2179
|
-
CookingSpinner = class {
|
|
2180
|
-
interval = null;
|
|
2181
|
-
frame = 0;
|
|
2182
|
-
phase = "";
|
|
2183
|
-
active = false;
|
|
2184
|
-
start(phase = "") {
|
|
2185
|
-
this.phase = phase;
|
|
2186
|
-
this.frame = 0;
|
|
2187
|
-
this.active = true;
|
|
2188
|
-
this.draw();
|
|
2189
|
-
this.interval = setInterval(() => {
|
|
2190
|
-
this.frame++;
|
|
2191
|
-
this.draw();
|
|
2192
|
-
}, FRAME_INTERVAL);
|
|
2193
|
-
}
|
|
2194
|
-
update(phase) {
|
|
2195
|
-
this.phase = phase;
|
|
2196
|
-
}
|
|
2197
|
-
log(message) {
|
|
2198
|
-
if (this.active) {
|
|
2199
|
-
process.stdout.write("\r\x1B[2K");
|
|
2200
|
-
}
|
|
2201
|
-
process.stdout.write(message + "\n");
|
|
2202
|
-
if (this.active) {
|
|
2203
|
-
this.draw();
|
|
2204
|
-
}
|
|
2205
|
-
}
|
|
2206
|
-
stop() {
|
|
2207
|
-
this.active = false;
|
|
2208
|
-
if (this.interval) {
|
|
2209
|
-
clearInterval(this.interval);
|
|
2210
|
-
this.interval = null;
|
|
2211
|
-
}
|
|
2212
|
-
process.stdout.write("\r\x1B[2K");
|
|
2213
|
-
}
|
|
2214
|
-
draw() {
|
|
2215
|
-
if (!this.active) return;
|
|
2216
|
-
const spinner = SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length];
|
|
2217
|
-
const shimmer = this.renderShimmer("Exporting");
|
|
2218
|
-
const frameStr = ui.primary(spinner);
|
|
2219
|
-
const phaseStr = this.phase ? ` ${ui.muted(this.limitLen(this.phase, 52))}` : "";
|
|
2220
|
-
process.stdout.write(`\r\x1B[2K ${frameStr} ${shimmer}${phaseStr}`);
|
|
2221
|
-
}
|
|
2222
|
-
renderShimmer(text) {
|
|
2223
|
-
let result = "";
|
|
2224
|
-
const pos = this.frame % (text.length + SHINE_WIDTH * 2) - SHINE_WIDTH;
|
|
2225
|
-
for (let i = 0; i < text.length; i++) {
|
|
2226
|
-
const dist = Math.abs(i - pos);
|
|
2227
|
-
if (dist < SHINE_WIDTH) {
|
|
2228
|
-
const t = 1 - dist / SHINE_WIDTH;
|
|
2229
|
-
const g = Math.floor(160 + t * 95);
|
|
2230
|
-
result += chalk4.rgb(250, Math.min(255, g), Math.min(255, Math.floor(g * 0.75)))(text[i]);
|
|
2231
|
-
} else {
|
|
2232
|
-
result += ui.muted(text[i]);
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
return result;
|
|
2236
|
-
}
|
|
2237
|
-
limitLen(s, max) {
|
|
2238
|
-
if (s.length <= max) return s;
|
|
2239
|
-
return s.slice(0, max - 1) + "\u2026";
|
|
2240
|
-
}
|
|
2241
|
-
};
|
|
2242
|
-
}
|
|
2243
|
-
});
|
|
2244
|
-
|
|
2245
2555
|
// src/exporter/index.ts
|
|
2246
2556
|
var exporter_exports = {};
|
|
2247
2557
|
__export(exporter_exports, {
|
|
@@ -2266,11 +2576,20 @@ function deriveOutputName(url, platformName) {
|
|
|
2266
2576
|
} else {
|
|
2267
2577
|
siteName = hostname.replace(/\./g, "-");
|
|
2268
2578
|
}
|
|
2269
|
-
|
|
2579
|
+
const cleanName = siteName.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "site";
|
|
2580
|
+
return `${platformName}-${cleanName}-${randomOutputSuffix()}`;
|
|
2270
2581
|
} catch {
|
|
2271
|
-
return
|
|
2582
|
+
return `framer-export-output-${randomOutputSuffix()}`;
|
|
2272
2583
|
}
|
|
2273
2584
|
}
|
|
2585
|
+
function randomOutputSuffix() {
|
|
2586
|
+
const adjectives = ["clean", "bright", "swift", "sharp", "fresh", "solid", "tidy", "prime"];
|
|
2587
|
+
const nouns = ["mirror", "export", "site", "build", "copy", "page", "stack", "bundle"];
|
|
2588
|
+
const adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
2589
|
+
const noun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
2590
|
+
const id = Math.random().toString(36).slice(2, 6);
|
|
2591
|
+
return `${adjective}-${noun}-${id}`;
|
|
2592
|
+
}
|
|
2274
2593
|
var FramerExporter;
|
|
2275
2594
|
var init_exporter = __esm({
|
|
2276
2595
|
"src/exporter/index.ts"() {
|
|
@@ -2463,71 +2782,117 @@ async function runSetup(legacyMode = false) {
|
|
|
2463
2782
|
` ${ui.muted("Export Framer, Webflow, and Wix sites into a clean local mirror.")}
|
|
2464
2783
|
`
|
|
2465
2784
|
);
|
|
2466
|
-
const rl = readline2.createInterface({ input: stdin3, output: stdout3 });
|
|
2467
|
-
const ask = async (question, defaultVal) => {
|
|
2785
|
+
const rl = legacyMode ? readline2.createInterface({ input: stdin3, output: stdout3 }) : null;
|
|
2786
|
+
const ask = async (question, defaultVal, headerLines = []) => {
|
|
2787
|
+
if (!legacyMode) {
|
|
2788
|
+
return promptInput(question, defaultVal || "", { headerLines });
|
|
2789
|
+
}
|
|
2468
2790
|
const suffix = defaultVal ? chalk6.gray(` (${defaultVal})`) : "";
|
|
2469
2791
|
const prompt = ` ${ui.primary("\u25CF")} ${ui.text.bold(question)}${suffix} ${ui.muted(">")} `;
|
|
2470
2792
|
const answer = await rl.question(prompt);
|
|
2471
2793
|
return answer.trim() || defaultVal || "";
|
|
2472
2794
|
};
|
|
2473
|
-
drawHeader("Step 1 : Site URL");
|
|
2795
|
+
if (legacyMode) drawHeader("Step 1 : Site URL");
|
|
2474
2796
|
let siteUrl = "";
|
|
2797
|
+
let urlError = "";
|
|
2475
2798
|
while (!siteUrl) {
|
|
2476
|
-
const input = await ask(
|
|
2799
|
+
const input = await ask(
|
|
2800
|
+
"Enter the site URL",
|
|
2801
|
+
"",
|
|
2802
|
+
["Step 1 : Site URL", urlError].filter(Boolean)
|
|
2803
|
+
);
|
|
2477
2804
|
try {
|
|
2478
2805
|
new URL4(input);
|
|
2479
2806
|
siteUrl = input;
|
|
2807
|
+
urlError = "";
|
|
2480
2808
|
} catch {
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
`
|
|
2484
|
-
|
|
2809
|
+
urlError = "Invalid URL. Enter a valid URL (https://...)";
|
|
2810
|
+
if (legacyMode) {
|
|
2811
|
+
console.log(` ${ui.error("\u2717")} ${ui.error(urlError)}
|
|
2812
|
+
`);
|
|
2813
|
+
}
|
|
2485
2814
|
}
|
|
2486
2815
|
}
|
|
2487
|
-
|
|
2816
|
+
if (legacyMode) {
|
|
2817
|
+
console.log(` ${ui.success("\u2713")} ${ui.success("URL:")} ${chalk6.underline(siteUrl)}
|
|
2488
2818
|
`);
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
let platformName;
|
|
2819
|
+
}
|
|
2820
|
+
let platformName = null;
|
|
2492
2821
|
if (legacyMode) {
|
|
2822
|
+
drawHeader("Step 2 : Platform");
|
|
2823
|
+
const detected = detectPlatform(siteUrl);
|
|
2493
2824
|
console.log(` ${ui.info("i")} Auto-detected: ${ui.primary(detected.displayName)}`);
|
|
2494
2825
|
const platformInput = await ask("Platform (framer/webflow/wix)", detected.name);
|
|
2495
2826
|
platformName = ["framer", "webflow", "wix"].includes(platformInput) ? platformInput : detected.name;
|
|
2496
2827
|
console.log(` ${ui.success("\u2713")} ${ui.success("Platform:")} ${ui.primary(platformName)}
|
|
2497
2828
|
`);
|
|
2498
2829
|
} else {
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
"Select platform",
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2830
|
+
while (!platformName) {
|
|
2831
|
+
const detected = detectPlatform(siteUrl);
|
|
2832
|
+
const platforms = [
|
|
2833
|
+
{
|
|
2834
|
+
label: `Framer${detected.name === "framer" ? chalk6.gray(" (detected)") : ""}`,
|
|
2835
|
+
value: "framer"
|
|
2836
|
+
},
|
|
2837
|
+
{
|
|
2838
|
+
label: `Webflow${detected.name === "webflow" ? chalk6.gray(" (detected)") : ""}`,
|
|
2839
|
+
value: "webflow"
|
|
2840
|
+
},
|
|
2841
|
+
{ label: `Wix${detected.name === "wix" ? chalk6.gray(" (detected)") : ""}`, value: "wix" }
|
|
2842
|
+
];
|
|
2843
|
+
const defaultIdx = ["framer", "webflow", "wix"].indexOf(detected.name);
|
|
2844
|
+
const platformChoice = await select("Select platform", platforms, Math.max(0, defaultIdx), {
|
|
2845
|
+
headerLines: [`URL: ${siteUrl}`],
|
|
2846
|
+
actions: [{ label: "Modify URL", value: "modify-url" }],
|
|
2847
|
+
footer: "tab focus button \xB7 mouse hover/click \xB7 enter select"
|
|
2848
|
+
});
|
|
2849
|
+
if (platformChoice === "modify-url") {
|
|
2850
|
+
siteUrl = "";
|
|
2851
|
+
urlError = "";
|
|
2852
|
+
while (!siteUrl) {
|
|
2853
|
+
const input = await ask(
|
|
2854
|
+
"Modify site URL",
|
|
2855
|
+
"",
|
|
2856
|
+
["Step 1 : Site URL", urlError].filter(Boolean)
|
|
2857
|
+
);
|
|
2858
|
+
try {
|
|
2859
|
+
new URL4(input);
|
|
2860
|
+
siteUrl = input;
|
|
2861
|
+
urlError = "";
|
|
2862
|
+
} catch {
|
|
2863
|
+
urlError = "Invalid URL. Enter a valid URL (https://...)";
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
continue;
|
|
2867
|
+
}
|
|
2868
|
+
platformName = platformChoice;
|
|
2869
|
+
}
|
|
2517
2870
|
}
|
|
2518
|
-
|
|
2519
|
-
|
|
2871
|
+
if (!platformName) {
|
|
2872
|
+
throw new Error("Platform selection failed");
|
|
2873
|
+
}
|
|
2874
|
+
const rl2 = legacyMode ? rl : null;
|
|
2875
|
+
const ask2 = async (question, defaultVal, headerLines = []) => {
|
|
2876
|
+
if (!legacyMode) {
|
|
2877
|
+
return promptInput(question, defaultVal || "", { headerLines });
|
|
2878
|
+
}
|
|
2520
2879
|
const suffix = defaultVal ? chalk6.gray(` (${defaultVal})`) : "";
|
|
2521
2880
|
const prompt = ` ${ui.primary("\u25CF")} ${ui.text.bold(question)}${suffix} ${ui.muted(">")} `;
|
|
2522
2881
|
const answer = await rl2.question(prompt);
|
|
2523
2882
|
return answer.trim() || defaultVal || "";
|
|
2524
2883
|
};
|
|
2525
2884
|
const derivedName = deriveOutputName(siteUrl, platformName);
|
|
2526
|
-
drawHeader("Step 3 : Output Directory");
|
|
2527
|
-
const outDir = await ask2("Output directory", "./" + derivedName
|
|
2528
|
-
|
|
2885
|
+
if (legacyMode) drawHeader("Step 3 : Output Directory");
|
|
2886
|
+
const outDir = await ask2("Output directory", "./" + derivedName, [
|
|
2887
|
+
"Step 3 : Output Directory",
|
|
2888
|
+
`URL: ${siteUrl}`,
|
|
2889
|
+
`Platform: ${platformName}`
|
|
2890
|
+
]);
|
|
2891
|
+
if (legacyMode) {
|
|
2892
|
+
console.log(` ${ui.success("\u2713")} ${ui.success("Output:")} ${ui.primary(outDir)}
|
|
2529
2893
|
`);
|
|
2530
|
-
|
|
2894
|
+
}
|
|
2895
|
+
if (legacyMode) drawHeader("Step 4 : Options");
|
|
2531
2896
|
let prettyPrint;
|
|
2532
2897
|
let concurrency;
|
|
2533
2898
|
let includeSubpages;
|
|
@@ -2549,7 +2914,6 @@ async function runSetup(legacyMode = false) {
|
|
|
2549
2914
|
console.log(` ${ui.success("\u2713")} Concurrency: ${ui.primary(String(concurrency))}
|
|
2550
2915
|
`);
|
|
2551
2916
|
} else {
|
|
2552
|
-
rl2.close();
|
|
2553
2917
|
const prettyVal = await select("Pretty-print JS files?", [
|
|
2554
2918
|
{ label: "Yes", value: "yes" },
|
|
2555
2919
|
{ label: "No", value: "no" }
|
|
@@ -2640,6 +3004,7 @@ var init_setup = __esm({
|
|
|
2640
3004
|
init_package();
|
|
2641
3005
|
import path8 from "path";
|
|
2642
3006
|
import { URL as URL5 } from "url";
|
|
3007
|
+
import { spawnSync } from "child_process";
|
|
2643
3008
|
|
|
2644
3009
|
// src/cli/help.ts
|
|
2645
3010
|
init_banner();
|
|
@@ -2702,6 +3067,7 @@ function showHelp() {
|
|
|
2702
3067
|
|
|
2703
3068
|
// src/cli/index.ts
|
|
2704
3069
|
init_banner();
|
|
3070
|
+
init_cooking();
|
|
2705
3071
|
|
|
2706
3072
|
// src/cli/update-check.ts
|
|
2707
3073
|
import https from "https";
|
|
@@ -2718,7 +3084,7 @@ async function checkForUpdates(currentVersion) {
|
|
|
2718
3084
|
const json = JSON.parse(data);
|
|
2719
3085
|
const latest = json.version;
|
|
2720
3086
|
if (!latest) return resolve(null);
|
|
2721
|
-
if (latest
|
|
3087
|
+
if (isNewerVersion(latest, currentVersion)) return resolve(latest);
|
|
2722
3088
|
resolve(null);
|
|
2723
3089
|
} catch {
|
|
2724
3090
|
resolve(null);
|
|
@@ -2733,8 +3099,23 @@ async function checkForUpdates(currentVersion) {
|
|
|
2733
3099
|
});
|
|
2734
3100
|
});
|
|
2735
3101
|
}
|
|
3102
|
+
function isNewerVersion(latest, current) {
|
|
3103
|
+
const latestParts = parseVersion(latest);
|
|
3104
|
+
const currentParts = parseVersion(current);
|
|
3105
|
+
for (let i = 0; i < Math.max(latestParts.length, currentParts.length); i++) {
|
|
3106
|
+
const latestPart = latestParts[i] ?? 0;
|
|
3107
|
+
const currentPart = currentParts[i] ?? 0;
|
|
3108
|
+
if (latestPart > currentPart) return true;
|
|
3109
|
+
if (latestPart < currentPart) return false;
|
|
3110
|
+
}
|
|
3111
|
+
return false;
|
|
3112
|
+
}
|
|
3113
|
+
function parseVersion(version) {
|
|
3114
|
+
return version.replace(/^v/, "").split(/[.-]/).map((part) => Number.parseInt(part, 10)).filter((part) => Number.isFinite(part));
|
|
3115
|
+
}
|
|
2736
3116
|
|
|
2737
3117
|
// src/cli/index.ts
|
|
3118
|
+
init_select();
|
|
2738
3119
|
init_theme();
|
|
2739
3120
|
var VERSION = package_default.version;
|
|
2740
3121
|
function extractFlag(args, flag) {
|
|
@@ -2750,6 +3131,56 @@ function hasFlag(args, flag) {
|
|
|
2750
3131
|
args.splice(idx, 1);
|
|
2751
3132
|
return true;
|
|
2752
3133
|
}
|
|
3134
|
+
async function showUpdateNotice() {
|
|
3135
|
+
const latest = await checkForUpdates(VERSION);
|
|
3136
|
+
if (!latest) return;
|
|
3137
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
3138
|
+
console.log("");
|
|
3139
|
+
console.log(
|
|
3140
|
+
` ${ui.warning("\u21B3")} Update available: ${ui.muted(VERSION)} -> ${ui.success(latest)}`
|
|
3141
|
+
);
|
|
3142
|
+
console.log(` ${ui.primary(" Run:")} ${ui.primarySoft("npm i -g framer-export@latest")}`);
|
|
3143
|
+
console.log("");
|
|
3144
|
+
return;
|
|
3145
|
+
}
|
|
3146
|
+
const action = await select(
|
|
3147
|
+
"Update available",
|
|
3148
|
+
[
|
|
3149
|
+
{ label: "Continue without updating", value: "continue" },
|
|
3150
|
+
{ label: "Update now", value: "update" }
|
|
3151
|
+
],
|
|
3152
|
+
0,
|
|
3153
|
+
{
|
|
3154
|
+
headerLines: [
|
|
3155
|
+
`Current version: ${VERSION}`,
|
|
3156
|
+
`Latest version: ${latest}`,
|
|
3157
|
+
"You can continue now and update later."
|
|
3158
|
+
],
|
|
3159
|
+
footer: "enter continue \xB7 mouse hover/click"
|
|
3160
|
+
}
|
|
3161
|
+
);
|
|
3162
|
+
if (action === "update") {
|
|
3163
|
+
console.log(
|
|
3164
|
+
` ${ui.primary("Updating:")} ${ui.primarySoft("npm i -g framer-export@latest")}
|
|
3165
|
+
`
|
|
3166
|
+
);
|
|
3167
|
+
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3168
|
+
const result = spawnSync(npmCommand, ["i", "-g", "framer-export@latest"], {
|
|
3169
|
+
stdio: "inherit"
|
|
3170
|
+
});
|
|
3171
|
+
if (result.status === 0) {
|
|
3172
|
+
console.log(`
|
|
3173
|
+
${ui.success("\u2713")} Updated. Re-run your command to use the new version.
|
|
3174
|
+
`);
|
|
3175
|
+
process.exit(0);
|
|
3176
|
+
}
|
|
3177
|
+
console.log(
|
|
3178
|
+
`
|
|
3179
|
+
${ui.error("\u2717")} Update failed. Run manually: ${ui.primarySoft("npm i -g framer-export@latest")}
|
|
3180
|
+
`
|
|
3181
|
+
);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
2753
3184
|
async function main() {
|
|
2754
3185
|
const args = process.argv.slice(2);
|
|
2755
3186
|
if (args.includes("--version") || args.includes("-v")) {
|
|
@@ -2777,19 +3208,12 @@ async function main() {
|
|
|
2777
3208
|
console.log("");
|
|
2778
3209
|
process.exit(0);
|
|
2779
3210
|
}
|
|
2780
|
-
checkForUpdates(VERSION).then((latest) => {
|
|
2781
|
-
if (!latest) return;
|
|
2782
|
-
console.log("");
|
|
2783
|
-
console.log(
|
|
2784
|
-
` ${ui.warning("\u21B3")} Update available: ${ui.muted(VERSION)} -> ${ui.success(latest)}`
|
|
2785
|
-
);
|
|
2786
|
-
console.log(` ${ui.primary(" Run:")} ${ui.primarySoft("npm i -g framer-export@latest")}`);
|
|
2787
|
-
console.log("");
|
|
2788
|
-
});
|
|
2789
3211
|
if (args.includes("--help") || args.includes("-h")) {
|
|
2790
3212
|
showHelp();
|
|
2791
3213
|
process.exit(0);
|
|
2792
3214
|
}
|
|
3215
|
+
await showLoadingIntro(VERSION);
|
|
3216
|
+
await showUpdateNotice();
|
|
2793
3217
|
if (args.includes("--setup")) {
|
|
2794
3218
|
hasFlag(args, "--setup");
|
|
2795
3219
|
const legacyMode = hasFlag(args, "--legacy-mode");
|