@jaredwray/fumanchu 4.6.1 → 4.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,41 +23,109 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  //#endregion
24
24
  let _cacheable_memory = require("@cacheable/memory");
25
25
  let handlebars = require("handlebars");
26
- handlebars = __toESM(handlebars);
26
+ handlebars = __toESM(handlebars, 1);
27
27
  let node_fs = require("node:fs");
28
- node_fs = __toESM(node_fs);
28
+ node_fs = __toESM(node_fs, 1);
29
29
  let node_path = require("node:path");
30
- node_path = __toESM(node_path);
31
- let html_tag = require("html-tag");
32
- html_tag = __toESM(html_tag);
33
- let to_gfm_code_block = require("to-gfm-code-block");
34
- to_gfm_code_block = __toESM(to_gfm_code_block);
30
+ node_path = __toESM(node_path, 1);
35
31
  let chrono_node = require("chrono-node");
36
32
  let dayjs = require("dayjs");
37
- dayjs = __toESM(dayjs);
33
+ dayjs = __toESM(dayjs, 1);
38
34
  let dayjs_plugin_isBetween_js = require("dayjs/plugin/isBetween.js");
39
- dayjs_plugin_isBetween_js = __toESM(dayjs_plugin_isBetween_js);
35
+ dayjs_plugin_isBetween_js = __toESM(dayjs_plugin_isBetween_js, 1);
40
36
  let dayjs_plugin_relativeTime_js = require("dayjs/plugin/relativeTime.js");
41
- dayjs_plugin_relativeTime_js = __toESM(dayjs_plugin_relativeTime_js);
37
+ dayjs_plugin_relativeTime_js = __toESM(dayjs_plugin_relativeTime_js, 1);
42
38
  let dayjs_plugin_timezone_js = require("dayjs/plugin/timezone.js");
43
- dayjs_plugin_timezone_js = __toESM(dayjs_plugin_timezone_js);
39
+ dayjs_plugin_timezone_js = __toESM(dayjs_plugin_timezone_js, 1);
44
40
  let dayjs_plugin_utc_js = require("dayjs/plugin/utc.js");
45
- dayjs_plugin_utc_js = __toESM(dayjs_plugin_utc_js);
46
- let is_glob = require("is-glob");
47
- is_glob = __toESM(is_glob);
41
+ dayjs_plugin_utc_js = __toESM(dayjs_plugin_utc_js, 1);
48
42
  let micromatch = require("micromatch");
49
- micromatch = __toESM(micromatch);
50
- let striptags = require("striptags");
51
- striptags = __toESM(striptags);
43
+ micromatch = __toESM(micromatch, 1);
52
44
  let node_process = require("node:process");
53
- node_process = __toESM(node_process);
54
- let ent = require("ent");
55
- ent = __toESM(ent);
56
- let remarkable = require("remarkable");
57
- let kind_of = require("kind-of");
58
- kind_of = __toESM(kind_of);
45
+ node_process = __toESM(node_process, 1);
46
+ let markdown_it = require("markdown-it");
47
+ markdown_it = __toESM(markdown_it, 1);
59
48
  let node_querystring = require("node:querystring");
60
49
  let node_url = require("node:url");
50
+ //#region src/helper-registry-base.ts
51
+ /**
52
+ * Base class for helper registries. Holds all state-management logic and
53
+ * leaves `init()` empty so environment-specific subclasses decide which
54
+ * helper sets to register. This lets the browser registry avoid importing
55
+ * any Node-only helper files.
56
+ */
57
+ var HelperRegistryBase = class {
58
+ _helpers = [];
59
+ constructor() {
60
+ this.init();
61
+ }
62
+ /**
63
+ * Get all registered helpers.
64
+ */
65
+ get helpers() {
66
+ return this._helpers;
67
+ }
68
+ /**
69
+ * Initialize the helper registry. Overridden by subclasses.
70
+ */
71
+ init() {}
72
+ /**
73
+ * Register a helper. Returns true if the helper was added, false if a
74
+ * helper with the same name was already present.
75
+ */
76
+ register(helper) {
77
+ if (this.has(helper.name)) return false;
78
+ this._helpers.push(helper);
79
+ return true;
80
+ }
81
+ /**
82
+ * Register multiple helpers.
83
+ */
84
+ registerHelpers(helpers) {
85
+ for (const helper of helpers) this.register(helper);
86
+ }
87
+ /**
88
+ * Check if a helper is registered.
89
+ */
90
+ has(name) {
91
+ return this._helpers.some((helper) => helper.name === name);
92
+ }
93
+ /**
94
+ * Filter helpers by the given criteria.
95
+ */
96
+ filter(filter) {
97
+ let result = this._helpers;
98
+ if (filter.names) {
99
+ const names = filter.names;
100
+ result = result.filter((helper) => names.includes(helper.name));
101
+ }
102
+ if (filter.categories) {
103
+ const categories = filter.categories;
104
+ result = result.filter((helper) => categories.includes(helper.category));
105
+ }
106
+ if (filter.compatibility) {
107
+ const compatibility = filter.compatibility;
108
+ result = result.filter((helper) => helper.compatibility?.some((c) => compatibility.includes(c)));
109
+ }
110
+ return result;
111
+ }
112
+ /**
113
+ * Load Handlebars helpers.
114
+ */
115
+ load(handlebars, filters) {
116
+ let helpers = this._helpers;
117
+ if (filters) helpers = this.filter(filters);
118
+ for (const helper of helpers) handlebars.registerHelper(helper.name, helper.fn);
119
+ }
120
+ /**
121
+ * Swap Handlebars helpers. This is used when you want to swap out legacy
122
+ * helpers for fumanchu helpers.
123
+ */
124
+ swap(handlebars) {
125
+ for (const helper of this._helpers) handlebars.registerHelper(helper.name, helper.fn);
126
+ }
127
+ };
128
+ //#endregion
61
129
  //#region src/helpers/array.ts
62
130
  const after = (array, n) => {
63
131
  if (!Array.isArray(array)) return [];
@@ -362,7 +430,7 @@ const unique = function(array, options) {
362
430
  }
363
431
  return "";
364
432
  };
365
- const helpers$20 = [
433
+ const helpers$23 = [
366
434
  {
367
435
  name: "after",
368
436
  category: "array",
@@ -527,23 +595,170 @@ const helpers$20 = [
527
595
  }
528
596
  ];
529
597
  //#endregion
530
- //#region src/helpers/code.ts
531
- const embed = (filepath, language) => {
532
- let ext = typeof language === "string" ? language : node_path.default.extname(filepath).slice(1);
533
- let code = node_fs.default.readFileSync(filepath, "utf8");
534
- if (ext === "markdown" || ext === "md") {
535
- ext = "markdown";
536
- code = code.split("`").join("&#x60");
598
+ //#region src/helpers/html.ts
599
+ const isTagStart = (ch) => ch !== void 0 && (ch === "/" || ch === "!" || ch === "?" || /[a-zA-Z]/.test(ch));
600
+ const stripTags = (str) => {
601
+ let result = "";
602
+ let inTag = false;
603
+ let inComment = false;
604
+ let quote = null;
605
+ for (let i = 0; i < str.length; i++) {
606
+ const ch = str[i];
607
+ if (inComment) {
608
+ if (ch === "-" && str[i + 1] === "-" && str[i + 2] === ">") {
609
+ inComment = false;
610
+ i += 2;
611
+ }
612
+ continue;
613
+ }
614
+ if (inTag) {
615
+ if (quote) {
616
+ if (ch === quote) quote = null;
617
+ } else if (ch === "\"" || ch === "'") quote = ch;
618
+ else if (ch === ">") inTag = false;
619
+ continue;
620
+ }
621
+ if (ch === "<") {
622
+ if (str[i + 1] === "!" && str[i + 2] === "-" && str[i + 3] === "-") {
623
+ inComment = true;
624
+ i += 3;
625
+ continue;
626
+ }
627
+ if (isTagStart(str[i + 1])) {
628
+ inTag = true;
629
+ continue;
630
+ }
631
+ }
632
+ result += ch;
633
+ }
634
+ return result;
635
+ };
636
+ const VOID_ELEMENTS = /* @__PURE__ */ new Set([
637
+ "area",
638
+ "base",
639
+ "br",
640
+ "col",
641
+ "command",
642
+ "embed",
643
+ "hr",
644
+ "img",
645
+ "input",
646
+ "keygen",
647
+ "link",
648
+ "meta",
649
+ "param",
650
+ "source",
651
+ "track",
652
+ "wbr",
653
+ "circle",
654
+ "ellipse",
655
+ "line",
656
+ "path",
657
+ "polygon",
658
+ "polyline",
659
+ "rect",
660
+ "stop",
661
+ "use"
662
+ ]);
663
+ const tag = (name, attribs = {}, text = "") => {
664
+ let html = `<${name}`;
665
+ for (const [key, val] of Object.entries(attribs)) if (val === true) html += ` ${key}`;
666
+ else if (typeof val === "string" || typeof val === "number") html += ` ${key}="${escapeAttr(String(val))}"`;
667
+ if (VOID_ELEMENTS.has(name.toLowerCase())) return `${html}>`;
668
+ return `${html}>${escapeText(text)}</${name}>`;
669
+ };
670
+ const escapeAttr = (str) => str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
671
+ const escapeText = (str) => str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
672
+ const parseAttributes = (hash = {}) => Object.keys(hash).map((key) => `${key}="${String(hash[key]).replace(/^['"]|["']$/g, "")}"`).join(" ");
673
+ const attr = (options) => {
674
+ const val = parseAttributes(options?.hash ?? {});
675
+ return val.trim() ? ` ${val}` : "";
676
+ };
677
+ const sanitize = (str) => {
678
+ if (typeof str !== "string") return "";
679
+ return stripTags(str).trim();
680
+ };
681
+ const ul = (context, options) => {
682
+ const attrs = parseAttributes(options.hash ?? {});
683
+ const items = context.map((item) => typeof item === "string" ? item : options.fn(item));
684
+ return `${attrs ? `<ul ${attrs}>` : "<ul>"}${items.map((i) => `<li>${i}</li>`).join("\n")}</ul>`;
685
+ };
686
+ const ol = (context, options) => {
687
+ const attrs = parseAttributes(options.hash ?? {});
688
+ const items = context.map((item) => typeof item === "string" ? item : options.fn(item));
689
+ return `${attrs ? `<ol ${attrs}>` : "<ol>"}${items.map((i) => `<li>${i}</li>`).join("\n")}</ol>`;
690
+ };
691
+ const thumbnailImage = (context) => {
692
+ let figure = "";
693
+ let image = "";
694
+ const link = context.full || false;
695
+ const imageAttributes = {
696
+ alt: context.alt,
697
+ src: context.thumbnail,
698
+ width: context.size.width,
699
+ height: context.size.height
700
+ };
701
+ const figureAttributes = { id: `image-${context.id}` };
702
+ const linkAttributes = {
703
+ href: link,
704
+ rel: "thumbnail"
705
+ };
706
+ /* c8 ignore next -- @preserve */
707
+ if (context.classes) {
708
+ if (context.classes.image) imageAttributes.class = context.classes.image.join(" ");
709
+ if (context.classes.figure) figureAttributes.class = context.classes.figure.join(" ");
710
+ if (context.classes.link) linkAttributes.class = context.classes.link.join(" ");
537
711
  }
538
- return `${(0, to_gfm_code_block.default)(code, ext).trim()}\n`;
712
+ figure += `<figure ${parseAttributes(figureAttributes)}>\n`;
713
+ image += `<img ${parseAttributes(imageAttributes)}>\n`;
714
+ if (link) figure += `<a ${parseAttributes(linkAttributes)}>\n${image}</a>\n`;
715
+ else figure += image;
716
+ /* c8 ignore next -- @preserve */
717
+ if (context.caption) figure += `<figcaption>${context.caption}</figcaption>\n`;
718
+ figure += "</figure>";
719
+ return figure;
539
720
  };
721
+ const helpers$22 = [
722
+ {
723
+ name: "attr",
724
+ category: "html",
725
+ compatibility: ["browser", "nodejs"],
726
+ fn: attr
727
+ },
728
+ {
729
+ name: "sanitize",
730
+ category: "html",
731
+ compatibility: ["browser", "nodejs"],
732
+ fn: sanitize
733
+ },
734
+ {
735
+ name: "ul",
736
+ category: "html",
737
+ compatibility: ["browser", "nodejs"],
738
+ fn: ul
739
+ },
740
+ {
741
+ name: "ol",
742
+ category: "html",
743
+ compatibility: ["browser", "nodejs"],
744
+ fn: ol
745
+ },
746
+ {
747
+ name: "thumbnailImage",
748
+ category: "html",
749
+ compatibility: ["browser", "nodejs"],
750
+ fn: thumbnailImage
751
+ }
752
+ ];
753
+ //#endregion
754
+ //#region src/helpers/code.ts
540
755
  const gist = (id) => {
541
- return (0, html_tag.default)("script", { src: `https://gist.github.com/${id}.js` });
756
+ return tag("script", { src: `https://gist.github.com/${id}.js` });
542
757
  };
543
758
  const jsfiddle = (options) => {
544
759
  if (!options?.id) throw new Error("jsfiddle helper expects an `id`");
545
760
  const { id, width = "100%", height = "300", skin = "/presentation/", tabs = "result,js,html,css", allowfullscreen = "allowfullscreen", frameborder = "0" } = options;
546
- return (0, html_tag.default)("iframe", {
761
+ return tag("iframe", {
547
762
  width,
548
763
  height,
549
764
  src: `http://jsfiddle.net/${id}/embedded/${tabs}${skin}`,
@@ -551,26 +766,37 @@ const jsfiddle = (options) => {
551
766
  frameborder
552
767
  });
553
768
  };
554
- const helpers$19 = [
555
- {
556
- name: "embed",
557
- category: "code",
558
- compatibility: ["nodejs"],
559
- fn: embed
560
- },
561
- {
562
- name: "gist",
563
- category: "code",
564
- compatibility: ["browser", "nodejs"],
565
- fn: gist
566
- },
567
- {
568
- name: "jsfiddle",
569
- category: "code",
570
- compatibility: ["browser", "nodejs"],
571
- fn: jsfiddle
769
+ const helpers$21 = [{
770
+ name: "gist",
771
+ category: "code",
772
+ compatibility: ["browser", "nodejs"],
773
+ fn: gist
774
+ }, {
775
+ name: "jsfiddle",
776
+ category: "code",
777
+ compatibility: ["browser", "nodejs"],
778
+ fn: jsfiddle
779
+ }];
780
+ //#endregion
781
+ //#region src/helpers/code.node.ts
782
+ const codeBlock = (code, lang) => {
783
+ return `\`\`\`${lang}\n${code}\n\`\`\`\n`;
784
+ };
785
+ const embed = (filepath, language) => {
786
+ let ext = typeof language === "string" ? language : node_path.default.extname(filepath).slice(1);
787
+ let code = node_fs.default.readFileSync(filepath, "utf8");
788
+ if (ext === "markdown" || ext === "md") {
789
+ ext = "markdown";
790
+ code = code.split("`").join("&#x60");
572
791
  }
573
- ];
792
+ return `${codeBlock(code, ext).trim()}\n`;
793
+ };
794
+ const helpers$20 = [{
795
+ name: "embed",
796
+ category: "code",
797
+ compatibility: ["nodejs"],
798
+ fn: embed
799
+ }];
574
800
  //#endregion
575
801
  //#region src/helpers/collection.ts
576
802
  const isEmpty = (collection) => {
@@ -592,7 +818,7 @@ const iterate = (collection, fn, inverse) => {
592
818
  }
593
819
  return inverse ? inverse() : "";
594
820
  };
595
- const helpers$18 = [{
821
+ const helpers$19 = [{
596
822
  name: "isEmpty",
597
823
  category: "collection",
598
824
  compatibility: ["browser", "nodejs"],
@@ -684,7 +910,7 @@ const unlessGt = (a, b) => a <= b;
684
910
  const unlessLt = (a, b) => a >= b;
685
911
  const unlessGteq = (a, b) => a < b;
686
912
  const unlessLteq = (a, b) => a > b;
687
- const helpers$17 = [
913
+ const helpers$18 = [
688
914
  {
689
915
  name: "and",
690
916
  category: "comparison",
@@ -965,7 +1191,7 @@ const dateLocale = (dateInput, locale, formatString) => {
965
1191
  if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
966
1192
  return parsed.locale(locale).format(convertedFormat);
967
1193
  };
968
- const helpers$16 = [
1194
+ const helpers$17 = [
969
1195
  {
970
1196
  name: "year",
971
1197
  category: "date",
@@ -1089,6 +1315,9 @@ const helpers$16 = [
1089
1315
  ];
1090
1316
  //#endregion
1091
1317
  //#region src/helpers/fs.ts
1318
+ const ESCAPE_SEQUENCE = /\\[\s\S]/g;
1319
+ const GLOB_PATTERN = /^!|[*?]|\[[^\]]+\]|\{[^}]+\}|[@?!+*]\([^)]*\)|\([^)]*\|[^)]*\)/;
1320
+ const isGlob = (value) => GLOB_PATTERN.test(value.replace(ESCAPE_SEQUENCE, ""));
1092
1321
  const fileSize = (value, precision) => {
1093
1322
  if (value == null) return "0 B";
1094
1323
  const number = typeof value === "number" ? value : value.length ?? 0;
@@ -1126,7 +1355,7 @@ const readdir = (dir, filter) => {
1126
1355
  if (typeof filterArg === "function") return filterArg(files);
1127
1356
  if (filterArg instanceof RegExp) return files.filter((fp) => filterArg.test(fp));
1128
1357
  if (typeof filterArg === "string") {
1129
- if ((0, is_glob.default)(filterArg)) return (0, micromatch.default)(files, filterArg);
1358
+ if (isGlob(filterArg)) return (0, micromatch.default)(files, filterArg);
1130
1359
  if (filterArg === "isFile" || filterArg === "isDirectory") return files.filter((fp) => {
1131
1360
  const stat = node_fs.default.statSync(fp);
1132
1361
  return filterArg === "isFile" ? stat.isFile() : stat.isDirectory();
@@ -1134,7 +1363,7 @@ const readdir = (dir, filter) => {
1134
1363
  }
1135
1364
  return files;
1136
1365
  };
1137
- const helpers$15 = [
1366
+ const helpers$16 = [
1138
1367
  {
1139
1368
  name: "fileSize",
1140
1369
  category: "fs",
@@ -1155,12 +1384,7 @@ const helpers$15 = [
1155
1384
  }
1156
1385
  ];
1157
1386
  //#endregion
1158
- //#region src/helpers/html.ts
1159
- const parseAttributes = (hash = {}) => Object.keys(hash).map((key) => `${key}="${String(hash[key]).replace(/^['"]|["']$/g, "")}"`).join(" ");
1160
- const attr = (options) => {
1161
- const val = parseAttributes(options?.hash ?? {});
1162
- return val.trim() ? ` ${val}` : "";
1163
- };
1387
+ //#region src/helpers/html.node.ts
1164
1388
  const css = function(list, options) {
1165
1389
  if (arguments.length < 2) {
1166
1390
  options = list;
@@ -1185,99 +1409,22 @@ const js = (context) => {
1185
1409
  return `<script${attrStr ? ` ${attrStr}` : ""}><\/script>`;
1186
1410
  }
1187
1411
  if (typeof context === "string") return `<script src="${context}"><\/script>`;
1188
- return arrayify(context).map((fp) => node_path.default.extname(fp) === ".coffee" ? (0, html_tag.default)("script", {
1412
+ return arrayify(context).map((fp) => node_path.default.extname(fp) === ".coffee" ? tag("script", {
1189
1413
  type: "text/coffeescript",
1190
1414
  src: fp
1191
- }) : (0, html_tag.default)("script", { src: fp })).join("\n");
1192
- };
1193
- const sanitize = (str) => {
1194
- if (typeof str !== "string") return "";
1195
- return (0, striptags.default)(str).trim();
1196
- };
1197
- const ul = (context, options) => {
1198
- const attrs = parseAttributes(options.hash ?? {});
1199
- const items = context.map((item) => typeof item === "string" ? item : options.fn(item));
1200
- return `${attrs ? `<ul ${attrs}>` : "<ul>"}${items.map((i) => `<li>${i}</li>`).join("\n")}</ul>`;
1201
- };
1202
- const ol = (context, options) => {
1203
- const attrs = parseAttributes(options.hash ?? {});
1204
- const items = context.map((item) => typeof item === "string" ? item : options.fn(item));
1205
- return `${attrs ? `<ol ${attrs}>` : "<ol>"}${items.map((i) => `<li>${i}</li>`).join("\n")}</ol>`;
1206
- };
1207
- const thumbnailImage = (context) => {
1208
- let figure = "";
1209
- let image = "";
1210
- const link = context.full || false;
1211
- const imageAttributes = {
1212
- alt: context.alt,
1213
- src: context.thumbnail,
1214
- width: context.size.width,
1215
- height: context.size.height
1216
- };
1217
- const figureAttributes = { id: `image-${context.id}` };
1218
- const linkAttributes = {
1219
- href: link,
1220
- rel: "thumbnail"
1221
- };
1222
- /* c8 ignore next -- @preserve */
1223
- if (context.classes) {
1224
- if (context.classes.image) imageAttributes.class = context.classes.image.join(" ");
1225
- if (context.classes.figure) figureAttributes.class = context.classes.figure.join(" ");
1226
- if (context.classes.link) linkAttributes.class = context.classes.link.join(" ");
1227
- }
1228
- figure += `<figure ${parseAttributes(figureAttributes)}>\n`;
1229
- image += `<img ${parseAttributes(imageAttributes)}>\n`;
1230
- if (link) figure += `<a ${parseAttributes(linkAttributes)}>\n${image}</a>\n`;
1231
- else figure += image;
1232
- /* c8 ignore next -- @preserve */
1233
- if (context.caption) figure += `<figcaption>${context.caption}</figcaption>\n`;
1234
- figure += "</figure>";
1235
- return figure;
1415
+ }) : tag("script", { src: fp })).join("\n");
1236
1416
  };
1237
- const helpers$14 = [
1238
- {
1239
- name: "attr",
1240
- category: "html",
1241
- compatibility: ["browser", "nodejs"],
1242
- fn: attr
1243
- },
1244
- {
1245
- name: "css",
1246
- category: "html",
1247
- compatibility: ["nodejs"],
1248
- fn: css
1249
- },
1250
- {
1251
- name: "js",
1252
- category: "html",
1253
- compatibility: ["nodejs"],
1254
- fn: js
1255
- },
1256
- {
1257
- name: "sanitize",
1258
- category: "html",
1259
- compatibility: ["browser", "nodejs"],
1260
- fn: sanitize
1261
- },
1262
- {
1263
- name: "ul",
1264
- category: "html",
1265
- compatibility: ["browser", "nodejs"],
1266
- fn: ul
1267
- },
1268
- {
1269
- name: "ol",
1270
- category: "html",
1271
- compatibility: ["browser", "nodejs"],
1272
- fn: ol
1273
- },
1274
- {
1275
- name: "thumbnailImage",
1276
- category: "html",
1277
- compatibility: ["browser", "nodejs"],
1278
- fn: thumbnailImage
1279
- }
1280
- ];
1417
+ const helpers$15 = [{
1418
+ name: "css",
1419
+ category: "html",
1420
+ compatibility: ["nodejs"],
1421
+ fn: css
1422
+ }, {
1423
+ name: "js",
1424
+ category: "html",
1425
+ compatibility: ["nodejs"],
1426
+ fn: js
1427
+ }];
1281
1428
  //#endregion
1282
1429
  //#region src/utils.ts
1283
1430
  /**
@@ -1355,7 +1502,7 @@ const i18n = function(prop, locals, options) {
1355
1502
  if (typeof result === "undefined") throw new Error("{{i18n}} helper cannot find property \"" + String(prop) + "\" for language \"" + lang + "\"");
1356
1503
  return String(result);
1357
1504
  };
1358
- const helpers$13 = [{
1505
+ const helpers$14 = [{
1359
1506
  name: "i18n",
1360
1507
  category: "i18n",
1361
1508
  compatibility: ["browser", "nodejs"],
@@ -1383,7 +1530,7 @@ const ordinalize = (value) => {
1383
1530
  default: return `${str}th`;
1384
1531
  }
1385
1532
  };
1386
- const helpers$12 = [{
1533
+ const helpers$13 = [{
1387
1534
  name: "inflect",
1388
1535
  category: "inflection",
1389
1536
  compatibility: ["browser", "nodejs"],
@@ -1511,7 +1658,7 @@ function switchOutput(type, json) {
1511
1658
  default: return json;
1512
1659
  }
1513
1660
  }
1514
- const helpers$11 = [
1661
+ const helpers$12 = [
1515
1662
  {
1516
1663
  name: "log",
1517
1664
  category: "logging",
@@ -1594,7 +1741,7 @@ const mm = (...args) => {
1594
1741
  console.log("helper instead.");
1595
1742
  return match(...args);
1596
1743
  };
1597
- const helpers$10 = [
1744
+ const helpers$11 = [
1598
1745
  {
1599
1746
  name: "match",
1600
1747
  category: "match",
@@ -1676,7 +1823,7 @@ const sum = (...values) => {
1676
1823
  return total;
1677
1824
  };
1678
1825
  const times = (a, b) => multiply(a, b);
1679
- const helpers$9 = [
1826
+ const helpers$10 = [
1680
1827
  {
1681
1828
  name: "abs",
1682
1829
  category: "math",
@@ -1776,6 +1923,18 @@ const helpers$9 = [
1776
1923
  ];
1777
1924
  //#endregion
1778
1925
  //#region src/helpers/md.ts
1926
+ const md = new markdown_it.default({
1927
+ breaks: true,
1928
+ html: true,
1929
+ langPrefix: "lang-",
1930
+ typographer: false,
1931
+ xhtmlOut: false
1932
+ });
1933
+ function renderString(input) {
1934
+ return new handlebars.default.SafeString(md.render(input));
1935
+ }
1936
+ //#endregion
1937
+ //#region src/helpers/md.node.ts
1779
1938
  const renderMarkdown = function(input, options) {
1780
1939
  if (typeof input === "object" && input && "fn" in input && typeof input.fn === "function") {
1781
1940
  options = input;
@@ -1785,21 +1944,14 @@ const renderMarkdown = function(input, options) {
1785
1944
  cwd: node_process.default.cwd(),
1786
1945
  ...options
1787
1946
  };
1788
- const md = new remarkable.Remarkable({
1789
- breaks: true,
1790
- html: true,
1791
- langPrefix: "lang-",
1792
- typographer: false,
1793
- xhtmlOut: false
1794
- });
1795
1947
  let string_ = input;
1796
- if (string_ && string_.length > 0) {
1948
+ if (string_.length > 0) {
1797
1949
  const filepath = node_path.default.resolve(options_.cwd, string_);
1798
1950
  if (node_fs.default.existsSync(filepath) && node_fs.default.statSync(filepath).isFile()) string_ = node_fs.default.readFileSync(filepath, "utf8");
1799
1951
  }
1800
- return new handlebars.default.SafeString(ent.default.decode(md.render(string_)));
1952
+ return renderString(string_);
1801
1953
  };
1802
- const helpers$8 = [{
1954
+ const helpers$9 = [{
1803
1955
  name: "md",
1804
1956
  category: "markdown",
1805
1957
  compatibility: ["nodejs"],
@@ -1812,6 +1964,68 @@ const helpers$8 = [{
1812
1964
  }];
1813
1965
  //#endregion
1814
1966
  //#region src/helpers/misc.ts
1967
+ const objectToString = Object.prototype.toString;
1968
+ function ctorName(val) {
1969
+ return typeof val.constructor === "function" ? val.constructor.name : null;
1970
+ }
1971
+ function isGeneratorFn(val) {
1972
+ return ctorName(val) === "GeneratorFunction";
1973
+ }
1974
+ function isGeneratorObj(val) {
1975
+ return typeof val.throw === "function" && typeof val.return === "function" && typeof val.next === "function";
1976
+ }
1977
+ function isDateLike(val) {
1978
+ return typeof val.toDateString === "function" && typeof val.getDate === "function" && typeof val.setDate === "function";
1979
+ }
1980
+ function isErrorLike(val) {
1981
+ return typeof val.message === "string" && val.constructor && typeof val.constructor.stackTraceLimit === "number";
1982
+ }
1983
+ function isRegexpLike(val) {
1984
+ return typeof val.flags === "string" && typeof val.ignoreCase === "boolean" && typeof val.multiline === "boolean" && typeof val.global === "boolean";
1985
+ }
1986
+ function kindOf(val) {
1987
+ if (val === void 0) return "undefined";
1988
+ if (val === null) return "null";
1989
+ const type = typeof val;
1990
+ if (type === "boolean") return "boolean";
1991
+ if (type === "string") return "string";
1992
+ if (type === "number") return "number";
1993
+ if (type === "symbol") return "symbol";
1994
+ if (type === "bigint") return "bigint";
1995
+ if (type === "function") return isGeneratorFn(val) ? "generatorfunction" : "function";
1996
+ if (Array.isArray(val)) return "array";
1997
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer?.(val)) return "buffer";
1998
+ if (typeof val.length === "number" && objectToString.call(val) === "[object Arguments]") return "arguments";
1999
+ if (val instanceof Date || isDateLike(val)) return "date";
2000
+ if (val instanceof Error || isErrorLike(val)) return "error";
2001
+ if (val instanceof RegExp || isRegexpLike(val)) return "regexp";
2002
+ switch (ctorName(val)) {
2003
+ case "Promise": return "promise";
2004
+ case "WeakMap": return "weakmap";
2005
+ case "WeakSet": return "weakset";
2006
+ case "Map": return "map";
2007
+ case "Set": return "set";
2008
+ case "Int8Array": return "int8array";
2009
+ case "Uint8Array": return "uint8array";
2010
+ case "Uint8ClampedArray": return "uint8clampedarray";
2011
+ case "Int16Array": return "int16array";
2012
+ case "Uint16Array": return "uint16array";
2013
+ case "Int32Array": return "int32array";
2014
+ case "Uint32Array": return "uint32array";
2015
+ case "Float32Array": return "float32array";
2016
+ case "Float64Array": return "float64array";
2017
+ }
2018
+ if (isGeneratorObj(val)) return "generator";
2019
+ const tag = objectToString.call(val);
2020
+ switch (tag) {
2021
+ case "[object Object]": return "object";
2022
+ case "[object Map Iterator]": return "mapiterator";
2023
+ case "[object Set Iterator]": return "setiterator";
2024
+ case "[object String Iterator]": return "stringiterator";
2025
+ case "[object Array Iterator]": return "arrayiterator";
2026
+ }
2027
+ return tag.slice(8, -1).toLowerCase().replace(/\s/g, "");
2028
+ }
1815
2029
  /**
1816
2030
  * Block helper for exposing private `@` variables on the context
1817
2031
  * Replaces the external handlebars-helper-create-frame package
@@ -1832,12 +2046,12 @@ function option(prop, locals, opts) {
1832
2046
  function noop(options) {
1833
2047
  return options.fn(this);
1834
2048
  }
1835
- const typeOf = kind_of.default;
2049
+ const typeOf = kindOf;
1836
2050
  function withHash(options) {
1837
2051
  if (options.hash && Object.keys(options.hash).length) return options.fn(options.hash);
1838
2052
  return options.inverse(this);
1839
2053
  }
1840
- const helpers$7 = [
2054
+ const helpers$8 = [
1841
2055
  {
1842
2056
  name: "frame",
1843
2057
  category: "misc",
@@ -1940,7 +2154,7 @@ const toPrecision = (value, precision) => {
1940
2154
  const prec = typeof precision === "number" && !Number.isNaN(precision) ? precision : 1;
1941
2155
  return Number(num).toPrecision(prec);
1942
2156
  };
1943
- const helpers$6 = [
2157
+ const helpers$7 = [
1944
2158
  {
1945
2159
  name: "bytes",
1946
2160
  category: "number",
@@ -2080,7 +2294,7 @@ const pick = (props, context, options) => {
2080
2294
  }
2081
2295
  return result;
2082
2296
  };
2083
- const helpers$5 = [
2297
+ const helpers$6 = [
2084
2298
  {
2085
2299
  name: "extend",
2086
2300
  category: "object",
@@ -2218,7 +2432,7 @@ const segments = (filepath, a, b) => {
2218
2432
  const end = Number(b);
2219
2433
  return fp.split(/[\\/]+/).slice(start, end).join("/");
2220
2434
  };
2221
- const helpers$4 = [
2435
+ const helpers$5 = [
2222
2436
  {
2223
2437
  name: "absolute",
2224
2438
  category: "path",
@@ -2279,7 +2493,7 @@ const test = (str, regex) => {
2279
2493
  if (!(regex instanceof RegExp)) throw new TypeError("expected a regular expression");
2280
2494
  return regex.test(str);
2281
2495
  };
2282
- const helpers$3 = [{
2496
+ const helpers$4 = [{
2283
2497
  name: "toRegex",
2284
2498
  category: "regex",
2285
2499
  compatibility: ["browser", "nodejs"],
@@ -2436,7 +2650,7 @@ const raw = (options) => {
2436
2650
  if (options && typeof options.fn === "function") return options.fn();
2437
2651
  return "";
2438
2652
  };
2439
- const helpers$2 = [
2653
+ const helpers$3 = [
2440
2654
  {
2441
2655
  name: "append",
2442
2656
  category: "string",
@@ -2660,9 +2874,6 @@ const all = ["browser", "nodejs"];
2660
2874
  const encodeUri = (str) => {
2661
2875
  if (typeof str === "string") return encodeURIComponent(str);
2662
2876
  };
2663
- const escapeFn = (str) => {
2664
- if (typeof str === "string") return (0, node_querystring.escape)(str);
2665
- };
2666
2877
  const decodeUri = (str) => {
2667
2878
  if (typeof str === "string") return decodeURIComponent(str);
2668
2879
  };
@@ -2672,31 +2883,16 @@ function urlEncode(...args) {
2672
2883
  function urlDecode(...args) {
2673
2884
  return decodeUri.apply(this, args);
2674
2885
  }
2675
- const urlResolve = (base, href) => (0, node_url.resolve)(String(base), String(href));
2676
- const urlParse = (str) => (0, node_url.parse)(String(str));
2677
2886
  const stripQuerystring = (str) => {
2678
2887
  if (typeof str === "string") return str.split("?")[0];
2679
2888
  };
2680
- const stripProtocol = (str) => {
2681
- if (typeof str === "string") {
2682
- const parsed = (0, node_url.parse)(str);
2683
- parsed.protocol = "";
2684
- return (0, node_url.format)(parsed);
2685
- }
2686
- };
2687
- const helpers$1 = [
2889
+ const helpers$2 = [
2688
2890
  {
2689
2891
  name: "encodeURI",
2690
2892
  category: "url",
2691
2893
  compatibility: all,
2692
2894
  fn: encodeUri
2693
2895
  },
2694
- {
2695
- name: "escape",
2696
- category: "url",
2697
- compatibility: ["nodejs"],
2698
- fn: escapeFn
2699
- },
2700
2896
  {
2701
2897
  name: "decodeURI",
2702
2898
  category: "url",
@@ -2715,6 +2911,34 @@ const helpers$1 = [
2715
2911
  compatibility: all,
2716
2912
  fn: urlDecode
2717
2913
  },
2914
+ {
2915
+ name: "stripQuerystring",
2916
+ category: "url",
2917
+ compatibility: all,
2918
+ fn: stripQuerystring
2919
+ }
2920
+ ];
2921
+ //#endregion
2922
+ //#region src/helpers/url.node.ts
2923
+ const escapeFn = (str) => {
2924
+ if (typeof str === "string") return (0, node_querystring.escape)(str);
2925
+ };
2926
+ const urlResolve = (base, href) => (0, node_url.resolve)(String(base), String(href));
2927
+ const urlParse = (str) => (0, node_url.parse)(String(str));
2928
+ const stripProtocol = (str) => {
2929
+ if (typeof str === "string") {
2930
+ const parsed = (0, node_url.parse)(str);
2931
+ parsed.protocol = "";
2932
+ return (0, node_url.format)(parsed);
2933
+ }
2934
+ };
2935
+ const helpers$1 = [
2936
+ {
2937
+ name: "escape",
2938
+ category: "url",
2939
+ compatibility: ["nodejs"],
2940
+ fn: escapeFn
2941
+ },
2718
2942
  {
2719
2943
  name: "urlResolve",
2720
2944
  category: "url",
@@ -2727,12 +2951,6 @@ const helpers$1 = [
2727
2951
  compatibility: ["nodejs"],
2728
2952
  fn: urlParse
2729
2953
  },
2730
- {
2731
- name: "stripQuerystring",
2732
- category: "url",
2733
- compatibility: all,
2734
- fn: stripQuerystring
2735
- },
2736
2954
  {
2737
2955
  name: "stripProtocol",
2738
2956
  category: "url",
@@ -2742,104 +2960,35 @@ const helpers$1 = [
2742
2960
  ];
2743
2961
  //#endregion
2744
2962
  //#region src/helper-registry.ts
2745
- var HelperRegistry = class {
2746
- _helpers = [];
2747
- constructor() {
2748
- this.init();
2749
- }
2750
- /**
2751
- * Get all registered helpers.
2752
- * @returns {Helper[]} The array of registered helpers.
2753
- */
2754
- get helpers() {
2755
- return this._helpers;
2756
- }
2757
- /**
2758
- * Initialize the helper registry. This is performed during the construction of the registry such as new HelperRegistry().
2759
- */
2963
+ var HelperRegistry = class extends HelperRegistryBase {
2760
2964
  init() {
2761
- this.registerHelpers(helpers$20);
2762
- this.registerHelpers(helpers$18);
2965
+ this.registerHelpers(helpers$23);
2966
+ this.registerHelpers(helpers$19);
2967
+ this.registerHelpers(helpers$17);
2763
2968
  this.registerHelpers(helpers$16);
2969
+ this.registerHelpers(helpers$21);
2970
+ this.registerHelpers(helpers$20);
2971
+ this.registerHelpers(helpers$9);
2972
+ this.registerHelpers(helpers$22);
2764
2973
  this.registerHelpers(helpers$15);
2765
- this.registerHelpers(helpers$19);
2766
- this.registerHelpers(helpers$8);
2974
+ this.registerHelpers(helpers$18);
2767
2975
  this.registerHelpers(helpers$14);
2768
- this.registerHelpers(helpers$17);
2769
2976
  this.registerHelpers(helpers$13);
2770
2977
  this.registerHelpers(helpers$12);
2771
2978
  this.registerHelpers(helpers$11);
2772
2979
  this.registerHelpers(helpers$10);
2773
- this.registerHelpers(helpers$9);
2980
+ this.registerHelpers(helpers$8);
2774
2981
  this.registerHelpers(helpers$7);
2775
- this.registerHelpers(helpers$6);
2982
+ this.registerHelpers(helpers$5);
2776
2983
  this.registerHelpers(helpers$4);
2777
2984
  this.registerHelpers(helpers$3);
2778
2985
  this.registerHelpers(helpers$2);
2779
2986
  this.registerHelpers(helpers$1);
2780
- this.registerHelpers(helpers$5);
2781
- }
2782
- /**
2783
- * Register a helper.
2784
- * @param {Helper} helper The helper to register.
2785
- * @returns True if the helper was registered, false otherwise.
2786
- */
2787
- register(helper) {
2788
- const result = false;
2789
- if (!this.has(helper.name)) this._helpers.push(helper);
2790
- return result;
2791
- }
2792
- /**
2793
- * Register multiple helpers.
2794
- * @param {Helper[]} helpers The array of helpers to register.
2795
- */
2796
- registerHelpers(helpers) {
2797
- for (const helper of helpers) this.register(helper);
2798
- }
2799
- /**
2800
- * Check if a helper is registered.
2801
- * @param name The name of the helper.
2802
- * @returns True if the helper is registered, false otherwise.
2803
- */
2804
- has(name) {
2805
- return this._helpers.some((helper) => helper.name === name);
2806
- }
2807
- /**
2808
- * Filter helpers by the given criteria.
2809
- * @param filter The filter criteria.
2810
- * @returns The filtered helpers.
2811
- */
2812
- filter(filter) {
2813
- let result = this._helpers;
2814
- if (filter.names) result = result.filter((helper) => filter.names?.includes(helper.name));
2815
- if (filter.categories) result = result.filter((helper) => filter.categories?.includes(helper.category));
2816
- if (filter.compatibility) result = result.filter((helper) => helper.compatibility?.some((c) => filter.compatibility?.includes(c)));
2817
- return result;
2818
- }
2819
- /**
2820
- * Load Handlebars helpers.
2821
- * @param {Handlebars} handlebars The Handlebars instance.
2822
- * @returns {void}
2823
- */
2824
- load(handlebars, filters) {
2825
- let helpers = this._helpers;
2826
- if (filters) helpers = this.filter(filters);
2827
- for (const helper of helpers) handlebars.registerHelper(helper.name, helper.fn);
2828
- }
2829
- /**
2830
- * Swap Handlebars helpers. This is used when you want to swap out legacy helpers for fumanchu helpers.
2831
- * @param handlebars The Handlebars instance.
2832
- * @returns {void}
2833
- */
2834
- swap(handlebars) {
2835
- for (const helper of this._helpers) {
2836
- handlebars.unregisterHelper(helper.name);
2837
- handlebars.registerHelper(helper.name, helper.fn);
2838
- }
2987
+ this.registerHelpers(helpers$6);
2839
2988
  }
2840
2989
  };
2841
2990
  //#endregion
2842
- //#region src/index.ts
2991
+ //#region src/index.node.ts
2843
2992
  /**
2844
2993
  * Handlebars library not initiated with helpers
2845
2994
  * @type {Handlebars}
@@ -2893,7 +3042,7 @@ function fumanchu(options) {
2893
3042
  else cache = new _cacheable_memory.CacheableMemory({ useClone: false });
2894
3043
  const originalCompile = handlebars$3.compile.bind(handlebars$3);
2895
3044
  handlebars$3.compile = (input, compileOptions) => {
2896
- const key = compileOptions ? input + JSON.stringify(compileOptions) : String(input);
3045
+ const key = compileOptions ? `${input}\0${JSON.stringify(compileOptions)}` : input;
2897
3046
  const cached = cache.get(key);
2898
3047
  if (cached) return cached;
2899
3048
  const compiled = originalCompile(input, compileOptions);