ansimax 1.2.5 → 1.2.7
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/CHANGELOG.md +149 -0
- package/README.es.md +110 -34
- package/README.md +110 -34
- package/dist/index.d.mts +64 -2
- package/dist/index.d.ts +64 -2
- package/dist/index.js +95 -19
- package/dist/index.mjs +95 -19
- package/examples/05-components.ts +4 -4
- package/examples/all-in-one.cjs +5 -5
- package/examples/all-in-one.mjs +5 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2346,12 +2346,16 @@ var validateFont = (name, fontMap) => {
|
|
|
2346
2346
|
};
|
|
2347
2347
|
var registerFont = (name, fontMap, opts = {}) => {
|
|
2348
2348
|
if (typeof name !== "string" || !name.length) {
|
|
2349
|
-
|
|
2349
|
+
const err = new TypeError("ascii.registerFont: name must be a non-empty string");
|
|
2350
|
+
err.code = "ANSIMAX_INVALID_FONT_NAME";
|
|
2351
|
+
throw err;
|
|
2350
2352
|
}
|
|
2351
2353
|
if (RESERVED_FONT_NAMES.has(name) && !opts.force) {
|
|
2352
|
-
|
|
2354
|
+
const err = new Error(
|
|
2353
2355
|
`Font name "${name}" is reserved. Pass { force: true } to override.`
|
|
2354
2356
|
);
|
|
2357
|
+
err.code = "ANSIMAX_RESERVED_FONT_NAME";
|
|
2358
|
+
throw err;
|
|
2355
2359
|
}
|
|
2356
2360
|
const safeMap = ensureFontMap(fontMap, name);
|
|
2357
2361
|
validateFont(name, safeMap);
|
|
@@ -2523,7 +2527,12 @@ var ASCII_RAMPS = {
|
|
|
2523
2527
|
standard: " .:-=+*#%@",
|
|
2524
2528
|
detailed: " .'`^\",:;Il!i><~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$",
|
|
2525
2529
|
blocks: " \u2591\u2592\u2593\u2588",
|
|
2526
|
-
simple: " .+#"
|
|
2530
|
+
simple: " .+#",
|
|
2531
|
+
// v1.2.6 — new ramps
|
|
2532
|
+
binary: " \u2588",
|
|
2533
|
+
dots: " \u2801\u2803\u2807\u2827\u2837\u2877\u28F7\u28FF",
|
|
2534
|
+
shades: " \u2801\u2803\u2807\u2827\u2837\u2877\u28F7\u28FF\u2588",
|
|
2535
|
+
ascii64: " `.'^,_:-+=<>i!lI?/\\|()1{}[]rcvunxzjftLCJUYXZO0Qoahkbdpqwm*WMB8&%$#@"
|
|
2527
2536
|
};
|
|
2528
2537
|
var _resolveRamp = (r) => {
|
|
2529
2538
|
if (typeof r === "string" && r.length > 0) {
|
|
@@ -2599,10 +2608,15 @@ var _resizePixels = (pixels, targetW, targetH) => {
|
|
|
2599
2608
|
for (let y = 0; y < targetH; y++) {
|
|
2600
2609
|
const sy = Math.min(srcH - 1, Math.floor(y / targetH * srcH));
|
|
2601
2610
|
const srcRow = pixels[sy];
|
|
2611
|
+
const actualRowW = Array.isArray(srcRow) ? srcRow.length : 0;
|
|
2602
2612
|
const newRow = new Array(targetW);
|
|
2603
2613
|
for (let x = 0; x < targetW; x++) {
|
|
2604
|
-
|
|
2605
|
-
|
|
2614
|
+
if (actualRowW === 0) {
|
|
2615
|
+
newRow[x] = null;
|
|
2616
|
+
continue;
|
|
2617
|
+
}
|
|
2618
|
+
const sx = Math.min(actualRowW - 1, Math.floor(x / targetW * actualRowW));
|
|
2619
|
+
newRow[x] = srcRow[sx] ?? null;
|
|
2606
2620
|
}
|
|
2607
2621
|
out.push(newRow);
|
|
2608
2622
|
}
|
|
@@ -2626,27 +2640,49 @@ var _enhanceForFace = (lum) => {
|
|
|
2626
2640
|
})
|
|
2627
2641
|
);
|
|
2628
2642
|
};
|
|
2643
|
+
var _adjustBrightnessContrast = (lum, brightness, contrast) => {
|
|
2644
|
+
const safeBrightness = Math.max(-1, Math.min(1, brightness)) * 255;
|
|
2645
|
+
const safeContrast = Math.max(-1, Math.min(1, contrast));
|
|
2646
|
+
const contrastFactor = 1 + safeContrast;
|
|
2647
|
+
return lum.map(
|
|
2648
|
+
(row) => row.map((v) => {
|
|
2649
|
+
const adjusted = (v - 128) * contrastFactor + 128 + safeBrightness;
|
|
2650
|
+
return Math.max(0, Math.min(255, adjusted));
|
|
2651
|
+
})
|
|
2652
|
+
);
|
|
2653
|
+
};
|
|
2629
2654
|
var fromImage = (pixels, opts = {}) => {
|
|
2630
2655
|
if (!Array.isArray(pixels) || pixels.length === 0) return "";
|
|
2631
2656
|
const firstRow = pixels[0];
|
|
2632
2657
|
if (!Array.isArray(firstRow) || firstRow.length === 0) return "";
|
|
2658
|
+
const requestedW = opts.width ?? 80;
|
|
2659
|
+
if (!Number.isFinite(requestedW) || requestedW <= 0) return "";
|
|
2660
|
+
if (opts.height !== void 0) {
|
|
2661
|
+
if (!Number.isFinite(opts.height) || opts.height <= 0) return "";
|
|
2662
|
+
}
|
|
2633
2663
|
const {
|
|
2634
|
-
width = 80,
|
|
2635
2664
|
ramp = "standard",
|
|
2636
2665
|
invert = false,
|
|
2637
2666
|
dither = "none",
|
|
2638
2667
|
edgeDetect = "none",
|
|
2639
2668
|
edgeThreshold = 40,
|
|
2640
2669
|
color: color2 = false,
|
|
2641
|
-
faceMode = false
|
|
2670
|
+
faceMode = false,
|
|
2671
|
+
// v1.2.6
|
|
2672
|
+
bgColor = false,
|
|
2673
|
+
brightness = 0,
|
|
2674
|
+
contrast = 0
|
|
2642
2675
|
} = opts;
|
|
2643
2676
|
const srcH = pixels.length;
|
|
2644
2677
|
const srcW = pixels[0].length;
|
|
2645
|
-
const safeW = Math.max(1, Math.floor(
|
|
2678
|
+
const safeW = Math.max(1, Math.floor(requestedW));
|
|
2646
2679
|
const computedH = Math.max(1, Math.round(srcH / srcW * safeW * 0.5));
|
|
2647
2680
|
const safeH = opts.height != null ? Math.max(1, Math.floor(opts.height)) : computedH;
|
|
2648
2681
|
const resized = _resizePixels(pixels, safeW, safeH);
|
|
2649
2682
|
let lum = _toLuminanceGrid(resized);
|
|
2683
|
+
if (brightness !== 0 || contrast !== 0) {
|
|
2684
|
+
lum = _adjustBrightnessContrast(lum, brightness, contrast);
|
|
2685
|
+
}
|
|
2650
2686
|
if (faceMode) lum = _enhanceForFace(lum);
|
|
2651
2687
|
let edgeGrid = null;
|
|
2652
2688
|
if (edgeDetect === "sobel") {
|
|
@@ -2657,7 +2693,7 @@ var fromImage = (pixels, opts = {}) => {
|
|
|
2657
2693
|
if (dither === "floyd-steinberg" && !edgeGrid) {
|
|
2658
2694
|
lum = _floydSteinberg(lum, rampLen);
|
|
2659
2695
|
}
|
|
2660
|
-
const useColor = color2 && !isNoColor();
|
|
2696
|
+
const useColor = (color2 || bgColor) && !isNoColor();
|
|
2661
2697
|
const lines = [];
|
|
2662
2698
|
for (let y = 0; y < safeH; y++) {
|
|
2663
2699
|
const lumRow = lum[y];
|
|
@@ -2679,7 +2715,11 @@ var fromImage = (pixels, opts = {}) => {
|
|
|
2679
2715
|
if (useColor) {
|
|
2680
2716
|
const p = pxRow[x];
|
|
2681
2717
|
if (p) {
|
|
2682
|
-
|
|
2718
|
+
if (bgColor) {
|
|
2719
|
+
line += bgRgb(p.r, p.g, p.b) + ch;
|
|
2720
|
+
} else {
|
|
2721
|
+
line += fgRgb(p.r, p.g, p.b) + ch;
|
|
2722
|
+
}
|
|
2683
2723
|
} else {
|
|
2684
2724
|
line += ch;
|
|
2685
2725
|
}
|
|
@@ -2694,7 +2734,9 @@ var fromImage = (pixels, opts = {}) => {
|
|
|
2694
2734
|
};
|
|
2695
2735
|
var parseFiglet = (flfContent) => {
|
|
2696
2736
|
if (typeof flfContent !== "string" || flfContent.length === 0) {
|
|
2697
|
-
|
|
2737
|
+
const err = new TypeError("parseFiglet: input must be a non-empty string");
|
|
2738
|
+
err.code = "ANSIMAX_INVALID_FIGLET_INPUT";
|
|
2739
|
+
throw err;
|
|
2698
2740
|
}
|
|
2699
2741
|
const lines = flfContent.split(/\r?\n/);
|
|
2700
2742
|
if (lines.length === 0) {
|
|
@@ -2703,13 +2745,20 @@ var parseFiglet = (flfContent) => {
|
|
|
2703
2745
|
const header = lines[0];
|
|
2704
2746
|
const m = /^flf2.\s*(\S)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(\d+)/.exec(header);
|
|
2705
2747
|
if (!m) {
|
|
2706
|
-
|
|
2748
|
+
const snippet = header.length > 60 ? header.slice(0, 60) + "\u2026" : header;
|
|
2749
|
+
const err = new TypeError(
|
|
2750
|
+
`parseFiglet: invalid FIGfont header. Expected "flf2a$..." prefix, got: "${snippet}"`
|
|
2751
|
+
);
|
|
2752
|
+
err.code = "ANSIMAX_INVALID_FIGLET_HEADER";
|
|
2753
|
+
throw err;
|
|
2707
2754
|
}
|
|
2708
2755
|
const hardblank = m[1];
|
|
2709
2756
|
const height = parseInt(m[2], 10);
|
|
2710
2757
|
const commentLines = parseInt(m[6], 10);
|
|
2711
2758
|
if (!Number.isFinite(height) || height <= 0) {
|
|
2712
|
-
|
|
2759
|
+
const err = new TypeError(`parseFiglet: invalid height ${m[2]} (must be positive integer)`);
|
|
2760
|
+
err.code = "ANSIMAX_INVALID_FIGLET_HEIGHT";
|
|
2761
|
+
throw err;
|
|
2713
2762
|
}
|
|
2714
2763
|
let cursor2 = 1 + Math.max(0, commentLines);
|
|
2715
2764
|
const glyphs = /* @__PURE__ */ new Map();
|
|
@@ -2732,8 +2781,32 @@ var parseFiglet = (flfContent) => {
|
|
|
2732
2781
|
};
|
|
2733
2782
|
var figletText = (text, font, opts = {}) => {
|
|
2734
2783
|
if (typeof text !== "string") return "";
|
|
2784
|
+
if (text.length === 0) return "";
|
|
2735
2785
|
if (!font || !font.glyphs || font.height <= 0) return "";
|
|
2736
|
-
const {
|
|
2786
|
+
const {
|
|
2787
|
+
trim = true,
|
|
2788
|
+
colorFn = null,
|
|
2789
|
+
// v1.2.6
|
|
2790
|
+
kerning = 0,
|
|
2791
|
+
lineSpacing = 0
|
|
2792
|
+
} = opts;
|
|
2793
|
+
const safeKerning = Math.max(0, Math.floor(kerning));
|
|
2794
|
+
const safeLineSpacing = Math.max(0, Math.floor(lineSpacing));
|
|
2795
|
+
if (text.includes("\n")) {
|
|
2796
|
+
const linesOfText = text.split("\n");
|
|
2797
|
+
const renderedBlocks = linesOfText.map(
|
|
2798
|
+
(line) => _renderFigletLine(line, font, safeKerning, trim)
|
|
2799
|
+
);
|
|
2800
|
+
const spacer = safeLineSpacing > 0 ? "\n".repeat(safeLineSpacing + 1) : "\n";
|
|
2801
|
+
let multiResult = renderedBlocks.join(spacer);
|
|
2802
|
+
if (colorFn) multiResult = colorFn(multiResult);
|
|
2803
|
+
return multiResult;
|
|
2804
|
+
}
|
|
2805
|
+
let result = _renderFigletLine(text, font, safeKerning, trim);
|
|
2806
|
+
if (colorFn) result = colorFn(result);
|
|
2807
|
+
return result;
|
|
2808
|
+
};
|
|
2809
|
+
var _renderFigletLine = (text, font, kerning, trim) => {
|
|
2737
2810
|
const glyphsForText = [];
|
|
2738
2811
|
for (const ch of text) {
|
|
2739
2812
|
const code = ch.codePointAt(0) ?? 32;
|
|
@@ -2745,23 +2818,26 @@ var figletText = (text, font, opts = {}) => {
|
|
|
2745
2818
|
glyphsForText.push(fallback ?? new Array(font.height).fill(""));
|
|
2746
2819
|
}
|
|
2747
2820
|
}
|
|
2821
|
+
const kerningSpacer = kerning > 0 ? " ".repeat(kerning) : "";
|
|
2748
2822
|
const hardblankRe = new RegExp(_escapeRe(font.hardblank), "g");
|
|
2749
2823
|
const rows = [];
|
|
2750
2824
|
for (let r = 0; r < font.height; r++) {
|
|
2751
2825
|
let row = "";
|
|
2752
|
-
for (
|
|
2826
|
+
for (let i = 0; i < glyphsForText.length; i++) {
|
|
2827
|
+
const g = glyphsForText[i];
|
|
2753
2828
|
row += g[r] ?? "";
|
|
2829
|
+
if (i < glyphsForText.length - 1 && kerningSpacer) {
|
|
2830
|
+
row += kerningSpacer;
|
|
2831
|
+
}
|
|
2754
2832
|
}
|
|
2755
2833
|
row = row.replace(hardblankRe, " ");
|
|
2756
2834
|
rows.push(row);
|
|
2757
2835
|
}
|
|
2758
|
-
let result = rows.join("\n");
|
|
2759
2836
|
if (trim) {
|
|
2760
2837
|
const trimmed = rows.filter((row) => row.trim().length > 0);
|
|
2761
|
-
|
|
2838
|
+
return trimmed.length > 0 ? trimmed.join("\n") : rows.join("\n");
|
|
2762
2839
|
}
|
|
2763
|
-
|
|
2764
|
-
return result;
|
|
2840
|
+
return rows.join("\n");
|
|
2765
2841
|
};
|
|
2766
2842
|
var _escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2767
2843
|
var ascii = {
|
package/dist/index.mjs
CHANGED
|
@@ -2166,12 +2166,16 @@ var validateFont = (name, fontMap) => {
|
|
|
2166
2166
|
};
|
|
2167
2167
|
var registerFont = (name, fontMap, opts = {}) => {
|
|
2168
2168
|
if (typeof name !== "string" || !name.length) {
|
|
2169
|
-
|
|
2169
|
+
const err = new TypeError("ascii.registerFont: name must be a non-empty string");
|
|
2170
|
+
err.code = "ANSIMAX_INVALID_FONT_NAME";
|
|
2171
|
+
throw err;
|
|
2170
2172
|
}
|
|
2171
2173
|
if (RESERVED_FONT_NAMES.has(name) && !opts.force) {
|
|
2172
|
-
|
|
2174
|
+
const err = new Error(
|
|
2173
2175
|
`Font name "${name}" is reserved. Pass { force: true } to override.`
|
|
2174
2176
|
);
|
|
2177
|
+
err.code = "ANSIMAX_RESERVED_FONT_NAME";
|
|
2178
|
+
throw err;
|
|
2175
2179
|
}
|
|
2176
2180
|
const safeMap = ensureFontMap(fontMap, name);
|
|
2177
2181
|
validateFont(name, safeMap);
|
|
@@ -2343,7 +2347,12 @@ var ASCII_RAMPS = {
|
|
|
2343
2347
|
standard: " .:-=+*#%@",
|
|
2344
2348
|
detailed: " .'`^\",:;Il!i><~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$",
|
|
2345
2349
|
blocks: " \u2591\u2592\u2593\u2588",
|
|
2346
|
-
simple: " .+#"
|
|
2350
|
+
simple: " .+#",
|
|
2351
|
+
// v1.2.6 — new ramps
|
|
2352
|
+
binary: " \u2588",
|
|
2353
|
+
dots: " \u2801\u2803\u2807\u2827\u2837\u2877\u28F7\u28FF",
|
|
2354
|
+
shades: " \u2801\u2803\u2807\u2827\u2837\u2877\u28F7\u28FF\u2588",
|
|
2355
|
+
ascii64: " `.'^,_:-+=<>i!lI?/\\|()1{}[]rcvunxzjftLCJUYXZO0Qoahkbdpqwm*WMB8&%$#@"
|
|
2347
2356
|
};
|
|
2348
2357
|
var _resolveRamp = (r) => {
|
|
2349
2358
|
if (typeof r === "string" && r.length > 0) {
|
|
@@ -2419,10 +2428,15 @@ var _resizePixels = (pixels, targetW, targetH) => {
|
|
|
2419
2428
|
for (let y = 0; y < targetH; y++) {
|
|
2420
2429
|
const sy = Math.min(srcH - 1, Math.floor(y / targetH * srcH));
|
|
2421
2430
|
const srcRow = pixels[sy];
|
|
2431
|
+
const actualRowW = Array.isArray(srcRow) ? srcRow.length : 0;
|
|
2422
2432
|
const newRow = new Array(targetW);
|
|
2423
2433
|
for (let x = 0; x < targetW; x++) {
|
|
2424
|
-
|
|
2425
|
-
|
|
2434
|
+
if (actualRowW === 0) {
|
|
2435
|
+
newRow[x] = null;
|
|
2436
|
+
continue;
|
|
2437
|
+
}
|
|
2438
|
+
const sx = Math.min(actualRowW - 1, Math.floor(x / targetW * actualRowW));
|
|
2439
|
+
newRow[x] = srcRow[sx] ?? null;
|
|
2426
2440
|
}
|
|
2427
2441
|
out.push(newRow);
|
|
2428
2442
|
}
|
|
@@ -2446,27 +2460,49 @@ var _enhanceForFace = (lum) => {
|
|
|
2446
2460
|
})
|
|
2447
2461
|
);
|
|
2448
2462
|
};
|
|
2463
|
+
var _adjustBrightnessContrast = (lum, brightness, contrast) => {
|
|
2464
|
+
const safeBrightness = Math.max(-1, Math.min(1, brightness)) * 255;
|
|
2465
|
+
const safeContrast = Math.max(-1, Math.min(1, contrast));
|
|
2466
|
+
const contrastFactor = 1 + safeContrast;
|
|
2467
|
+
return lum.map(
|
|
2468
|
+
(row) => row.map((v) => {
|
|
2469
|
+
const adjusted = (v - 128) * contrastFactor + 128 + safeBrightness;
|
|
2470
|
+
return Math.max(0, Math.min(255, adjusted));
|
|
2471
|
+
})
|
|
2472
|
+
);
|
|
2473
|
+
};
|
|
2449
2474
|
var fromImage = (pixels, opts = {}) => {
|
|
2450
2475
|
if (!Array.isArray(pixels) || pixels.length === 0) return "";
|
|
2451
2476
|
const firstRow = pixels[0];
|
|
2452
2477
|
if (!Array.isArray(firstRow) || firstRow.length === 0) return "";
|
|
2478
|
+
const requestedW = opts.width ?? 80;
|
|
2479
|
+
if (!Number.isFinite(requestedW) || requestedW <= 0) return "";
|
|
2480
|
+
if (opts.height !== void 0) {
|
|
2481
|
+
if (!Number.isFinite(opts.height) || opts.height <= 0) return "";
|
|
2482
|
+
}
|
|
2453
2483
|
const {
|
|
2454
|
-
width = 80,
|
|
2455
2484
|
ramp = "standard",
|
|
2456
2485
|
invert = false,
|
|
2457
2486
|
dither = "none",
|
|
2458
2487
|
edgeDetect = "none",
|
|
2459
2488
|
edgeThreshold = 40,
|
|
2460
2489
|
color: color2 = false,
|
|
2461
|
-
faceMode = false
|
|
2490
|
+
faceMode = false,
|
|
2491
|
+
// v1.2.6
|
|
2492
|
+
bgColor = false,
|
|
2493
|
+
brightness = 0,
|
|
2494
|
+
contrast = 0
|
|
2462
2495
|
} = opts;
|
|
2463
2496
|
const srcH = pixels.length;
|
|
2464
2497
|
const srcW = pixels[0].length;
|
|
2465
|
-
const safeW = Math.max(1, Math.floor(
|
|
2498
|
+
const safeW = Math.max(1, Math.floor(requestedW));
|
|
2466
2499
|
const computedH = Math.max(1, Math.round(srcH / srcW * safeW * 0.5));
|
|
2467
2500
|
const safeH = opts.height != null ? Math.max(1, Math.floor(opts.height)) : computedH;
|
|
2468
2501
|
const resized = _resizePixels(pixels, safeW, safeH);
|
|
2469
2502
|
let lum = _toLuminanceGrid(resized);
|
|
2503
|
+
if (brightness !== 0 || contrast !== 0) {
|
|
2504
|
+
lum = _adjustBrightnessContrast(lum, brightness, contrast);
|
|
2505
|
+
}
|
|
2470
2506
|
if (faceMode) lum = _enhanceForFace(lum);
|
|
2471
2507
|
let edgeGrid = null;
|
|
2472
2508
|
if (edgeDetect === "sobel") {
|
|
@@ -2477,7 +2513,7 @@ var fromImage = (pixels, opts = {}) => {
|
|
|
2477
2513
|
if (dither === "floyd-steinberg" && !edgeGrid) {
|
|
2478
2514
|
lum = _floydSteinberg(lum, rampLen);
|
|
2479
2515
|
}
|
|
2480
|
-
const useColor = color2 && !isNoColor();
|
|
2516
|
+
const useColor = (color2 || bgColor) && !isNoColor();
|
|
2481
2517
|
const lines = [];
|
|
2482
2518
|
for (let y = 0; y < safeH; y++) {
|
|
2483
2519
|
const lumRow = lum[y];
|
|
@@ -2499,7 +2535,11 @@ var fromImage = (pixels, opts = {}) => {
|
|
|
2499
2535
|
if (useColor) {
|
|
2500
2536
|
const p = pxRow[x];
|
|
2501
2537
|
if (p) {
|
|
2502
|
-
|
|
2538
|
+
if (bgColor) {
|
|
2539
|
+
line += bgRgb(p.r, p.g, p.b) + ch;
|
|
2540
|
+
} else {
|
|
2541
|
+
line += fgRgb(p.r, p.g, p.b) + ch;
|
|
2542
|
+
}
|
|
2503
2543
|
} else {
|
|
2504
2544
|
line += ch;
|
|
2505
2545
|
}
|
|
@@ -2514,7 +2554,9 @@ var fromImage = (pixels, opts = {}) => {
|
|
|
2514
2554
|
};
|
|
2515
2555
|
var parseFiglet = (flfContent) => {
|
|
2516
2556
|
if (typeof flfContent !== "string" || flfContent.length === 0) {
|
|
2517
|
-
|
|
2557
|
+
const err = new TypeError("parseFiglet: input must be a non-empty string");
|
|
2558
|
+
err.code = "ANSIMAX_INVALID_FIGLET_INPUT";
|
|
2559
|
+
throw err;
|
|
2518
2560
|
}
|
|
2519
2561
|
const lines = flfContent.split(/\r?\n/);
|
|
2520
2562
|
if (lines.length === 0) {
|
|
@@ -2523,13 +2565,20 @@ var parseFiglet = (flfContent) => {
|
|
|
2523
2565
|
const header = lines[0];
|
|
2524
2566
|
const m = /^flf2.\s*(\S)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(\d+)/.exec(header);
|
|
2525
2567
|
if (!m) {
|
|
2526
|
-
|
|
2568
|
+
const snippet = header.length > 60 ? header.slice(0, 60) + "\u2026" : header;
|
|
2569
|
+
const err = new TypeError(
|
|
2570
|
+
`parseFiglet: invalid FIGfont header. Expected "flf2a$..." prefix, got: "${snippet}"`
|
|
2571
|
+
);
|
|
2572
|
+
err.code = "ANSIMAX_INVALID_FIGLET_HEADER";
|
|
2573
|
+
throw err;
|
|
2527
2574
|
}
|
|
2528
2575
|
const hardblank = m[1];
|
|
2529
2576
|
const height = parseInt(m[2], 10);
|
|
2530
2577
|
const commentLines = parseInt(m[6], 10);
|
|
2531
2578
|
if (!Number.isFinite(height) || height <= 0) {
|
|
2532
|
-
|
|
2579
|
+
const err = new TypeError(`parseFiglet: invalid height ${m[2]} (must be positive integer)`);
|
|
2580
|
+
err.code = "ANSIMAX_INVALID_FIGLET_HEIGHT";
|
|
2581
|
+
throw err;
|
|
2533
2582
|
}
|
|
2534
2583
|
let cursor2 = 1 + Math.max(0, commentLines);
|
|
2535
2584
|
const glyphs = /* @__PURE__ */ new Map();
|
|
@@ -2552,8 +2601,32 @@ var parseFiglet = (flfContent) => {
|
|
|
2552
2601
|
};
|
|
2553
2602
|
var figletText = (text, font, opts = {}) => {
|
|
2554
2603
|
if (typeof text !== "string") return "";
|
|
2604
|
+
if (text.length === 0) return "";
|
|
2555
2605
|
if (!font || !font.glyphs || font.height <= 0) return "";
|
|
2556
|
-
const {
|
|
2606
|
+
const {
|
|
2607
|
+
trim = true,
|
|
2608
|
+
colorFn = null,
|
|
2609
|
+
// v1.2.6
|
|
2610
|
+
kerning = 0,
|
|
2611
|
+
lineSpacing = 0
|
|
2612
|
+
} = opts;
|
|
2613
|
+
const safeKerning = Math.max(0, Math.floor(kerning));
|
|
2614
|
+
const safeLineSpacing = Math.max(0, Math.floor(lineSpacing));
|
|
2615
|
+
if (text.includes("\n")) {
|
|
2616
|
+
const linesOfText = text.split("\n");
|
|
2617
|
+
const renderedBlocks = linesOfText.map(
|
|
2618
|
+
(line) => _renderFigletLine(line, font, safeKerning, trim)
|
|
2619
|
+
);
|
|
2620
|
+
const spacer = safeLineSpacing > 0 ? "\n".repeat(safeLineSpacing + 1) : "\n";
|
|
2621
|
+
let multiResult = renderedBlocks.join(spacer);
|
|
2622
|
+
if (colorFn) multiResult = colorFn(multiResult);
|
|
2623
|
+
return multiResult;
|
|
2624
|
+
}
|
|
2625
|
+
let result = _renderFigletLine(text, font, safeKerning, trim);
|
|
2626
|
+
if (colorFn) result = colorFn(result);
|
|
2627
|
+
return result;
|
|
2628
|
+
};
|
|
2629
|
+
var _renderFigletLine = (text, font, kerning, trim) => {
|
|
2557
2630
|
const glyphsForText = [];
|
|
2558
2631
|
for (const ch of text) {
|
|
2559
2632
|
const code = ch.codePointAt(0) ?? 32;
|
|
@@ -2565,23 +2638,26 @@ var figletText = (text, font, opts = {}) => {
|
|
|
2565
2638
|
glyphsForText.push(fallback ?? new Array(font.height).fill(""));
|
|
2566
2639
|
}
|
|
2567
2640
|
}
|
|
2641
|
+
const kerningSpacer = kerning > 0 ? " ".repeat(kerning) : "";
|
|
2568
2642
|
const hardblankRe = new RegExp(_escapeRe(font.hardblank), "g");
|
|
2569
2643
|
const rows = [];
|
|
2570
2644
|
for (let r = 0; r < font.height; r++) {
|
|
2571
2645
|
let row = "";
|
|
2572
|
-
for (
|
|
2646
|
+
for (let i = 0; i < glyphsForText.length; i++) {
|
|
2647
|
+
const g = glyphsForText[i];
|
|
2573
2648
|
row += g[r] ?? "";
|
|
2649
|
+
if (i < glyphsForText.length - 1 && kerningSpacer) {
|
|
2650
|
+
row += kerningSpacer;
|
|
2651
|
+
}
|
|
2574
2652
|
}
|
|
2575
2653
|
row = row.replace(hardblankRe, " ");
|
|
2576
2654
|
rows.push(row);
|
|
2577
2655
|
}
|
|
2578
|
-
let result = rows.join("\n");
|
|
2579
2656
|
if (trim) {
|
|
2580
2657
|
const trimmed = rows.filter((row) => row.trim().length > 0);
|
|
2581
|
-
|
|
2658
|
+
return trimmed.length > 0 ? trimmed.join("\n") : rows.join("\n");
|
|
2582
2659
|
}
|
|
2583
|
-
|
|
2584
|
-
return result;
|
|
2660
|
+
return rows.join("\n");
|
|
2585
2661
|
};
|
|
2586
2662
|
var _escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2587
2663
|
var ascii = {
|
|
@@ -42,10 +42,10 @@ console.log();
|
|
|
42
42
|
|
|
43
43
|
console.log(color.bold('━━━ Status ━━━'));
|
|
44
44
|
console.log();
|
|
45
|
-
console.log(components.status('Build started'
|
|
46
|
-
console.log(components.status('
|
|
47
|
-
console.log(components.status('5 deprecation warnings'
|
|
48
|
-
console.log(components.status('Build failed'
|
|
45
|
+
console.log(components.status('info', 'Build started'));
|
|
46
|
+
console.log(components.status('success', 'Linting passed'));
|
|
47
|
+
console.log(components.status('warn', '5 deprecation warnings'));
|
|
48
|
+
console.log(components.status('error', 'Build failed'));
|
|
49
49
|
console.log();
|
|
50
50
|
|
|
51
51
|
console.log(color.bold('━━━ Section ━━━'));
|
package/examples/all-in-one.cjs
CHANGED
|
@@ -118,14 +118,14 @@ async function main() {
|
|
|
118
118
|
console.log(components.section('🏷️ Badges & Status', { width: 60 }));
|
|
119
119
|
console.log();
|
|
120
120
|
console.log(' ',
|
|
121
|
-
components.badge('VERSION', 'v1.2.
|
|
121
|
+
components.badge('VERSION', 'v1.2.7'),
|
|
122
122
|
components.badge('BUILD', 'passing'),
|
|
123
123
|
components.badge('LICENSE', 'Apache 2.0'));
|
|
124
124
|
console.log();
|
|
125
|
-
console.log(components.status('Build started'
|
|
126
|
-
console.log(components.status('
|
|
127
|
-
console.log(components.status('1 deprecation'
|
|
128
|
-
console.log(components.status('Build failed'
|
|
125
|
+
console.log(components.status('info', 'Build started'));
|
|
126
|
+
console.log(components.status('success', 'Tests passed'));
|
|
127
|
+
console.log(components.status('warn', '1 deprecation'));
|
|
128
|
+
console.log(components.status('error', 'Build failed'));
|
|
129
129
|
console.log();
|
|
130
130
|
|
|
131
131
|
// ── 9. Loaders ────────────────────────────────────────────
|
package/examples/all-in-one.mjs
CHANGED
|
@@ -117,14 +117,14 @@ console.log();
|
|
|
117
117
|
console.log(components.section('🏷️ Badges & Status', { width: 60 }));
|
|
118
118
|
console.log();
|
|
119
119
|
console.log(' ',
|
|
120
|
-
components.badge('VERSION', 'v1.2.
|
|
120
|
+
components.badge('VERSION', 'v1.2.7'),
|
|
121
121
|
components.badge('BUILD', 'passing'),
|
|
122
122
|
components.badge('LICENSE', 'Apache 2.0'));
|
|
123
123
|
console.log();
|
|
124
|
-
console.log(components.status('Build started'
|
|
125
|
-
console.log(components.status('
|
|
126
|
-
console.log(components.status('1 deprecation'
|
|
127
|
-
console.log(components.status('Build failed'
|
|
124
|
+
console.log(components.status('info', 'Build started'));
|
|
125
|
+
console.log(components.status('success', 'Tests passed'));
|
|
126
|
+
console.log(components.status('warn', '1 deprecation'));
|
|
127
|
+
console.log(components.status('error', 'Build failed'));
|
|
128
128
|
console.log();
|
|
129
129
|
|
|
130
130
|
// ── 9. Loaders ────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ansimax",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "Zero-dependency CLI rendering library: colors, gradients, animations, ASCII art, pixel art, components, and themes \u2014 all in TypeScript.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|