| const LAYOUT = { | ||
| FULL_WIDTH: 0, | ||
| FITTING: 1, | ||
| SMUSHING: 2, | ||
| CONTROLLED_SMUSHING: 3 | ||
| }; | ||
| class FigletFont { | ||
| constructor() { | ||
| this.comment = ""; | ||
| this.numChars = 0; | ||
| this.options = {}; | ||
| } | ||
| } | ||
| const fontList = [ | ||
| "1Row", | ||
| "3-D", | ||
| "3D Diagonal", | ||
| "3D-ASCII", | ||
| "3x5", | ||
| "4Max", | ||
| "5 Line Oblique", | ||
| "AMC 3 Line", | ||
| "AMC 3 Liv1", | ||
| "AMC AAA01", | ||
| "AMC Neko", | ||
| "AMC Razor", | ||
| "AMC Razor2", | ||
| "AMC Slash", | ||
| "AMC Slider", | ||
| "AMC Thin", | ||
| "AMC Tubes", | ||
| "AMC Untitled", | ||
| "ANSI Compact", | ||
| "ANSI Regular", | ||
| "ANSI Shadow", | ||
| "ASCII 12", | ||
| "ASCII 9", | ||
| "ASCII New Roman", | ||
| "Acrobatic", | ||
| "Alligator", | ||
| "Alligator2", | ||
| "Alpha", | ||
| "Alphabet", | ||
| "Arrows", | ||
| "Avatar", | ||
| "B1FF", | ||
| "Babyface Lame", | ||
| "Babyface Leet", | ||
| "Banner", | ||
| "Banner3-D", | ||
| "Banner3", | ||
| "Banner4", | ||
| "Barbwire", | ||
| "Basic", | ||
| "Bear", | ||
| "Bell", | ||
| "Benjamin", | ||
| "Big ASCII 12", | ||
| "Big ASCII 9", | ||
| "Big Chief", | ||
| "Big Money-ne", | ||
| "Big Money-nw", | ||
| "Big Money-se", | ||
| "Big Money-sw", | ||
| "Big Mono 12", | ||
| "Big Mono 9", | ||
| "Big", | ||
| "Bigfig", | ||
| "Binary", | ||
| "Block", | ||
| "Blocks", | ||
| "Bloody", | ||
| "BlurVision ASCII", | ||
| "Bolger", | ||
| "Braced", | ||
| "Bright", | ||
| "Broadway KB", | ||
| "Broadway", | ||
| "Bubble", | ||
| "Bulbhead", | ||
| "Caligraphy", | ||
| "Caligraphy2", | ||
| "Calvin S", | ||
| "Cards", | ||
| "Catwalk", | ||
| "Chiseled", | ||
| "Chunky", | ||
| "Circle", | ||
| "Classy", | ||
| "Coder Mini", | ||
| "Coinstak", | ||
| "Cola", | ||
| "Colossal", | ||
| "Computer", | ||
| "Contessa", | ||
| "Contrast", | ||
| "Cosmike", | ||
| "Cosmike2", | ||
| "Crawford", | ||
| "Crawford2", | ||
| "Crazy", | ||
| "Cricket", | ||
| "Cursive", | ||
| "Cyberlarge", | ||
| "Cybermedium", | ||
| "Cybersmall", | ||
| "Cygnet", | ||
| "DANC4", | ||
| "DOS Rebel", | ||
| "DWhistled", | ||
| "Dancing Font", | ||
| "Decimal", | ||
| "Def Leppard", | ||
| "Delta Corps Priest 1", | ||
| "DiamFont", | ||
| "Diamond", | ||
| "Diet Cola", | ||
| "Digital", | ||
| "Doh", | ||
| "Doom", | ||
| "Dot Matrix", | ||
| "Double Shorts", | ||
| "Double", | ||
| "Dr Pepper", | ||
| "Efti Chess", | ||
| "Efti Font", | ||
| "Efti Italic", | ||
| "Efti Piti", | ||
| "Efti Robot", | ||
| "Efti Wall", | ||
| "Efti Water", | ||
| "Electronic", | ||
| "Elite", | ||
| "Emboss 2", | ||
| "Emboss", | ||
| "Epic", | ||
| "Fender", | ||
| "Filter", | ||
| "Fire Font-k", | ||
| "Fire Font-s", | ||
| "Flipped", | ||
| "Flower Power", | ||
| "Font Font", | ||
| "Four Tops", | ||
| "Fraktur", | ||
| "Fun Face", | ||
| "Fun Faces", | ||
| "Future Smooth", | ||
| "Future Thin", | ||
| "Future", | ||
| "Fuzzy", | ||
| "Georgi16", | ||
| "Georgia11", | ||
| "Ghost", | ||
| "Ghoulish", | ||
| "Glenyn", | ||
| "Goofy", | ||
| "Gothic", | ||
| "Graceful", | ||
| "Gradient", | ||
| "Graffiti", | ||
| "Greek", | ||
| "Heart Left", | ||
| "Heart Right", | ||
| "Henry 3D", | ||
| "Hex", | ||
| "Hieroglyphs", | ||
| "Hollywood", | ||
| "Horizontal Left", | ||
| "Horizontal Right", | ||
| "ICL-1900", | ||
| "Impossible", | ||
| "Invita", | ||
| "Isometric1", | ||
| "Isometric2", | ||
| "Isometric3", | ||
| "Isometric4", | ||
| "Italic", | ||
| "Ivrit", | ||
| "JS Block Letters", | ||
| "JS Bracket Letters", | ||
| "JS Capital Curves", | ||
| "JS Cursive", | ||
| "JS Stick Letters", | ||
| "Jacky", | ||
| "Jazmine", | ||
| "Jerusalem", | ||
| "Katakana", | ||
| "Kban", | ||
| "Keyboard", | ||
| "Knob", | ||
| "Konto Slant", | ||
| "Konto", | ||
| "LCD", | ||
| "Larry 3D 2", | ||
| "Larry 3D", | ||
| "Lean", | ||
| "Letter", | ||
| "Letters", | ||
| "Lil Devil", | ||
| "Line Blocks", | ||
| "Linux", | ||
| "Lockergnome", | ||
| "Madrid", | ||
| "Marquee", | ||
| "Maxfour", | ||
| "Merlin1", | ||
| "Merlin2", | ||
| "Mike", | ||
| "Mini", | ||
| "Mirror", | ||
| "Mnemonic", | ||
| "Modular", | ||
| "Mono 12", | ||
| "Mono 9", | ||
| "Morse", | ||
| "Morse2", | ||
| "Moscow", | ||
| "Mshebrew210", | ||
| "Muzzle", | ||
| "NScript", | ||
| "NT Greek", | ||
| "NV Script", | ||
| "Nancyj-Fancy", | ||
| "Nancyj-Improved", | ||
| "Nancyj-Underlined", | ||
| "Nancyj", | ||
| "Nipples", | ||
| "O8", | ||
| "OS2", | ||
| "Octal", | ||
| "Ogre", | ||
| "Old Banner", | ||
| "Pagga", | ||
| "Patorjk's Cheese", | ||
| "Patorjk-HeX", | ||
| "Pawp", | ||
| "Peaks Slant", | ||
| "Peaks", | ||
| "Pebbles", | ||
| "Pepper", | ||
| "Poison", | ||
| "Puffy", | ||
| "Puzzle", | ||
| "Pyramid", | ||
| "Rammstein", | ||
| "Rebel", | ||
| "Rectangles", | ||
| "Red Phoenix", | ||
| "Relief", | ||
| "Relief2", | ||
| "Reverse", | ||
| "Roman", | ||
| "Rot13", | ||
| "Rotated", | ||
| "Rounded", | ||
| "Rowan Cap", | ||
| "Rozzo", | ||
| "RubiFont", | ||
| "Runic", | ||
| "Runyc", | ||
| "S Blood", | ||
| "SL Script", | ||
| "Santa Clara", | ||
| "Script", | ||
| "Serifcap", | ||
| "Shaded Blocky", | ||
| "Shadow", | ||
| "Shimrod", | ||
| "Short", | ||
| "Slant Relief", | ||
| "Slant", | ||
| "Slide", | ||
| "Small ASCII 12", | ||
| "Small ASCII 9", | ||
| "Small Block", | ||
| "Small Braille", | ||
| "Small Caps", | ||
| "Small Isometric1", | ||
| "Small Keyboard", | ||
| "Small Mono 12", | ||
| "Small Mono 9", | ||
| "Small Poison", | ||
| "Small Script", | ||
| "Small Shadow", | ||
| "Small Slant", | ||
| "Small Tengwar", | ||
| "Small", | ||
| "Soft", | ||
| "Speed", | ||
| "Spliff", | ||
| "Stacey", | ||
| "Stampate", | ||
| "Stampatello", | ||
| "Standard", | ||
| "Star Strips", | ||
| "Star Wars", | ||
| "Stellar", | ||
| "Stforek", | ||
| "Stick Letters", | ||
| "Stop", | ||
| "Straight", | ||
| "Stronger Than All", | ||
| "Sub-Zero", | ||
| "Swamp Land", | ||
| "Swan", | ||
| "Sweet", | ||
| "THIS", | ||
| "Tanja", | ||
| "Tengwar", | ||
| "Term", | ||
| "Terrace", | ||
| "Test1", | ||
| "The Edge", | ||
| "Thick", | ||
| "Thin", | ||
| "Thorned", | ||
| "Three Point", | ||
| "Ticks Slant", | ||
| "Ticks", | ||
| "Tiles", | ||
| "Tinker-Toy", | ||
| "Tmplr", | ||
| "Tombstone", | ||
| "Train", | ||
| "Trek", | ||
| "Tsalagi", | ||
| "Tubular", | ||
| "Twisted", | ||
| "Two Point", | ||
| "USA Flag", | ||
| "Univers", | ||
| "Upside Down Text", | ||
| "Varsity", | ||
| "Wavescape", | ||
| "Wavy", | ||
| "Weird", | ||
| "Wet Letter", | ||
| "Whimsy", | ||
| "WideTerm", | ||
| "Wow", | ||
| "miniwi" | ||
| ]; | ||
| const renamedFonts = { | ||
| "ANSI-Compact": "ANSI Compact" | ||
| }; | ||
| const getFontName = (name) => { | ||
| return renamedFonts[name] ? renamedFonts[name] : name; | ||
| }; | ||
| function escapeRegExpChar(char) { | ||
| const specialChars = /[.*+?^${}()|[\]\\]/; | ||
| return specialChars.test(char) ? "\\" + char : char; | ||
| } | ||
| const figlet = (() => { | ||
| const { FULL_WIDTH = 0, FITTING, SMUSHING, CONTROLLED_SMUSHING } = LAYOUT; | ||
| const figFonts = {}; | ||
| const figDefaults = { | ||
| font: "Standard", | ||
| fontPath: "./fonts", | ||
| fetchFontIfMissing: true | ||
| }; | ||
| function removeEndChar(line, lineNum, fontHeight) { | ||
| const endChar = escapeRegExpChar(line.trim().slice(-1)) || "@"; | ||
| const endCharRegEx = lineNum === fontHeight - 1 ? new RegExp(endChar + endChar + "?\\s*$") : new RegExp(endChar + "\\s*$"); | ||
| return line.replace(endCharRegEx, ""); | ||
| } | ||
| function getSmushingRules(oldLayout = -1, newLayout = null) { | ||
| let rules = {}; | ||
| let val; | ||
| let codes = [ | ||
| [16384, "vLayout", SMUSHING], | ||
| [8192, "vLayout", FITTING], | ||
| [4096, "vRule5", true], | ||
| [2048, "vRule4", true], | ||
| [1024, "vRule3", true], | ||
| [512, "vRule2", true], | ||
| [256, "vRule1", true], | ||
| [128, "hLayout", SMUSHING], | ||
| [64, "hLayout", FITTING], | ||
| [32, "hRule6", true], | ||
| [16, "hRule5", true], | ||
| [8, "hRule4", true], | ||
| [4, "hRule3", true], | ||
| [2, "hRule2", true], | ||
| [1, "hRule1", true] | ||
| ]; | ||
| val = newLayout !== null ? newLayout : oldLayout; | ||
| for (const [code, rule, value] of codes) { | ||
| if (val >= code) { | ||
| val -= code; | ||
| if (rules[rule] === void 0) { | ||
| rules[rule] = value; | ||
| } | ||
| } else if (rule !== "vLayout" && rule !== "hLayout") { | ||
| rules[rule] = false; | ||
| } | ||
| } | ||
| if (typeof rules["hLayout"] === "undefined") { | ||
| if (oldLayout === 0) { | ||
| rules["hLayout"] = FITTING; | ||
| } else if (oldLayout === -1) { | ||
| rules["hLayout"] = FULL_WIDTH; | ||
| } else { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["hLayout"] = SMUSHING; | ||
| } | ||
| } | ||
| } else if (rules["hLayout"] === SMUSHING) { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| if (typeof rules["vLayout"] === "undefined") { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["vLayout"] = FULL_WIDTH; | ||
| } | ||
| } else if (rules["vLayout"] === SMUSHING) { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| return rules; | ||
| } | ||
| function hRule1_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === ch2 && ch1 !== hardBlank) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function hRule2_Smush(ch1, ch2) { | ||
| let rule2Str = "|/\\[]{}()<>"; | ||
| if (ch1 === "_") { | ||
| if (rule2Str.indexOf(ch2) !== -1) { | ||
| return ch2; | ||
| } | ||
| } else if (ch2 === "_") { | ||
| if (rule2Str.indexOf(ch1) !== -1) { | ||
| return ch1; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule3_Smush(ch1, ch2) { | ||
| let rule3Classes = "| /\\ [] {} () <>"; | ||
| let r3_pos1 = rule3Classes.indexOf(ch1); | ||
| let r3_pos2 = rule3Classes.indexOf(ch2); | ||
| if (r3_pos1 !== -1 && r3_pos2 !== -1) { | ||
| if (r3_pos1 !== r3_pos2 && Math.abs(r3_pos1 - r3_pos2) !== 1) { | ||
| const startPos = Math.max(r3_pos1, r3_pos2); | ||
| const endPos = startPos + 1; | ||
| return rule3Classes.substring(startPos, endPos); | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule4_Smush(ch1, ch2) { | ||
| let rule4Str = "[] {} ()"; | ||
| let r4_pos1 = rule4Str.indexOf(ch1); | ||
| let r4_pos2 = rule4Str.indexOf(ch2); | ||
| if (r4_pos1 !== -1 && r4_pos2 !== -1) { | ||
| if (Math.abs(r4_pos1 - r4_pos2) <= 1) { | ||
| return "|"; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule5_Smush(ch1, ch2) { | ||
| const patterns = { | ||
| "/\\": "|", | ||
| "\\/": "Y", | ||
| "><": "X" | ||
| }; | ||
| return patterns[ch1 + ch2] || false; | ||
| } | ||
| function hRule6_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === hardBlank && ch2 === hardBlank) { | ||
| return hardBlank; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule1_Smush(ch1, ch2) { | ||
| if (ch1 === ch2) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule2_Smush(ch1, ch2) { | ||
| return hRule2_Smush(ch1, ch2); | ||
| } | ||
| function vRule3_Smush(ch1, ch2) { | ||
| return hRule3_Smush(ch1, ch2); | ||
| } | ||
| function vRule4_Smush(ch1, ch2) { | ||
| if (ch1 === "-" && ch2 === "_" || ch1 === "_" && ch2 === "-") { | ||
| return "="; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule5_Smush(ch1, ch2) { | ||
| if (ch1 === "|" && ch2 === "|") { | ||
| return "|"; | ||
| } | ||
| return false; | ||
| } | ||
| function uni_Smush(ch1, ch2, hardBlank) { | ||
| if (ch2 === " " || ch2 === "") { | ||
| return ch1; | ||
| } else if (ch2 === hardBlank && ch1 !== " ") { | ||
| return ch1; | ||
| } else { | ||
| return ch2; | ||
| } | ||
| } | ||
| function canVerticalSmush(txt1, txt2, opts) { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FULL_WIDTH) { | ||
| return "invalid"; | ||
| } | ||
| let ii, len = Math.min(txt1.length, txt2.length), ch1, ch2, endSmush = false, validSmush; | ||
| if (len === 0) { | ||
| return "invalid"; | ||
| } | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = txt1.substring(ii, ii + 1); | ||
| ch2 = txt2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FITTING) { | ||
| return "invalid"; | ||
| } else if (opts.fittingRules && opts.fittingRules.vLayout === SMUSHING) { | ||
| return "end"; | ||
| } else { | ||
| if (vRule5_Smush(ch1, ch2)) { | ||
| endSmush = endSmush || false; | ||
| continue; | ||
| } | ||
| validSmush = false; | ||
| validSmush = opts.fittingRules && opts.fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| endSmush = true; | ||
| if (!validSmush) { | ||
| return "invalid"; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (endSmush) { | ||
| return "end"; | ||
| } else { | ||
| return "valid"; | ||
| } | ||
| } | ||
| function getVerticalSmushDist(lines1, lines2, opts) { | ||
| let maxDist = lines1.length; | ||
| let len1 = lines1.length; | ||
| let subLines1, subLines2, slen; | ||
| let curDist = 1; | ||
| let ii, ret, result; | ||
| while (curDist <= maxDist) { | ||
| subLines1 = lines1.slice(Math.max(0, len1 - curDist), len1); | ||
| subLines2 = lines2.slice(0, Math.min(maxDist, curDist)); | ||
| slen = subLines2.length; | ||
| result = ""; | ||
| for (ii = 0; ii < slen; ii++) { | ||
| ret = canVerticalSmush(subLines1[ii], subLines2[ii], opts); | ||
| if (ret === "end") { | ||
| result = ret; | ||
| } else if (ret === "invalid") { | ||
| result = ret; | ||
| break; | ||
| } else { | ||
| if (result === "") { | ||
| result = "valid"; | ||
| } | ||
| } | ||
| } | ||
| if (result === "invalid") { | ||
| curDist--; | ||
| break; | ||
| } | ||
| if (result === "end") { | ||
| break; | ||
| } | ||
| if (result === "valid") { | ||
| curDist++; | ||
| } | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function verticallySmushLines(line1, line2, opts) { | ||
| let ii, len = Math.min(line1.length, line2.length); | ||
| let ch1, ch2, result = "", validSmush; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = line1.substring(ii, ii + 1); | ||
| ch2 = line2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.vLayout === FITTING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else if (fittingRules.vLayout === SMUSHING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else { | ||
| validSmush = false; | ||
| validSmush = fittingRules.vRule5 ? vRule5_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| result += validSmush; | ||
| } | ||
| } else { | ||
| result += uni_Smush(ch1, ch2); | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| function verticalSmush(lines1, lines2, overlap, opts) { | ||
| let len1 = lines1.length; | ||
| let len2 = lines2.length; | ||
| let piece1 = lines1.slice(0, Math.max(0, len1 - overlap)); | ||
| let piece2_1 = lines1.slice(Math.max(0, len1 - overlap), len1); | ||
| let piece2_2 = lines2.slice(0, Math.min(overlap, len2)); | ||
| let ii, len, line, piece2 = [], piece3; | ||
| len = piece2_1.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| if (ii >= len2) { | ||
| line = piece2_1[ii]; | ||
| } else { | ||
| line = verticallySmushLines(piece2_1[ii], piece2_2[ii], opts); | ||
| } | ||
| piece2.push(line); | ||
| } | ||
| piece3 = lines2.slice(Math.min(overlap, len2), len2); | ||
| return [...piece1, ...piece2, ...piece3]; | ||
| } | ||
| function padLines(lines, numSpaces) { | ||
| const padding = " ".repeat(numSpaces); | ||
| return lines.map((line) => line + padding); | ||
| } | ||
| function smushVerticalFigLines(output, lines, opts) { | ||
| let len1 = output[0].length; | ||
| let len2 = lines[0].length; | ||
| let overlap; | ||
| if (len1 > len2) { | ||
| lines = padLines(lines, len1 - len2); | ||
| } else if (len2 > len1) { | ||
| output = padLines(output, len2 - len1); | ||
| } | ||
| overlap = getVerticalSmushDist(output, lines, opts); | ||
| return verticalSmush(output, lines, overlap, opts); | ||
| } | ||
| function getHorizontalSmushLength(txt1, txt2, opts) { | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (fittingRules.hLayout === FULL_WIDTH) { | ||
| return 0; | ||
| } | ||
| let ii, len1 = txt1.length, len2 = txt2.length; | ||
| let maxDist = len1; | ||
| let curDist = 1; | ||
| let breakAfter = false; | ||
| let seg1, seg2, ch1, ch2; | ||
| if (len1 === 0) { | ||
| return 0; | ||
| } | ||
| distCal: while (curDist <= maxDist) { | ||
| const seg1StartPos = len1 - curDist; | ||
| seg1 = txt1.substring(seg1StartPos, seg1StartPos + curDist); | ||
| seg2 = txt2.substring(0, Math.min(curDist, len2)); | ||
| for (ii = 0; ii < Math.min(curDist, len2); ii++) { | ||
| ch1 = seg1.substring(ii, ii + 1); | ||
| ch2 = seg2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } else if (fittingRules.hLayout === SMUSHING) { | ||
| if (ch1 === opts.hardBlank || ch2 === opts.hardBlank) { | ||
| curDist = curDist - 1; | ||
| } | ||
| break distCal; | ||
| } else { | ||
| breakAfter = true; | ||
| const validSmush = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank); | ||
| if (!validSmush) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (breakAfter) { | ||
| break; | ||
| } | ||
| curDist++; | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function horizontalSmush(textBlock1, textBlock2, overlap, opts) { | ||
| let ii, jj, outputFig = [], overlapStart, piece1, piece2, piece3, len1, len2, txt1, txt2; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (typeof opts.height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| for (ii = 0; ii < opts.height; ii++) { | ||
| txt1 = textBlock1[ii]; | ||
| txt2 = textBlock2[ii]; | ||
| len1 = txt1.length; | ||
| len2 = txt2.length; | ||
| overlapStart = len1 - overlap; | ||
| piece1 = txt1.slice(0, Math.max(0, overlapStart)); | ||
| piece2 = ""; | ||
| const seg1StartPos = Math.max(0, len1 - overlap); | ||
| let seg1 = txt1.substring(seg1StartPos, seg1StartPos + overlap); | ||
| let seg2 = txt2.substring(0, Math.min(overlap, len2)); | ||
| for (jj = 0; jj < overlap; jj++) { | ||
| let ch1 = jj < len1 ? seg1.substring(jj, jj + 1) : " "; | ||
| let ch2 = jj < len2 ? seg2.substring(jj, jj + 1) : " "; | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING || fittingRules.hLayout === SMUSHING) { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } else { | ||
| const nextCh = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank) || uni_Smush(ch1, ch2, opts.hardBlank); | ||
| piece2 += nextCh; | ||
| } | ||
| } else { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } | ||
| } | ||
| if (overlap >= len2) { | ||
| piece3 = ""; | ||
| } else { | ||
| piece3 = txt2.substring(overlap, overlap + Math.max(0, len2 - overlap)); | ||
| } | ||
| outputFig[ii] = piece1 + piece2 + piece3; | ||
| } | ||
| return outputFig; | ||
| } | ||
| function newFigChar(len) { | ||
| return new Array(len).fill(""); | ||
| } | ||
| const figLinesWidth = function(textLines) { | ||
| return Math.max(...textLines.map((line) => line.length)); | ||
| }; | ||
| function joinFigArray(array, len, opts) { | ||
| return array.reduce(function(acc, data) { | ||
| return horizontalSmush(acc, data.fig, data.overlap || 0, opts); | ||
| }, newFigChar(len)); | ||
| } | ||
| function breakWord(figChars, len, opts) { | ||
| for (let i = figChars.length - 1; i > 0; i--) { | ||
| const w = joinFigArray(figChars.slice(0, i), len, opts); | ||
| if (figLinesWidth(w) <= opts.width) { | ||
| return { | ||
| outputFigText: w, | ||
| chars: figChars.slice(i) | ||
| }; | ||
| } | ||
| } | ||
| return { outputFigText: newFigChar(len), chars: figChars }; | ||
| } | ||
| function generateFigTextLines(txt, figChars, opts) { | ||
| let charIndex, figChar, overlap = 0, row, outputFigText, len, height = opts.height, outputFigLines = [], maxWidth, nextFigChars = { | ||
| chars: [], | ||
| // list of characters is used to break in the middle of the word when word is longer | ||
| overlap | ||
| // chars is array of characters with {fig, overlap} and overlap is for whole word | ||
| }, figWords = [], char, isSpace, textFigWord, textFigLine, tmpBreak; | ||
| if (typeof height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| outputFigText = newFigChar(height); | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (opts.printDirection === 1) { | ||
| txt = txt.split("").reverse().join(""); | ||
| } | ||
| len = txt.length; | ||
| for (charIndex = 0; charIndex < len; charIndex++) { | ||
| char = txt.substring(charIndex, charIndex + 1); | ||
| isSpace = char.match(/\s/); | ||
| figChar = figChars[char.charCodeAt(0)]; | ||
| textFigLine = null; | ||
| if (figChar) { | ||
| if (fittingRules.hLayout !== FULL_WIDTH) { | ||
| overlap = 1e4; | ||
| for (row = 0; row < height; row++) { | ||
| overlap = Math.min( | ||
| overlap, | ||
| getHorizontalSmushLength(outputFigText[row], figChar[row], opts) | ||
| ); | ||
| } | ||
| overlap = overlap === 1e4 ? 0 : overlap; | ||
| } | ||
| if (opts.width > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| textFigWord = joinFigArray( | ||
| nextFigChars.chars.concat([ | ||
| { | ||
| fig: figChar, | ||
| overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| textFigLine = joinFigArray( | ||
| figWords.concat([ | ||
| { | ||
| fig: textFigWord, | ||
| overlap: nextFigChars.overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } else { | ||
| textFigLine = horizontalSmush( | ||
| outputFigText, | ||
| figChar, | ||
| overlap, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } | ||
| if (maxWidth >= opts.width && charIndex > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| outputFigText = joinFigArray(figWords.slice(0, -1), height, opts); | ||
| if (figWords.length > 1) { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| figWords = []; | ||
| } else { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| } | ||
| } | ||
| if (opts.width > 0 && opts.whitespaceBreak) { | ||
| if (!isSpace || charIndex === len - 1) { | ||
| nextFigChars.chars.push({ fig: figChar, overlap }); | ||
| } | ||
| if (isSpace || charIndex === len - 1) { | ||
| tmpBreak = null; | ||
| while (true) { | ||
| textFigLine = joinFigArray(nextFigChars.chars, height, opts); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| if (maxWidth >= opts.width) { | ||
| tmpBreak = breakWord(nextFigChars.chars, height, opts); | ||
| nextFigChars = { chars: tmpBreak.chars }; | ||
| outputFigLines.push(tmpBreak.outputFigText); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| if (maxWidth > 0) { | ||
| if (tmpBreak) { | ||
| figWords.push({ fig: textFigLine, overlap: 1 }); | ||
| } else { | ||
| figWords.push({ | ||
| fig: textFigLine, | ||
| overlap: nextFigChars.overlap | ||
| }); | ||
| } | ||
| } | ||
| if (isSpace) { | ||
| figWords.push({ fig: figChar, overlap }); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| if (charIndex === len - 1) { | ||
| outputFigText = joinFigArray(figWords, height, opts); | ||
| } | ||
| nextFigChars = { | ||
| chars: [], | ||
| overlap | ||
| }; | ||
| continue; | ||
| } | ||
| } | ||
| outputFigText = horizontalSmush(outputFigText, figChar, overlap, opts); | ||
| } | ||
| } | ||
| if (figLinesWidth(outputFigText) > 0) { | ||
| outputFigLines.push(outputFigText); | ||
| } | ||
| if (!opts.showHardBlanks) { | ||
| outputFigLines.forEach(function(outputFigText2) { | ||
| len = outputFigText2.length; | ||
| for (row = 0; row < len; row++) { | ||
| outputFigText2[row] = outputFigText2[row].replace( | ||
| new RegExp("\\" + opts.hardBlank, "g"), | ||
| " " | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| if (txt === "" && outputFigLines.length === 0) { | ||
| outputFigLines.push(new Array(height).fill("")); | ||
| } | ||
| return outputFigLines; | ||
| } | ||
| const getHorizontalFittingRules = function(layout, options) { | ||
| let params; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| hLayout: fittingRules.hLayout, | ||
| hRule1: fittingRules.hRule1, | ||
| hRule2: fittingRules.hRule2, | ||
| hRule3: fittingRules.hRule3, | ||
| hRule4: fittingRules.hRule4, | ||
| hRule5: fittingRules.hRule5, | ||
| hRule6: fittingRules.hRule6 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| hLayout: FULL_WIDTH, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| hLayout: FITTING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| hLayout: CONTROLLED_SMUSHING, | ||
| hRule1: true, | ||
| hRule2: true, | ||
| hRule3: true, | ||
| hRule4: true, | ||
| hRule5: true, | ||
| hRule6: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| hLayout: SMUSHING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const getVerticalFittingRules = function(layout, options) { | ||
| let params = {}; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| vLayout: fittingRules.vLayout, | ||
| vRule1: fittingRules.vRule1, | ||
| vRule2: fittingRules.vRule2, | ||
| vRule3: fittingRules.vRule3, | ||
| vRule4: fittingRules.vRule4, | ||
| vRule5: fittingRules.vRule5 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| vLayout: FULL_WIDTH, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| vLayout: FITTING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| vLayout: CONTROLLED_SMUSHING, | ||
| vRule1: true, | ||
| vRule2: true, | ||
| vRule3: true, | ||
| vRule4: true, | ||
| vRule5: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| vLayout: SMUSHING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const generateText = function(fontName, options, txt) { | ||
| txt = txt.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const actualFontName = getFontName(fontName); | ||
| let lines = txt.split("\n"); | ||
| let figLines = []; | ||
| let ii, len, output; | ||
| len = lines.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| figLines = figLines.concat( | ||
| generateFigTextLines(lines[ii], figFonts[actualFontName], options) | ||
| ); | ||
| } | ||
| len = figLines.length; | ||
| output = figLines[0]; | ||
| for (ii = 1; ii < len; ii++) { | ||
| output = smushVerticalFigLines(output, figLines[ii], options); | ||
| } | ||
| return output ? output.join("\n") : ""; | ||
| }; | ||
| function _reworkFontOpts(fontMeta, options) { | ||
| let myOpts; | ||
| if (typeof structuredClone !== "undefined") { | ||
| myOpts = structuredClone(fontMeta); | ||
| } else { | ||
| myOpts = JSON.parse(JSON.stringify(fontMeta)); | ||
| } | ||
| myOpts.showHardBlanks = options.showHardBlanks || false; | ||
| myOpts.width = options.width || -1; | ||
| myOpts.whitespaceBreak = options.whitespaceBreak || false; | ||
| if (options.horizontalLayout) { | ||
| const params = getHorizontalFittingRules( | ||
| options.horizontalLayout, | ||
| fontMeta | ||
| ); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| if (options.verticalLayout) { | ||
| const params = getVerticalFittingRules(options.verticalLayout, fontMeta); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| myOpts.printDirection = options.printDirection !== null && options.printDirection !== void 0 ? options.printDirection : fontMeta.printDirection; | ||
| return myOpts; | ||
| } | ||
| const me = async function(txt, optionsOrFontOrCallback, callback) { | ||
| return me.text(txt, optionsOrFontOrCallback, callback); | ||
| }; | ||
| me.text = async function(txt, optionsOrFontOrCallback, callback) { | ||
| txt = txt + ""; | ||
| let options, next; | ||
| if (typeof optionsOrFontOrCallback === "function") { | ||
| next = optionsOrFontOrCallback; | ||
| options = { font: figDefaults.font }; | ||
| } else if (typeof optionsOrFontOrCallback === "string") { | ||
| options = { font: optionsOrFontOrCallback }; | ||
| next = callback; | ||
| } else if (optionsOrFontOrCallback) { | ||
| options = optionsOrFontOrCallback; | ||
| next = callback; | ||
| } else { | ||
| options = { font: figDefaults.font }; | ||
| next = callback; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| const generatedTxt = fontOpts ? generateText(fontName, _reworkFontOpts(fontOpts, options), txt) : ""; | ||
| if (next) { | ||
| next(null, generatedTxt); | ||
| } | ||
| return generatedTxt; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (next) { | ||
| next(error); | ||
| return ""; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.textSync = function(txt, options) { | ||
| txt = txt + ""; | ||
| if (typeof options === "string") { | ||
| options = { font: options }; | ||
| } else { | ||
| options = options || {}; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| let fontOpts = _reworkFontOpts(me.loadFontSync(fontName), options); | ||
| return generateText(fontName, fontOpts, txt); | ||
| }; | ||
| me.metadata = async function(fontName, callback) { | ||
| fontName = fontName + ""; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| if (!fontOpts) { | ||
| throw new Error("Error loading font."); | ||
| } | ||
| const actualFontName = getFontName(fontName); | ||
| const font = figFonts[actualFontName] || {}; | ||
| const result = [fontOpts, font.comment || ""]; | ||
| if (callback) { | ||
| callback(null, fontOpts, font.comment); | ||
| } | ||
| return result; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (callback) { | ||
| callback(error); | ||
| return null; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.defaults = function(opts) { | ||
| if (opts && typeof opts === "object") { | ||
| Object.assign(figDefaults, opts); | ||
| } | ||
| if (typeof structuredClone !== "undefined") { | ||
| return structuredClone(figDefaults); | ||
| } else { | ||
| return JSON.parse(JSON.stringify(figDefaults)); | ||
| } | ||
| }; | ||
| me.parseFont = function(fontName, data, override = true) { | ||
| if (figFonts[fontName] && !override) { | ||
| return figFonts[fontName].options; | ||
| } | ||
| data = data.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const font = new FigletFont(); | ||
| const lines = data.split("\n"); | ||
| const headerLine = lines.shift(); | ||
| if (!headerLine) { | ||
| throw new Error("Invalid font file: missing header"); | ||
| } | ||
| const headerData = headerLine.split(" "); | ||
| const opts = { | ||
| hardBlank: headerData[0].substring(5, 6), | ||
| height: parseInt(headerData[1], 10), | ||
| baseline: parseInt(headerData[2], 10), | ||
| maxLength: parseInt(headerData[3], 10), | ||
| oldLayout: parseInt(headerData[4], 10), | ||
| numCommentLines: parseInt(headerData[5], 10), | ||
| printDirection: headerData[6] ? parseInt(headerData[6], 10) : 0, | ||
| fullLayout: headerData[7] ? parseInt(headerData[7], 10) : null, | ||
| codeTagCount: headerData[8] ? parseInt(headerData[8], 10) : null | ||
| }; | ||
| const hardBlank = opts.hardBlank || ""; | ||
| if (hardBlank.length !== 1 || [ | ||
| opts.height, | ||
| opts.baseline, | ||
| opts.maxLength, | ||
| opts.oldLayout, | ||
| opts.numCommentLines | ||
| ].some((val) => val === null || val === void 0 || isNaN(val))) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| if (opts.height == null || opts.numCommentLines == null) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| opts.fittingRules = getSmushingRules(opts.oldLayout, opts.fullLayout); | ||
| font.options = opts; | ||
| const charNums = []; | ||
| for (let i = 32; i <= 126; i++) { | ||
| charNums.push(i); | ||
| } | ||
| charNums.push(196, 214, 220, 228, 246, 252, 223); | ||
| if (lines.length < opts.numCommentLines + opts.height * charNums.length) { | ||
| throw new Error( | ||
| `FIGlet file is missing data. Line length: ${lines.length}. Comment lines: ${opts.numCommentLines}. Height: ${opts.height}. Num chars: ${charNums.length}.` | ||
| ); | ||
| } | ||
| font.comment = lines.splice(0, opts.numCommentLines).join("\n"); | ||
| font.numChars = 0; | ||
| while (lines.length > 0 && font.numChars < charNums.length) { | ||
| const cNum = charNums[font.numChars]; | ||
| font[cNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[cNum][i] === "undefined") { | ||
| font[cNum][i] = ""; | ||
| } else { | ||
| font[cNum][i] = removeEndChar(font[cNum][i], i, opts.height); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| while (lines.length > 0) { | ||
| const cNumLine = lines.shift(); | ||
| if (!cNumLine || cNumLine.trim() === "") break; | ||
| let cNum = cNumLine.split(" ")[0]; | ||
| let parsedNum; | ||
| if (/^-?0[xX][0-9a-fA-F]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 16); | ||
| } else if (/^-?0[0-7]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 8); | ||
| } else if (/^-?[0-9]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 10); | ||
| } else { | ||
| throw new Error(`Error parsing data. Invalid data: ${cNum}`); | ||
| } | ||
| if (parsedNum === -1 || parsedNum < -2147483648 || parsedNum > 2147483647) { | ||
| const msg = parsedNum === -1 ? "The char code -1 is not permitted." : `The char code cannot be ${parsedNum < -2147483648 ? "less than -2147483648" : "greater than 2147483647"}.`; | ||
| throw new Error(`Error parsing data. ${msg}`); | ||
| } | ||
| font[parsedNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[parsedNum][i] === "undefined") { | ||
| font[parsedNum][i] = ""; | ||
| } else { | ||
| font[parsedNum][i] = removeEndChar( | ||
| font[parsedNum][i], | ||
| i, | ||
| opts.height | ||
| ); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| figFonts[fontName] = font; | ||
| return opts; | ||
| }; | ||
| me.loadedFonts = () => { | ||
| return Object.keys(figFonts); | ||
| }; | ||
| me.clearLoadedFonts = () => { | ||
| Object.keys(figFonts).forEach((key) => { | ||
| delete figFonts[key]; | ||
| }); | ||
| }; | ||
| me.loadFont = async function(fontName, callback) { | ||
| const actualFontName = getFontName(fontName); | ||
| if (figFonts[actualFontName]) { | ||
| const result = figFonts[actualFontName].options; | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return Promise.resolve(result); | ||
| } | ||
| try { | ||
| if (!figDefaults.fetchFontIfMissing) { | ||
| throw new Error(`Font is not loaded: ${actualFontName}`); | ||
| } | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error(`Network response was not ok: ${response.status}`); | ||
| } | ||
| const text = await response.text(); | ||
| const result = me.parseFont(actualFontName, text); | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return result; | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return null; | ||
| } | ||
| throw err; | ||
| } | ||
| }; | ||
| me.loadFontSync = function(name) { | ||
| const actualFontName = getFontName(name); | ||
| if (figFonts[actualFontName]) { | ||
| return figFonts[actualFontName].options; | ||
| } | ||
| throw new Error( | ||
| "Synchronous font loading is not implemented for the browser, it will only work for fonts already loaded." | ||
| ); | ||
| }; | ||
| me.preloadFonts = async function(fonts, callback) { | ||
| try { | ||
| for (const name of fonts) { | ||
| const actualFontName = getFontName(name); | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error( | ||
| `Failed to preload fonts. Error fetching font: ${actualFontName}, status code: ${response.statusText}` | ||
| ); | ||
| } | ||
| const data = await response.text(); | ||
| me.parseFont(actualFontName, data); | ||
| } | ||
| if (callback) { | ||
| callback(); | ||
| } | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.fonts = function(callback) { | ||
| return new Promise(function(resolve, reject) { | ||
| resolve(fontList); | ||
| if (callback) { | ||
| callback(null, fontList); | ||
| } | ||
| }); | ||
| }; | ||
| me.fontsSync = function() { | ||
| return fontList; | ||
| }; | ||
| me.figFonts = figFonts; | ||
| return me; | ||
| })(); | ||
| export { | ||
| figlet as f, | ||
| getFontName as g | ||
| }; |
| "use strict"; | ||
| const LAYOUT = { | ||
| FULL_WIDTH: 0, | ||
| FITTING: 1, | ||
| SMUSHING: 2, | ||
| CONTROLLED_SMUSHING: 3 | ||
| }; | ||
| class FigletFont { | ||
| constructor() { | ||
| this.comment = ""; | ||
| this.numChars = 0; | ||
| this.options = {}; | ||
| } | ||
| } | ||
| const fontList = [ | ||
| "1Row", | ||
| "3-D", | ||
| "3D Diagonal", | ||
| "3D-ASCII", | ||
| "3x5", | ||
| "4Max", | ||
| "5 Line Oblique", | ||
| "AMC 3 Line", | ||
| "AMC 3 Liv1", | ||
| "AMC AAA01", | ||
| "AMC Neko", | ||
| "AMC Razor", | ||
| "AMC Razor2", | ||
| "AMC Slash", | ||
| "AMC Slider", | ||
| "AMC Thin", | ||
| "AMC Tubes", | ||
| "AMC Untitled", | ||
| "ANSI Compact", | ||
| "ANSI Regular", | ||
| "ANSI Shadow", | ||
| "ASCII 12", | ||
| "ASCII 9", | ||
| "ASCII New Roman", | ||
| "Acrobatic", | ||
| "Alligator", | ||
| "Alligator2", | ||
| "Alpha", | ||
| "Alphabet", | ||
| "Arrows", | ||
| "Avatar", | ||
| "B1FF", | ||
| "Babyface Lame", | ||
| "Babyface Leet", | ||
| "Banner", | ||
| "Banner3-D", | ||
| "Banner3", | ||
| "Banner4", | ||
| "Barbwire", | ||
| "Basic", | ||
| "Bear", | ||
| "Bell", | ||
| "Benjamin", | ||
| "Big ASCII 12", | ||
| "Big ASCII 9", | ||
| "Big Chief", | ||
| "Big Money-ne", | ||
| "Big Money-nw", | ||
| "Big Money-se", | ||
| "Big Money-sw", | ||
| "Big Mono 12", | ||
| "Big Mono 9", | ||
| "Big", | ||
| "Bigfig", | ||
| "Binary", | ||
| "Block", | ||
| "Blocks", | ||
| "Bloody", | ||
| "BlurVision ASCII", | ||
| "Bolger", | ||
| "Braced", | ||
| "Bright", | ||
| "Broadway KB", | ||
| "Broadway", | ||
| "Bubble", | ||
| "Bulbhead", | ||
| "Caligraphy", | ||
| "Caligraphy2", | ||
| "Calvin S", | ||
| "Cards", | ||
| "Catwalk", | ||
| "Chiseled", | ||
| "Chunky", | ||
| "Circle", | ||
| "Classy", | ||
| "Coder Mini", | ||
| "Coinstak", | ||
| "Cola", | ||
| "Colossal", | ||
| "Computer", | ||
| "Contessa", | ||
| "Contrast", | ||
| "Cosmike", | ||
| "Cosmike2", | ||
| "Crawford", | ||
| "Crawford2", | ||
| "Crazy", | ||
| "Cricket", | ||
| "Cursive", | ||
| "Cyberlarge", | ||
| "Cybermedium", | ||
| "Cybersmall", | ||
| "Cygnet", | ||
| "DANC4", | ||
| "DOS Rebel", | ||
| "DWhistled", | ||
| "Dancing Font", | ||
| "Decimal", | ||
| "Def Leppard", | ||
| "Delta Corps Priest 1", | ||
| "DiamFont", | ||
| "Diamond", | ||
| "Diet Cola", | ||
| "Digital", | ||
| "Doh", | ||
| "Doom", | ||
| "Dot Matrix", | ||
| "Double Shorts", | ||
| "Double", | ||
| "Dr Pepper", | ||
| "Efti Chess", | ||
| "Efti Font", | ||
| "Efti Italic", | ||
| "Efti Piti", | ||
| "Efti Robot", | ||
| "Efti Wall", | ||
| "Efti Water", | ||
| "Electronic", | ||
| "Elite", | ||
| "Emboss 2", | ||
| "Emboss", | ||
| "Epic", | ||
| "Fender", | ||
| "Filter", | ||
| "Fire Font-k", | ||
| "Fire Font-s", | ||
| "Flipped", | ||
| "Flower Power", | ||
| "Font Font", | ||
| "Four Tops", | ||
| "Fraktur", | ||
| "Fun Face", | ||
| "Fun Faces", | ||
| "Future Smooth", | ||
| "Future Thin", | ||
| "Future", | ||
| "Fuzzy", | ||
| "Georgi16", | ||
| "Georgia11", | ||
| "Ghost", | ||
| "Ghoulish", | ||
| "Glenyn", | ||
| "Goofy", | ||
| "Gothic", | ||
| "Graceful", | ||
| "Gradient", | ||
| "Graffiti", | ||
| "Greek", | ||
| "Heart Left", | ||
| "Heart Right", | ||
| "Henry 3D", | ||
| "Hex", | ||
| "Hieroglyphs", | ||
| "Hollywood", | ||
| "Horizontal Left", | ||
| "Horizontal Right", | ||
| "ICL-1900", | ||
| "Impossible", | ||
| "Invita", | ||
| "Isometric1", | ||
| "Isometric2", | ||
| "Isometric3", | ||
| "Isometric4", | ||
| "Italic", | ||
| "Ivrit", | ||
| "JS Block Letters", | ||
| "JS Bracket Letters", | ||
| "JS Capital Curves", | ||
| "JS Cursive", | ||
| "JS Stick Letters", | ||
| "Jacky", | ||
| "Jazmine", | ||
| "Jerusalem", | ||
| "Katakana", | ||
| "Kban", | ||
| "Keyboard", | ||
| "Knob", | ||
| "Konto Slant", | ||
| "Konto", | ||
| "LCD", | ||
| "Larry 3D 2", | ||
| "Larry 3D", | ||
| "Lean", | ||
| "Letter", | ||
| "Letters", | ||
| "Lil Devil", | ||
| "Line Blocks", | ||
| "Linux", | ||
| "Lockergnome", | ||
| "Madrid", | ||
| "Marquee", | ||
| "Maxfour", | ||
| "Merlin1", | ||
| "Merlin2", | ||
| "Mike", | ||
| "Mini", | ||
| "Mirror", | ||
| "Mnemonic", | ||
| "Modular", | ||
| "Mono 12", | ||
| "Mono 9", | ||
| "Morse", | ||
| "Morse2", | ||
| "Moscow", | ||
| "Mshebrew210", | ||
| "Muzzle", | ||
| "NScript", | ||
| "NT Greek", | ||
| "NV Script", | ||
| "Nancyj-Fancy", | ||
| "Nancyj-Improved", | ||
| "Nancyj-Underlined", | ||
| "Nancyj", | ||
| "Nipples", | ||
| "O8", | ||
| "OS2", | ||
| "Octal", | ||
| "Ogre", | ||
| "Old Banner", | ||
| "Pagga", | ||
| "Patorjk's Cheese", | ||
| "Patorjk-HeX", | ||
| "Pawp", | ||
| "Peaks Slant", | ||
| "Peaks", | ||
| "Pebbles", | ||
| "Pepper", | ||
| "Poison", | ||
| "Puffy", | ||
| "Puzzle", | ||
| "Pyramid", | ||
| "Rammstein", | ||
| "Rebel", | ||
| "Rectangles", | ||
| "Red Phoenix", | ||
| "Relief", | ||
| "Relief2", | ||
| "Reverse", | ||
| "Roman", | ||
| "Rot13", | ||
| "Rotated", | ||
| "Rounded", | ||
| "Rowan Cap", | ||
| "Rozzo", | ||
| "RubiFont", | ||
| "Runic", | ||
| "Runyc", | ||
| "S Blood", | ||
| "SL Script", | ||
| "Santa Clara", | ||
| "Script", | ||
| "Serifcap", | ||
| "Shaded Blocky", | ||
| "Shadow", | ||
| "Shimrod", | ||
| "Short", | ||
| "Slant Relief", | ||
| "Slant", | ||
| "Slide", | ||
| "Small ASCII 12", | ||
| "Small ASCII 9", | ||
| "Small Block", | ||
| "Small Braille", | ||
| "Small Caps", | ||
| "Small Isometric1", | ||
| "Small Keyboard", | ||
| "Small Mono 12", | ||
| "Small Mono 9", | ||
| "Small Poison", | ||
| "Small Script", | ||
| "Small Shadow", | ||
| "Small Slant", | ||
| "Small Tengwar", | ||
| "Small", | ||
| "Soft", | ||
| "Speed", | ||
| "Spliff", | ||
| "Stacey", | ||
| "Stampate", | ||
| "Stampatello", | ||
| "Standard", | ||
| "Star Strips", | ||
| "Star Wars", | ||
| "Stellar", | ||
| "Stforek", | ||
| "Stick Letters", | ||
| "Stop", | ||
| "Straight", | ||
| "Stronger Than All", | ||
| "Sub-Zero", | ||
| "Swamp Land", | ||
| "Swan", | ||
| "Sweet", | ||
| "THIS", | ||
| "Tanja", | ||
| "Tengwar", | ||
| "Term", | ||
| "Terrace", | ||
| "Test1", | ||
| "The Edge", | ||
| "Thick", | ||
| "Thin", | ||
| "Thorned", | ||
| "Three Point", | ||
| "Ticks Slant", | ||
| "Ticks", | ||
| "Tiles", | ||
| "Tinker-Toy", | ||
| "Tmplr", | ||
| "Tombstone", | ||
| "Train", | ||
| "Trek", | ||
| "Tsalagi", | ||
| "Tubular", | ||
| "Twisted", | ||
| "Two Point", | ||
| "USA Flag", | ||
| "Univers", | ||
| "Upside Down Text", | ||
| "Varsity", | ||
| "Wavescape", | ||
| "Wavy", | ||
| "Weird", | ||
| "Wet Letter", | ||
| "Whimsy", | ||
| "WideTerm", | ||
| "Wow", | ||
| "miniwi" | ||
| ]; | ||
| const renamedFonts = { | ||
| "ANSI-Compact": "ANSI Compact" | ||
| }; | ||
| const getFontName = (name) => { | ||
| return renamedFonts[name] ? renamedFonts[name] : name; | ||
| }; | ||
| function escapeRegExpChar(char) { | ||
| const specialChars = /[.*+?^${}()|[\]\\]/; | ||
| return specialChars.test(char) ? "\\" + char : char; | ||
| } | ||
| const figlet = (() => { | ||
| const { FULL_WIDTH = 0, FITTING, SMUSHING, CONTROLLED_SMUSHING } = LAYOUT; | ||
| const figFonts = {}; | ||
| const figDefaults = { | ||
| font: "Standard", | ||
| fontPath: "./fonts", | ||
| fetchFontIfMissing: true | ||
| }; | ||
| function removeEndChar(line, lineNum, fontHeight) { | ||
| const endChar = escapeRegExpChar(line.trim().slice(-1)) || "@"; | ||
| const endCharRegEx = lineNum === fontHeight - 1 ? new RegExp(endChar + endChar + "?\\s*$") : new RegExp(endChar + "\\s*$"); | ||
| return line.replace(endCharRegEx, ""); | ||
| } | ||
| function getSmushingRules(oldLayout = -1, newLayout = null) { | ||
| let rules = {}; | ||
| let val; | ||
| let codes = [ | ||
| [16384, "vLayout", SMUSHING], | ||
| [8192, "vLayout", FITTING], | ||
| [4096, "vRule5", true], | ||
| [2048, "vRule4", true], | ||
| [1024, "vRule3", true], | ||
| [512, "vRule2", true], | ||
| [256, "vRule1", true], | ||
| [128, "hLayout", SMUSHING], | ||
| [64, "hLayout", FITTING], | ||
| [32, "hRule6", true], | ||
| [16, "hRule5", true], | ||
| [8, "hRule4", true], | ||
| [4, "hRule3", true], | ||
| [2, "hRule2", true], | ||
| [1, "hRule1", true] | ||
| ]; | ||
| val = newLayout !== null ? newLayout : oldLayout; | ||
| for (const [code, rule, value] of codes) { | ||
| if (val >= code) { | ||
| val -= code; | ||
| if (rules[rule] === void 0) { | ||
| rules[rule] = value; | ||
| } | ||
| } else if (rule !== "vLayout" && rule !== "hLayout") { | ||
| rules[rule] = false; | ||
| } | ||
| } | ||
| if (typeof rules["hLayout"] === "undefined") { | ||
| if (oldLayout === 0) { | ||
| rules["hLayout"] = FITTING; | ||
| } else if (oldLayout === -1) { | ||
| rules["hLayout"] = FULL_WIDTH; | ||
| } else { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["hLayout"] = SMUSHING; | ||
| } | ||
| } | ||
| } else if (rules["hLayout"] === SMUSHING) { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| if (typeof rules["vLayout"] === "undefined") { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["vLayout"] = FULL_WIDTH; | ||
| } | ||
| } else if (rules["vLayout"] === SMUSHING) { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| return rules; | ||
| } | ||
| function hRule1_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === ch2 && ch1 !== hardBlank) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function hRule2_Smush(ch1, ch2) { | ||
| let rule2Str = "|/\\[]{}()<>"; | ||
| if (ch1 === "_") { | ||
| if (rule2Str.indexOf(ch2) !== -1) { | ||
| return ch2; | ||
| } | ||
| } else if (ch2 === "_") { | ||
| if (rule2Str.indexOf(ch1) !== -1) { | ||
| return ch1; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule3_Smush(ch1, ch2) { | ||
| let rule3Classes = "| /\\ [] {} () <>"; | ||
| let r3_pos1 = rule3Classes.indexOf(ch1); | ||
| let r3_pos2 = rule3Classes.indexOf(ch2); | ||
| if (r3_pos1 !== -1 && r3_pos2 !== -1) { | ||
| if (r3_pos1 !== r3_pos2 && Math.abs(r3_pos1 - r3_pos2) !== 1) { | ||
| const startPos = Math.max(r3_pos1, r3_pos2); | ||
| const endPos = startPos + 1; | ||
| return rule3Classes.substring(startPos, endPos); | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule4_Smush(ch1, ch2) { | ||
| let rule4Str = "[] {} ()"; | ||
| let r4_pos1 = rule4Str.indexOf(ch1); | ||
| let r4_pos2 = rule4Str.indexOf(ch2); | ||
| if (r4_pos1 !== -1 && r4_pos2 !== -1) { | ||
| if (Math.abs(r4_pos1 - r4_pos2) <= 1) { | ||
| return "|"; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule5_Smush(ch1, ch2) { | ||
| const patterns = { | ||
| "/\\": "|", | ||
| "\\/": "Y", | ||
| "><": "X" | ||
| }; | ||
| return patterns[ch1 + ch2] || false; | ||
| } | ||
| function hRule6_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === hardBlank && ch2 === hardBlank) { | ||
| return hardBlank; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule1_Smush(ch1, ch2) { | ||
| if (ch1 === ch2) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule2_Smush(ch1, ch2) { | ||
| return hRule2_Smush(ch1, ch2); | ||
| } | ||
| function vRule3_Smush(ch1, ch2) { | ||
| return hRule3_Smush(ch1, ch2); | ||
| } | ||
| function vRule4_Smush(ch1, ch2) { | ||
| if (ch1 === "-" && ch2 === "_" || ch1 === "_" && ch2 === "-") { | ||
| return "="; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule5_Smush(ch1, ch2) { | ||
| if (ch1 === "|" && ch2 === "|") { | ||
| return "|"; | ||
| } | ||
| return false; | ||
| } | ||
| function uni_Smush(ch1, ch2, hardBlank) { | ||
| if (ch2 === " " || ch2 === "") { | ||
| return ch1; | ||
| } else if (ch2 === hardBlank && ch1 !== " ") { | ||
| return ch1; | ||
| } else { | ||
| return ch2; | ||
| } | ||
| } | ||
| function canVerticalSmush(txt1, txt2, opts) { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FULL_WIDTH) { | ||
| return "invalid"; | ||
| } | ||
| let ii, len = Math.min(txt1.length, txt2.length), ch1, ch2, endSmush = false, validSmush; | ||
| if (len === 0) { | ||
| return "invalid"; | ||
| } | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = txt1.substring(ii, ii + 1); | ||
| ch2 = txt2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FITTING) { | ||
| return "invalid"; | ||
| } else if (opts.fittingRules && opts.fittingRules.vLayout === SMUSHING) { | ||
| return "end"; | ||
| } else { | ||
| if (vRule5_Smush(ch1, ch2)) { | ||
| endSmush = endSmush || false; | ||
| continue; | ||
| } | ||
| validSmush = false; | ||
| validSmush = opts.fittingRules && opts.fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| endSmush = true; | ||
| if (!validSmush) { | ||
| return "invalid"; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (endSmush) { | ||
| return "end"; | ||
| } else { | ||
| return "valid"; | ||
| } | ||
| } | ||
| function getVerticalSmushDist(lines1, lines2, opts) { | ||
| let maxDist = lines1.length; | ||
| let len1 = lines1.length; | ||
| let subLines1, subLines2, slen; | ||
| let curDist = 1; | ||
| let ii, ret, result; | ||
| while (curDist <= maxDist) { | ||
| subLines1 = lines1.slice(Math.max(0, len1 - curDist), len1); | ||
| subLines2 = lines2.slice(0, Math.min(maxDist, curDist)); | ||
| slen = subLines2.length; | ||
| result = ""; | ||
| for (ii = 0; ii < slen; ii++) { | ||
| ret = canVerticalSmush(subLines1[ii], subLines2[ii], opts); | ||
| if (ret === "end") { | ||
| result = ret; | ||
| } else if (ret === "invalid") { | ||
| result = ret; | ||
| break; | ||
| } else { | ||
| if (result === "") { | ||
| result = "valid"; | ||
| } | ||
| } | ||
| } | ||
| if (result === "invalid") { | ||
| curDist--; | ||
| break; | ||
| } | ||
| if (result === "end") { | ||
| break; | ||
| } | ||
| if (result === "valid") { | ||
| curDist++; | ||
| } | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function verticallySmushLines(line1, line2, opts) { | ||
| let ii, len = Math.min(line1.length, line2.length); | ||
| let ch1, ch2, result = "", validSmush; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = line1.substring(ii, ii + 1); | ||
| ch2 = line2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.vLayout === FITTING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else if (fittingRules.vLayout === SMUSHING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else { | ||
| validSmush = false; | ||
| validSmush = fittingRules.vRule5 ? vRule5_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| result += validSmush; | ||
| } | ||
| } else { | ||
| result += uni_Smush(ch1, ch2); | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| function verticalSmush(lines1, lines2, overlap, opts) { | ||
| let len1 = lines1.length; | ||
| let len2 = lines2.length; | ||
| let piece1 = lines1.slice(0, Math.max(0, len1 - overlap)); | ||
| let piece2_1 = lines1.slice(Math.max(0, len1 - overlap), len1); | ||
| let piece2_2 = lines2.slice(0, Math.min(overlap, len2)); | ||
| let ii, len, line, piece2 = [], piece3; | ||
| len = piece2_1.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| if (ii >= len2) { | ||
| line = piece2_1[ii]; | ||
| } else { | ||
| line = verticallySmushLines(piece2_1[ii], piece2_2[ii], opts); | ||
| } | ||
| piece2.push(line); | ||
| } | ||
| piece3 = lines2.slice(Math.min(overlap, len2), len2); | ||
| return [...piece1, ...piece2, ...piece3]; | ||
| } | ||
| function padLines(lines, numSpaces) { | ||
| const padding = " ".repeat(numSpaces); | ||
| return lines.map((line) => line + padding); | ||
| } | ||
| function smushVerticalFigLines(output, lines, opts) { | ||
| let len1 = output[0].length; | ||
| let len2 = lines[0].length; | ||
| let overlap; | ||
| if (len1 > len2) { | ||
| lines = padLines(lines, len1 - len2); | ||
| } else if (len2 > len1) { | ||
| output = padLines(output, len2 - len1); | ||
| } | ||
| overlap = getVerticalSmushDist(output, lines, opts); | ||
| return verticalSmush(output, lines, overlap, opts); | ||
| } | ||
| function getHorizontalSmushLength(txt1, txt2, opts) { | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (fittingRules.hLayout === FULL_WIDTH) { | ||
| return 0; | ||
| } | ||
| let ii, len1 = txt1.length, len2 = txt2.length; | ||
| let maxDist = len1; | ||
| let curDist = 1; | ||
| let breakAfter = false; | ||
| let seg1, seg2, ch1, ch2; | ||
| if (len1 === 0) { | ||
| return 0; | ||
| } | ||
| distCal: while (curDist <= maxDist) { | ||
| const seg1StartPos = len1 - curDist; | ||
| seg1 = txt1.substring(seg1StartPos, seg1StartPos + curDist); | ||
| seg2 = txt2.substring(0, Math.min(curDist, len2)); | ||
| for (ii = 0; ii < Math.min(curDist, len2); ii++) { | ||
| ch1 = seg1.substring(ii, ii + 1); | ||
| ch2 = seg2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } else if (fittingRules.hLayout === SMUSHING) { | ||
| if (ch1 === opts.hardBlank || ch2 === opts.hardBlank) { | ||
| curDist = curDist - 1; | ||
| } | ||
| break distCal; | ||
| } else { | ||
| breakAfter = true; | ||
| const validSmush = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank); | ||
| if (!validSmush) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (breakAfter) { | ||
| break; | ||
| } | ||
| curDist++; | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function horizontalSmush(textBlock1, textBlock2, overlap, opts) { | ||
| let ii, jj, outputFig = [], overlapStart, piece1, piece2, piece3, len1, len2, txt1, txt2; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (typeof opts.height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| for (ii = 0; ii < opts.height; ii++) { | ||
| txt1 = textBlock1[ii]; | ||
| txt2 = textBlock2[ii]; | ||
| len1 = txt1.length; | ||
| len2 = txt2.length; | ||
| overlapStart = len1 - overlap; | ||
| piece1 = txt1.slice(0, Math.max(0, overlapStart)); | ||
| piece2 = ""; | ||
| const seg1StartPos = Math.max(0, len1 - overlap); | ||
| let seg1 = txt1.substring(seg1StartPos, seg1StartPos + overlap); | ||
| let seg2 = txt2.substring(0, Math.min(overlap, len2)); | ||
| for (jj = 0; jj < overlap; jj++) { | ||
| let ch1 = jj < len1 ? seg1.substring(jj, jj + 1) : " "; | ||
| let ch2 = jj < len2 ? seg2.substring(jj, jj + 1) : " "; | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING || fittingRules.hLayout === SMUSHING) { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } else { | ||
| const nextCh = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank) || uni_Smush(ch1, ch2, opts.hardBlank); | ||
| piece2 += nextCh; | ||
| } | ||
| } else { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } | ||
| } | ||
| if (overlap >= len2) { | ||
| piece3 = ""; | ||
| } else { | ||
| piece3 = txt2.substring(overlap, overlap + Math.max(0, len2 - overlap)); | ||
| } | ||
| outputFig[ii] = piece1 + piece2 + piece3; | ||
| } | ||
| return outputFig; | ||
| } | ||
| function newFigChar(len) { | ||
| return new Array(len).fill(""); | ||
| } | ||
| const figLinesWidth = function(textLines) { | ||
| return Math.max(...textLines.map((line) => line.length)); | ||
| }; | ||
| function joinFigArray(array, len, opts) { | ||
| return array.reduce(function(acc, data) { | ||
| return horizontalSmush(acc, data.fig, data.overlap || 0, opts); | ||
| }, newFigChar(len)); | ||
| } | ||
| function breakWord(figChars, len, opts) { | ||
| for (let i = figChars.length - 1; i > 0; i--) { | ||
| const w = joinFigArray(figChars.slice(0, i), len, opts); | ||
| if (figLinesWidth(w) <= opts.width) { | ||
| return { | ||
| outputFigText: w, | ||
| chars: figChars.slice(i) | ||
| }; | ||
| } | ||
| } | ||
| return { outputFigText: newFigChar(len), chars: figChars }; | ||
| } | ||
| function generateFigTextLines(txt, figChars, opts) { | ||
| let charIndex, figChar, overlap = 0, row, outputFigText, len, height = opts.height, outputFigLines = [], maxWidth, nextFigChars = { | ||
| chars: [], | ||
| // list of characters is used to break in the middle of the word when word is longer | ||
| overlap | ||
| // chars is array of characters with {fig, overlap} and overlap is for whole word | ||
| }, figWords = [], char, isSpace, textFigWord, textFigLine, tmpBreak; | ||
| if (typeof height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| outputFigText = newFigChar(height); | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (opts.printDirection === 1) { | ||
| txt = txt.split("").reverse().join(""); | ||
| } | ||
| len = txt.length; | ||
| for (charIndex = 0; charIndex < len; charIndex++) { | ||
| char = txt.substring(charIndex, charIndex + 1); | ||
| isSpace = char.match(/\s/); | ||
| figChar = figChars[char.charCodeAt(0)]; | ||
| textFigLine = null; | ||
| if (figChar) { | ||
| if (fittingRules.hLayout !== FULL_WIDTH) { | ||
| overlap = 1e4; | ||
| for (row = 0; row < height; row++) { | ||
| overlap = Math.min( | ||
| overlap, | ||
| getHorizontalSmushLength(outputFigText[row], figChar[row], opts) | ||
| ); | ||
| } | ||
| overlap = overlap === 1e4 ? 0 : overlap; | ||
| } | ||
| if (opts.width > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| textFigWord = joinFigArray( | ||
| nextFigChars.chars.concat([ | ||
| { | ||
| fig: figChar, | ||
| overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| textFigLine = joinFigArray( | ||
| figWords.concat([ | ||
| { | ||
| fig: textFigWord, | ||
| overlap: nextFigChars.overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } else { | ||
| textFigLine = horizontalSmush( | ||
| outputFigText, | ||
| figChar, | ||
| overlap, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } | ||
| if (maxWidth >= opts.width && charIndex > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| outputFigText = joinFigArray(figWords.slice(0, -1), height, opts); | ||
| if (figWords.length > 1) { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| figWords = []; | ||
| } else { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| } | ||
| } | ||
| if (opts.width > 0 && opts.whitespaceBreak) { | ||
| if (!isSpace || charIndex === len - 1) { | ||
| nextFigChars.chars.push({ fig: figChar, overlap }); | ||
| } | ||
| if (isSpace || charIndex === len - 1) { | ||
| tmpBreak = null; | ||
| while (true) { | ||
| textFigLine = joinFigArray(nextFigChars.chars, height, opts); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| if (maxWidth >= opts.width) { | ||
| tmpBreak = breakWord(nextFigChars.chars, height, opts); | ||
| nextFigChars = { chars: tmpBreak.chars }; | ||
| outputFigLines.push(tmpBreak.outputFigText); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| if (maxWidth > 0) { | ||
| if (tmpBreak) { | ||
| figWords.push({ fig: textFigLine, overlap: 1 }); | ||
| } else { | ||
| figWords.push({ | ||
| fig: textFigLine, | ||
| overlap: nextFigChars.overlap | ||
| }); | ||
| } | ||
| } | ||
| if (isSpace) { | ||
| figWords.push({ fig: figChar, overlap }); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| if (charIndex === len - 1) { | ||
| outputFigText = joinFigArray(figWords, height, opts); | ||
| } | ||
| nextFigChars = { | ||
| chars: [], | ||
| overlap | ||
| }; | ||
| continue; | ||
| } | ||
| } | ||
| outputFigText = horizontalSmush(outputFigText, figChar, overlap, opts); | ||
| } | ||
| } | ||
| if (figLinesWidth(outputFigText) > 0) { | ||
| outputFigLines.push(outputFigText); | ||
| } | ||
| if (!opts.showHardBlanks) { | ||
| outputFigLines.forEach(function(outputFigText2) { | ||
| len = outputFigText2.length; | ||
| for (row = 0; row < len; row++) { | ||
| outputFigText2[row] = outputFigText2[row].replace( | ||
| new RegExp("\\" + opts.hardBlank, "g"), | ||
| " " | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| if (txt === "" && outputFigLines.length === 0) { | ||
| outputFigLines.push(new Array(height).fill("")); | ||
| } | ||
| return outputFigLines; | ||
| } | ||
| const getHorizontalFittingRules = function(layout, options) { | ||
| let params; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| hLayout: fittingRules.hLayout, | ||
| hRule1: fittingRules.hRule1, | ||
| hRule2: fittingRules.hRule2, | ||
| hRule3: fittingRules.hRule3, | ||
| hRule4: fittingRules.hRule4, | ||
| hRule5: fittingRules.hRule5, | ||
| hRule6: fittingRules.hRule6 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| hLayout: FULL_WIDTH, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| hLayout: FITTING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| hLayout: CONTROLLED_SMUSHING, | ||
| hRule1: true, | ||
| hRule2: true, | ||
| hRule3: true, | ||
| hRule4: true, | ||
| hRule5: true, | ||
| hRule6: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| hLayout: SMUSHING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const getVerticalFittingRules = function(layout, options) { | ||
| let params = {}; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| vLayout: fittingRules.vLayout, | ||
| vRule1: fittingRules.vRule1, | ||
| vRule2: fittingRules.vRule2, | ||
| vRule3: fittingRules.vRule3, | ||
| vRule4: fittingRules.vRule4, | ||
| vRule5: fittingRules.vRule5 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| vLayout: FULL_WIDTH, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| vLayout: FITTING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| vLayout: CONTROLLED_SMUSHING, | ||
| vRule1: true, | ||
| vRule2: true, | ||
| vRule3: true, | ||
| vRule4: true, | ||
| vRule5: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| vLayout: SMUSHING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const generateText = function(fontName, options, txt) { | ||
| txt = txt.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const actualFontName = getFontName(fontName); | ||
| let lines = txt.split("\n"); | ||
| let figLines = []; | ||
| let ii, len, output; | ||
| len = lines.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| figLines = figLines.concat( | ||
| generateFigTextLines(lines[ii], figFonts[actualFontName], options) | ||
| ); | ||
| } | ||
| len = figLines.length; | ||
| output = figLines[0]; | ||
| for (ii = 1; ii < len; ii++) { | ||
| output = smushVerticalFigLines(output, figLines[ii], options); | ||
| } | ||
| return output ? output.join("\n") : ""; | ||
| }; | ||
| function _reworkFontOpts(fontMeta, options) { | ||
| let myOpts; | ||
| if (typeof structuredClone !== "undefined") { | ||
| myOpts = structuredClone(fontMeta); | ||
| } else { | ||
| myOpts = JSON.parse(JSON.stringify(fontMeta)); | ||
| } | ||
| myOpts.showHardBlanks = options.showHardBlanks || false; | ||
| myOpts.width = options.width || -1; | ||
| myOpts.whitespaceBreak = options.whitespaceBreak || false; | ||
| if (options.horizontalLayout) { | ||
| const params = getHorizontalFittingRules( | ||
| options.horizontalLayout, | ||
| fontMeta | ||
| ); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| if (options.verticalLayout) { | ||
| const params = getVerticalFittingRules(options.verticalLayout, fontMeta); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| myOpts.printDirection = options.printDirection !== null && options.printDirection !== void 0 ? options.printDirection : fontMeta.printDirection; | ||
| return myOpts; | ||
| } | ||
| const me = async function(txt, optionsOrFontOrCallback, callback) { | ||
| return me.text(txt, optionsOrFontOrCallback, callback); | ||
| }; | ||
| me.text = async function(txt, optionsOrFontOrCallback, callback) { | ||
| txt = txt + ""; | ||
| let options, next; | ||
| if (typeof optionsOrFontOrCallback === "function") { | ||
| next = optionsOrFontOrCallback; | ||
| options = { font: figDefaults.font }; | ||
| } else if (typeof optionsOrFontOrCallback === "string") { | ||
| options = { font: optionsOrFontOrCallback }; | ||
| next = callback; | ||
| } else if (optionsOrFontOrCallback) { | ||
| options = optionsOrFontOrCallback; | ||
| next = callback; | ||
| } else { | ||
| options = { font: figDefaults.font }; | ||
| next = callback; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| const generatedTxt = fontOpts ? generateText(fontName, _reworkFontOpts(fontOpts, options), txt) : ""; | ||
| if (next) { | ||
| next(null, generatedTxt); | ||
| } | ||
| return generatedTxt; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (next) { | ||
| next(error); | ||
| return ""; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.textSync = function(txt, options) { | ||
| txt = txt + ""; | ||
| if (typeof options === "string") { | ||
| options = { font: options }; | ||
| } else { | ||
| options = options || {}; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| let fontOpts = _reworkFontOpts(me.loadFontSync(fontName), options); | ||
| return generateText(fontName, fontOpts, txt); | ||
| }; | ||
| me.metadata = async function(fontName, callback) { | ||
| fontName = fontName + ""; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| if (!fontOpts) { | ||
| throw new Error("Error loading font."); | ||
| } | ||
| const actualFontName = getFontName(fontName); | ||
| const font = figFonts[actualFontName] || {}; | ||
| const result = [fontOpts, font.comment || ""]; | ||
| if (callback) { | ||
| callback(null, fontOpts, font.comment); | ||
| } | ||
| return result; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (callback) { | ||
| callback(error); | ||
| return null; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.defaults = function(opts) { | ||
| if (opts && typeof opts === "object") { | ||
| Object.assign(figDefaults, opts); | ||
| } | ||
| if (typeof structuredClone !== "undefined") { | ||
| return structuredClone(figDefaults); | ||
| } else { | ||
| return JSON.parse(JSON.stringify(figDefaults)); | ||
| } | ||
| }; | ||
| me.parseFont = function(fontName, data, override = true) { | ||
| if (figFonts[fontName] && !override) { | ||
| return figFonts[fontName].options; | ||
| } | ||
| data = data.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const font = new FigletFont(); | ||
| const lines = data.split("\n"); | ||
| const headerLine = lines.shift(); | ||
| if (!headerLine) { | ||
| throw new Error("Invalid font file: missing header"); | ||
| } | ||
| const headerData = headerLine.split(" "); | ||
| const opts = { | ||
| hardBlank: headerData[0].substring(5, 6), | ||
| height: parseInt(headerData[1], 10), | ||
| baseline: parseInt(headerData[2], 10), | ||
| maxLength: parseInt(headerData[3], 10), | ||
| oldLayout: parseInt(headerData[4], 10), | ||
| numCommentLines: parseInt(headerData[5], 10), | ||
| printDirection: headerData[6] ? parseInt(headerData[6], 10) : 0, | ||
| fullLayout: headerData[7] ? parseInt(headerData[7], 10) : null, | ||
| codeTagCount: headerData[8] ? parseInt(headerData[8], 10) : null | ||
| }; | ||
| const hardBlank = opts.hardBlank || ""; | ||
| if (hardBlank.length !== 1 || [ | ||
| opts.height, | ||
| opts.baseline, | ||
| opts.maxLength, | ||
| opts.oldLayout, | ||
| opts.numCommentLines | ||
| ].some((val) => val === null || val === void 0 || isNaN(val))) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| if (opts.height == null || opts.numCommentLines == null) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| opts.fittingRules = getSmushingRules(opts.oldLayout, opts.fullLayout); | ||
| font.options = opts; | ||
| const charNums = []; | ||
| for (let i = 32; i <= 126; i++) { | ||
| charNums.push(i); | ||
| } | ||
| charNums.push(196, 214, 220, 228, 246, 252, 223); | ||
| if (lines.length < opts.numCommentLines + opts.height * charNums.length) { | ||
| throw new Error( | ||
| `FIGlet file is missing data. Line length: ${lines.length}. Comment lines: ${opts.numCommentLines}. Height: ${opts.height}. Num chars: ${charNums.length}.` | ||
| ); | ||
| } | ||
| font.comment = lines.splice(0, opts.numCommentLines).join("\n"); | ||
| font.numChars = 0; | ||
| while (lines.length > 0 && font.numChars < charNums.length) { | ||
| const cNum = charNums[font.numChars]; | ||
| font[cNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[cNum][i] === "undefined") { | ||
| font[cNum][i] = ""; | ||
| } else { | ||
| font[cNum][i] = removeEndChar(font[cNum][i], i, opts.height); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| while (lines.length > 0) { | ||
| const cNumLine = lines.shift(); | ||
| if (!cNumLine || cNumLine.trim() === "") break; | ||
| let cNum = cNumLine.split(" ")[0]; | ||
| let parsedNum; | ||
| if (/^-?0[xX][0-9a-fA-F]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 16); | ||
| } else if (/^-?0[0-7]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 8); | ||
| } else if (/^-?[0-9]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 10); | ||
| } else { | ||
| throw new Error(`Error parsing data. Invalid data: ${cNum}`); | ||
| } | ||
| if (parsedNum === -1 || parsedNum < -2147483648 || parsedNum > 2147483647) { | ||
| const msg = parsedNum === -1 ? "The char code -1 is not permitted." : `The char code cannot be ${parsedNum < -2147483648 ? "less than -2147483648" : "greater than 2147483647"}.`; | ||
| throw new Error(`Error parsing data. ${msg}`); | ||
| } | ||
| font[parsedNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[parsedNum][i] === "undefined") { | ||
| font[parsedNum][i] = ""; | ||
| } else { | ||
| font[parsedNum][i] = removeEndChar( | ||
| font[parsedNum][i], | ||
| i, | ||
| opts.height | ||
| ); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| figFonts[fontName] = font; | ||
| return opts; | ||
| }; | ||
| me.loadedFonts = () => { | ||
| return Object.keys(figFonts); | ||
| }; | ||
| me.clearLoadedFonts = () => { | ||
| Object.keys(figFonts).forEach((key) => { | ||
| delete figFonts[key]; | ||
| }); | ||
| }; | ||
| me.loadFont = async function(fontName, callback) { | ||
| const actualFontName = getFontName(fontName); | ||
| if (figFonts[actualFontName]) { | ||
| const result = figFonts[actualFontName].options; | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return Promise.resolve(result); | ||
| } | ||
| try { | ||
| if (!figDefaults.fetchFontIfMissing) { | ||
| throw new Error(`Font is not loaded: ${actualFontName}`); | ||
| } | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error(`Network response was not ok: ${response.status}`); | ||
| } | ||
| const text = await response.text(); | ||
| const result = me.parseFont(actualFontName, text); | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return result; | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return null; | ||
| } | ||
| throw err; | ||
| } | ||
| }; | ||
| me.loadFontSync = function(name) { | ||
| const actualFontName = getFontName(name); | ||
| if (figFonts[actualFontName]) { | ||
| return figFonts[actualFontName].options; | ||
| } | ||
| throw new Error( | ||
| "Synchronous font loading is not implemented for the browser, it will only work for fonts already loaded." | ||
| ); | ||
| }; | ||
| me.preloadFonts = async function(fonts, callback) { | ||
| try { | ||
| for (const name of fonts) { | ||
| const actualFontName = getFontName(name); | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error( | ||
| `Failed to preload fonts. Error fetching font: ${actualFontName}, status code: ${response.statusText}` | ||
| ); | ||
| } | ||
| const data = await response.text(); | ||
| me.parseFont(actualFontName, data); | ||
| } | ||
| if (callback) { | ||
| callback(); | ||
| } | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.fonts = function(callback) { | ||
| return new Promise(function(resolve, reject) { | ||
| resolve(fontList); | ||
| if (callback) { | ||
| callback(null, fontList); | ||
| } | ||
| }); | ||
| }; | ||
| me.fontsSync = function() { | ||
| return fontList; | ||
| }; | ||
| me.figFonts = figFonts; | ||
| return me; | ||
| })(); | ||
| exports.figlet = figlet; | ||
| exports.getFontName = getFontName; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| declare const fontData: string; | ||
| export default fontData; |
| export default `tlf2a 3 3 8 -1 28 0 0 0 | ||
| =============================================================================== | ||
| This is "Future Smooth" (Future Smooth.flf), based on "Future" (future.tlf) by Sam Hocevar. This variant uses arcs instead of sharp corners to smooth out the font. Because heavy arc characters don't exist, the font uses light box drawings instead of heavy ones for consistency. | ||
| 2006/10/01 -- Sam Hocevar <sam@hocevar.net> | ||
| font creation | ||
| still missing: # % ( ) * / < > \\ ^ ~ | ||
| 2006/10/02 -- Sam Hocevar <sam@hocevar.net> | ||
| added Unicode block and line glyphs | ||
| added: % ( ) * / \\ ~ | ||
| fixed: & 2 5 X | ||
| 2026/02/19 -- John Goodliff <johng.io> | ||
| replaced ┏ with ╭ | ||
| replaced ┓ with ╮ | ||
| replaced ┗ with ╰ | ||
| replaced ┛ with ╯ | ||
| replaced heavy box drawings with light box drawings | ||
| This font is free software. It comes without any warranty, to the extent | ||
| permitted by applicable law. You can redistribute it and/or modify it under | ||
| the terms of the Do What The Fuck You Want To Public License, Version 2, | ||
| as published by Sam Hocevar. See http://sam.zoy.org/wtfpl/COPYING for more | ||
| details. | ||
| Missing characters: # < > ^ | ||
| This font is part of TOIlet’s official distribution. More information | ||
| on the TOIlet website at http://caca.zoy.org/wiki/toilet | ||
| =============================================================================== | ||
| @ | ||
| @ | ||
| @@ | ||
| ╷! | ||
| ╵! | ||
| ╵!! | ||
| ╷╷" | ||
| " | ||
| "" | ||
| @ | ||
| @ | ||
| #@@ | ||
| ╭┬╮$ | ||
| ╰┼╮$ | ||
| ╰┴╯$$ | ||
| ╭╮╷% | ||
| ╭─╯% | ||
| ╵╰╯%% | ||
| ╭╮ & | ||
| │╶┼╴& | ||
| ╰─╯ && | ||
| ╷' | ||
| ' | ||
| '' | ||
| ╭╴( | ||
| │ ( | ||
| ╰╴(( | ||
| ╶╮) | ||
| │) | ||
| ╶╯)) | ||
| ╷ ╷* | ||
| ╶┼╴* | ||
| ╵ ╵** | ||
| ╷ + | ||
| ╶┼╴+ | ||
| ╵ ++ | ||
| , | ||
| , | ||
| ╯,, | ||
| - | ||
| ╶─╴- | ||
| -- | ||
| . | ||
| . | ||
| ╵.. | ||
| ╷/ | ||
| ╭╯/ | ||
| ╵ // | ||
| ╭─╮0 | ||
| │││0 | ||
| ╰─╯00 | ||
| ╶╮ 1 | ||
| │ 1 | ||
| ╶┴╴11 | ||
| ╭─╮2 | ||
| ╭─╯2 | ||
| ╰─╴22 | ||
| ╭─╮3 | ||
| ╶─┤3 | ||
| ╰─╯33 | ||
| ╷ ╷4 | ||
| ╰─┤4 | ||
| ╵44 | ||
| ╭─╴5 | ||
| ╰─╮5 | ||
| ╰─╯55 | ||
| ╭─╮6 | ||
| ├─╮6 | ||
| ╰─╯66 | ||
| ╭─╮7 | ||
| │7 | ||
| ╵77 | ||
| ╭─╮8 | ||
| ├─┤8 | ||
| ╰─╯88 | ||
| ╭─╮9 | ||
| ╰─┤9 | ||
| ╰─╯99 | ||
| : | ||
| ╵: | ||
| ╵:: | ||
| ; | ||
| ╵; | ||
| ╯;; | ||
| @ | ||
| @ | ||
| <@@ | ||
| = | ||
| ╶─╴= | ||
| ╶─╴== | ||
| @ | ||
| @ | ||
| >@@ | ||
| ╭─╮? | ||
| ╶╯? | ||
| ╵ ?? | ||
| ╭─╮@ | ||
| │├╯@ | ||
| ╰─╴@@ | ||
| ╭─╮A | ||
| ├─┤A | ||
| ╵ ╵AA | ||
| ╭╮ B | ||
| ├┴╮B | ||
| ╰─╯BB | ||
| ╭─╴C | ||
| │ C | ||
| ╰─╴CC | ||
| ╶┬╮D | ||
| ││D | ||
| ╶┴╯DD | ||
| ╭─╴E | ||
| ├╴ E | ||
| ╰─╴EE | ||
| ╭─╴F | ||
| ├╴ F | ||
| ╵ FF | ||
| ╭─╴G | ||
| │╶╮G | ||
| ╰─╯GG | ||
| ╷ ╷H | ||
| ├─┤H | ||
| ╵ ╵HH | ||
| ╷I | ||
| │I | ||
| ╵II | ||
| ╭╮J | ||
| │J | ||
| ╰─╯JJ | ||
| ╷╭ K | ||
| ├┴╮K | ||
| ╵ ╵KK | ||
| ╷ L | ||
| │ L | ||
| ╰─╴LL | ||
| ╭┬╮M | ||
| │││M | ||
| ╵ ╵MM | ||
| ╭╮╷N | ||
| │╰┤N | ||
| ╵ ╵NN | ||
| ╭─╮O | ||
| │ │O | ||
| ╰─╯OO | ||
| ╭─╮P | ||
| ├─╯P | ||
| ╵ PP | ||
| ╭─╮Q | ||
| │╮│Q | ||
| ╭─╮R | ||
| ├┬╯R | ||
| ╵╰╴RR | ||
| ╭─╮S | ||
| ╰─╮S | ||
| ╰─╯SS | ||
| ╶┬╴T | ||
| │ T | ||
| ╵ TT | ||
| ╷ ╷U | ||
| │ │U | ||
| ╰─╯UU | ||
| ╷ ╷V | ||
| │╭╯V | ||
| ╰╯ VV | ||
| ╷ ╷W | ||
| │╷│W | ||
| ╰┴╯WW | ||
| ╷ ╷X | ||
| ╭┼╯X | ||
| ╵ ╵XX | ||
| ╷ ╷Y | ||
| ╰┬╯Y | ||
| ╵ YY | ||
| ╶─╮Z | ||
| ╭─╯Z | ||
| ╰─╴ZZ | ||
| ╭─ [ | ||
| │ [ | ||
| ╰─ [[ | ||
| ╷ \\ | ||
| ╰╮\\ | ||
| ╵\\\\ | ||
| ─╮] | ||
| │] | ||
| ─╯]] | ||
| @ | ||
| @ | ||
| ^@@ | ||
| _ | ||
| _ | ||
| ╶─╴__ | ||
| ╮\` | ||
| \` | ||
| \`\` | ||
| ╭─╮a | ||
| ├─┤a | ||
| ╵ ╵aa | ||
| ╭╮ b | ||
| ├┴╮b | ||
| ╰─╯bb | ||
| ╭─╴c | ||
| │ c | ||
| ╰─╴cc | ||
| ╶┬╮d | ||
| ││d | ||
| ╶┴╯dd | ||
| ╭─╴e | ||
| ├╴ e | ||
| ╰─╴ee | ||
| ╭─╴f | ||
| ├╴ f | ||
| ╵ ff | ||
| ╭─╴g | ||
| │╶╮g | ||
| ╰─╯gg | ||
| ╷ ╷h | ||
| ├─┤h | ||
| ╵ ╵hh | ||
| ╷i | ||
| │i | ||
| ╵ii | ||
| ╭╮j | ||
| │j | ||
| ╰─╯jj | ||
| ╷╭ k | ||
| ├┴╮k | ||
| ╵ ╵kk | ||
| ╷ l | ||
| │ l | ||
| ╰─╴ll | ||
| ╭┬╮m | ||
| │││m | ||
| ╵ ╵mm | ||
| ╭╮╷n | ||
| │╰┤n | ||
| ╵ ╵nn | ||
| ╭─╮o | ||
| │ │o | ||
| ╰─╯oo | ||
| ╭─╮p | ||
| ├─╯p | ||
| ╵ pp | ||
| ╭─╮q | ||
| │╮│q | ||
| ╭─╮r | ||
| ├┬╯r | ||
| ╵╰╴rr | ||
| ╭─╮s | ||
| ╰─╮s | ||
| ╰─╯ss | ||
| ╶┬╴t | ||
| │ t | ||
| ╵ tt | ||
| ╷ ╷u | ||
| │ │u | ||
| ╰─╯uu | ||
| ╷ ╷v | ||
| │╭╯v | ||
| ╰╯ vv | ||
| ╷ ╷w | ||
| │╷│w | ||
| ╰┴╯ww | ||
| ╷ ╷x | ||
| ╭┼╯x | ||
| ╵ ╵xx | ||
| ╷ ╷y | ||
| ╰┬╯y | ||
| ╵ yy | ||
| ╶─╮z | ||
| ╭─╯z | ||
| ╰─╴zz | ||
| ╭╴{ | ||
| ╶┤ { | ||
| ╰╴{{ | ||
| ╷| | ||
| │| | ||
| ╵|| | ||
| ╶╮ } | ||
| ├╴} | ||
| ╶╯ }} | ||
| ~ | ||
| ╭─╯~ | ||
| ~~ | ||
| ╭─╮╭─╴Ä | ||
| ├─┤├╴ Ä | ||
| ╵ ╵╰─╴ÄÄ | ||
| ╭─╮╭─╴Ö | ||
| │ │├╴ Ö | ||
| ╰─╯╰─╴ÖÖ | ||
| ╷ ╷╭─╴Ü | ||
| │ │├╴ Ü | ||
| ╰─╯╰─╴ÜÜ | ||
| ╭─╮╭─╴ä | ||
| ├─┤├╴ ä | ||
| ╵ ╵╰─╴ää | ||
| ╭─╮╭─╴ö | ||
| │ │├╴ ö | ||
| ╰─╯╰─╴öö | ||
| ╷ ╷╭─╴ü | ||
| │ │├╴ ü | ||
| ╰─╯╰─╴üü | ||
| ╭─╮╭─╮ß | ||
| ╰─╮╰─╮ß | ||
| ╰─╯╰─╯ßß | ||
| 0x2500 ─ BOX DRAWINGS LIGHT HORIZONTAL | ||
| @ | ||
| ───@ | ||
| @@ | ||
| 0x2501 ━ BOX DRAWINGS HEAVY HORIZONTAL | ||
| @ | ||
| ■■■@ | ||
| @@ | ||
| 0x2502 │ BOX DRAWINGS LIGHT VERTICAL | ||
| │ @ | ||
| │ @ | ||
| │@@ | ||
| 0x2503 ┃ BOX DRAWINGS HEAVY VERTICAL | ||
| █ @ | ||
| █ @ | ||
| █@@ | ||
| 0x250C ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT | ||
| @ | ||
| ╭─@ | ||
| │ @@ | ||
| 0x250F ┏ BOX DRAWINGS HEAVY DOWN AND RIGHT | ||
| @ | ||
| ▄■@ | ||
| █ @@ | ||
| 0x2510 ┐ BOX DRAWINGS LIGHT DOWN AND LEFT | ||
| @ | ||
| ─╮ @ | ||
| │@@ | ||
| 0x2513 ┓ BOX DRAWINGS HEAVY DOWN AND LEFT | ||
| @ | ||
| ■▄ @ | ||
| █@@ | ||
| 0x2514 └ BOX DRAWINGS LIGHT UP AND RIGHT | ||
| │ @ | ||
| ╰─@ | ||
| @@ | ||
| 0x2517 ┗ BOX DRAWINGS HEAVY UP AND RIGHT | ||
| █ @ | ||
| ▀■@ | ||
| @@ | ||
| 0x2518 ┘ BOX DRAWINGS LIGHT UP AND LEFT | ||
| │ @ | ||
| ─╯ @ | ||
| @@ | ||
| 0x251B ┛ BOX DRAWINGS HEAVY UP AND LEFT | ||
| █ @ | ||
| ■▀ @ | ||
| @@ | ||
| 0x251c ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT | ||
| │ @ | ||
| ├─@ | ||
| │ @@ | ||
| 0x2523 ┣ BOX DRAWINGS HEAVY VERTICAL AND RIGHT | ||
| █ @ | ||
| █■@ | ||
| █ @@ | ||
| 0x2524 ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT | ||
| │ @ | ||
| ─┤ @ | ||
| │@@ | ||
| 0x252B ┫ BOX DRAWINGS HEAVY VERTICAL AND LEFT | ||
| █ @ | ||
| ■█ @ | ||
| █@@ | ||
| 0x252c ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL | ||
| @ | ||
| ─┬─@ | ||
| │ @@ | ||
| 0x2533 ┳ BOX DRAWINGS HEAVY DOWN AND HORIZONTAL | ||
| @ | ||
| ■▄■@ | ||
| █ @@ | ||
| 0x2534 ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL | ||
| │ @ | ||
| ─┴─@ | ||
| @@ | ||
| 0x253B ┻ BOX DRAWINGS HEAVY UP AND HORIZONTAL | ||
| █ @ | ||
| ■▀■@ | ||
| @@ | ||
| 0x253c ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL | ||
| │ @ | ||
| ─┼─@ | ||
| │ @@ | ||
| 0x254B ╋ BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL | ||
| █ @ | ||
| ■█■@ | ||
| █ @@ | ||
| 0x2578 ╸ BOX DRAWINGS HEAVY LEFT | ||
| @ | ||
| ■■ @ | ||
| @@ | ||
| 0x2579 ╹ BOX DRAWINGS HEAVY UP | ||
| █ @ | ||
| ▀ @ | ||
| @@ | ||
| 0x257A ╺ BOX DRAWINGS HEAVY RIGHT | ||
| @ | ||
| ■■@ | ||
| @@ | ||
| 0x257B ╻ BOX DRAWINGS HEAVY DOWN | ||
| @ | ||
| ▄ @ | ||
| █@@ | ||
| 0x2580 ▀ UPPER HALF BLOCK | ||
| ███@ | ||
| ▀▀▀@ | ||
| @@ | ||
| 0x2584 ▄ LOWER HALF BLOCK | ||
| @ | ||
| ▄▄▄@ | ||
| ███@ | ||
| 0x2588 █ FULL BLOCK | ||
| ███@ | ||
| ███@ | ||
| ███@@ | ||
| 0x25A0 ■ BLACK SQUARE | ||
| ▄▄▄@ | ||
| ███@ | ||
| ▀▀▀@@ | ||
| 0x5350 卐 CJK UNIFIED IDEOGRAPH-5350 | ||
| ╷╭╴@ | ||
| ╰┼╮@ | ||
| ╶╯╵@@ | ||
| 0x534D 卍 CJK UNIFIED IDEOGRAPH-534D | ||
| ╶╮╷@ | ||
| ╭┼╯@ | ||
| ╵╰╴@@ | ||
| ` |
| declare const fontData: string; | ||
| export default fontData; |
| export default `tlf2a 3 3 8 -1 24 0 0 0 | ||
| =============================================================================== | ||
| This is "Future Thin" (Future Thin.flf), based on "Future" (future.tlf) by Sam Hocevar. This variant uses light box drawing characters for a thinner look. | ||
| 2006/10/01 -- Sam Hocevar <sam@hocevar.net> | ||
| font creation | ||
| still missing: # % ( ) * / < > \\ ^ ~ | ||
| 2006/10/02 -- Sam Hocevar <sam@hocevar.net> | ||
| added Unicode block and line glyphs | ||
| added: % ( ) * / \\ ~ | ||
| fixed: & 2 5 X | ||
| 2026/02/19 -- John Goodliff <johng.io> | ||
| replaced heavy box drawings with light box drawings | ||
| This font is free software. It comes without any warranty, to the extent | ||
| permitted by applicable law. You can redistribute it and/or modify it under | ||
| the terms of the Do What The Fuck You Want To Public License, Version 2, | ||
| as published by Sam Hocevar. See http://sam.zoy.org/wtfpl/COPYING for more | ||
| details. | ||
| Missing characters: # < > ^ | ||
| This font is part of TOIlet’s official distribution. More information | ||
| on the TOIlet website at http://caca.zoy.org/wiki/toilet | ||
| =============================================================================== | ||
| @ | ||
| @ | ||
| @@ | ||
| ╷! | ||
| ╵! | ||
| ╵!! | ||
| ╷╷" | ||
| " | ||
| "" | ||
| @ | ||
| @ | ||
| #@@ | ||
| ┌┬┐$ | ||
| └┼┐$ | ||
| └┴┘$$ | ||
| ┌┐╷% | ||
| ┌─┘% | ||
| ╵└┘%% | ||
| ┌┐ & | ||
| │╶┼╴& | ||
| └─┘ && | ||
| ╷' | ||
| ' | ||
| '' | ||
| ┌╴( | ||
| │ ( | ||
| └╴(( | ||
| ╶┐) | ||
| │) | ||
| ╶┘)) | ||
| ╷ ╷* | ||
| ╶┼╴* | ||
| ╵ ╵** | ||
| ╷ + | ||
| ╶┼╴+ | ||
| ╵ ++ | ||
| , | ||
| , | ||
| ┘,, | ||
| - | ||
| ╶─╴- | ||
| -- | ||
| . | ||
| . | ||
| ╵.. | ||
| ╷/ | ||
| ┌┘/ | ||
| ╵ // | ||
| ┌─┐0 | ||
| │││0 | ||
| └─┘00 | ||
| ╶┐ 1 | ||
| │ 1 | ||
| ╶┴╴11 | ||
| ┌─┐2 | ||
| ┌─┘2 | ||
| └─╴22 | ||
| ┌─┐3 | ||
| ╶─┤3 | ||
| └─┘33 | ||
| ╷ ╷4 | ||
| └─┤4 | ||
| ╵44 | ||
| ┌─╴5 | ||
| └─┐5 | ||
| └─┘55 | ||
| ┌─┐6 | ||
| ├─┐6 | ||
| └─┘66 | ||
| ┌─┐7 | ||
| │7 | ||
| ╵77 | ||
| ┌─┐8 | ||
| ├─┤8 | ||
| └─┘88 | ||
| ┌─┐9 | ||
| └─┤9 | ||
| └─┘99 | ||
| : | ||
| ╵: | ||
| ╵:: | ||
| ; | ||
| ╵; | ||
| ┘;; | ||
| @ | ||
| @ | ||
| <@@ | ||
| = | ||
| ╶─╴= | ||
| ╶─╴== | ||
| @ | ||
| @ | ||
| >@@ | ||
| ┌─┐? | ||
| ╶┘? | ||
| ╵ ?? | ||
| ┌─┐@ | ||
| │├┘@ | ||
| └─╴@@ | ||
| ┌─┐A | ||
| ├─┤A | ||
| ╵ ╵AA | ||
| ┌┐ B | ||
| ├┴┐B | ||
| └─┘BB | ||
| ┌─╴C | ||
| │ C | ||
| └─╴CC | ||
| ╶┬┐D | ||
| ││D | ||
| ╶┴┘DD | ||
| ┌─╴E | ||
| ├╴ E | ||
| └─╴EE | ||
| ┌─╴F | ||
| ├╴ F | ||
| ╵ FF | ||
| ┌─╴G | ||
| │╶┐G | ||
| └─┘GG | ||
| ╷ ╷H | ||
| ├─┤H | ||
| ╵ ╵HH | ||
| ╷I | ||
| │I | ||
| ╵II | ||
| ┌┐J | ||
| │J | ||
| └─┘JJ | ||
| ╷┌ K | ||
| ├┴┐K | ||
| ╵ ╵KK | ||
| ╷ L | ||
| │ L | ||
| └─╴LL | ||
| ┌┬┐M | ||
| │││M | ||
| ╵ ╵MM | ||
| ┌┐╷N | ||
| │└┤N | ||
| ╵ ╵NN | ||
| ┌─┐O | ||
| │ │O | ||
| └─┘OO | ||
| ┌─┐P | ||
| ├─┘P | ||
| ╵ PP | ||
| ┌─┐Q | ||
| │┐│Q | ||
| ┌─┐R | ||
| ├┬┘R | ||
| ╵└╴RR | ||
| ┌─┐S | ||
| └─┐S | ||
| └─┘SS | ||
| ╶┬╴T | ||
| │ T | ||
| ╵ TT | ||
| ╷ ╷U | ||
| │ │U | ||
| └─┘UU | ||
| ╷ ╷V | ||
| │┌┘V | ||
| └┘ VV | ||
| ╷ ╷W | ||
| │╷│W | ||
| └┴┘WW | ||
| ╷ ╷X | ||
| ┌┼┘X | ||
| ╵ ╵XX | ||
| ╷ ╷Y | ||
| └┬┘Y | ||
| ╵ YY | ||
| ╶─┐Z | ||
| ┌─┘Z | ||
| └─╴ZZ | ||
| ┌─ [ | ||
| │ [ | ||
| └─ [[ | ||
| ╷ \\ | ||
| └┐\\ | ||
| ╵\\\\ | ||
| ─┐] | ||
| │] | ||
| ─┘]] | ||
| @ | ||
| @ | ||
| ^@@ | ||
| _ | ||
| _ | ||
| ╶─╴__ | ||
| ┐\` | ||
| \` | ||
| \`\` | ||
| ┌─┐a | ||
| ├─┤a | ||
| ╵ ╵aa | ||
| ┌┐ b | ||
| ├┴┐b | ||
| └─┘bb | ||
| ┌─╴c | ||
| │ c | ||
| └─╴cc | ||
| ╶┬┐d | ||
| ││d | ||
| ╶┴┘dd | ||
| ┌─╴e | ||
| ├╴ e | ||
| └─╴ee | ||
| ┌─╴f | ||
| ├╴ f | ||
| ╵ ff | ||
| ┌─╴g | ||
| │╶┐g | ||
| └─┘gg | ||
| ╷ ╷h | ||
| ├─┤h | ||
| ╵ ╵hh | ||
| ╷i | ||
| │i | ||
| ╵ii | ||
| ┌┐j | ||
| │j | ||
| └─┘jj | ||
| ╷┌ k | ||
| ├┴┐k | ||
| ╵ ╵kk | ||
| ╷ l | ||
| │ l | ||
| └─╴ll | ||
| ┌┬┐m | ||
| │││m | ||
| ╵ ╵mm | ||
| ┌┐╷n | ||
| │└┤n | ||
| ╵ ╵nn | ||
| ┌─┐o | ||
| │ │o | ||
| └─┘oo | ||
| ┌─┐p | ||
| ├─┘p | ||
| ╵ pp | ||
| ┌─┐q | ||
| │┐│q | ||
| ┌─┐r | ||
| ├┬┘r | ||
| ╵└╴rr | ||
| ┌─┐s | ||
| └─┐s | ||
| └─┘ss | ||
| ╶┬╴t | ||
| │ t | ||
| ╵ tt | ||
| ╷ ╷u | ||
| │ │u | ||
| └─┘uu | ||
| ╷ ╷v | ||
| │┌┘v | ||
| └┘ vv | ||
| ╷ ╷w | ||
| │╷│w | ||
| └┴┘ww | ||
| ╷ ╷x | ||
| ┌┼┘x | ||
| ╵ ╵xx | ||
| ╷ ╷y | ||
| └┬┘y | ||
| ╵ yy | ||
| ╶─┐z | ||
| ┌─┘z | ||
| └─╴zz | ||
| ┌╴{ | ||
| ╶┤ { | ||
| └╴{{ | ||
| ╷| | ||
| │| | ||
| ╵|| | ||
| ╶┐ } | ||
| ├╴} | ||
| ╶┘ }} | ||
| ~ | ||
| ┌─┘~ | ||
| ~~ | ||
| ┌─┐┌─╴Ä | ||
| ├─┤├╴ Ä | ||
| ╵ ╵└─╴ÄÄ | ||
| ┌─┐┌─╴Ö | ||
| │ │├╴ Ö | ||
| └─┘└─╴ÖÖ | ||
| ╷ ╷┌─╴Ü | ||
| │ │├╴ Ü | ||
| └─┘└─╴ÜÜ | ||
| ┌─┐┌─╴ä | ||
| ├─┤├╴ ä | ||
| ╵ ╵└─╴ää | ||
| ┌─┐┌─╴ö | ||
| │ │├╴ ö | ||
| └─┘└─╴öö | ||
| ╷ ╷┌─╴ü | ||
| │ │├╴ ü | ||
| └─┘└─╴üü | ||
| ┌─┐┌─┐ß | ||
| └─┐└─┐ß | ||
| └─┘└─┘ßß | ||
| 0x2500 ─ BOX DRAWINGS LIGHT HORIZONTAL | ||
| @ | ||
| ───@ | ||
| @@ | ||
| 0x2501 ━ BOX DRAWINGS HEAVY HORIZONTAL | ||
| @ | ||
| ■■■@ | ||
| @@ | ||
| 0x2502 │ BOX DRAWINGS LIGHT VERTICAL | ||
| │ @ | ||
| │ @ | ||
| │@@ | ||
| 0x2503 ┃ BOX DRAWINGS HEAVY VERTICAL | ||
| █ @ | ||
| █ @ | ||
| █@@ | ||
| 0x250C ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT | ||
| @ | ||
| ┌─@ | ||
| │ @@ | ||
| 0x250F ┏ BOX DRAWINGS HEAVY DOWN AND RIGHT | ||
| @ | ||
| ▄■@ | ||
| █ @@ | ||
| 0x2510 ┐ BOX DRAWINGS LIGHT DOWN AND LEFT | ||
| @ | ||
| ─┐ @ | ||
| │@@ | ||
| 0x2513 ┓ BOX DRAWINGS HEAVY DOWN AND LEFT | ||
| @ | ||
| ■▄ @ | ||
| █@@ | ||
| 0x2514 └ BOX DRAWINGS LIGHT UP AND RIGHT | ||
| │ @ | ||
| └─@ | ||
| @@ | ||
| 0x2517 ┗ BOX DRAWINGS HEAVY UP AND RIGHT | ||
| █ @ | ||
| ▀■@ | ||
| @@ | ||
| 0x2518 ┘ BOX DRAWINGS LIGHT UP AND LEFT | ||
| │ @ | ||
| ─┘ @ | ||
| @@ | ||
| 0x251B ┛ BOX DRAWINGS HEAVY UP AND LEFT | ||
| █ @ | ||
| ■▀ @ | ||
| @@ | ||
| 0x251c ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT | ||
| │ @ | ||
| ├─@ | ||
| │ @@ | ||
| 0x2523 ┣ BOX DRAWINGS HEAVY VERTICAL AND RIGHT | ||
| █ @ | ||
| █■@ | ||
| █ @@ | ||
| 0x2524 ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT | ||
| │ @ | ||
| ─┤ @ | ||
| │@@ | ||
| 0x252B ┫ BOX DRAWINGS HEAVY VERTICAL AND LEFT | ||
| █ @ | ||
| ■█ @ | ||
| █@@ | ||
| 0x252c ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL | ||
| @ | ||
| ─┬─@ | ||
| │ @@ | ||
| 0x2533 ┳ BOX DRAWINGS HEAVY DOWN AND HORIZONTAL | ||
| @ | ||
| ■▄■@ | ||
| █ @@ | ||
| 0x2534 ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL | ||
| │ @ | ||
| ─┴─@ | ||
| @@ | ||
| 0x253B ┻ BOX DRAWINGS HEAVY UP AND HORIZONTAL | ||
| █ @ | ||
| ■▀■@ | ||
| @@ | ||
| 0x253c ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL | ||
| │ @ | ||
| ─┼─@ | ||
| │ @@ | ||
| 0x254B ╋ BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL | ||
| █ @ | ||
| ■█■@ | ||
| █ @@ | ||
| 0x2578 ╸ BOX DRAWINGS HEAVY LEFT | ||
| @ | ||
| ■■ @ | ||
| @@ | ||
| 0x2579 ╹ BOX DRAWINGS HEAVY UP | ||
| █ @ | ||
| ▀ @ | ||
| @@ | ||
| 0x257A ╺ BOX DRAWINGS HEAVY RIGHT | ||
| @ | ||
| ■■@ | ||
| @@ | ||
| 0x257B ╻ BOX DRAWINGS HEAVY DOWN | ||
| @ | ||
| ▄ @ | ||
| █@@ | ||
| 0x2580 ▀ UPPER HALF BLOCK | ||
| ███@ | ||
| ▀▀▀@ | ||
| @@ | ||
| 0x2584 ▄ LOWER HALF BLOCK | ||
| @ | ||
| ▄▄▄@ | ||
| ███@ | ||
| 0x2588 █ FULL BLOCK | ||
| ███@ | ||
| ███@ | ||
| ███@@ | ||
| 0x25A0 ■ BLACK SQUARE | ||
| ▄▄▄@ | ||
| ███@ | ||
| ▀▀▀@@ | ||
| 0x5350 卐 CJK UNIFIED IDEOGRAPH-5350 | ||
| ╷┌╴@ | ||
| └┼┐@ | ||
| ╶┘╵@@ | ||
| 0x534D 卍 CJK UNIFIED IDEOGRAPH-534D | ||
| ╶┐╷@ | ||
| ┌┼┘@ | ||
| ╵└╴@@ | ||
| ` |
+1
-1
| "use strict"; | ||
| const figlet = require("./figlet-CZhFEDtO.cjs"); | ||
| const figlet = require("./figlet-DvMutUbn.cjs"); | ||
| module.exports = figlet.figlet; |
+1
-1
@@ -1,4 +0,4 @@ | ||
| import { f } from "./figlet-B0EdFl3_.js"; | ||
| import { f } from "./figlet-C8Ns3Vyn.js"; | ||
| export { | ||
| f as default | ||
| }; |
| "use strict"; | ||
| const fs = require("fs"); | ||
| const path = require("path"); | ||
| const figlet = require("./figlet-CZhFEDtO.cjs"); | ||
| const figlet = require("./figlet-DvMutUbn.cjs"); | ||
| const url = require("url"); | ||
@@ -6,0 +6,0 @@ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null; |
| import * as fs from "fs"; | ||
| import * as path from "path"; | ||
| import { f as figlet, g as getFontName } from "./figlet-B0EdFl3_.js"; | ||
| import { f as figlet, g as getFontName } from "./figlet-C8Ns3Vyn.js"; | ||
| import { fileURLToPath } from "url"; | ||
@@ -5,0 +5,0 @@ const __filename = fileURLToPath(import.meta.url); |
+1
-1
| { | ||
| "name": "figlet", | ||
| "version": "1.10.0", | ||
| "version": "1.11.0", | ||
| "description": "Creates ASCII Art from text. A full implementation of the FIGfont spec.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+1
-0
@@ -441,2 +441,3 @@ ``` | ||
| - 2025.03.08 v1.11.0 Added Future Thin and Future Smooth fonts. | ||
| - 2025.12.25 v1.10.0 Renamed "ANSI-Compact" to "ANSI Compact" (with backward compatibility). Added the fonts: Classy, Coder Mini, and Font Font. Fixed the "U" characters in the "Isometric 4" font. | ||
@@ -443,0 +444,0 @@ - 2025.11.15 v1.9.4 Added the "ANSI-Compact" font and adjustments for older versions of Node |
| const LAYOUT = { | ||
| FULL_WIDTH: 0, | ||
| FITTING: 1, | ||
| SMUSHING: 2, | ||
| CONTROLLED_SMUSHING: 3 | ||
| }; | ||
| class FigletFont { | ||
| constructor() { | ||
| this.comment = ""; | ||
| this.numChars = 0; | ||
| this.options = {}; | ||
| } | ||
| } | ||
| const fontList = [ | ||
| "1Row", | ||
| "3-D", | ||
| "3D Diagonal", | ||
| "3D-ASCII", | ||
| "3x5", | ||
| "4Max", | ||
| "5 Line Oblique", | ||
| "AMC 3 Line", | ||
| "AMC 3 Liv1", | ||
| "AMC AAA01", | ||
| "AMC Neko", | ||
| "AMC Razor", | ||
| "AMC Razor2", | ||
| "AMC Slash", | ||
| "AMC Slider", | ||
| "AMC Thin", | ||
| "AMC Tubes", | ||
| "AMC Untitled", | ||
| "ANSI Compact", | ||
| "ANSI Regular", | ||
| "ANSI Shadow", | ||
| "ASCII 12", | ||
| "ASCII 9", | ||
| "ASCII New Roman", | ||
| "Acrobatic", | ||
| "Alligator", | ||
| "Alligator2", | ||
| "Alpha", | ||
| "Alphabet", | ||
| "Arrows", | ||
| "Avatar", | ||
| "B1FF", | ||
| "Babyface Lame", | ||
| "Babyface Leet", | ||
| "Banner", | ||
| "Banner3-D", | ||
| "Banner3", | ||
| "Banner4", | ||
| "Barbwire", | ||
| "Basic", | ||
| "Bear", | ||
| "Bell", | ||
| "Benjamin", | ||
| "Big ASCII 12", | ||
| "Big ASCII 9", | ||
| "Big Chief", | ||
| "Big Money-ne", | ||
| "Big Money-nw", | ||
| "Big Money-se", | ||
| "Big Money-sw", | ||
| "Big Mono 12", | ||
| "Big Mono 9", | ||
| "Big", | ||
| "Bigfig", | ||
| "Binary", | ||
| "Block", | ||
| "Blocks", | ||
| "Bloody", | ||
| "BlurVision ASCII", | ||
| "Bolger", | ||
| "Braced", | ||
| "Bright", | ||
| "Broadway KB", | ||
| "Broadway", | ||
| "Bubble", | ||
| "Bulbhead", | ||
| "Caligraphy", | ||
| "Caligraphy2", | ||
| "Calvin S", | ||
| "Cards", | ||
| "Catwalk", | ||
| "Chiseled", | ||
| "Chunky", | ||
| "Circle", | ||
| "Classy", | ||
| "Coder Mini", | ||
| "Coinstak", | ||
| "Cola", | ||
| "Colossal", | ||
| "Computer", | ||
| "Contessa", | ||
| "Contrast", | ||
| "Cosmike", | ||
| "Cosmike2", | ||
| "Crawford", | ||
| "Crawford2", | ||
| "Crazy", | ||
| "Cricket", | ||
| "Cursive", | ||
| "Cyberlarge", | ||
| "Cybermedium", | ||
| "Cybersmall", | ||
| "Cygnet", | ||
| "DANC4", | ||
| "DOS Rebel", | ||
| "DWhistled", | ||
| "Dancing Font", | ||
| "Decimal", | ||
| "Def Leppard", | ||
| "Delta Corps Priest 1", | ||
| "DiamFont", | ||
| "Diamond", | ||
| "Diet Cola", | ||
| "Digital", | ||
| "Doh", | ||
| "Doom", | ||
| "Dot Matrix", | ||
| "Double Shorts", | ||
| "Double", | ||
| "Dr Pepper", | ||
| "Efti Chess", | ||
| "Efti Font", | ||
| "Efti Italic", | ||
| "Efti Piti", | ||
| "Efti Robot", | ||
| "Efti Wall", | ||
| "Efti Water", | ||
| "Electronic", | ||
| "Elite", | ||
| "Emboss 2", | ||
| "Emboss", | ||
| "Epic", | ||
| "Fender", | ||
| "Filter", | ||
| "Fire Font-k", | ||
| "Fire Font-s", | ||
| "Flipped", | ||
| "Flower Power", | ||
| "Font Font", | ||
| "Four Tops", | ||
| "Fraktur", | ||
| "Fun Face", | ||
| "Fun Faces", | ||
| "Future", | ||
| "Fuzzy", | ||
| "Georgi16", | ||
| "Georgia11", | ||
| "Ghost", | ||
| "Ghoulish", | ||
| "Glenyn", | ||
| "Goofy", | ||
| "Gothic", | ||
| "Graceful", | ||
| "Gradient", | ||
| "Graffiti", | ||
| "Greek", | ||
| "Heart Left", | ||
| "Heart Right", | ||
| "Henry 3D", | ||
| "Hex", | ||
| "Hieroglyphs", | ||
| "Hollywood", | ||
| "Horizontal Left", | ||
| "Horizontal Right", | ||
| "ICL-1900", | ||
| "Impossible", | ||
| "Invita", | ||
| "Isometric1", | ||
| "Isometric2", | ||
| "Isometric3", | ||
| "Isometric4", | ||
| "Italic", | ||
| "Ivrit", | ||
| "JS Block Letters", | ||
| "JS Bracket Letters", | ||
| "JS Capital Curves", | ||
| "JS Cursive", | ||
| "JS Stick Letters", | ||
| "Jacky", | ||
| "Jazmine", | ||
| "Jerusalem", | ||
| "Katakana", | ||
| "Kban", | ||
| "Keyboard", | ||
| "Knob", | ||
| "Konto Slant", | ||
| "Konto", | ||
| "LCD", | ||
| "Larry 3D 2", | ||
| "Larry 3D", | ||
| "Lean", | ||
| "Letter", | ||
| "Letters", | ||
| "Lil Devil", | ||
| "Line Blocks", | ||
| "Linux", | ||
| "Lockergnome", | ||
| "Madrid", | ||
| "Marquee", | ||
| "Maxfour", | ||
| "Merlin1", | ||
| "Merlin2", | ||
| "Mike", | ||
| "Mini", | ||
| "Mirror", | ||
| "Mnemonic", | ||
| "Modular", | ||
| "Mono 12", | ||
| "Mono 9", | ||
| "Morse", | ||
| "Morse2", | ||
| "Moscow", | ||
| "Mshebrew210", | ||
| "Muzzle", | ||
| "NScript", | ||
| "NT Greek", | ||
| "NV Script", | ||
| "Nancyj-Fancy", | ||
| "Nancyj-Improved", | ||
| "Nancyj-Underlined", | ||
| "Nancyj", | ||
| "Nipples", | ||
| "O8", | ||
| "OS2", | ||
| "Octal", | ||
| "Ogre", | ||
| "Old Banner", | ||
| "Pagga", | ||
| "Patorjk's Cheese", | ||
| "Patorjk-HeX", | ||
| "Pawp", | ||
| "Peaks Slant", | ||
| "Peaks", | ||
| "Pebbles", | ||
| "Pepper", | ||
| "Poison", | ||
| "Puffy", | ||
| "Puzzle", | ||
| "Pyramid", | ||
| "Rammstein", | ||
| "Rebel", | ||
| "Rectangles", | ||
| "Red Phoenix", | ||
| "Relief", | ||
| "Relief2", | ||
| "Reverse", | ||
| "Roman", | ||
| "Rot13", | ||
| "Rotated", | ||
| "Rounded", | ||
| "Rowan Cap", | ||
| "Rozzo", | ||
| "RubiFont", | ||
| "Runic", | ||
| "Runyc", | ||
| "S Blood", | ||
| "SL Script", | ||
| "Santa Clara", | ||
| "Script", | ||
| "Serifcap", | ||
| "Shaded Blocky", | ||
| "Shadow", | ||
| "Shimrod", | ||
| "Short", | ||
| "Slant Relief", | ||
| "Slant", | ||
| "Slide", | ||
| "Small ASCII 12", | ||
| "Small ASCII 9", | ||
| "Small Block", | ||
| "Small Braille", | ||
| "Small Caps", | ||
| "Small Isometric1", | ||
| "Small Keyboard", | ||
| "Small Mono 12", | ||
| "Small Mono 9", | ||
| "Small Poison", | ||
| "Small Script", | ||
| "Small Shadow", | ||
| "Small Slant", | ||
| "Small Tengwar", | ||
| "Small", | ||
| "Soft", | ||
| "Speed", | ||
| "Spliff", | ||
| "Stacey", | ||
| "Stampate", | ||
| "Stampatello", | ||
| "Standard", | ||
| "Star Strips", | ||
| "Star Wars", | ||
| "Stellar", | ||
| "Stforek", | ||
| "Stick Letters", | ||
| "Stop", | ||
| "Straight", | ||
| "Stronger Than All", | ||
| "Sub-Zero", | ||
| "Swamp Land", | ||
| "Swan", | ||
| "Sweet", | ||
| "THIS", | ||
| "Tanja", | ||
| "Tengwar", | ||
| "Term", | ||
| "Terrace", | ||
| "Test1", | ||
| "The Edge", | ||
| "Thick", | ||
| "Thin", | ||
| "Thorned", | ||
| "Three Point", | ||
| "Ticks Slant", | ||
| "Ticks", | ||
| "Tiles", | ||
| "Tinker-Toy", | ||
| "Tmplr", | ||
| "Tombstone", | ||
| "Train", | ||
| "Trek", | ||
| "Tsalagi", | ||
| "Tubular", | ||
| "Twisted", | ||
| "Two Point", | ||
| "USA Flag", | ||
| "Univers", | ||
| "Upside Down Text", | ||
| "Varsity", | ||
| "Wavescape", | ||
| "Wavy", | ||
| "Weird", | ||
| "Wet Letter", | ||
| "Whimsy", | ||
| "WideTerm", | ||
| "Wow", | ||
| "miniwi" | ||
| ]; | ||
| const renamedFonts = { | ||
| "ANSI-Compact": "ANSI Compact" | ||
| }; | ||
| const getFontName = (name) => { | ||
| return renamedFonts[name] ? renamedFonts[name] : name; | ||
| }; | ||
| function escapeRegExpChar(char) { | ||
| const specialChars = /[.*+?^${}()|[\]\\]/; | ||
| return specialChars.test(char) ? "\\" + char : char; | ||
| } | ||
| const figlet = (() => { | ||
| const { FULL_WIDTH = 0, FITTING, SMUSHING, CONTROLLED_SMUSHING } = LAYOUT; | ||
| const figFonts = {}; | ||
| const figDefaults = { | ||
| font: "Standard", | ||
| fontPath: "./fonts", | ||
| fetchFontIfMissing: true | ||
| }; | ||
| function removeEndChar(line, lineNum, fontHeight) { | ||
| const endChar = escapeRegExpChar(line.trim().slice(-1)) || "@"; | ||
| const endCharRegEx = lineNum === fontHeight - 1 ? new RegExp(endChar + endChar + "?\\s*$") : new RegExp(endChar + "\\s*$"); | ||
| return line.replace(endCharRegEx, ""); | ||
| } | ||
| function getSmushingRules(oldLayout = -1, newLayout = null) { | ||
| let rules = {}; | ||
| let val; | ||
| let codes = [ | ||
| [16384, "vLayout", SMUSHING], | ||
| [8192, "vLayout", FITTING], | ||
| [4096, "vRule5", true], | ||
| [2048, "vRule4", true], | ||
| [1024, "vRule3", true], | ||
| [512, "vRule2", true], | ||
| [256, "vRule1", true], | ||
| [128, "hLayout", SMUSHING], | ||
| [64, "hLayout", FITTING], | ||
| [32, "hRule6", true], | ||
| [16, "hRule5", true], | ||
| [8, "hRule4", true], | ||
| [4, "hRule3", true], | ||
| [2, "hRule2", true], | ||
| [1, "hRule1", true] | ||
| ]; | ||
| val = newLayout !== null ? newLayout : oldLayout; | ||
| for (const [code, rule, value] of codes) { | ||
| if (val >= code) { | ||
| val -= code; | ||
| if (rules[rule] === void 0) { | ||
| rules[rule] = value; | ||
| } | ||
| } else if (rule !== "vLayout" && rule !== "hLayout") { | ||
| rules[rule] = false; | ||
| } | ||
| } | ||
| if (typeof rules["hLayout"] === "undefined") { | ||
| if (oldLayout === 0) { | ||
| rules["hLayout"] = FITTING; | ||
| } else if (oldLayout === -1) { | ||
| rules["hLayout"] = FULL_WIDTH; | ||
| } else { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["hLayout"] = SMUSHING; | ||
| } | ||
| } | ||
| } else if (rules["hLayout"] === SMUSHING) { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| if (typeof rules["vLayout"] === "undefined") { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["vLayout"] = FULL_WIDTH; | ||
| } | ||
| } else if (rules["vLayout"] === SMUSHING) { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| return rules; | ||
| } | ||
| function hRule1_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === ch2 && ch1 !== hardBlank) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function hRule2_Smush(ch1, ch2) { | ||
| let rule2Str = "|/\\[]{}()<>"; | ||
| if (ch1 === "_") { | ||
| if (rule2Str.indexOf(ch2) !== -1) { | ||
| return ch2; | ||
| } | ||
| } else if (ch2 === "_") { | ||
| if (rule2Str.indexOf(ch1) !== -1) { | ||
| return ch1; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule3_Smush(ch1, ch2) { | ||
| let rule3Classes = "| /\\ [] {} () <>"; | ||
| let r3_pos1 = rule3Classes.indexOf(ch1); | ||
| let r3_pos2 = rule3Classes.indexOf(ch2); | ||
| if (r3_pos1 !== -1 && r3_pos2 !== -1) { | ||
| if (r3_pos1 !== r3_pos2 && Math.abs(r3_pos1 - r3_pos2) !== 1) { | ||
| const startPos = Math.max(r3_pos1, r3_pos2); | ||
| const endPos = startPos + 1; | ||
| return rule3Classes.substring(startPos, endPos); | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule4_Smush(ch1, ch2) { | ||
| let rule4Str = "[] {} ()"; | ||
| let r4_pos1 = rule4Str.indexOf(ch1); | ||
| let r4_pos2 = rule4Str.indexOf(ch2); | ||
| if (r4_pos1 !== -1 && r4_pos2 !== -1) { | ||
| if (Math.abs(r4_pos1 - r4_pos2) <= 1) { | ||
| return "|"; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule5_Smush(ch1, ch2) { | ||
| const patterns = { | ||
| "/\\": "|", | ||
| "\\/": "Y", | ||
| "><": "X" | ||
| }; | ||
| return patterns[ch1 + ch2] || false; | ||
| } | ||
| function hRule6_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === hardBlank && ch2 === hardBlank) { | ||
| return hardBlank; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule1_Smush(ch1, ch2) { | ||
| if (ch1 === ch2) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule2_Smush(ch1, ch2) { | ||
| return hRule2_Smush(ch1, ch2); | ||
| } | ||
| function vRule3_Smush(ch1, ch2) { | ||
| return hRule3_Smush(ch1, ch2); | ||
| } | ||
| function vRule4_Smush(ch1, ch2) { | ||
| if (ch1 === "-" && ch2 === "_" || ch1 === "_" && ch2 === "-") { | ||
| return "="; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule5_Smush(ch1, ch2) { | ||
| if (ch1 === "|" && ch2 === "|") { | ||
| return "|"; | ||
| } | ||
| return false; | ||
| } | ||
| function uni_Smush(ch1, ch2, hardBlank) { | ||
| if (ch2 === " " || ch2 === "") { | ||
| return ch1; | ||
| } else if (ch2 === hardBlank && ch1 !== " ") { | ||
| return ch1; | ||
| } else { | ||
| return ch2; | ||
| } | ||
| } | ||
| function canVerticalSmush(txt1, txt2, opts) { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FULL_WIDTH) { | ||
| return "invalid"; | ||
| } | ||
| let ii, len = Math.min(txt1.length, txt2.length), ch1, ch2, endSmush = false, validSmush; | ||
| if (len === 0) { | ||
| return "invalid"; | ||
| } | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = txt1.substring(ii, ii + 1); | ||
| ch2 = txt2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FITTING) { | ||
| return "invalid"; | ||
| } else if (opts.fittingRules && opts.fittingRules.vLayout === SMUSHING) { | ||
| return "end"; | ||
| } else { | ||
| if (vRule5_Smush(ch1, ch2)) { | ||
| endSmush = endSmush || false; | ||
| continue; | ||
| } | ||
| validSmush = false; | ||
| validSmush = opts.fittingRules && opts.fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| endSmush = true; | ||
| if (!validSmush) { | ||
| return "invalid"; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (endSmush) { | ||
| return "end"; | ||
| } else { | ||
| return "valid"; | ||
| } | ||
| } | ||
| function getVerticalSmushDist(lines1, lines2, opts) { | ||
| let maxDist = lines1.length; | ||
| let len1 = lines1.length; | ||
| let subLines1, subLines2, slen; | ||
| let curDist = 1; | ||
| let ii, ret, result; | ||
| while (curDist <= maxDist) { | ||
| subLines1 = lines1.slice(Math.max(0, len1 - curDist), len1); | ||
| subLines2 = lines2.slice(0, Math.min(maxDist, curDist)); | ||
| slen = subLines2.length; | ||
| result = ""; | ||
| for (ii = 0; ii < slen; ii++) { | ||
| ret = canVerticalSmush(subLines1[ii], subLines2[ii], opts); | ||
| if (ret === "end") { | ||
| result = ret; | ||
| } else if (ret === "invalid") { | ||
| result = ret; | ||
| break; | ||
| } else { | ||
| if (result === "") { | ||
| result = "valid"; | ||
| } | ||
| } | ||
| } | ||
| if (result === "invalid") { | ||
| curDist--; | ||
| break; | ||
| } | ||
| if (result === "end") { | ||
| break; | ||
| } | ||
| if (result === "valid") { | ||
| curDist++; | ||
| } | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function verticallySmushLines(line1, line2, opts) { | ||
| let ii, len = Math.min(line1.length, line2.length); | ||
| let ch1, ch2, result = "", validSmush; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = line1.substring(ii, ii + 1); | ||
| ch2 = line2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.vLayout === FITTING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else if (fittingRules.vLayout === SMUSHING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else { | ||
| validSmush = false; | ||
| validSmush = fittingRules.vRule5 ? vRule5_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| result += validSmush; | ||
| } | ||
| } else { | ||
| result += uni_Smush(ch1, ch2); | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| function verticalSmush(lines1, lines2, overlap, opts) { | ||
| let len1 = lines1.length; | ||
| let len2 = lines2.length; | ||
| let piece1 = lines1.slice(0, Math.max(0, len1 - overlap)); | ||
| let piece2_1 = lines1.slice(Math.max(0, len1 - overlap), len1); | ||
| let piece2_2 = lines2.slice(0, Math.min(overlap, len2)); | ||
| let ii, len, line, piece2 = [], piece3; | ||
| len = piece2_1.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| if (ii >= len2) { | ||
| line = piece2_1[ii]; | ||
| } else { | ||
| line = verticallySmushLines(piece2_1[ii], piece2_2[ii], opts); | ||
| } | ||
| piece2.push(line); | ||
| } | ||
| piece3 = lines2.slice(Math.min(overlap, len2), len2); | ||
| return [...piece1, ...piece2, ...piece3]; | ||
| } | ||
| function padLines(lines, numSpaces) { | ||
| const padding = " ".repeat(numSpaces); | ||
| return lines.map((line) => line + padding); | ||
| } | ||
| function smushVerticalFigLines(output, lines, opts) { | ||
| let len1 = output[0].length; | ||
| let len2 = lines[0].length; | ||
| let overlap; | ||
| if (len1 > len2) { | ||
| lines = padLines(lines, len1 - len2); | ||
| } else if (len2 > len1) { | ||
| output = padLines(output, len2 - len1); | ||
| } | ||
| overlap = getVerticalSmushDist(output, lines, opts); | ||
| return verticalSmush(output, lines, overlap, opts); | ||
| } | ||
| function getHorizontalSmushLength(txt1, txt2, opts) { | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (fittingRules.hLayout === FULL_WIDTH) { | ||
| return 0; | ||
| } | ||
| let ii, len1 = txt1.length, len2 = txt2.length; | ||
| let maxDist = len1; | ||
| let curDist = 1; | ||
| let breakAfter = false; | ||
| let seg1, seg2, ch1, ch2; | ||
| if (len1 === 0) { | ||
| return 0; | ||
| } | ||
| distCal: while (curDist <= maxDist) { | ||
| const seg1StartPos = len1 - curDist; | ||
| seg1 = txt1.substring(seg1StartPos, seg1StartPos + curDist); | ||
| seg2 = txt2.substring(0, Math.min(curDist, len2)); | ||
| for (ii = 0; ii < Math.min(curDist, len2); ii++) { | ||
| ch1 = seg1.substring(ii, ii + 1); | ||
| ch2 = seg2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } else if (fittingRules.hLayout === SMUSHING) { | ||
| if (ch1 === opts.hardBlank || ch2 === opts.hardBlank) { | ||
| curDist = curDist - 1; | ||
| } | ||
| break distCal; | ||
| } else { | ||
| breakAfter = true; | ||
| const validSmush = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank); | ||
| if (!validSmush) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (breakAfter) { | ||
| break; | ||
| } | ||
| curDist++; | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function horizontalSmush(textBlock1, textBlock2, overlap, opts) { | ||
| let ii, jj, outputFig = [], overlapStart, piece1, piece2, piece3, len1, len2, txt1, txt2; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (typeof opts.height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| for (ii = 0; ii < opts.height; ii++) { | ||
| txt1 = textBlock1[ii]; | ||
| txt2 = textBlock2[ii]; | ||
| len1 = txt1.length; | ||
| len2 = txt2.length; | ||
| overlapStart = len1 - overlap; | ||
| piece1 = txt1.slice(0, Math.max(0, overlapStart)); | ||
| piece2 = ""; | ||
| const seg1StartPos = Math.max(0, len1 - overlap); | ||
| let seg1 = txt1.substring(seg1StartPos, seg1StartPos + overlap); | ||
| let seg2 = txt2.substring(0, Math.min(overlap, len2)); | ||
| for (jj = 0; jj < overlap; jj++) { | ||
| let ch1 = jj < len1 ? seg1.substring(jj, jj + 1) : " "; | ||
| let ch2 = jj < len2 ? seg2.substring(jj, jj + 1) : " "; | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING || fittingRules.hLayout === SMUSHING) { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } else { | ||
| const nextCh = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank) || uni_Smush(ch1, ch2, opts.hardBlank); | ||
| piece2 += nextCh; | ||
| } | ||
| } else { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } | ||
| } | ||
| if (overlap >= len2) { | ||
| piece3 = ""; | ||
| } else { | ||
| piece3 = txt2.substring(overlap, overlap + Math.max(0, len2 - overlap)); | ||
| } | ||
| outputFig[ii] = piece1 + piece2 + piece3; | ||
| } | ||
| return outputFig; | ||
| } | ||
| function newFigChar(len) { | ||
| return new Array(len).fill(""); | ||
| } | ||
| const figLinesWidth = function(textLines) { | ||
| return Math.max(...textLines.map((line) => line.length)); | ||
| }; | ||
| function joinFigArray(array, len, opts) { | ||
| return array.reduce(function(acc, data) { | ||
| return horizontalSmush(acc, data.fig, data.overlap || 0, opts); | ||
| }, newFigChar(len)); | ||
| } | ||
| function breakWord(figChars, len, opts) { | ||
| for (let i = figChars.length - 1; i > 0; i--) { | ||
| const w = joinFigArray(figChars.slice(0, i), len, opts); | ||
| if (figLinesWidth(w) <= opts.width) { | ||
| return { | ||
| outputFigText: w, | ||
| chars: figChars.slice(i) | ||
| }; | ||
| } | ||
| } | ||
| return { outputFigText: newFigChar(len), chars: figChars }; | ||
| } | ||
| function generateFigTextLines(txt, figChars, opts) { | ||
| let charIndex, figChar, overlap = 0, row, outputFigText, len, height = opts.height, outputFigLines = [], maxWidth, nextFigChars = { | ||
| chars: [], | ||
| // list of characters is used to break in the middle of the word when word is longer | ||
| overlap | ||
| // chars is array of characters with {fig, overlap} and overlap is for whole word | ||
| }, figWords = [], char, isSpace, textFigWord, textFigLine, tmpBreak; | ||
| if (typeof height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| outputFigText = newFigChar(height); | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (opts.printDirection === 1) { | ||
| txt = txt.split("").reverse().join(""); | ||
| } | ||
| len = txt.length; | ||
| for (charIndex = 0; charIndex < len; charIndex++) { | ||
| char = txt.substring(charIndex, charIndex + 1); | ||
| isSpace = char.match(/\s/); | ||
| figChar = figChars[char.charCodeAt(0)]; | ||
| textFigLine = null; | ||
| if (figChar) { | ||
| if (fittingRules.hLayout !== FULL_WIDTH) { | ||
| overlap = 1e4; | ||
| for (row = 0; row < height; row++) { | ||
| overlap = Math.min( | ||
| overlap, | ||
| getHorizontalSmushLength(outputFigText[row], figChar[row], opts) | ||
| ); | ||
| } | ||
| overlap = overlap === 1e4 ? 0 : overlap; | ||
| } | ||
| if (opts.width > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| textFigWord = joinFigArray( | ||
| nextFigChars.chars.concat([ | ||
| { | ||
| fig: figChar, | ||
| overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| textFigLine = joinFigArray( | ||
| figWords.concat([ | ||
| { | ||
| fig: textFigWord, | ||
| overlap: nextFigChars.overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } else { | ||
| textFigLine = horizontalSmush( | ||
| outputFigText, | ||
| figChar, | ||
| overlap, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } | ||
| if (maxWidth >= opts.width && charIndex > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| outputFigText = joinFigArray(figWords.slice(0, -1), height, opts); | ||
| if (figWords.length > 1) { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| figWords = []; | ||
| } else { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| } | ||
| } | ||
| if (opts.width > 0 && opts.whitespaceBreak) { | ||
| if (!isSpace || charIndex === len - 1) { | ||
| nextFigChars.chars.push({ fig: figChar, overlap }); | ||
| } | ||
| if (isSpace || charIndex === len - 1) { | ||
| tmpBreak = null; | ||
| while (true) { | ||
| textFigLine = joinFigArray(nextFigChars.chars, height, opts); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| if (maxWidth >= opts.width) { | ||
| tmpBreak = breakWord(nextFigChars.chars, height, opts); | ||
| nextFigChars = { chars: tmpBreak.chars }; | ||
| outputFigLines.push(tmpBreak.outputFigText); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| if (maxWidth > 0) { | ||
| if (tmpBreak) { | ||
| figWords.push({ fig: textFigLine, overlap: 1 }); | ||
| } else { | ||
| figWords.push({ | ||
| fig: textFigLine, | ||
| overlap: nextFigChars.overlap | ||
| }); | ||
| } | ||
| } | ||
| if (isSpace) { | ||
| figWords.push({ fig: figChar, overlap }); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| if (charIndex === len - 1) { | ||
| outputFigText = joinFigArray(figWords, height, opts); | ||
| } | ||
| nextFigChars = { | ||
| chars: [], | ||
| overlap | ||
| }; | ||
| continue; | ||
| } | ||
| } | ||
| outputFigText = horizontalSmush(outputFigText, figChar, overlap, opts); | ||
| } | ||
| } | ||
| if (figLinesWidth(outputFigText) > 0) { | ||
| outputFigLines.push(outputFigText); | ||
| } | ||
| if (!opts.showHardBlanks) { | ||
| outputFigLines.forEach(function(outputFigText2) { | ||
| len = outputFigText2.length; | ||
| for (row = 0; row < len; row++) { | ||
| outputFigText2[row] = outputFigText2[row].replace( | ||
| new RegExp("\\" + opts.hardBlank, "g"), | ||
| " " | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| if (txt === "" && outputFigLines.length === 0) { | ||
| outputFigLines.push(new Array(height).fill("")); | ||
| } | ||
| return outputFigLines; | ||
| } | ||
| const getHorizontalFittingRules = function(layout, options) { | ||
| let params; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| hLayout: fittingRules.hLayout, | ||
| hRule1: fittingRules.hRule1, | ||
| hRule2: fittingRules.hRule2, | ||
| hRule3: fittingRules.hRule3, | ||
| hRule4: fittingRules.hRule4, | ||
| hRule5: fittingRules.hRule5, | ||
| hRule6: fittingRules.hRule6 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| hLayout: FULL_WIDTH, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| hLayout: FITTING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| hLayout: CONTROLLED_SMUSHING, | ||
| hRule1: true, | ||
| hRule2: true, | ||
| hRule3: true, | ||
| hRule4: true, | ||
| hRule5: true, | ||
| hRule6: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| hLayout: SMUSHING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const getVerticalFittingRules = function(layout, options) { | ||
| let params = {}; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| vLayout: fittingRules.vLayout, | ||
| vRule1: fittingRules.vRule1, | ||
| vRule2: fittingRules.vRule2, | ||
| vRule3: fittingRules.vRule3, | ||
| vRule4: fittingRules.vRule4, | ||
| vRule5: fittingRules.vRule5 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| vLayout: FULL_WIDTH, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| vLayout: FITTING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| vLayout: CONTROLLED_SMUSHING, | ||
| vRule1: true, | ||
| vRule2: true, | ||
| vRule3: true, | ||
| vRule4: true, | ||
| vRule5: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| vLayout: SMUSHING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const generateText = function(fontName, options, txt) { | ||
| txt = txt.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const actualFontName = getFontName(fontName); | ||
| let lines = txt.split("\n"); | ||
| let figLines = []; | ||
| let ii, len, output; | ||
| len = lines.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| figLines = figLines.concat( | ||
| generateFigTextLines(lines[ii], figFonts[actualFontName], options) | ||
| ); | ||
| } | ||
| len = figLines.length; | ||
| output = figLines[0]; | ||
| for (ii = 1; ii < len; ii++) { | ||
| output = smushVerticalFigLines(output, figLines[ii], options); | ||
| } | ||
| return output ? output.join("\n") : ""; | ||
| }; | ||
| function _reworkFontOpts(fontMeta, options) { | ||
| let myOpts; | ||
| if (typeof structuredClone !== "undefined") { | ||
| myOpts = structuredClone(fontMeta); | ||
| } else { | ||
| myOpts = JSON.parse(JSON.stringify(fontMeta)); | ||
| } | ||
| myOpts.showHardBlanks = options.showHardBlanks || false; | ||
| myOpts.width = options.width || -1; | ||
| myOpts.whitespaceBreak = options.whitespaceBreak || false; | ||
| if (options.horizontalLayout) { | ||
| const params = getHorizontalFittingRules( | ||
| options.horizontalLayout, | ||
| fontMeta | ||
| ); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| if (options.verticalLayout) { | ||
| const params = getVerticalFittingRules(options.verticalLayout, fontMeta); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| myOpts.printDirection = options.printDirection !== null && options.printDirection !== void 0 ? options.printDirection : fontMeta.printDirection; | ||
| return myOpts; | ||
| } | ||
| const me = async function(txt, optionsOrFontOrCallback, callback) { | ||
| return me.text(txt, optionsOrFontOrCallback, callback); | ||
| }; | ||
| me.text = async function(txt, optionsOrFontOrCallback, callback) { | ||
| txt = txt + ""; | ||
| let options, next; | ||
| if (typeof optionsOrFontOrCallback === "function") { | ||
| next = optionsOrFontOrCallback; | ||
| options = { font: figDefaults.font }; | ||
| } else if (typeof optionsOrFontOrCallback === "string") { | ||
| options = { font: optionsOrFontOrCallback }; | ||
| next = callback; | ||
| } else if (optionsOrFontOrCallback) { | ||
| options = optionsOrFontOrCallback; | ||
| next = callback; | ||
| } else { | ||
| options = { font: figDefaults.font }; | ||
| next = callback; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| const generatedTxt = fontOpts ? generateText(fontName, _reworkFontOpts(fontOpts, options), txt) : ""; | ||
| if (next) { | ||
| next(null, generatedTxt); | ||
| } | ||
| return generatedTxt; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (next) { | ||
| next(error); | ||
| return ""; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.textSync = function(txt, options) { | ||
| txt = txt + ""; | ||
| if (typeof options === "string") { | ||
| options = { font: options }; | ||
| } else { | ||
| options = options || {}; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| let fontOpts = _reworkFontOpts(me.loadFontSync(fontName), options); | ||
| return generateText(fontName, fontOpts, txt); | ||
| }; | ||
| me.metadata = async function(fontName, callback) { | ||
| fontName = fontName + ""; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| if (!fontOpts) { | ||
| throw new Error("Error loading font."); | ||
| } | ||
| const actualFontName = getFontName(fontName); | ||
| const font = figFonts[actualFontName] || {}; | ||
| const result = [fontOpts, font.comment || ""]; | ||
| if (callback) { | ||
| callback(null, fontOpts, font.comment); | ||
| } | ||
| return result; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (callback) { | ||
| callback(error); | ||
| return null; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.defaults = function(opts) { | ||
| if (opts && typeof opts === "object") { | ||
| Object.assign(figDefaults, opts); | ||
| } | ||
| if (typeof structuredClone !== "undefined") { | ||
| return structuredClone(figDefaults); | ||
| } else { | ||
| return JSON.parse(JSON.stringify(figDefaults)); | ||
| } | ||
| }; | ||
| me.parseFont = function(fontName, data, override = true) { | ||
| if (figFonts[fontName] && !override) { | ||
| return figFonts[fontName].options; | ||
| } | ||
| data = data.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const font = new FigletFont(); | ||
| const lines = data.split("\n"); | ||
| const headerLine = lines.shift(); | ||
| if (!headerLine) { | ||
| throw new Error("Invalid font file: missing header"); | ||
| } | ||
| const headerData = headerLine.split(" "); | ||
| const opts = { | ||
| hardBlank: headerData[0].substring(5, 6), | ||
| height: parseInt(headerData[1], 10), | ||
| baseline: parseInt(headerData[2], 10), | ||
| maxLength: parseInt(headerData[3], 10), | ||
| oldLayout: parseInt(headerData[4], 10), | ||
| numCommentLines: parseInt(headerData[5], 10), | ||
| printDirection: headerData[6] ? parseInt(headerData[6], 10) : 0, | ||
| fullLayout: headerData[7] ? parseInt(headerData[7], 10) : null, | ||
| codeTagCount: headerData[8] ? parseInt(headerData[8], 10) : null | ||
| }; | ||
| const hardBlank = opts.hardBlank || ""; | ||
| if (hardBlank.length !== 1 || [ | ||
| opts.height, | ||
| opts.baseline, | ||
| opts.maxLength, | ||
| opts.oldLayout, | ||
| opts.numCommentLines | ||
| ].some((val) => val === null || val === void 0 || isNaN(val))) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| if (opts.height == null || opts.numCommentLines == null) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| opts.fittingRules = getSmushingRules(opts.oldLayout, opts.fullLayout); | ||
| font.options = opts; | ||
| const charNums = []; | ||
| for (let i = 32; i <= 126; i++) { | ||
| charNums.push(i); | ||
| } | ||
| charNums.push(196, 214, 220, 228, 246, 252, 223); | ||
| if (lines.length < opts.numCommentLines + opts.height * charNums.length) { | ||
| throw new Error( | ||
| `FIGlet file is missing data. Line length: ${lines.length}. Comment lines: ${opts.numCommentLines}. Height: ${opts.height}. Num chars: ${charNums.length}.` | ||
| ); | ||
| } | ||
| font.comment = lines.splice(0, opts.numCommentLines).join("\n"); | ||
| font.numChars = 0; | ||
| while (lines.length > 0 && font.numChars < charNums.length) { | ||
| const cNum = charNums[font.numChars]; | ||
| font[cNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[cNum][i] === "undefined") { | ||
| font[cNum][i] = ""; | ||
| } else { | ||
| font[cNum][i] = removeEndChar(font[cNum][i], i, opts.height); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| while (lines.length > 0) { | ||
| const cNumLine = lines.shift(); | ||
| if (!cNumLine || cNumLine.trim() === "") break; | ||
| let cNum = cNumLine.split(" ")[0]; | ||
| let parsedNum; | ||
| if (/^-?0[xX][0-9a-fA-F]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 16); | ||
| } else if (/^-?0[0-7]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 8); | ||
| } else if (/^-?[0-9]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 10); | ||
| } else { | ||
| throw new Error(`Error parsing data. Invalid data: ${cNum}`); | ||
| } | ||
| if (parsedNum === -1 || parsedNum < -2147483648 || parsedNum > 2147483647) { | ||
| const msg = parsedNum === -1 ? "The char code -1 is not permitted." : `The char code cannot be ${parsedNum < -2147483648 ? "less than -2147483648" : "greater than 2147483647"}.`; | ||
| throw new Error(`Error parsing data. ${msg}`); | ||
| } | ||
| font[parsedNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[parsedNum][i] === "undefined") { | ||
| font[parsedNum][i] = ""; | ||
| } else { | ||
| font[parsedNum][i] = removeEndChar( | ||
| font[parsedNum][i], | ||
| i, | ||
| opts.height | ||
| ); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| figFonts[fontName] = font; | ||
| return opts; | ||
| }; | ||
| me.loadedFonts = () => { | ||
| return Object.keys(figFonts); | ||
| }; | ||
| me.clearLoadedFonts = () => { | ||
| Object.keys(figFonts).forEach((key) => { | ||
| delete figFonts[key]; | ||
| }); | ||
| }; | ||
| me.loadFont = async function(fontName, callback) { | ||
| const actualFontName = getFontName(fontName); | ||
| if (figFonts[actualFontName]) { | ||
| const result = figFonts[actualFontName].options; | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return Promise.resolve(result); | ||
| } | ||
| try { | ||
| if (!figDefaults.fetchFontIfMissing) { | ||
| throw new Error(`Font is not loaded: ${actualFontName}`); | ||
| } | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error(`Network response was not ok: ${response.status}`); | ||
| } | ||
| const text = await response.text(); | ||
| const result = me.parseFont(actualFontName, text); | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return result; | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return null; | ||
| } | ||
| throw err; | ||
| } | ||
| }; | ||
| me.loadFontSync = function(name) { | ||
| const actualFontName = getFontName(name); | ||
| if (figFonts[actualFontName]) { | ||
| return figFonts[actualFontName].options; | ||
| } | ||
| throw new Error( | ||
| "Synchronous font loading is not implemented for the browser, it will only work for fonts already loaded." | ||
| ); | ||
| }; | ||
| me.preloadFonts = async function(fonts, callback) { | ||
| try { | ||
| for (const name of fonts) { | ||
| const actualFontName = getFontName(name); | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error( | ||
| `Failed to preload fonts. Error fetching font: ${actualFontName}, status code: ${response.statusText}` | ||
| ); | ||
| } | ||
| const data = await response.text(); | ||
| me.parseFont(actualFontName, data); | ||
| } | ||
| if (callback) { | ||
| callback(); | ||
| } | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.fonts = function(callback) { | ||
| return new Promise(function(resolve, reject) { | ||
| resolve(fontList); | ||
| if (callback) { | ||
| callback(null, fontList); | ||
| } | ||
| }); | ||
| }; | ||
| me.fontsSync = function() { | ||
| return fontList; | ||
| }; | ||
| me.figFonts = figFonts; | ||
| return me; | ||
| })(); | ||
| export { | ||
| figlet as f, | ||
| getFontName as g | ||
| }; |
| "use strict"; | ||
| const LAYOUT = { | ||
| FULL_WIDTH: 0, | ||
| FITTING: 1, | ||
| SMUSHING: 2, | ||
| CONTROLLED_SMUSHING: 3 | ||
| }; | ||
| class FigletFont { | ||
| constructor() { | ||
| this.comment = ""; | ||
| this.numChars = 0; | ||
| this.options = {}; | ||
| } | ||
| } | ||
| const fontList = [ | ||
| "1Row", | ||
| "3-D", | ||
| "3D Diagonal", | ||
| "3D-ASCII", | ||
| "3x5", | ||
| "4Max", | ||
| "5 Line Oblique", | ||
| "AMC 3 Line", | ||
| "AMC 3 Liv1", | ||
| "AMC AAA01", | ||
| "AMC Neko", | ||
| "AMC Razor", | ||
| "AMC Razor2", | ||
| "AMC Slash", | ||
| "AMC Slider", | ||
| "AMC Thin", | ||
| "AMC Tubes", | ||
| "AMC Untitled", | ||
| "ANSI Compact", | ||
| "ANSI Regular", | ||
| "ANSI Shadow", | ||
| "ASCII 12", | ||
| "ASCII 9", | ||
| "ASCII New Roman", | ||
| "Acrobatic", | ||
| "Alligator", | ||
| "Alligator2", | ||
| "Alpha", | ||
| "Alphabet", | ||
| "Arrows", | ||
| "Avatar", | ||
| "B1FF", | ||
| "Babyface Lame", | ||
| "Babyface Leet", | ||
| "Banner", | ||
| "Banner3-D", | ||
| "Banner3", | ||
| "Banner4", | ||
| "Barbwire", | ||
| "Basic", | ||
| "Bear", | ||
| "Bell", | ||
| "Benjamin", | ||
| "Big ASCII 12", | ||
| "Big ASCII 9", | ||
| "Big Chief", | ||
| "Big Money-ne", | ||
| "Big Money-nw", | ||
| "Big Money-se", | ||
| "Big Money-sw", | ||
| "Big Mono 12", | ||
| "Big Mono 9", | ||
| "Big", | ||
| "Bigfig", | ||
| "Binary", | ||
| "Block", | ||
| "Blocks", | ||
| "Bloody", | ||
| "BlurVision ASCII", | ||
| "Bolger", | ||
| "Braced", | ||
| "Bright", | ||
| "Broadway KB", | ||
| "Broadway", | ||
| "Bubble", | ||
| "Bulbhead", | ||
| "Caligraphy", | ||
| "Caligraphy2", | ||
| "Calvin S", | ||
| "Cards", | ||
| "Catwalk", | ||
| "Chiseled", | ||
| "Chunky", | ||
| "Circle", | ||
| "Classy", | ||
| "Coder Mini", | ||
| "Coinstak", | ||
| "Cola", | ||
| "Colossal", | ||
| "Computer", | ||
| "Contessa", | ||
| "Contrast", | ||
| "Cosmike", | ||
| "Cosmike2", | ||
| "Crawford", | ||
| "Crawford2", | ||
| "Crazy", | ||
| "Cricket", | ||
| "Cursive", | ||
| "Cyberlarge", | ||
| "Cybermedium", | ||
| "Cybersmall", | ||
| "Cygnet", | ||
| "DANC4", | ||
| "DOS Rebel", | ||
| "DWhistled", | ||
| "Dancing Font", | ||
| "Decimal", | ||
| "Def Leppard", | ||
| "Delta Corps Priest 1", | ||
| "DiamFont", | ||
| "Diamond", | ||
| "Diet Cola", | ||
| "Digital", | ||
| "Doh", | ||
| "Doom", | ||
| "Dot Matrix", | ||
| "Double Shorts", | ||
| "Double", | ||
| "Dr Pepper", | ||
| "Efti Chess", | ||
| "Efti Font", | ||
| "Efti Italic", | ||
| "Efti Piti", | ||
| "Efti Robot", | ||
| "Efti Wall", | ||
| "Efti Water", | ||
| "Electronic", | ||
| "Elite", | ||
| "Emboss 2", | ||
| "Emboss", | ||
| "Epic", | ||
| "Fender", | ||
| "Filter", | ||
| "Fire Font-k", | ||
| "Fire Font-s", | ||
| "Flipped", | ||
| "Flower Power", | ||
| "Font Font", | ||
| "Four Tops", | ||
| "Fraktur", | ||
| "Fun Face", | ||
| "Fun Faces", | ||
| "Future", | ||
| "Fuzzy", | ||
| "Georgi16", | ||
| "Georgia11", | ||
| "Ghost", | ||
| "Ghoulish", | ||
| "Glenyn", | ||
| "Goofy", | ||
| "Gothic", | ||
| "Graceful", | ||
| "Gradient", | ||
| "Graffiti", | ||
| "Greek", | ||
| "Heart Left", | ||
| "Heart Right", | ||
| "Henry 3D", | ||
| "Hex", | ||
| "Hieroglyphs", | ||
| "Hollywood", | ||
| "Horizontal Left", | ||
| "Horizontal Right", | ||
| "ICL-1900", | ||
| "Impossible", | ||
| "Invita", | ||
| "Isometric1", | ||
| "Isometric2", | ||
| "Isometric3", | ||
| "Isometric4", | ||
| "Italic", | ||
| "Ivrit", | ||
| "JS Block Letters", | ||
| "JS Bracket Letters", | ||
| "JS Capital Curves", | ||
| "JS Cursive", | ||
| "JS Stick Letters", | ||
| "Jacky", | ||
| "Jazmine", | ||
| "Jerusalem", | ||
| "Katakana", | ||
| "Kban", | ||
| "Keyboard", | ||
| "Knob", | ||
| "Konto Slant", | ||
| "Konto", | ||
| "LCD", | ||
| "Larry 3D 2", | ||
| "Larry 3D", | ||
| "Lean", | ||
| "Letter", | ||
| "Letters", | ||
| "Lil Devil", | ||
| "Line Blocks", | ||
| "Linux", | ||
| "Lockergnome", | ||
| "Madrid", | ||
| "Marquee", | ||
| "Maxfour", | ||
| "Merlin1", | ||
| "Merlin2", | ||
| "Mike", | ||
| "Mini", | ||
| "Mirror", | ||
| "Mnemonic", | ||
| "Modular", | ||
| "Mono 12", | ||
| "Mono 9", | ||
| "Morse", | ||
| "Morse2", | ||
| "Moscow", | ||
| "Mshebrew210", | ||
| "Muzzle", | ||
| "NScript", | ||
| "NT Greek", | ||
| "NV Script", | ||
| "Nancyj-Fancy", | ||
| "Nancyj-Improved", | ||
| "Nancyj-Underlined", | ||
| "Nancyj", | ||
| "Nipples", | ||
| "O8", | ||
| "OS2", | ||
| "Octal", | ||
| "Ogre", | ||
| "Old Banner", | ||
| "Pagga", | ||
| "Patorjk's Cheese", | ||
| "Patorjk-HeX", | ||
| "Pawp", | ||
| "Peaks Slant", | ||
| "Peaks", | ||
| "Pebbles", | ||
| "Pepper", | ||
| "Poison", | ||
| "Puffy", | ||
| "Puzzle", | ||
| "Pyramid", | ||
| "Rammstein", | ||
| "Rebel", | ||
| "Rectangles", | ||
| "Red Phoenix", | ||
| "Relief", | ||
| "Relief2", | ||
| "Reverse", | ||
| "Roman", | ||
| "Rot13", | ||
| "Rotated", | ||
| "Rounded", | ||
| "Rowan Cap", | ||
| "Rozzo", | ||
| "RubiFont", | ||
| "Runic", | ||
| "Runyc", | ||
| "S Blood", | ||
| "SL Script", | ||
| "Santa Clara", | ||
| "Script", | ||
| "Serifcap", | ||
| "Shaded Blocky", | ||
| "Shadow", | ||
| "Shimrod", | ||
| "Short", | ||
| "Slant Relief", | ||
| "Slant", | ||
| "Slide", | ||
| "Small ASCII 12", | ||
| "Small ASCII 9", | ||
| "Small Block", | ||
| "Small Braille", | ||
| "Small Caps", | ||
| "Small Isometric1", | ||
| "Small Keyboard", | ||
| "Small Mono 12", | ||
| "Small Mono 9", | ||
| "Small Poison", | ||
| "Small Script", | ||
| "Small Shadow", | ||
| "Small Slant", | ||
| "Small Tengwar", | ||
| "Small", | ||
| "Soft", | ||
| "Speed", | ||
| "Spliff", | ||
| "Stacey", | ||
| "Stampate", | ||
| "Stampatello", | ||
| "Standard", | ||
| "Star Strips", | ||
| "Star Wars", | ||
| "Stellar", | ||
| "Stforek", | ||
| "Stick Letters", | ||
| "Stop", | ||
| "Straight", | ||
| "Stronger Than All", | ||
| "Sub-Zero", | ||
| "Swamp Land", | ||
| "Swan", | ||
| "Sweet", | ||
| "THIS", | ||
| "Tanja", | ||
| "Tengwar", | ||
| "Term", | ||
| "Terrace", | ||
| "Test1", | ||
| "The Edge", | ||
| "Thick", | ||
| "Thin", | ||
| "Thorned", | ||
| "Three Point", | ||
| "Ticks Slant", | ||
| "Ticks", | ||
| "Tiles", | ||
| "Tinker-Toy", | ||
| "Tmplr", | ||
| "Tombstone", | ||
| "Train", | ||
| "Trek", | ||
| "Tsalagi", | ||
| "Tubular", | ||
| "Twisted", | ||
| "Two Point", | ||
| "USA Flag", | ||
| "Univers", | ||
| "Upside Down Text", | ||
| "Varsity", | ||
| "Wavescape", | ||
| "Wavy", | ||
| "Weird", | ||
| "Wet Letter", | ||
| "Whimsy", | ||
| "WideTerm", | ||
| "Wow", | ||
| "miniwi" | ||
| ]; | ||
| const renamedFonts = { | ||
| "ANSI-Compact": "ANSI Compact" | ||
| }; | ||
| const getFontName = (name) => { | ||
| return renamedFonts[name] ? renamedFonts[name] : name; | ||
| }; | ||
| function escapeRegExpChar(char) { | ||
| const specialChars = /[.*+?^${}()|[\]\\]/; | ||
| return specialChars.test(char) ? "\\" + char : char; | ||
| } | ||
| const figlet = (() => { | ||
| const { FULL_WIDTH = 0, FITTING, SMUSHING, CONTROLLED_SMUSHING } = LAYOUT; | ||
| const figFonts = {}; | ||
| const figDefaults = { | ||
| font: "Standard", | ||
| fontPath: "./fonts", | ||
| fetchFontIfMissing: true | ||
| }; | ||
| function removeEndChar(line, lineNum, fontHeight) { | ||
| const endChar = escapeRegExpChar(line.trim().slice(-1)) || "@"; | ||
| const endCharRegEx = lineNum === fontHeight - 1 ? new RegExp(endChar + endChar + "?\\s*$") : new RegExp(endChar + "\\s*$"); | ||
| return line.replace(endCharRegEx, ""); | ||
| } | ||
| function getSmushingRules(oldLayout = -1, newLayout = null) { | ||
| let rules = {}; | ||
| let val; | ||
| let codes = [ | ||
| [16384, "vLayout", SMUSHING], | ||
| [8192, "vLayout", FITTING], | ||
| [4096, "vRule5", true], | ||
| [2048, "vRule4", true], | ||
| [1024, "vRule3", true], | ||
| [512, "vRule2", true], | ||
| [256, "vRule1", true], | ||
| [128, "hLayout", SMUSHING], | ||
| [64, "hLayout", FITTING], | ||
| [32, "hRule6", true], | ||
| [16, "hRule5", true], | ||
| [8, "hRule4", true], | ||
| [4, "hRule3", true], | ||
| [2, "hRule2", true], | ||
| [1, "hRule1", true] | ||
| ]; | ||
| val = newLayout !== null ? newLayout : oldLayout; | ||
| for (const [code, rule, value] of codes) { | ||
| if (val >= code) { | ||
| val -= code; | ||
| if (rules[rule] === void 0) { | ||
| rules[rule] = value; | ||
| } | ||
| } else if (rule !== "vLayout" && rule !== "hLayout") { | ||
| rules[rule] = false; | ||
| } | ||
| } | ||
| if (typeof rules["hLayout"] === "undefined") { | ||
| if (oldLayout === 0) { | ||
| rules["hLayout"] = FITTING; | ||
| } else if (oldLayout === -1) { | ||
| rules["hLayout"] = FULL_WIDTH; | ||
| } else { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["hLayout"] = SMUSHING; | ||
| } | ||
| } | ||
| } else if (rules["hLayout"] === SMUSHING) { | ||
| if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) { | ||
| rules["hLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| if (typeof rules["vLayout"] === "undefined") { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } else { | ||
| rules["vLayout"] = FULL_WIDTH; | ||
| } | ||
| } else if (rules["vLayout"] === SMUSHING) { | ||
| if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) { | ||
| rules["vLayout"] = CONTROLLED_SMUSHING; | ||
| } | ||
| } | ||
| return rules; | ||
| } | ||
| function hRule1_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === ch2 && ch1 !== hardBlank) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function hRule2_Smush(ch1, ch2) { | ||
| let rule2Str = "|/\\[]{}()<>"; | ||
| if (ch1 === "_") { | ||
| if (rule2Str.indexOf(ch2) !== -1) { | ||
| return ch2; | ||
| } | ||
| } else if (ch2 === "_") { | ||
| if (rule2Str.indexOf(ch1) !== -1) { | ||
| return ch1; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule3_Smush(ch1, ch2) { | ||
| let rule3Classes = "| /\\ [] {} () <>"; | ||
| let r3_pos1 = rule3Classes.indexOf(ch1); | ||
| let r3_pos2 = rule3Classes.indexOf(ch2); | ||
| if (r3_pos1 !== -1 && r3_pos2 !== -1) { | ||
| if (r3_pos1 !== r3_pos2 && Math.abs(r3_pos1 - r3_pos2) !== 1) { | ||
| const startPos = Math.max(r3_pos1, r3_pos2); | ||
| const endPos = startPos + 1; | ||
| return rule3Classes.substring(startPos, endPos); | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule4_Smush(ch1, ch2) { | ||
| let rule4Str = "[] {} ()"; | ||
| let r4_pos1 = rule4Str.indexOf(ch1); | ||
| let r4_pos2 = rule4Str.indexOf(ch2); | ||
| if (r4_pos1 !== -1 && r4_pos2 !== -1) { | ||
| if (Math.abs(r4_pos1 - r4_pos2) <= 1) { | ||
| return "|"; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| function hRule5_Smush(ch1, ch2) { | ||
| const patterns = { | ||
| "/\\": "|", | ||
| "\\/": "Y", | ||
| "><": "X" | ||
| }; | ||
| return patterns[ch1 + ch2] || false; | ||
| } | ||
| function hRule6_Smush(ch1, ch2, hardBlank = "") { | ||
| if (ch1 === hardBlank && ch2 === hardBlank) { | ||
| return hardBlank; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule1_Smush(ch1, ch2) { | ||
| if (ch1 === ch2) { | ||
| return ch1; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule2_Smush(ch1, ch2) { | ||
| return hRule2_Smush(ch1, ch2); | ||
| } | ||
| function vRule3_Smush(ch1, ch2) { | ||
| return hRule3_Smush(ch1, ch2); | ||
| } | ||
| function vRule4_Smush(ch1, ch2) { | ||
| if (ch1 === "-" && ch2 === "_" || ch1 === "_" && ch2 === "-") { | ||
| return "="; | ||
| } | ||
| return false; | ||
| } | ||
| function vRule5_Smush(ch1, ch2) { | ||
| if (ch1 === "|" && ch2 === "|") { | ||
| return "|"; | ||
| } | ||
| return false; | ||
| } | ||
| function uni_Smush(ch1, ch2, hardBlank) { | ||
| if (ch2 === " " || ch2 === "") { | ||
| return ch1; | ||
| } else if (ch2 === hardBlank && ch1 !== " ") { | ||
| return ch1; | ||
| } else { | ||
| return ch2; | ||
| } | ||
| } | ||
| function canVerticalSmush(txt1, txt2, opts) { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FULL_WIDTH) { | ||
| return "invalid"; | ||
| } | ||
| let ii, len = Math.min(txt1.length, txt2.length), ch1, ch2, endSmush = false, validSmush; | ||
| if (len === 0) { | ||
| return "invalid"; | ||
| } | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = txt1.substring(ii, ii + 1); | ||
| ch2 = txt2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (opts.fittingRules && opts.fittingRules.vLayout === FITTING) { | ||
| return "invalid"; | ||
| } else if (opts.fittingRules && opts.fittingRules.vLayout === SMUSHING) { | ||
| return "end"; | ||
| } else { | ||
| if (vRule5_Smush(ch1, ch2)) { | ||
| endSmush = endSmush || false; | ||
| continue; | ||
| } | ||
| validSmush = false; | ||
| validSmush = opts.fittingRules && opts.fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| endSmush = true; | ||
| if (!validSmush) { | ||
| return "invalid"; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (endSmush) { | ||
| return "end"; | ||
| } else { | ||
| return "valid"; | ||
| } | ||
| } | ||
| function getVerticalSmushDist(lines1, lines2, opts) { | ||
| let maxDist = lines1.length; | ||
| let len1 = lines1.length; | ||
| let subLines1, subLines2, slen; | ||
| let curDist = 1; | ||
| let ii, ret, result; | ||
| while (curDist <= maxDist) { | ||
| subLines1 = lines1.slice(Math.max(0, len1 - curDist), len1); | ||
| subLines2 = lines2.slice(0, Math.min(maxDist, curDist)); | ||
| slen = subLines2.length; | ||
| result = ""; | ||
| for (ii = 0; ii < slen; ii++) { | ||
| ret = canVerticalSmush(subLines1[ii], subLines2[ii], opts); | ||
| if (ret === "end") { | ||
| result = ret; | ||
| } else if (ret === "invalid") { | ||
| result = ret; | ||
| break; | ||
| } else { | ||
| if (result === "") { | ||
| result = "valid"; | ||
| } | ||
| } | ||
| } | ||
| if (result === "invalid") { | ||
| curDist--; | ||
| break; | ||
| } | ||
| if (result === "end") { | ||
| break; | ||
| } | ||
| if (result === "valid") { | ||
| curDist++; | ||
| } | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function verticallySmushLines(line1, line2, opts) { | ||
| let ii, len = Math.min(line1.length, line2.length); | ||
| let ch1, ch2, result = "", validSmush; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| for (ii = 0; ii < len; ii++) { | ||
| ch1 = line1.substring(ii, ii + 1); | ||
| ch2 = line2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.vLayout === FITTING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else if (fittingRules.vLayout === SMUSHING) { | ||
| result += uni_Smush(ch1, ch2); | ||
| } else { | ||
| validSmush = false; | ||
| validSmush = fittingRules.vRule5 ? vRule5_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush; | ||
| validSmush = !validSmush && fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush; | ||
| result += validSmush; | ||
| } | ||
| } else { | ||
| result += uni_Smush(ch1, ch2); | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| function verticalSmush(lines1, lines2, overlap, opts) { | ||
| let len1 = lines1.length; | ||
| let len2 = lines2.length; | ||
| let piece1 = lines1.slice(0, Math.max(0, len1 - overlap)); | ||
| let piece2_1 = lines1.slice(Math.max(0, len1 - overlap), len1); | ||
| let piece2_2 = lines2.slice(0, Math.min(overlap, len2)); | ||
| let ii, len, line, piece2 = [], piece3; | ||
| len = piece2_1.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| if (ii >= len2) { | ||
| line = piece2_1[ii]; | ||
| } else { | ||
| line = verticallySmushLines(piece2_1[ii], piece2_2[ii], opts); | ||
| } | ||
| piece2.push(line); | ||
| } | ||
| piece3 = lines2.slice(Math.min(overlap, len2), len2); | ||
| return [...piece1, ...piece2, ...piece3]; | ||
| } | ||
| function padLines(lines, numSpaces) { | ||
| const padding = " ".repeat(numSpaces); | ||
| return lines.map((line) => line + padding); | ||
| } | ||
| function smushVerticalFigLines(output, lines, opts) { | ||
| let len1 = output[0].length; | ||
| let len2 = lines[0].length; | ||
| let overlap; | ||
| if (len1 > len2) { | ||
| lines = padLines(lines, len1 - len2); | ||
| } else if (len2 > len1) { | ||
| output = padLines(output, len2 - len1); | ||
| } | ||
| overlap = getVerticalSmushDist(output, lines, opts); | ||
| return verticalSmush(output, lines, overlap, opts); | ||
| } | ||
| function getHorizontalSmushLength(txt1, txt2, opts) { | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (fittingRules.hLayout === FULL_WIDTH) { | ||
| return 0; | ||
| } | ||
| let ii, len1 = txt1.length, len2 = txt2.length; | ||
| let maxDist = len1; | ||
| let curDist = 1; | ||
| let breakAfter = false; | ||
| let seg1, seg2, ch1, ch2; | ||
| if (len1 === 0) { | ||
| return 0; | ||
| } | ||
| distCal: while (curDist <= maxDist) { | ||
| const seg1StartPos = len1 - curDist; | ||
| seg1 = txt1.substring(seg1StartPos, seg1StartPos + curDist); | ||
| seg2 = txt2.substring(0, Math.min(curDist, len2)); | ||
| for (ii = 0; ii < Math.min(curDist, len2); ii++) { | ||
| ch1 = seg1.substring(ii, ii + 1); | ||
| ch2 = seg2.substring(ii, ii + 1); | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } else if (fittingRules.hLayout === SMUSHING) { | ||
| if (ch1 === opts.hardBlank || ch2 === opts.hardBlank) { | ||
| curDist = curDist - 1; | ||
| } | ||
| break distCal; | ||
| } else { | ||
| breakAfter = true; | ||
| const validSmush = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank); | ||
| if (!validSmush) { | ||
| curDist = curDist - 1; | ||
| break distCal; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (breakAfter) { | ||
| break; | ||
| } | ||
| curDist++; | ||
| } | ||
| return Math.min(maxDist, curDist); | ||
| } | ||
| function horizontalSmush(textBlock1, textBlock2, overlap, opts) { | ||
| let ii, jj, outputFig = [], overlapStart, piece1, piece2, piece3, len1, len2, txt1, txt2; | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (typeof opts.height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| for (ii = 0; ii < opts.height; ii++) { | ||
| txt1 = textBlock1[ii]; | ||
| txt2 = textBlock2[ii]; | ||
| len1 = txt1.length; | ||
| len2 = txt2.length; | ||
| overlapStart = len1 - overlap; | ||
| piece1 = txt1.slice(0, Math.max(0, overlapStart)); | ||
| piece2 = ""; | ||
| const seg1StartPos = Math.max(0, len1 - overlap); | ||
| let seg1 = txt1.substring(seg1StartPos, seg1StartPos + overlap); | ||
| let seg2 = txt2.substring(0, Math.min(overlap, len2)); | ||
| for (jj = 0; jj < overlap; jj++) { | ||
| let ch1 = jj < len1 ? seg1.substring(jj, jj + 1) : " "; | ||
| let ch2 = jj < len2 ? seg2.substring(jj, jj + 1) : " "; | ||
| if (ch1 !== " " && ch2 !== " ") { | ||
| if (fittingRules.hLayout === FITTING || fittingRules.hLayout === SMUSHING) { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } else { | ||
| const nextCh = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank) || uni_Smush(ch1, ch2, opts.hardBlank); | ||
| piece2 += nextCh; | ||
| } | ||
| } else { | ||
| piece2 += uni_Smush(ch1, ch2, opts.hardBlank); | ||
| } | ||
| } | ||
| if (overlap >= len2) { | ||
| piece3 = ""; | ||
| } else { | ||
| piece3 = txt2.substring(overlap, overlap + Math.max(0, len2 - overlap)); | ||
| } | ||
| outputFig[ii] = piece1 + piece2 + piece3; | ||
| } | ||
| return outputFig; | ||
| } | ||
| function newFigChar(len) { | ||
| return new Array(len).fill(""); | ||
| } | ||
| const figLinesWidth = function(textLines) { | ||
| return Math.max(...textLines.map((line) => line.length)); | ||
| }; | ||
| function joinFigArray(array, len, opts) { | ||
| return array.reduce(function(acc, data) { | ||
| return horizontalSmush(acc, data.fig, data.overlap || 0, opts); | ||
| }, newFigChar(len)); | ||
| } | ||
| function breakWord(figChars, len, opts) { | ||
| for (let i = figChars.length - 1; i > 0; i--) { | ||
| const w = joinFigArray(figChars.slice(0, i), len, opts); | ||
| if (figLinesWidth(w) <= opts.width) { | ||
| return { | ||
| outputFigText: w, | ||
| chars: figChars.slice(i) | ||
| }; | ||
| } | ||
| } | ||
| return { outputFigText: newFigChar(len), chars: figChars }; | ||
| } | ||
| function generateFigTextLines(txt, figChars, opts) { | ||
| let charIndex, figChar, overlap = 0, row, outputFigText, len, height = opts.height, outputFigLines = [], maxWidth, nextFigChars = { | ||
| chars: [], | ||
| // list of characters is used to break in the middle of the word when word is longer | ||
| overlap | ||
| // chars is array of characters with {fig, overlap} and overlap is for whole word | ||
| }, figWords = [], char, isSpace, textFigWord, textFigLine, tmpBreak; | ||
| if (typeof height !== "number") { | ||
| throw new Error("height is not defined."); | ||
| } | ||
| outputFigText = newFigChar(height); | ||
| const fittingRules = opts.fittingRules || {}; | ||
| if (opts.printDirection === 1) { | ||
| txt = txt.split("").reverse().join(""); | ||
| } | ||
| len = txt.length; | ||
| for (charIndex = 0; charIndex < len; charIndex++) { | ||
| char = txt.substring(charIndex, charIndex + 1); | ||
| isSpace = char.match(/\s/); | ||
| figChar = figChars[char.charCodeAt(0)]; | ||
| textFigLine = null; | ||
| if (figChar) { | ||
| if (fittingRules.hLayout !== FULL_WIDTH) { | ||
| overlap = 1e4; | ||
| for (row = 0; row < height; row++) { | ||
| overlap = Math.min( | ||
| overlap, | ||
| getHorizontalSmushLength(outputFigText[row], figChar[row], opts) | ||
| ); | ||
| } | ||
| overlap = overlap === 1e4 ? 0 : overlap; | ||
| } | ||
| if (opts.width > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| textFigWord = joinFigArray( | ||
| nextFigChars.chars.concat([ | ||
| { | ||
| fig: figChar, | ||
| overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| textFigLine = joinFigArray( | ||
| figWords.concat([ | ||
| { | ||
| fig: textFigWord, | ||
| overlap: nextFigChars.overlap | ||
| } | ||
| ]), | ||
| height, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } else { | ||
| textFigLine = horizontalSmush( | ||
| outputFigText, | ||
| figChar, | ||
| overlap, | ||
| opts | ||
| ); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| } | ||
| if (maxWidth >= opts.width && charIndex > 0) { | ||
| if (opts.whitespaceBreak) { | ||
| outputFigText = joinFigArray(figWords.slice(0, -1), height, opts); | ||
| if (figWords.length > 1) { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| figWords = []; | ||
| } else { | ||
| outputFigLines.push(outputFigText); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| } | ||
| } | ||
| if (opts.width > 0 && opts.whitespaceBreak) { | ||
| if (!isSpace || charIndex === len - 1) { | ||
| nextFigChars.chars.push({ fig: figChar, overlap }); | ||
| } | ||
| if (isSpace || charIndex === len - 1) { | ||
| tmpBreak = null; | ||
| while (true) { | ||
| textFigLine = joinFigArray(nextFigChars.chars, height, opts); | ||
| maxWidth = figLinesWidth(textFigLine); | ||
| if (maxWidth >= opts.width) { | ||
| tmpBreak = breakWord(nextFigChars.chars, height, opts); | ||
| nextFigChars = { chars: tmpBreak.chars }; | ||
| outputFigLines.push(tmpBreak.outputFigText); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| if (maxWidth > 0) { | ||
| if (tmpBreak) { | ||
| figWords.push({ fig: textFigLine, overlap: 1 }); | ||
| } else { | ||
| figWords.push({ | ||
| fig: textFigLine, | ||
| overlap: nextFigChars.overlap | ||
| }); | ||
| } | ||
| } | ||
| if (isSpace) { | ||
| figWords.push({ fig: figChar, overlap }); | ||
| outputFigText = newFigChar(height); | ||
| } | ||
| if (charIndex === len - 1) { | ||
| outputFigText = joinFigArray(figWords, height, opts); | ||
| } | ||
| nextFigChars = { | ||
| chars: [], | ||
| overlap | ||
| }; | ||
| continue; | ||
| } | ||
| } | ||
| outputFigText = horizontalSmush(outputFigText, figChar, overlap, opts); | ||
| } | ||
| } | ||
| if (figLinesWidth(outputFigText) > 0) { | ||
| outputFigLines.push(outputFigText); | ||
| } | ||
| if (!opts.showHardBlanks) { | ||
| outputFigLines.forEach(function(outputFigText2) { | ||
| len = outputFigText2.length; | ||
| for (row = 0; row < len; row++) { | ||
| outputFigText2[row] = outputFigText2[row].replace( | ||
| new RegExp("\\" + opts.hardBlank, "g"), | ||
| " " | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| if (txt === "" && outputFigLines.length === 0) { | ||
| outputFigLines.push(new Array(height).fill("")); | ||
| } | ||
| return outputFigLines; | ||
| } | ||
| const getHorizontalFittingRules = function(layout, options) { | ||
| let params; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| hLayout: fittingRules.hLayout, | ||
| hRule1: fittingRules.hRule1, | ||
| hRule2: fittingRules.hRule2, | ||
| hRule3: fittingRules.hRule3, | ||
| hRule4: fittingRules.hRule4, | ||
| hRule5: fittingRules.hRule5, | ||
| hRule6: fittingRules.hRule6 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| hLayout: FULL_WIDTH, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| hLayout: FITTING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| hLayout: CONTROLLED_SMUSHING, | ||
| hRule1: true, | ||
| hRule2: true, | ||
| hRule3: true, | ||
| hRule4: true, | ||
| hRule5: true, | ||
| hRule6: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| hLayout: SMUSHING, | ||
| hRule1: false, | ||
| hRule2: false, | ||
| hRule3: false, | ||
| hRule4: false, | ||
| hRule5: false, | ||
| hRule6: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const getVerticalFittingRules = function(layout, options) { | ||
| let params = {}; | ||
| const fittingRules = options.fittingRules || {}; | ||
| if (layout === "default") { | ||
| params = { | ||
| vLayout: fittingRules.vLayout, | ||
| vRule1: fittingRules.vRule1, | ||
| vRule2: fittingRules.vRule2, | ||
| vRule3: fittingRules.vRule3, | ||
| vRule4: fittingRules.vRule4, | ||
| vRule5: fittingRules.vRule5 | ||
| }; | ||
| } else if (layout === "full") { | ||
| params = { | ||
| vLayout: FULL_WIDTH, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "fitted") { | ||
| params = { | ||
| vLayout: FITTING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else if (layout === "controlled smushing") { | ||
| params = { | ||
| vLayout: CONTROLLED_SMUSHING, | ||
| vRule1: true, | ||
| vRule2: true, | ||
| vRule3: true, | ||
| vRule4: true, | ||
| vRule5: true | ||
| }; | ||
| } else if (layout === "universal smushing") { | ||
| params = { | ||
| vLayout: SMUSHING, | ||
| vRule1: false, | ||
| vRule2: false, | ||
| vRule3: false, | ||
| vRule4: false, | ||
| vRule5: false | ||
| }; | ||
| } else { | ||
| return; | ||
| } | ||
| return params; | ||
| }; | ||
| const generateText = function(fontName, options, txt) { | ||
| txt = txt.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const actualFontName = getFontName(fontName); | ||
| let lines = txt.split("\n"); | ||
| let figLines = []; | ||
| let ii, len, output; | ||
| len = lines.length; | ||
| for (ii = 0; ii < len; ii++) { | ||
| figLines = figLines.concat( | ||
| generateFigTextLines(lines[ii], figFonts[actualFontName], options) | ||
| ); | ||
| } | ||
| len = figLines.length; | ||
| output = figLines[0]; | ||
| for (ii = 1; ii < len; ii++) { | ||
| output = smushVerticalFigLines(output, figLines[ii], options); | ||
| } | ||
| return output ? output.join("\n") : ""; | ||
| }; | ||
| function _reworkFontOpts(fontMeta, options) { | ||
| let myOpts; | ||
| if (typeof structuredClone !== "undefined") { | ||
| myOpts = structuredClone(fontMeta); | ||
| } else { | ||
| myOpts = JSON.parse(JSON.stringify(fontMeta)); | ||
| } | ||
| myOpts.showHardBlanks = options.showHardBlanks || false; | ||
| myOpts.width = options.width || -1; | ||
| myOpts.whitespaceBreak = options.whitespaceBreak || false; | ||
| if (options.horizontalLayout) { | ||
| const params = getHorizontalFittingRules( | ||
| options.horizontalLayout, | ||
| fontMeta | ||
| ); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| if (options.verticalLayout) { | ||
| const params = getVerticalFittingRules(options.verticalLayout, fontMeta); | ||
| if (params) { | ||
| Object.assign(myOpts.fittingRules, params); | ||
| } | ||
| } | ||
| myOpts.printDirection = options.printDirection !== null && options.printDirection !== void 0 ? options.printDirection : fontMeta.printDirection; | ||
| return myOpts; | ||
| } | ||
| const me = async function(txt, optionsOrFontOrCallback, callback) { | ||
| return me.text(txt, optionsOrFontOrCallback, callback); | ||
| }; | ||
| me.text = async function(txt, optionsOrFontOrCallback, callback) { | ||
| txt = txt + ""; | ||
| let options, next; | ||
| if (typeof optionsOrFontOrCallback === "function") { | ||
| next = optionsOrFontOrCallback; | ||
| options = { font: figDefaults.font }; | ||
| } else if (typeof optionsOrFontOrCallback === "string") { | ||
| options = { font: optionsOrFontOrCallback }; | ||
| next = callback; | ||
| } else if (optionsOrFontOrCallback) { | ||
| options = optionsOrFontOrCallback; | ||
| next = callback; | ||
| } else { | ||
| options = { font: figDefaults.font }; | ||
| next = callback; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| const generatedTxt = fontOpts ? generateText(fontName, _reworkFontOpts(fontOpts, options), txt) : ""; | ||
| if (next) { | ||
| next(null, generatedTxt); | ||
| } | ||
| return generatedTxt; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (next) { | ||
| next(error); | ||
| return ""; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.textSync = function(txt, options) { | ||
| txt = txt + ""; | ||
| if (typeof options === "string") { | ||
| options = { font: options }; | ||
| } else { | ||
| options = options || {}; | ||
| } | ||
| const fontName = options.font || figDefaults.font; | ||
| let fontOpts = _reworkFontOpts(me.loadFontSync(fontName), options); | ||
| return generateText(fontName, fontOpts, txt); | ||
| }; | ||
| me.metadata = async function(fontName, callback) { | ||
| fontName = fontName + ""; | ||
| try { | ||
| const fontOpts = await me.loadFont(fontName); | ||
| if (!fontOpts) { | ||
| throw new Error("Error loading font."); | ||
| } | ||
| const actualFontName = getFontName(fontName); | ||
| const font = figFonts[actualFontName] || {}; | ||
| const result = [fontOpts, font.comment || ""]; | ||
| if (callback) { | ||
| callback(null, fontOpts, font.comment); | ||
| } | ||
| return result; | ||
| } catch (err) { | ||
| const error = err instanceof Error ? err : new Error(String(err)); | ||
| if (callback) { | ||
| callback(error); | ||
| return null; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.defaults = function(opts) { | ||
| if (opts && typeof opts === "object") { | ||
| Object.assign(figDefaults, opts); | ||
| } | ||
| if (typeof structuredClone !== "undefined") { | ||
| return structuredClone(figDefaults); | ||
| } else { | ||
| return JSON.parse(JSON.stringify(figDefaults)); | ||
| } | ||
| }; | ||
| me.parseFont = function(fontName, data, override = true) { | ||
| if (figFonts[fontName] && !override) { | ||
| return figFonts[fontName].options; | ||
| } | ||
| data = data.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); | ||
| const font = new FigletFont(); | ||
| const lines = data.split("\n"); | ||
| const headerLine = lines.shift(); | ||
| if (!headerLine) { | ||
| throw new Error("Invalid font file: missing header"); | ||
| } | ||
| const headerData = headerLine.split(" "); | ||
| const opts = { | ||
| hardBlank: headerData[0].substring(5, 6), | ||
| height: parseInt(headerData[1], 10), | ||
| baseline: parseInt(headerData[2], 10), | ||
| maxLength: parseInt(headerData[3], 10), | ||
| oldLayout: parseInt(headerData[4], 10), | ||
| numCommentLines: parseInt(headerData[5], 10), | ||
| printDirection: headerData[6] ? parseInt(headerData[6], 10) : 0, | ||
| fullLayout: headerData[7] ? parseInt(headerData[7], 10) : null, | ||
| codeTagCount: headerData[8] ? parseInt(headerData[8], 10) : null | ||
| }; | ||
| const hardBlank = opts.hardBlank || ""; | ||
| if (hardBlank.length !== 1 || [ | ||
| opts.height, | ||
| opts.baseline, | ||
| opts.maxLength, | ||
| opts.oldLayout, | ||
| opts.numCommentLines | ||
| ].some((val) => val === null || val === void 0 || isNaN(val))) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| if (opts.height == null || opts.numCommentLines == null) { | ||
| throw new Error("FIGlet header contains invalid values."); | ||
| } | ||
| opts.fittingRules = getSmushingRules(opts.oldLayout, opts.fullLayout); | ||
| font.options = opts; | ||
| const charNums = []; | ||
| for (let i = 32; i <= 126; i++) { | ||
| charNums.push(i); | ||
| } | ||
| charNums.push(196, 214, 220, 228, 246, 252, 223); | ||
| if (lines.length < opts.numCommentLines + opts.height * charNums.length) { | ||
| throw new Error( | ||
| `FIGlet file is missing data. Line length: ${lines.length}. Comment lines: ${opts.numCommentLines}. Height: ${opts.height}. Num chars: ${charNums.length}.` | ||
| ); | ||
| } | ||
| font.comment = lines.splice(0, opts.numCommentLines).join("\n"); | ||
| font.numChars = 0; | ||
| while (lines.length > 0 && font.numChars < charNums.length) { | ||
| const cNum = charNums[font.numChars]; | ||
| font[cNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[cNum][i] === "undefined") { | ||
| font[cNum][i] = ""; | ||
| } else { | ||
| font[cNum][i] = removeEndChar(font[cNum][i], i, opts.height); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| while (lines.length > 0) { | ||
| const cNumLine = lines.shift(); | ||
| if (!cNumLine || cNumLine.trim() === "") break; | ||
| let cNum = cNumLine.split(" ")[0]; | ||
| let parsedNum; | ||
| if (/^-?0[xX][0-9a-fA-F]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 16); | ||
| } else if (/^-?0[0-7]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 8); | ||
| } else if (/^-?[0-9]+$/.test(cNum)) { | ||
| parsedNum = parseInt(cNum, 10); | ||
| } else { | ||
| throw new Error(`Error parsing data. Invalid data: ${cNum}`); | ||
| } | ||
| if (parsedNum === -1 || parsedNum < -2147483648 || parsedNum > 2147483647) { | ||
| const msg = parsedNum === -1 ? "The char code -1 is not permitted." : `The char code cannot be ${parsedNum < -2147483648 ? "less than -2147483648" : "greater than 2147483647"}.`; | ||
| throw new Error(`Error parsing data. ${msg}`); | ||
| } | ||
| font[parsedNum] = lines.splice(0, opts.height); | ||
| for (let i = 0; i < opts.height; i++) { | ||
| if (typeof font[parsedNum][i] === "undefined") { | ||
| font[parsedNum][i] = ""; | ||
| } else { | ||
| font[parsedNum][i] = removeEndChar( | ||
| font[parsedNum][i], | ||
| i, | ||
| opts.height | ||
| ); | ||
| } | ||
| } | ||
| font.numChars++; | ||
| } | ||
| figFonts[fontName] = font; | ||
| return opts; | ||
| }; | ||
| me.loadedFonts = () => { | ||
| return Object.keys(figFonts); | ||
| }; | ||
| me.clearLoadedFonts = () => { | ||
| Object.keys(figFonts).forEach((key) => { | ||
| delete figFonts[key]; | ||
| }); | ||
| }; | ||
| me.loadFont = async function(fontName, callback) { | ||
| const actualFontName = getFontName(fontName); | ||
| if (figFonts[actualFontName]) { | ||
| const result = figFonts[actualFontName].options; | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return Promise.resolve(result); | ||
| } | ||
| try { | ||
| if (!figDefaults.fetchFontIfMissing) { | ||
| throw new Error(`Font is not loaded: ${actualFontName}`); | ||
| } | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error(`Network response was not ok: ${response.status}`); | ||
| } | ||
| const text = await response.text(); | ||
| const result = me.parseFont(actualFontName, text); | ||
| if (callback) { | ||
| callback(null, result); | ||
| } | ||
| return result; | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return null; | ||
| } | ||
| throw err; | ||
| } | ||
| }; | ||
| me.loadFontSync = function(name) { | ||
| const actualFontName = getFontName(name); | ||
| if (figFonts[actualFontName]) { | ||
| return figFonts[actualFontName].options; | ||
| } | ||
| throw new Error( | ||
| "Synchronous font loading is not implemented for the browser, it will only work for fonts already loaded." | ||
| ); | ||
| }; | ||
| me.preloadFonts = async function(fonts, callback) { | ||
| try { | ||
| for (const name of fonts) { | ||
| const actualFontName = getFontName(name); | ||
| const response = await fetch( | ||
| `${figDefaults.fontPath}/${actualFontName}.flf` | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error( | ||
| `Failed to preload fonts. Error fetching font: ${actualFontName}, status code: ${response.statusText}` | ||
| ); | ||
| } | ||
| const data = await response.text(); | ||
| me.parseFont(actualFontName, data); | ||
| } | ||
| if (callback) { | ||
| callback(); | ||
| } | ||
| } catch (error) { | ||
| const err = error instanceof Error ? error : new Error(String(error)); | ||
| if (callback) { | ||
| callback(err); | ||
| return; | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
| me.fonts = function(callback) { | ||
| return new Promise(function(resolve, reject) { | ||
| resolve(fontList); | ||
| if (callback) { | ||
| callback(null, fontList); | ||
| } | ||
| }); | ||
| }; | ||
| me.fontsSync = function() { | ||
| return fontList; | ||
| }; | ||
| me.figFonts = figFonts; | ||
| return me; | ||
| })(); | ||
| exports.figlet = figlet; | ||
| exports.getFontName = getFontName; |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
18802683
0.14%1004
0.6%726011
0.13%466
0.22%472
0.64%