@jaredwray/fumanchu 4.6.0 → 4.7.0

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.
@@ -0,0 +1,3064 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let _cacheable_memory = require("@cacheable/memory");
25
+ let handlebars = require("handlebars");
26
+ handlebars = __toESM(handlebars);
27
+ let node_fs = require("node:fs");
28
+ node_fs = __toESM(node_fs);
29
+ let node_path = require("node:path");
30
+ node_path = __toESM(node_path);
31
+ let chrono_node = require("chrono-node");
32
+ let dayjs = require("dayjs");
33
+ dayjs = __toESM(dayjs);
34
+ let dayjs_plugin_isBetween_js = require("dayjs/plugin/isBetween.js");
35
+ dayjs_plugin_isBetween_js = __toESM(dayjs_plugin_isBetween_js);
36
+ let dayjs_plugin_relativeTime_js = require("dayjs/plugin/relativeTime.js");
37
+ dayjs_plugin_relativeTime_js = __toESM(dayjs_plugin_relativeTime_js);
38
+ let dayjs_plugin_timezone_js = require("dayjs/plugin/timezone.js");
39
+ dayjs_plugin_timezone_js = __toESM(dayjs_plugin_timezone_js);
40
+ let dayjs_plugin_utc_js = require("dayjs/plugin/utc.js");
41
+ dayjs_plugin_utc_js = __toESM(dayjs_plugin_utc_js);
42
+ let micromatch = require("micromatch");
43
+ micromatch = __toESM(micromatch);
44
+ let node_process = require("node:process");
45
+ node_process = __toESM(node_process);
46
+ let ent = require("ent");
47
+ ent = __toESM(ent);
48
+ let markdown_it = require("markdown-it");
49
+ markdown_it = __toESM(markdown_it);
50
+ let node_querystring = require("node:querystring");
51
+ let node_url = require("node:url");
52
+ //#region src/helper-registry-base.ts
53
+ /**
54
+ * Base class for helper registries. Holds all state-management logic and
55
+ * leaves `init()` empty so environment-specific subclasses decide which
56
+ * helper sets to register. This lets the browser registry avoid importing
57
+ * any Node-only helper files.
58
+ */
59
+ var HelperRegistryBase = class {
60
+ _helpers = [];
61
+ constructor() {
62
+ this.init();
63
+ }
64
+ /**
65
+ * Get all registered helpers.
66
+ */
67
+ get helpers() {
68
+ return this._helpers;
69
+ }
70
+ /**
71
+ * Initialize the helper registry. Overridden by subclasses.
72
+ */
73
+ init() {}
74
+ /**
75
+ * Register a helper. Returns true if the helper was added, false if a
76
+ * helper with the same name was already present.
77
+ */
78
+ register(helper) {
79
+ if (this.has(helper.name)) return false;
80
+ this._helpers.push(helper);
81
+ return true;
82
+ }
83
+ /**
84
+ * Register multiple helpers.
85
+ */
86
+ registerHelpers(helpers) {
87
+ for (const helper of helpers) this.register(helper);
88
+ }
89
+ /**
90
+ * Check if a helper is registered.
91
+ */
92
+ has(name) {
93
+ return this._helpers.some((helper) => helper.name === name);
94
+ }
95
+ /**
96
+ * Filter helpers by the given criteria.
97
+ */
98
+ filter(filter) {
99
+ let result = this._helpers;
100
+ if (filter.names) {
101
+ const names = filter.names;
102
+ result = result.filter((helper) => names.includes(helper.name));
103
+ }
104
+ if (filter.categories) {
105
+ const categories = filter.categories;
106
+ result = result.filter((helper) => categories.includes(helper.category));
107
+ }
108
+ if (filter.compatibility) {
109
+ const compatibility = filter.compatibility;
110
+ result = result.filter((helper) => helper.compatibility?.some((c) => compatibility.includes(c)));
111
+ }
112
+ return result;
113
+ }
114
+ /**
115
+ * Load Handlebars helpers.
116
+ */
117
+ load(handlebars, filters) {
118
+ let helpers = this._helpers;
119
+ if (filters) helpers = this.filter(filters);
120
+ for (const helper of helpers) handlebars.registerHelper(helper.name, helper.fn);
121
+ }
122
+ /**
123
+ * Swap Handlebars helpers. This is used when you want to swap out legacy
124
+ * helpers for fumanchu helpers.
125
+ */
126
+ swap(handlebars) {
127
+ for (const helper of this._helpers) handlebars.registerHelper(helper.name, helper.fn);
128
+ }
129
+ };
130
+ //#endregion
131
+ //#region src/helpers/array.ts
132
+ const after = (array, n) => {
133
+ if (!Array.isArray(array)) return [];
134
+ return array.slice(n);
135
+ };
136
+ const before = (array, n) => {
137
+ if (!Array.isArray(array)) return [];
138
+ return array.slice(0, -n);
139
+ };
140
+ const arrayify = (value) => {
141
+ if (value == null) return [];
142
+ return Array.isArray(value) ? value : [value];
143
+ };
144
+ const first = (array, n) => {
145
+ if (!Array.isArray(array)) return void 0;
146
+ if (typeof n !== "number") return array[0];
147
+ return array.slice(0, n);
148
+ };
149
+ const last = (value, n) => {
150
+ if (!Array.isArray(value) && typeof value !== "string") return;
151
+ if (typeof n !== "number") {
152
+ const array = value;
153
+ return array[array.length - 1];
154
+ }
155
+ const start = Math.abs(n);
156
+ if (typeof value === "string") return value.slice(-start);
157
+ return value.slice(-start);
158
+ };
159
+ const length = (value) => {
160
+ if (value && typeof value === "object" && !Array.isArray(value)) return Object.keys(value).length;
161
+ if (typeof value === "string" || Array.isArray(value)) return value.length;
162
+ return 0;
163
+ };
164
+ const join = (array, separator = ", ") => {
165
+ if (typeof array === "string") return array;
166
+ if (!Array.isArray(array)) return "";
167
+ return array.join(separator);
168
+ };
169
+ const forEach = function(collection, options) {
170
+ if (!Array.isArray(collection) || !options || typeof options.fn !== "function") return options?.inverse ? options.inverse(this) ?? "" : "";
171
+ if (collection.length === 0) return options.inverse ? options.inverse(this) ?? "" : "";
172
+ const total = collection.length;
173
+ const hash = options.hash ?? {};
174
+ const baseData = options.data ? { ...options.data } : void 0;
175
+ let result = "";
176
+ for (let index = 0; index < total; index++) {
177
+ const value = collection[index];
178
+ const meta = {
179
+ index,
180
+ total,
181
+ isFirst: index === 0,
182
+ isLast: index === total - 1
183
+ };
184
+ const data = {
185
+ ...baseData ? { ...baseData } : {},
186
+ ...hash,
187
+ ...meta
188
+ };
189
+ let context;
190
+ if (value != null && typeof value === "object") context = {
191
+ ...value,
192
+ ...hash,
193
+ ...meta
194
+ };
195
+ else context = {
196
+ value,
197
+ ...hash,
198
+ ...meta
199
+ };
200
+ result += options.fn(context, { data });
201
+ }
202
+ return result;
203
+ };
204
+ const inArray = function(array, value, options) {
205
+ if (!Array.isArray(array) || !options) return "";
206
+ const found = array.includes(value);
207
+ if (found && options.fn) return options.fn(this);
208
+ if (!found && options.inverse) return options.inverse(this);
209
+ return "";
210
+ };
211
+ const isArray = (value) => {
212
+ return Array.isArray(value);
213
+ };
214
+ const itemAt = (array, idx) => {
215
+ if (!Array.isArray(array)) return void 0;
216
+ return array[idx];
217
+ };
218
+ const equalsLength = function(value, targetLength, options) {
219
+ const isEqual = length(value) === targetLength;
220
+ if (options && (options.fn || options.inverse)) {
221
+ if (isEqual && options.fn) return options.fn(this);
222
+ if (!isEqual && options.inverse) return options.inverse(this);
223
+ return "";
224
+ }
225
+ return isEqual;
226
+ };
227
+ const some = function(array, iter, options) {
228
+ /* v8 ignore next -- @preserve */
229
+ if (!Array.isArray(array) || typeof iter !== "function" || !options) return options?.inverse ? options.inverse(this) ?? "" : "";
230
+ const hasSome = array.some(iter);
231
+ if (hasSome && options.fn) return options.fn(this);
232
+ if (!hasSome && options.inverse) return options.inverse(this);
233
+ return "";
234
+ };
235
+ const eachIndex = function(array, options) {
236
+ if (!Array.isArray(array) || !options || typeof options.fn !== "function") return options?.inverse ? options.inverse(this) ?? "" : "";
237
+ /* v8 ignore next -- @preserve */
238
+ if (array.length === 0) return options.inverse ? options.inverse(this) ?? "" : "";
239
+ let result = "";
240
+ for (let index = 0; index < array.length; index++) {
241
+ const context = {
242
+ item: array[index],
243
+ index
244
+ };
245
+ result += options.fn(context);
246
+ }
247
+ return result;
248
+ };
249
+ const withAfter = function(array, idx, options) {
250
+ if (!Array.isArray(array) || !options || typeof options.fn !== "function") return "";
251
+ const sliced = array.slice(idx + 1);
252
+ /* v8 ignore next -- @preserve */
253
+ if (sliced.length === 0) return options.inverse ? options.inverse(this) ?? "" : "";
254
+ let result = "";
255
+ for (const item of sliced) result += options.fn(item);
256
+ return result;
257
+ };
258
+ const withBefore = function(array, idx, options) {
259
+ if (!Array.isArray(array) || !options || typeof options.fn !== "function") return "";
260
+ const sliced = array.slice(0, idx);
261
+ /* v8 ignore next -- @preserve */
262
+ if (sliced.length === 0) return options.inverse ? options.inverse(this) ?? "" : "";
263
+ let result = "";
264
+ for (const item of sliced) result += options.fn(item);
265
+ return result;
266
+ };
267
+ const withFirst = function(array, n, options) {
268
+ let count = 1;
269
+ let opts = options;
270
+ if (typeof n === "object" && n !== null && !Array.isArray(n)) opts = n;
271
+ else if (typeof n === "number") count = n;
272
+ if (!Array.isArray(array) || !opts || typeof opts.fn !== "function") return "";
273
+ /* v8 ignore next -- @preserve */
274
+ if (array.length === 0) return opts.inverse ? opts.inverse(this) ?? "" : "";
275
+ const items = array.slice(0, count);
276
+ let result = "";
277
+ for (const item of items) result += opts.fn(item);
278
+ return result;
279
+ };
280
+ const withLast = function(array, n, options) {
281
+ let count = 1;
282
+ let opts = options;
283
+ if (typeof n === "object" && n !== null && !Array.isArray(n)) opts = n;
284
+ else if (typeof n === "number") count = n;
285
+ if (!Array.isArray(array) || !opts || typeof opts.fn !== "function") return "";
286
+ /* v8 ignore next -- @preserve */
287
+ if (array.length === 0) return opts.inverse ? opts.inverse(this) ?? "" : "";
288
+ const items = array.slice(-count);
289
+ let result = "";
290
+ for (const item of items) result += opts.fn(item);
291
+ return result;
292
+ };
293
+ const withGroup = function(array, size, options) {
294
+ if (!Array.isArray(array) || typeof size !== "number" || size <= 0 || !options || typeof options.fn !== "function") return "";
295
+ /* v8 ignore next -- @preserve */
296
+ if (array.length === 0) return options.inverse ? options.inverse(this) ?? "" : "";
297
+ let result = "";
298
+ const groups = [];
299
+ for (let i = 0; i < array.length; i += size) groups.push(array.slice(i, i + size));
300
+ for (const group of groups) result += options.fn(group);
301
+ return result;
302
+ };
303
+ const withSort = function(array, prop, options) {
304
+ let sortProp;
305
+ let opts = options;
306
+ if (typeof prop === "object" && prop !== null && !Array.isArray(prop)) opts = prop;
307
+ else if (typeof prop === "string") sortProp = prop;
308
+ if (!Array.isArray(array) || !opts || typeof opts.fn !== "function") return "";
309
+ /* v8 ignore next -- @preserve */
310
+ if (array.length === 0) return opts.inverse ? opts.inverse(this) ?? "" : "";
311
+ const sorted = [...array];
312
+ if (sortProp) sorted.sort((a, b) => {
313
+ const aVal = a?.[sortProp];
314
+ const bVal = b?.[sortProp];
315
+ /* v8 ignore next -- @preserve */
316
+ if (aVal === bVal) return 0;
317
+ if (aVal == null) return 1;
318
+ if (bVal == null) return -1;
319
+ /* v8 ignore next -- @preserve */
320
+ if (typeof aVal === "string" && typeof bVal === "string") return aVal.localeCompare(bVal);
321
+ /* v8 ignore next -- @preserve */
322
+ return aVal < bVal ? -1 : 1;
323
+ });
324
+ else sorted.sort((a, b) => {
325
+ /* v8 ignore next -- @preserve */
326
+ if (a === b) return 0;
327
+ if (a == null) return 1;
328
+ if (b == null) return -1;
329
+ if (typeof a === "string" && typeof b === "string") return a.localeCompare(b);
330
+ return a < b ? -1 : 1;
331
+ });
332
+ if (opts.hash?.reverse === true || opts.hash?.reverse === "true") sorted.reverse();
333
+ let result = "";
334
+ for (const item of sorted) result += opts.fn(item);
335
+ return result;
336
+ };
337
+ const filter = function(array, value, options) {
338
+ /* v8 ignore next -- @preserve */
339
+ if (!Array.isArray(array) || !options) return options?.inverse ? options.inverse(this) ?? "" : "";
340
+ const filtered = array.filter((item) => item === value);
341
+ if (filtered.length > 0 && options.fn) return options.fn(this);
342
+ /* v8 ignore next -- @preserve */
343
+ if (filtered.length === 0 && options.inverse) return options.inverse(this);
344
+ /* v8 ignore next -- @preserve */
345
+ return "";
346
+ };
347
+ const map = (array, fn) => {
348
+ if (!Array.isArray(array) || typeof fn !== "function") return [];
349
+ return array.map(fn);
350
+ };
351
+ const pluck = (collection, prop) => {
352
+ if (!Array.isArray(collection) || typeof prop !== "string") return [];
353
+ return collection.map((item) => {
354
+ if (item == null || typeof item !== "object") return;
355
+ const parts = prop.split(".");
356
+ let value = item;
357
+ for (const part of parts) {
358
+ /* v8 ignore next -- @preserve */
359
+ if (value == null || typeof value !== "object") return;
360
+ value = value[part];
361
+ }
362
+ return value;
363
+ });
364
+ };
365
+ const reverse$1 = (value) => {
366
+ if (typeof value === "string") return value.split("").reverse().join("");
367
+ if (Array.isArray(value)) return [...value].reverse();
368
+ };
369
+ const sort = (array, key) => {
370
+ if (!Array.isArray(array)) return [];
371
+ const sorted = [...array];
372
+ if (typeof key === "function") sorted.sort(key);
373
+ else if (typeof key === "string")
374
+ /* v8 ignore next -- @preserve */
375
+ sorted.sort((a, b) => {
376
+ const aVal = a?.[key];
377
+ const bVal = b?.[key];
378
+ /* v8 ignore next -- @preserve */
379
+ if (aVal === bVal) return 0;
380
+ /* v8 ignore next -- @preserve */
381
+ if (aVal == null) return 1;
382
+ if (bVal == null) return -1;
383
+ if (typeof aVal === "string" && typeof bVal === "string") return aVal.localeCompare(bVal);
384
+ /* v8 ignore next -- @preserve */
385
+ return aVal < bVal ? -1 : 1;
386
+ });
387
+ else sorted.sort((a, b) => {
388
+ /* v8 ignore next -- @preserve */
389
+ if (a === b) return 0;
390
+ if (a == null) return 1;
391
+ if (b == null) return -1;
392
+ if (typeof a === "string" && typeof b === "string") return a.localeCompare(b);
393
+ return a < b ? -1 : 1;
394
+ });
395
+ return sorted;
396
+ };
397
+ const sortBy = (array, ...props) => {
398
+ if (!Array.isArray(array) || props.length === 0) return [];
399
+ const sorted = [...array];
400
+ sorted.sort((a, b) => {
401
+ for (const prop of props) {
402
+ const aVal = a?.[prop];
403
+ const bVal = b?.[prop];
404
+ if (aVal === bVal) continue;
405
+ if (aVal == null) return 1;
406
+ if (bVal == null) return -1;
407
+ if (typeof aVal === "string" && typeof bVal === "string") {
408
+ const result = aVal.localeCompare(bVal);
409
+ /* v8 ignore next -- @preserve */
410
+ if (result !== 0) return result;
411
+ } else return aVal < bVal ? -1 : 1;
412
+ }
413
+ /* v8 ignore next -- @preserve */
414
+ return 0;
415
+ });
416
+ return sorted;
417
+ };
418
+ const unique = function(array, options) {
419
+ if (!Array.isArray(array)) {
420
+ /* v8 ignore next -- @preserve */
421
+ if (!options) return [];
422
+ /* v8 ignore next -- @preserve */
423
+ return options.inverse ? options.inverse(this) ?? "" : "";
424
+ }
425
+ const uniqueArray = [...new Set(array)];
426
+ if (!options) return uniqueArray;
427
+ if (uniqueArray.length === 0 && options.inverse) return options.inverse(this);
428
+ if (uniqueArray.length > 0 && options.fn) {
429
+ let result = "";
430
+ for (const item of uniqueArray) result += options.fn(item);
431
+ return result;
432
+ }
433
+ return "";
434
+ };
435
+ const helpers$23 = [
436
+ {
437
+ name: "after",
438
+ category: "array",
439
+ compatibility: ["browser", "nodejs"],
440
+ fn: after
441
+ },
442
+ {
443
+ name: "before",
444
+ category: "array",
445
+ compatibility: ["browser", "nodejs"],
446
+ fn: before
447
+ },
448
+ {
449
+ name: "arrayify",
450
+ category: "array",
451
+ compatibility: ["browser", "nodejs"],
452
+ fn: arrayify
453
+ },
454
+ {
455
+ name: "first",
456
+ category: "array",
457
+ compatibility: ["browser", "nodejs"],
458
+ fn: first
459
+ },
460
+ {
461
+ name: "last",
462
+ category: "array",
463
+ compatibility: ["browser", "nodejs"],
464
+ fn: last
465
+ },
466
+ {
467
+ name: "length",
468
+ category: "array",
469
+ compatibility: ["browser", "nodejs"],
470
+ fn: length
471
+ },
472
+ {
473
+ name: "join",
474
+ category: "array",
475
+ compatibility: ["browser", "nodejs"],
476
+ fn: join
477
+ },
478
+ {
479
+ name: "forEach",
480
+ category: "array",
481
+ compatibility: ["browser", "nodejs"],
482
+ fn: forEach
483
+ },
484
+ {
485
+ name: "inArray",
486
+ category: "array",
487
+ compatibility: ["browser", "nodejs"],
488
+ fn: inArray
489
+ },
490
+ {
491
+ name: "isArray",
492
+ category: "array",
493
+ compatibility: ["browser", "nodejs"],
494
+ fn: isArray
495
+ },
496
+ {
497
+ name: "itemAt",
498
+ category: "array",
499
+ compatibility: ["browser", "nodejs"],
500
+ fn: itemAt
501
+ },
502
+ {
503
+ name: "equalsLength",
504
+ category: "array",
505
+ compatibility: ["browser", "nodejs"],
506
+ fn: equalsLength
507
+ },
508
+ {
509
+ name: "some",
510
+ category: "array",
511
+ compatibility: ["browser", "nodejs"],
512
+ fn: some
513
+ },
514
+ {
515
+ name: "eachIndex",
516
+ category: "array",
517
+ compatibility: ["browser", "nodejs"],
518
+ fn: eachIndex
519
+ },
520
+ {
521
+ name: "withAfter",
522
+ category: "array",
523
+ compatibility: ["browser", "nodejs"],
524
+ fn: withAfter
525
+ },
526
+ {
527
+ name: "withBefore",
528
+ category: "array",
529
+ compatibility: ["browser", "nodejs"],
530
+ fn: withBefore
531
+ },
532
+ {
533
+ name: "withFirst",
534
+ category: "array",
535
+ compatibility: ["browser", "nodejs"],
536
+ fn: withFirst
537
+ },
538
+ {
539
+ name: "withLast",
540
+ category: "array",
541
+ compatibility: ["browser", "nodejs"],
542
+ fn: withLast
543
+ },
544
+ {
545
+ name: "withGroup",
546
+ category: "array",
547
+ compatibility: ["browser", "nodejs"],
548
+ fn: withGroup
549
+ },
550
+ {
551
+ name: "withSort",
552
+ category: "array",
553
+ compatibility: ["browser", "nodejs"],
554
+ fn: withSort
555
+ },
556
+ {
557
+ name: "filter",
558
+ category: "array",
559
+ compatibility: ["browser", "nodejs"],
560
+ fn: filter
561
+ },
562
+ {
563
+ name: "map",
564
+ category: "array",
565
+ compatibility: ["browser", "nodejs"],
566
+ fn: map
567
+ },
568
+ {
569
+ name: "pluck",
570
+ category: "array",
571
+ compatibility: ["browser", "nodejs"],
572
+ fn: pluck
573
+ },
574
+ {
575
+ name: "reverse",
576
+ category: "array",
577
+ compatibility: ["browser", "nodejs"],
578
+ fn: reverse$1
579
+ },
580
+ {
581
+ name: "sort",
582
+ category: "array",
583
+ compatibility: ["browser", "nodejs"],
584
+ fn: sort
585
+ },
586
+ {
587
+ name: "sortBy",
588
+ category: "array",
589
+ compatibility: ["browser", "nodejs"],
590
+ fn: sortBy
591
+ },
592
+ {
593
+ name: "unique",
594
+ category: "array",
595
+ compatibility: ["browser", "nodejs"],
596
+ fn: unique
597
+ }
598
+ ];
599
+ //#endregion
600
+ //#region src/helpers/html.ts
601
+ const isTagStart = (ch) => ch !== void 0 && (ch === "/" || ch === "!" || ch === "?" || /[a-zA-Z]/.test(ch));
602
+ const stripTags = (str) => {
603
+ let result = "";
604
+ let inTag = false;
605
+ let inComment = false;
606
+ let quote = null;
607
+ for (let i = 0; i < str.length; i++) {
608
+ const ch = str[i];
609
+ if (inComment) {
610
+ if (ch === "-" && str[i + 1] === "-" && str[i + 2] === ">") {
611
+ inComment = false;
612
+ i += 2;
613
+ }
614
+ continue;
615
+ }
616
+ if (inTag) {
617
+ if (quote) {
618
+ if (ch === quote) quote = null;
619
+ } else if (ch === "\"" || ch === "'") quote = ch;
620
+ else if (ch === ">") inTag = false;
621
+ continue;
622
+ }
623
+ if (ch === "<") {
624
+ if (str[i + 1] === "!" && str[i + 2] === "-" && str[i + 3] === "-") {
625
+ inComment = true;
626
+ i += 3;
627
+ continue;
628
+ }
629
+ if (isTagStart(str[i + 1])) {
630
+ inTag = true;
631
+ continue;
632
+ }
633
+ }
634
+ result += ch;
635
+ }
636
+ return result;
637
+ };
638
+ const VOID_ELEMENTS = new Set([
639
+ "area",
640
+ "base",
641
+ "br",
642
+ "col",
643
+ "command",
644
+ "embed",
645
+ "hr",
646
+ "img",
647
+ "input",
648
+ "keygen",
649
+ "link",
650
+ "meta",
651
+ "param",
652
+ "source",
653
+ "track",
654
+ "wbr",
655
+ "circle",
656
+ "ellipse",
657
+ "line",
658
+ "path",
659
+ "polygon",
660
+ "polyline",
661
+ "rect",
662
+ "stop",
663
+ "use"
664
+ ]);
665
+ const tag = (name, attribs = {}, text = "") => {
666
+ let html = `<${name}`;
667
+ for (const [key, val] of Object.entries(attribs)) if (val === true) html += ` ${key}`;
668
+ else if (typeof val === "string" || typeof val === "number") html += ` ${key}="${escapeAttr(String(val))}"`;
669
+ if (VOID_ELEMENTS.has(name.toLowerCase())) return `${html}>`;
670
+ return `${html}>${escapeText(text)}</${name}>`;
671
+ };
672
+ const escapeAttr = (str) => str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
673
+ const escapeText = (str) => str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
674
+ const parseAttributes = (hash = {}) => Object.keys(hash).map((key) => `${key}="${String(hash[key]).replace(/^['"]|["']$/g, "")}"`).join(" ");
675
+ const attr = (options) => {
676
+ const val = parseAttributes(options?.hash ?? {});
677
+ return val.trim() ? ` ${val}` : "";
678
+ };
679
+ const sanitize = (str) => {
680
+ if (typeof str !== "string") return "";
681
+ return stripTags(str).trim();
682
+ };
683
+ const ul = (context, options) => {
684
+ const attrs = parseAttributes(options.hash ?? {});
685
+ const items = context.map((item) => typeof item === "string" ? item : options.fn(item));
686
+ return `${attrs ? `<ul ${attrs}>` : "<ul>"}${items.map((i) => `<li>${i}</li>`).join("\n")}</ul>`;
687
+ };
688
+ const ol = (context, options) => {
689
+ const attrs = parseAttributes(options.hash ?? {});
690
+ const items = context.map((item) => typeof item === "string" ? item : options.fn(item));
691
+ return `${attrs ? `<ol ${attrs}>` : "<ol>"}${items.map((i) => `<li>${i}</li>`).join("\n")}</ol>`;
692
+ };
693
+ const thumbnailImage = (context) => {
694
+ let figure = "";
695
+ let image = "";
696
+ const link = context.full || false;
697
+ const imageAttributes = {
698
+ alt: context.alt,
699
+ src: context.thumbnail,
700
+ width: context.size.width,
701
+ height: context.size.height
702
+ };
703
+ const figureAttributes = { id: `image-${context.id}` };
704
+ const linkAttributes = {
705
+ href: link,
706
+ rel: "thumbnail"
707
+ };
708
+ /* c8 ignore next -- @preserve */
709
+ if (context.classes) {
710
+ if (context.classes.image) imageAttributes.class = context.classes.image.join(" ");
711
+ if (context.classes.figure) figureAttributes.class = context.classes.figure.join(" ");
712
+ if (context.classes.link) linkAttributes.class = context.classes.link.join(" ");
713
+ }
714
+ figure += `<figure ${parseAttributes(figureAttributes)}>\n`;
715
+ image += `<img ${parseAttributes(imageAttributes)}>\n`;
716
+ if (link) figure += `<a ${parseAttributes(linkAttributes)}>\n${image}</a>\n`;
717
+ else figure += image;
718
+ /* c8 ignore next -- @preserve */
719
+ if (context.caption) figure += `<figcaption>${context.caption}</figcaption>\n`;
720
+ figure += "</figure>";
721
+ return figure;
722
+ };
723
+ const helpers$22 = [
724
+ {
725
+ name: "attr",
726
+ category: "html",
727
+ compatibility: ["browser", "nodejs"],
728
+ fn: attr
729
+ },
730
+ {
731
+ name: "sanitize",
732
+ category: "html",
733
+ compatibility: ["browser", "nodejs"],
734
+ fn: sanitize
735
+ },
736
+ {
737
+ name: "ul",
738
+ category: "html",
739
+ compatibility: ["browser", "nodejs"],
740
+ fn: ul
741
+ },
742
+ {
743
+ name: "ol",
744
+ category: "html",
745
+ compatibility: ["browser", "nodejs"],
746
+ fn: ol
747
+ },
748
+ {
749
+ name: "thumbnailImage",
750
+ category: "html",
751
+ compatibility: ["browser", "nodejs"],
752
+ fn: thumbnailImage
753
+ }
754
+ ];
755
+ //#endregion
756
+ //#region src/helpers/code.ts
757
+ const gist = (id) => {
758
+ return tag("script", { src: `https://gist.github.com/${id}.js` });
759
+ };
760
+ const jsfiddle = (options) => {
761
+ if (!options?.id) throw new Error("jsfiddle helper expects an `id`");
762
+ const { id, width = "100%", height = "300", skin = "/presentation/", tabs = "result,js,html,css", allowfullscreen = "allowfullscreen", frameborder = "0" } = options;
763
+ return tag("iframe", {
764
+ width,
765
+ height,
766
+ src: `http://jsfiddle.net/${id}/embedded/${tabs}${skin}`,
767
+ allowfullscreen,
768
+ frameborder
769
+ });
770
+ };
771
+ const helpers$21 = [{
772
+ name: "gist",
773
+ category: "code",
774
+ compatibility: ["browser", "nodejs"],
775
+ fn: gist
776
+ }, {
777
+ name: "jsfiddle",
778
+ category: "code",
779
+ compatibility: ["browser", "nodejs"],
780
+ fn: jsfiddle
781
+ }];
782
+ //#endregion
783
+ //#region src/helpers/code.node.ts
784
+ const codeBlock = (code, lang) => {
785
+ return `\`\`\`${lang}\n${code}\n\`\`\`\n`;
786
+ };
787
+ const embed = (filepath, language) => {
788
+ let ext = typeof language === "string" ? language : node_path.default.extname(filepath).slice(1);
789
+ let code = node_fs.default.readFileSync(filepath, "utf8");
790
+ if (ext === "markdown" || ext === "md") {
791
+ ext = "markdown";
792
+ code = code.split("`").join("&#x60");
793
+ }
794
+ return `${codeBlock(code, ext).trim()}\n`;
795
+ };
796
+ const helpers$20 = [{
797
+ name: "embed",
798
+ category: "code",
799
+ compatibility: ["nodejs"],
800
+ fn: embed
801
+ }];
802
+ //#endregion
803
+ //#region src/helpers/collection.ts
804
+ const isEmpty = (collection) => {
805
+ if (collection == null) return true;
806
+ if (Array.isArray(collection)) return collection.length === 0;
807
+ if (typeof collection === "object") return Object.keys(collection).length === 0;
808
+ return false;
809
+ };
810
+ const iterate = (collection, fn, inverse) => {
811
+ if (Array.isArray(collection)) {
812
+ let result = "";
813
+ for (let i = 0; i < collection.length; i++) result += fn(collection[i], i);
814
+ return result;
815
+ }
816
+ if (collection && typeof collection === "object") {
817
+ let result = "";
818
+ for (const key of Object.keys(collection)) result += fn(collection[key], key);
819
+ return result;
820
+ }
821
+ return inverse ? inverse() : "";
822
+ };
823
+ const helpers$19 = [{
824
+ name: "isEmpty",
825
+ category: "collection",
826
+ compatibility: ["browser", "nodejs"],
827
+ fn: isEmpty
828
+ }, {
829
+ name: "iterate",
830
+ category: "collection",
831
+ compatibility: ["browser", "nodejs"],
832
+ fn: iterate
833
+ }];
834
+ //#endregion
835
+ //#region src/helpers/comparison.ts
836
+ const and = (...values) => values.every(Boolean);
837
+ const compare = (a, operator, b) => {
838
+ switch (operator) {
839
+ case "==": return a == b;
840
+ case "===": return a === b;
841
+ case "!=": return a != b;
842
+ case "!==": return a !== b;
843
+ case "<": return a < b;
844
+ case ">": return a > b;
845
+ case "<=": return a <= b;
846
+ case ">=": return a >= b;
847
+ case "typeof": return typeof a === b;
848
+ default: throw new Error(`helper {{compare}}: invalid operator: '${operator}'`);
849
+ }
850
+ };
851
+ const contains = (collection, value, startIndex = 0) => {
852
+ if (collection == null) return false;
853
+ if (typeof collection === "string" || Array.isArray(collection)) return collection.indexOf(value, startIndex) > -1;
854
+ if (typeof collection === "object") return value in collection;
855
+ return false;
856
+ };
857
+ const defaultHelper = (...values) => {
858
+ for (const val of values) if (val != null) return val;
859
+ return "";
860
+ };
861
+ const eq = (a, b) => a === b;
862
+ const gt = (a, b) => a > b;
863
+ const gte = (a, b) => a >= b;
864
+ const has = (value, pattern) => {
865
+ if (value == null || pattern == null) return false;
866
+ if (Array.isArray(value) || typeof value === "string") return value.indexOf(pattern) > -1;
867
+ if (typeof value === "object") return pattern in value;
868
+ return false;
869
+ };
870
+ const falsey = (val, keywords) => {
871
+ if (!val) return true;
872
+ const words = Array.isArray(keywords) ? keywords : keywords != null ? [keywords] : [
873
+ "0",
874
+ "false",
875
+ "nada",
876
+ "nil",
877
+ "nay",
878
+ "nah",
879
+ "negative",
880
+ "no",
881
+ "none",
882
+ "nope",
883
+ "nul",
884
+ "null",
885
+ "nix",
886
+ "nyet",
887
+ "uh-uh",
888
+ "veto",
889
+ "zero"
890
+ ];
891
+ const lower = typeof val === "string" ? val.toLowerCase() : null;
892
+ for (const word of words) {
893
+ if (word === val) return true;
894
+ if (lower != null && word === lower) return true;
895
+ }
896
+ return false;
897
+ };
898
+ const isFalsey = (val) => falsey(val);
899
+ const isTruthy = (val) => !falsey(val);
900
+ const ifEven = (num) => typeof num === "number" && num % 2 === 0;
901
+ const ifNth = (a, b) => typeof a === "number" && typeof b === "number" && b % a === 0;
902
+ const ifOdd = (val) => typeof val === "number" && Math.abs(val % 2) === 1;
903
+ const is = (a, b) => a == b;
904
+ const isnt = (a, b) => a != b;
905
+ const lt = (a, b) => a < b;
906
+ const lte = (a, b) => a <= b;
907
+ const neither = (a, b) => !a && !b;
908
+ const not = (val) => !val;
909
+ const or = (...values) => values.some(Boolean);
910
+ const unlessEq = (a, b) => a !== b;
911
+ const unlessGt = (a, b) => a <= b;
912
+ const unlessLt = (a, b) => a >= b;
913
+ const unlessGteq = (a, b) => a < b;
914
+ const unlessLteq = (a, b) => a > b;
915
+ const helpers$18 = [
916
+ {
917
+ name: "and",
918
+ category: "comparison",
919
+ compatibility: ["browser", "nodejs"],
920
+ fn: and
921
+ },
922
+ {
923
+ name: "compare",
924
+ category: "comparison",
925
+ compatibility: ["browser", "nodejs"],
926
+ fn: compare
927
+ },
928
+ {
929
+ name: "contains",
930
+ category: "comparison",
931
+ compatibility: ["browser", "nodejs"],
932
+ fn: contains
933
+ },
934
+ {
935
+ name: "default",
936
+ category: "comparison",
937
+ compatibility: ["browser", "nodejs"],
938
+ fn: defaultHelper
939
+ },
940
+ {
941
+ name: "eq",
942
+ category: "comparison",
943
+ compatibility: ["browser", "nodejs"],
944
+ fn: eq
945
+ },
946
+ {
947
+ name: "gt",
948
+ category: "comparison",
949
+ compatibility: ["browser", "nodejs"],
950
+ fn: gt
951
+ },
952
+ {
953
+ name: "gte",
954
+ category: "comparison",
955
+ compatibility: ["browser", "nodejs"],
956
+ fn: gte
957
+ },
958
+ {
959
+ name: "has",
960
+ category: "comparison",
961
+ compatibility: ["browser", "nodejs"],
962
+ fn: has
963
+ },
964
+ {
965
+ name: "isFalsey",
966
+ category: "comparison",
967
+ compatibility: ["browser", "nodejs"],
968
+ fn: isFalsey
969
+ },
970
+ {
971
+ name: "isTruthy",
972
+ category: "comparison",
973
+ compatibility: ["browser", "nodejs"],
974
+ fn: isTruthy
975
+ },
976
+ {
977
+ name: "ifEven",
978
+ category: "comparison",
979
+ compatibility: ["browser", "nodejs"],
980
+ fn: ifEven
981
+ },
982
+ {
983
+ name: "ifNth",
984
+ category: "comparison",
985
+ compatibility: ["browser", "nodejs"],
986
+ fn: ifNth
987
+ },
988
+ {
989
+ name: "ifOdd",
990
+ category: "comparison",
991
+ compatibility: ["browser", "nodejs"],
992
+ fn: ifOdd
993
+ },
994
+ {
995
+ name: "is",
996
+ category: "comparison",
997
+ compatibility: ["browser", "nodejs"],
998
+ fn: is
999
+ },
1000
+ {
1001
+ name: "isnt",
1002
+ category: "comparison",
1003
+ compatibility: ["browser", "nodejs"],
1004
+ fn: isnt
1005
+ },
1006
+ {
1007
+ name: "lt",
1008
+ category: "comparison",
1009
+ compatibility: ["browser", "nodejs"],
1010
+ fn: lt
1011
+ },
1012
+ {
1013
+ name: "lte",
1014
+ category: "comparison",
1015
+ compatibility: ["browser", "nodejs"],
1016
+ fn: lte
1017
+ },
1018
+ {
1019
+ name: "neither",
1020
+ category: "comparison",
1021
+ compatibility: ["browser", "nodejs"],
1022
+ fn: neither
1023
+ },
1024
+ {
1025
+ name: "not",
1026
+ category: "comparison",
1027
+ compatibility: ["browser", "nodejs"],
1028
+ fn: not
1029
+ },
1030
+ {
1031
+ name: "or",
1032
+ category: "comparison",
1033
+ compatibility: ["browser", "nodejs"],
1034
+ fn: or
1035
+ },
1036
+ {
1037
+ name: "unlessEq",
1038
+ category: "comparison",
1039
+ compatibility: ["browser", "nodejs"],
1040
+ fn: unlessEq
1041
+ },
1042
+ {
1043
+ name: "unlessGt",
1044
+ category: "comparison",
1045
+ compatibility: ["browser", "nodejs"],
1046
+ fn: unlessGt
1047
+ },
1048
+ {
1049
+ name: "unlessLt",
1050
+ category: "comparison",
1051
+ compatibility: ["browser", "nodejs"],
1052
+ fn: unlessLt
1053
+ },
1054
+ {
1055
+ name: "unlessGteq",
1056
+ category: "comparison",
1057
+ compatibility: ["browser", "nodejs"],
1058
+ fn: unlessGteq
1059
+ },
1060
+ {
1061
+ name: "unlessLteq",
1062
+ category: "comparison",
1063
+ compatibility: ["browser", "nodejs"],
1064
+ fn: unlessLteq
1065
+ }
1066
+ ];
1067
+ //#endregion
1068
+ //#region src/helpers/date.ts
1069
+ dayjs.default.extend(dayjs_plugin_relativeTime_js.default);
1070
+ dayjs.default.extend(dayjs_plugin_isBetween_js.default);
1071
+ dayjs.default.extend(dayjs_plugin_utc_js.default);
1072
+ dayjs.default.extend(dayjs_plugin_timezone_js.default);
1073
+ const parseDateInput = (input) => {
1074
+ if (!input) return (0, dayjs.default)();
1075
+ if (typeof input === "string") {
1076
+ const parsed = (0, chrono_node.parseDate)(input);
1077
+ if (parsed) return (0, dayjs.default)(parsed);
1078
+ return (0, dayjs.default)(input);
1079
+ }
1080
+ return (0, dayjs.default)(input);
1081
+ };
1082
+ const year = () => (/* @__PURE__ */ new Date()).getFullYear().toString();
1083
+ const convertFormatString = (format) => {
1084
+ return format.replace(/yyyy/g, "YYYY").replace(/yy/g, "YY").replace(/dd/g, "DD").replace(/mm/g, "MM").replace(/hh/g, "HH");
1085
+ };
1086
+ const date = (humanReadableDate, formatString) => {
1087
+ const format = formatString || "YYYY-MM-DD";
1088
+ const parsedDate = parseDateInput(humanReadableDate);
1089
+ /* v8 ignore next -- @preserve */
1090
+ if (!parsedDate.isValid()) throw new Error(`Unable to parse date: ${humanReadableDate}`);
1091
+ const convertedFormat = convertFormatString(format);
1092
+ return parsedDate.format(convertedFormat);
1093
+ };
1094
+ const timestamp = () => {
1095
+ return Date.now().toString();
1096
+ };
1097
+ const now = (formatString) => {
1098
+ const convertedFormat = convertFormatString(formatString || "YYYY-MM-DD HH:mm:ss");
1099
+ return (0, dayjs.default)().format(convertedFormat);
1100
+ };
1101
+ const fromNow = (dateInput) => {
1102
+ const parsed = parseDateInput(dateInput);
1103
+ /* v8 ignore next -- @preserve */
1104
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1105
+ return parsed.fromNow();
1106
+ };
1107
+ const toNow = (dateInput) => {
1108
+ const parsed = parseDateInput(dateInput);
1109
+ /* v8 ignore next -- @preserve */
1110
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1111
+ return parsed.toNow();
1112
+ };
1113
+ const ago = (dateInput) => {
1114
+ return fromNow(dateInput);
1115
+ };
1116
+ const dateAdd = (dateInput, amount, unit) => {
1117
+ const parsed = parseDateInput(dateInput);
1118
+ /* v8 ignore next -- @preserve */
1119
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1120
+ return parsed.add(amount, unit).format("YYYY-MM-DD HH:mm:ss");
1121
+ };
1122
+ const dateSubtract = (dateInput, amount, unit) => {
1123
+ const parsed = parseDateInput(dateInput);
1124
+ /* v8 ignore next -- @preserve */
1125
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1126
+ return parsed.subtract(amount, unit).format("YYYY-MM-DD HH:mm:ss");
1127
+ };
1128
+ const startOf = (dateInput, unit) => {
1129
+ const parsed = parseDateInput(dateInput);
1130
+ /* v8 ignore next -- @preserve */
1131
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1132
+ return parsed.startOf(unit).format("YYYY-MM-DD HH:mm:ss");
1133
+ };
1134
+ const endOf = (dateInput, unit) => {
1135
+ const parsed = parseDateInput(dateInput);
1136
+ /* v8 ignore next -- @preserve */
1137
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1138
+ return parsed.endOf(unit).format("YYYY-MM-DD HH:mm:ss");
1139
+ };
1140
+ const isBefore = (date1, date2) => {
1141
+ const parsed1 = parseDateInput(date1);
1142
+ const parsed2 = parseDateInput(date2);
1143
+ /* v8 ignore next -- @preserve */
1144
+ if (!parsed1.isValid() || !parsed2.isValid()) throw new Error(`Unable to parse dates: ${date1}, ${date2}`);
1145
+ return parsed1.isBefore(parsed2);
1146
+ };
1147
+ const isAfter = (date1, date2) => {
1148
+ const parsed1 = parseDateInput(date1);
1149
+ const parsed2 = parseDateInput(date2);
1150
+ /* v8 ignore next -- @preserve */
1151
+ if (!parsed1.isValid() || !parsed2.isValid()) throw new Error(`Unable to parse dates: ${date1}, ${date2}`);
1152
+ return parsed1.isAfter(parsed2);
1153
+ };
1154
+ const isSame = (date1, date2, unit) => {
1155
+ const parsed1 = parseDateInput(date1);
1156
+ const parsed2 = parseDateInput(date2);
1157
+ /* v8 ignore next -- @preserve */
1158
+ if (!parsed1.isValid() || !parsed2.isValid()) throw new Error(`Unable to parse dates: ${date1}, ${date2}`);
1159
+ return parsed1.isSame(parsed2, unit);
1160
+ };
1161
+ const isBetweenDates = (dateInput, startDate, endDate) => {
1162
+ const parsed = parseDateInput(dateInput);
1163
+ const parsedStart = parseDateInput(startDate);
1164
+ const parsedEnd = parseDateInput(endDate);
1165
+ /* v8 ignore next -- @preserve */
1166
+ if (!parsed.isValid() || !parsedStart.isValid() || !parsedEnd.isValid()) throw new Error(`Unable to parse dates: ${dateInput}, ${startDate}, ${endDate}`);
1167
+ return parsed.isBetween(parsedStart, parsedEnd, null, "[]");
1168
+ };
1169
+ const diff = (date1, date2, unit) => {
1170
+ const parsed1 = parseDateInput(date1);
1171
+ const parsed2 = parseDateInput(date2);
1172
+ /* v8 ignore next -- @preserve */
1173
+ if (!parsed1.isValid() || !parsed2.isValid()) throw new Error(`Unable to parse dates: ${date1}, ${date2}`);
1174
+ return parsed1.diff(parsed2, unit);
1175
+ };
1176
+ const toISOString = (dateInput) => {
1177
+ const parsed = parseDateInput(dateInput);
1178
+ /* v8 ignore next -- @preserve */
1179
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1180
+ return parsed.toISOString();
1181
+ };
1182
+ const dateTimezone = (dateInput, timezoneStr, formatString) => {
1183
+ const convertedFormat = convertFormatString(formatString || "YYYY-MM-DD HH:mm:ss");
1184
+ const parsed = parseDateInput(dateInput);
1185
+ /* v8 ignore next -- @preserve */
1186
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1187
+ return parsed.tz(timezoneStr).format(convertedFormat);
1188
+ };
1189
+ const dateLocale = (dateInput, locale, formatString) => {
1190
+ const convertedFormat = convertFormatString(formatString || "YYYY-MM-DD HH:mm:ss");
1191
+ const parsed = parseDateInput(dateInput);
1192
+ /* v8 ignore next -- @preserve */
1193
+ if (!parsed.isValid()) throw new Error(`Unable to parse date: ${dateInput}`);
1194
+ return parsed.locale(locale).format(convertedFormat);
1195
+ };
1196
+ const helpers$17 = [
1197
+ {
1198
+ name: "year",
1199
+ category: "date",
1200
+ compatibility: ["browser", "nodejs"],
1201
+ fn: year
1202
+ },
1203
+ {
1204
+ name: "date",
1205
+ category: "date",
1206
+ compatibility: ["browser", "nodejs"],
1207
+ fn: date
1208
+ },
1209
+ {
1210
+ name: "moment",
1211
+ category: "date",
1212
+ compatibility: ["browser", "nodejs"],
1213
+ fn: date
1214
+ },
1215
+ {
1216
+ name: "timestamp",
1217
+ category: "date",
1218
+ compatibility: ["browser", "nodejs"],
1219
+ fn: timestamp
1220
+ },
1221
+ {
1222
+ name: "now",
1223
+ category: "date",
1224
+ compatibility: ["browser", "nodejs"],
1225
+ fn: now
1226
+ },
1227
+ {
1228
+ name: "fromNow",
1229
+ category: "date",
1230
+ compatibility: ["browser", "nodejs"],
1231
+ fn: fromNow
1232
+ },
1233
+ {
1234
+ name: "toNow",
1235
+ category: "date",
1236
+ compatibility: ["browser", "nodejs"],
1237
+ fn: toNow
1238
+ },
1239
+ {
1240
+ name: "ago",
1241
+ category: "date",
1242
+ compatibility: ["browser", "nodejs"],
1243
+ fn: ago
1244
+ },
1245
+ {
1246
+ name: "dateAdd",
1247
+ category: "date",
1248
+ compatibility: ["browser", "nodejs"],
1249
+ fn: dateAdd
1250
+ },
1251
+ {
1252
+ name: "dateSubtract",
1253
+ category: "date",
1254
+ compatibility: ["browser", "nodejs"],
1255
+ fn: dateSubtract
1256
+ },
1257
+ {
1258
+ name: "startOf",
1259
+ category: "date",
1260
+ compatibility: ["browser", "nodejs"],
1261
+ fn: startOf
1262
+ },
1263
+ {
1264
+ name: "endOf",
1265
+ category: "date",
1266
+ compatibility: ["browser", "nodejs"],
1267
+ fn: endOf
1268
+ },
1269
+ {
1270
+ name: "isBefore",
1271
+ category: "date",
1272
+ compatibility: ["browser", "nodejs"],
1273
+ fn: isBefore
1274
+ },
1275
+ {
1276
+ name: "isAfter",
1277
+ category: "date",
1278
+ compatibility: ["browser", "nodejs"],
1279
+ fn: isAfter
1280
+ },
1281
+ {
1282
+ name: "isSame",
1283
+ category: "date",
1284
+ compatibility: ["browser", "nodejs"],
1285
+ fn: isSame
1286
+ },
1287
+ {
1288
+ name: "isBetween",
1289
+ category: "date",
1290
+ compatibility: ["browser", "nodejs"],
1291
+ fn: isBetweenDates
1292
+ },
1293
+ {
1294
+ name: "diff",
1295
+ category: "date",
1296
+ compatibility: ["browser", "nodejs"],
1297
+ fn: diff
1298
+ },
1299
+ {
1300
+ name: "toISOString",
1301
+ category: "date",
1302
+ compatibility: ["browser", "nodejs"],
1303
+ fn: toISOString
1304
+ },
1305
+ {
1306
+ name: "dateTimezone",
1307
+ category: "date",
1308
+ compatibility: ["browser", "nodejs"],
1309
+ fn: dateTimezone
1310
+ },
1311
+ {
1312
+ name: "dateLocale",
1313
+ category: "date",
1314
+ compatibility: ["browser", "nodejs"],
1315
+ fn: dateLocale
1316
+ }
1317
+ ];
1318
+ //#endregion
1319
+ //#region src/helpers/fs.ts
1320
+ const ESCAPE_SEQUENCE = /\\[\s\S]/g;
1321
+ const GLOB_PATTERN = /^!|[*?]|\[[^\]]+\]|\{[^}]+\}|[@?!+*]\([^)]*\)|\([^)]*\|[^)]*\)/;
1322
+ const isGlob = (value) => GLOB_PATTERN.test(value.replace(ESCAPE_SEQUENCE, ""));
1323
+ const fileSize = (value, precision) => {
1324
+ if (value == null) return "0 B";
1325
+ const number = typeof value === "number" ? value : value.length ?? 0;
1326
+ if (!number) return "0 B";
1327
+ const precisionNumber = typeof precision === "number" ? precision : 2;
1328
+ const abbr = [
1329
+ "B",
1330
+ "kB",
1331
+ "MB",
1332
+ "GB",
1333
+ "TB",
1334
+ "PB",
1335
+ "EB",
1336
+ "ZB",
1337
+ "YB"
1338
+ ];
1339
+ const factor = 10 ** precisionNumber;
1340
+ let i = abbr.length - 1;
1341
+ do {
1342
+ const size = 10 ** (i * 3);
1343
+ if (size <= number + 1) return `${Math.round(number * factor / size) / factor} ${abbr[i]}`;
1344
+ } while (--i >= 0);
1345
+ /* c8 ignore next -- @preserve */
1346
+ return `${number} B`;
1347
+ };
1348
+ const read = (filepath) => {
1349
+ return node_fs.default.readFileSync(filepath, "utf8");
1350
+ };
1351
+ const isOptions$1 = (value) => {
1352
+ return Boolean(value && typeof value === "object" && "hash" in value);
1353
+ };
1354
+ const readdir = (dir, filter) => {
1355
+ const files = node_fs.default.readdirSync(dir).map((fp) => node_path.default.join(dir, fp));
1356
+ const filterArg = isOptions$1(filter) ? void 0 : filter;
1357
+ if (typeof filterArg === "function") return filterArg(files);
1358
+ if (filterArg instanceof RegExp) return files.filter((fp) => filterArg.test(fp));
1359
+ if (typeof filterArg === "string") {
1360
+ if (isGlob(filterArg)) return (0, micromatch.default)(files, filterArg);
1361
+ if (filterArg === "isFile" || filterArg === "isDirectory") return files.filter((fp) => {
1362
+ const stat = node_fs.default.statSync(fp);
1363
+ return filterArg === "isFile" ? stat.isFile() : stat.isDirectory();
1364
+ });
1365
+ }
1366
+ return files;
1367
+ };
1368
+ const helpers$16 = [
1369
+ {
1370
+ name: "fileSize",
1371
+ category: "fs",
1372
+ compatibility: ["nodejs"],
1373
+ fn: fileSize
1374
+ },
1375
+ {
1376
+ name: "read",
1377
+ category: "fs",
1378
+ compatibility: ["nodejs"],
1379
+ fn: read
1380
+ },
1381
+ {
1382
+ name: "readdir",
1383
+ category: "fs",
1384
+ compatibility: ["nodejs"],
1385
+ fn: readdir
1386
+ }
1387
+ ];
1388
+ //#endregion
1389
+ //#region src/helpers/html.node.ts
1390
+ const css = function(list, options) {
1391
+ if (arguments.length < 2) {
1392
+ options = list;
1393
+ list = [];
1394
+ }
1395
+ let styles = arrayify(list ?? []);
1396
+ let assets = "";
1397
+ if (this && this.options) assets = this.options.assets || "";
1398
+ if (options?.hash?.href) styles = arrayify(options.hash.href);
1399
+ return styles.map((item) => {
1400
+ const ext = node_path.default.extname(item);
1401
+ let fp = item;
1402
+ /* c8 ignore next -- @preserve */
1403
+ if (!/(^\/\/)|(:\/\/)/.test(item)) fp = node_path.default.posix.join(assets, item);
1404
+ if (ext === ".less") return `<link type="text/css" rel="stylesheet/less" href="${fp}">`;
1405
+ return `<link type="text/css" rel="stylesheet" href="${fp}">`;
1406
+ }).join("\n");
1407
+ };
1408
+ const js = (context) => {
1409
+ if (context && typeof context === "object" && !Array.isArray(context)) {
1410
+ const attrStr = parseAttributes(context.hash ?? {});
1411
+ return `<script${attrStr ? ` ${attrStr}` : ""}><\/script>`;
1412
+ }
1413
+ if (typeof context === "string") return `<script src="${context}"><\/script>`;
1414
+ return arrayify(context).map((fp) => node_path.default.extname(fp) === ".coffee" ? tag("script", {
1415
+ type: "text/coffeescript",
1416
+ src: fp
1417
+ }) : tag("script", { src: fp })).join("\n");
1418
+ };
1419
+ const helpers$15 = [{
1420
+ name: "css",
1421
+ category: "html",
1422
+ compatibility: ["nodejs"],
1423
+ fn: css
1424
+ }, {
1425
+ name: "js",
1426
+ category: "html",
1427
+ compatibility: ["nodejs"],
1428
+ fn: js
1429
+ }];
1430
+ //#endregion
1431
+ //#region src/utils.ts
1432
+ /**
1433
+ * Native implementation to replace get-value module
1434
+ * Safely gets nested object properties using dot notation or array paths
1435
+ * @param object - The object to traverse
1436
+ * @param path - Dot notation string or array of keys
1437
+ * @returns The value at the path or undefined if not found
1438
+ */
1439
+ const get = (object, path) => {
1440
+ if (!object || typeof object !== "object") return void 0;
1441
+ const keys = Array.isArray(path) ? path : path.split(".");
1442
+ let result = object;
1443
+ for (const key of keys) {
1444
+ if (result == null || typeof result !== "object") return void 0;
1445
+ result = result[key];
1446
+ }
1447
+ return result;
1448
+ };
1449
+ /**
1450
+ * Native implementation to replace get-object module
1451
+ * Returns an object containing the key-value pair at the specified path
1452
+ * @param object - The object to traverse
1453
+ * @param path - Dot notation string or array of keys
1454
+ * @returns An object containing the key-value pair, or undefined if not found
1455
+ */
1456
+ const getObject = (object, path) => {
1457
+ if (!object || typeof object !== "object") return void 0;
1458
+ const keys = Array.isArray(path) ? path : path.split(".");
1459
+ if (keys.length === 0) return void 0;
1460
+ let current = object;
1461
+ for (let i = 0; i < keys.length - 1; i++) {
1462
+ if (current == null || typeof current !== "object") return void 0;
1463
+ current = current[keys[i]];
1464
+ }
1465
+ const finalKey = keys[keys.length - 1];
1466
+ if (current == null || typeof current !== "object" || !(finalKey in current)) return;
1467
+ return { [finalKey]: current[finalKey] };
1468
+ };
1469
+ /**
1470
+ * Merges options from multiple sources for Handlebars helpers
1471
+ * Replaces handlebars-utils util.options()
1472
+ * @param thisArg - The context (this) from the helper, may have an options property
1473
+ * @param locals - Local options or a Handlebars options object with hash
1474
+ * @param opts - Additional options or a Handlebars options object with hash
1475
+ * @returns Merged options object
1476
+ */
1477
+ const options = (thisArg, locals, opts) => {
1478
+ const result = {};
1479
+ if (thisArg && typeof thisArg === "object" && thisArg.options) Object.assign(result, thisArg.options);
1480
+ if (locals && typeof locals === "object") if ("hash" in locals) Object.assign(result, locals.hash);
1481
+ else Object.assign(result, locals);
1482
+ if (opts && typeof opts === "object") if ("hash" in opts) Object.assign(result, opts.hash);
1483
+ else Object.assign(result, opts);
1484
+ return result;
1485
+ };
1486
+ //#endregion
1487
+ //#region src/helpers/i18n.ts
1488
+ const i18n = function(prop, locals, options) {
1489
+ if (locals && typeof locals === "object" && "hash" in locals && options === void 0) {
1490
+ options = locals;
1491
+ locals = {};
1492
+ }
1493
+ if (typeof prop !== "string") throw new Error("{{i18n}} helper expected \"key\" to be a string");
1494
+ const context = {
1495
+ ...this,
1496
+ ...locals,
1497
+ ...options?.hash ?? {}
1498
+ };
1499
+ const lang = context.language || context.lang;
1500
+ if (typeof lang !== "string") throw new TypeError("{{i18n}} helper expected \"language\" to be a string");
1501
+ const cache = context[lang];
1502
+ if (typeof cache === "undefined") throw new Error(`{{i18n}} helper cannot find language "${lang}"`);
1503
+ const result = get(cache, prop);
1504
+ if (typeof result === "undefined") throw new Error("{{i18n}} helper cannot find property \"" + String(prop) + "\" for language \"" + lang + "\"");
1505
+ return String(result);
1506
+ };
1507
+ const helpers$14 = [{
1508
+ name: "i18n",
1509
+ category: "i18n",
1510
+ compatibility: ["browser", "nodejs"],
1511
+ fn: i18n
1512
+ }];
1513
+ //#endregion
1514
+ //#region src/helpers/inflection.ts
1515
+ const inflect = (count, singular, plural, includeCount) => {
1516
+ const word = count > 1 || count === 0 ? plural : singular;
1517
+ return includeCount ? `${count} ${word}` : word;
1518
+ };
1519
+ const ordinalize = (value) => {
1520
+ const num = Math.abs(Math.round(Number(value)));
1521
+ const str = String(value);
1522
+ const res = num % 100;
1523
+ if ([
1524
+ 11,
1525
+ 12,
1526
+ 13
1527
+ ].includes(res)) return `${str}th`;
1528
+ switch (num % 10) {
1529
+ case 1: return `${str}st`;
1530
+ case 2: return `${str}nd`;
1531
+ case 3: return `${str}rd`;
1532
+ default: return `${str}th`;
1533
+ }
1534
+ };
1535
+ const helpers$13 = [{
1536
+ name: "inflect",
1537
+ category: "inflection",
1538
+ compatibility: ["browser", "nodejs"],
1539
+ fn: inflect
1540
+ }, {
1541
+ name: "ordinalize",
1542
+ category: "inflection",
1543
+ compatibility: ["browser", "nodejs"],
1544
+ fn: ordinalize
1545
+ }];
1546
+ //#endregion
1547
+ //#region src/helpers/logging.ts
1548
+ /**
1549
+ * ANSI color codes for terminal output
1550
+ */
1551
+ const colors = {
1552
+ green: (str) => `\x1b[32m${str}\x1b[0m`,
1553
+ cyan: (str) => `\x1b[36m${str}\x1b[0m`,
1554
+ yellow: (str) => `\x1b[33m${str}\x1b[0m`,
1555
+ red: (str) => `\x1b[31m${str}\x1b[0m`,
1556
+ bold: (str) => `\x1b[1m${str}\x1b[0m`
1557
+ };
1558
+ /**
1559
+ * Remove handlebars options from arguments if present
1560
+ */
1561
+ function cleanArgs(args) {
1562
+ const last = args[args.length - 1];
1563
+ if (args.length > 1 && typeof last === "object" && last !== null && "hash" in last) return args.slice(0, -1);
1564
+ return args;
1565
+ }
1566
+ /**
1567
+ * Helper for logging an unstyled message to the terminal.
1568
+ */
1569
+ function log(...args) {
1570
+ const cleanedArgs = cleanArgs(args);
1571
+ console.log(...cleanedArgs);
1572
+ return "";
1573
+ }
1574
+ /**
1575
+ * Helper for logging a green colored "ok" message preceded by a checkmark
1576
+ * to the terminal.
1577
+ */
1578
+ function ok(...args) {
1579
+ const message = cleanArgs(args).join(" ");
1580
+ console.log(colors.green(`✓ ${message}`));
1581
+ return "";
1582
+ }
1583
+ /**
1584
+ * Helper for logging a green colored "success" message to the terminal.
1585
+ */
1586
+ function success(...args) {
1587
+ const message = cleanArgs(args).map((arg) => String(arg)).join(" ");
1588
+ console.log(colors.green(message));
1589
+ return "";
1590
+ }
1591
+ /**
1592
+ * Helper for logging a cyan colored "informational" message to the terminal.
1593
+ */
1594
+ function info(...args) {
1595
+ const message = cleanArgs(args).map((arg) => String(arg)).join(" ");
1596
+ console.log(colors.cyan(message));
1597
+ return "";
1598
+ }
1599
+ /**
1600
+ * Helper for logging a yellow colored "warning" message to the terminal.
1601
+ */
1602
+ function warning(...args) {
1603
+ const message = cleanArgs(args).map((arg) => String(arg)).join(" ");
1604
+ console.error(colors.yellow(message));
1605
+ return "";
1606
+ }
1607
+ /**
1608
+ * Alias for warning helper.
1609
+ */
1610
+ const warn = warning;
1611
+ /**
1612
+ * Helper for logging a red colored "error" message to the terminal.
1613
+ */
1614
+ function error(...args) {
1615
+ const message = cleanArgs(args).map((arg) => String(arg)).join(" ");
1616
+ console.error(colors.red(message));
1617
+ return "";
1618
+ }
1619
+ /**
1620
+ * Alias for error helper.
1621
+ */
1622
+ const danger = error;
1623
+ /**
1624
+ * Helper for logging a bold formatted message to the terminal.
1625
+ */
1626
+ function bold(...args) {
1627
+ const message = cleanArgs(args).map((arg) => String(arg)).join(" ");
1628
+ console.error(colors.bold(message));
1629
+ return "";
1630
+ }
1631
+ /**
1632
+ * Helper for outputting a debug statement with the current context
1633
+ */
1634
+ function _debug(...args) {
1635
+ const separator = "─".repeat(50);
1636
+ console.error(colors.cyan(separator));
1637
+ if (args.length > 0) {
1638
+ const cleanedArgs = cleanArgs(args);
1639
+ console.error(colors.cyan("VALUE:"), cleanedArgs[0]);
1640
+ }
1641
+ if (this && Object.keys(this).length > 0) console.error(colors.cyan("CONTEXT:"), this);
1642
+ console.error(colors.cyan(separator));
1643
+ return "";
1644
+ }
1645
+ /**
1646
+ * Helper for inspecting and formatting values as JSON
1647
+ */
1648
+ function _inspect(context, options) {
1649
+ const val = JSON.stringify(context, null, 2);
1650
+ return switchOutput(options?.hash?.type || "html", val);
1651
+ }
1652
+ /**
1653
+ * Generate output based on the given type
1654
+ */
1655
+ function switchOutput(type, json) {
1656
+ if (type[0] === ".") type = type.slice(1);
1657
+ switch (type) {
1658
+ case "md": return `\n\`\`\`json\n${json}\n\`\`\`\n`;
1659
+ case "html": return `<div class="highlight highlight-json">\n<pre><code>\n${json}</code></pre></div>`;
1660
+ default: return json;
1661
+ }
1662
+ }
1663
+ const helpers$12 = [
1664
+ {
1665
+ name: "log",
1666
+ category: "logging",
1667
+ compatibility: ["nodejs"],
1668
+ fn: log
1669
+ },
1670
+ {
1671
+ name: "ok",
1672
+ category: "logging",
1673
+ compatibility: ["nodejs"],
1674
+ fn: ok
1675
+ },
1676
+ {
1677
+ name: "success",
1678
+ category: "logging",
1679
+ compatibility: ["nodejs"],
1680
+ fn: success
1681
+ },
1682
+ {
1683
+ name: "info",
1684
+ category: "logging",
1685
+ compatibility: ["nodejs"],
1686
+ fn: info
1687
+ },
1688
+ {
1689
+ name: "warning",
1690
+ category: "logging",
1691
+ compatibility: ["nodejs"],
1692
+ fn: warning
1693
+ },
1694
+ {
1695
+ name: "warn",
1696
+ category: "logging",
1697
+ compatibility: ["nodejs"],
1698
+ fn: warn
1699
+ },
1700
+ {
1701
+ name: "error",
1702
+ category: "logging",
1703
+ compatibility: ["nodejs"],
1704
+ fn: error
1705
+ },
1706
+ {
1707
+ name: "danger",
1708
+ category: "logging",
1709
+ compatibility: ["nodejs"],
1710
+ fn: danger
1711
+ },
1712
+ {
1713
+ name: "bold",
1714
+ category: "logging",
1715
+ compatibility: ["nodejs"],
1716
+ fn: bold
1717
+ },
1718
+ {
1719
+ name: "_debug",
1720
+ category: "logging",
1721
+ compatibility: ["nodejs"],
1722
+ fn: _debug
1723
+ },
1724
+ {
1725
+ name: "_inspect",
1726
+ category: "logging",
1727
+ compatibility: ["nodejs"],
1728
+ fn: _inspect
1729
+ }
1730
+ ];
1731
+ //#endregion
1732
+ //#region src/helpers/match.ts
1733
+ const match = (files, patterns, options) => {
1734
+ const pats = typeof patterns === "string" ? patterns.split(/, */) : patterns;
1735
+ return (0, micromatch.default)(typeof files === "string" ? [files] : files, pats, options);
1736
+ };
1737
+ const isMatch = (filepath, pattern, options) => {
1738
+ return micromatch.default.isMatch(filepath, pattern, options);
1739
+ };
1740
+ const mm = (...args) => {
1741
+ console.log("the {{mm}} helper is depcrecated and will be removed");
1742
+ console.log("in handlebars-helpers v1.0.0, please use the {{match}}");
1743
+ console.log("helper instead.");
1744
+ return match(...args);
1745
+ };
1746
+ const helpers$11 = [
1747
+ {
1748
+ name: "match",
1749
+ category: "match",
1750
+ compatibility: ["browser", "nodejs"],
1751
+ fn: match
1752
+ },
1753
+ {
1754
+ name: "isMatch",
1755
+ category: "match",
1756
+ compatibility: ["browser", "nodejs"],
1757
+ fn: isMatch
1758
+ },
1759
+ {
1760
+ name: "mm",
1761
+ category: "match",
1762
+ compatibility: ["browser", "nodejs"],
1763
+ fn: mm
1764
+ }
1765
+ ];
1766
+ //#endregion
1767
+ //#region src/helpers/math.ts
1768
+ const isNumeric$1 = (value) => typeof value === "number" && !Number.isNaN(value) || typeof value === "string" && value.trim() !== "" && !Number.isNaN(Number(value));
1769
+ const toNumber = (value, message = "expected a number") => {
1770
+ if (isNumeric$1(value)) return Number(value);
1771
+ throw new TypeError(message);
1772
+ };
1773
+ const abs = (value) => {
1774
+ const num = toNumber(value);
1775
+ return Math.abs(num);
1776
+ };
1777
+ const add = (a, b) => {
1778
+ if (isNumeric$1(a) && isNumeric$1(b)) return Number(a) + Number(b);
1779
+ return "";
1780
+ };
1781
+ const avg = (...values) => {
1782
+ const flat = values.flat().map((n) => Number(n));
1783
+ return sum(flat) / flat.length;
1784
+ };
1785
+ const ceil = (value) => {
1786
+ const num = toNumber(value);
1787
+ return Math.ceil(num);
1788
+ };
1789
+ const divide = (a, b) => {
1790
+ return toNumber(a, "expected the first argument to be a number") / toNumber(b, "expected the second argument to be a number");
1791
+ };
1792
+ const floor = (value) => {
1793
+ const num = toNumber(value);
1794
+ return Math.floor(num);
1795
+ };
1796
+ const minus = (a, b) => {
1797
+ return toNumber(a, "expected the first argument to be a number") - toNumber(b, "expected the second argument to be a number");
1798
+ };
1799
+ const modulo = (a, b) => {
1800
+ return toNumber(a, "expected the first argument to be a number") % toNumber(b, "expected the second argument to be a number");
1801
+ };
1802
+ const multiply = (a, b) => {
1803
+ return toNumber(a, "expected the first argument to be a number") * toNumber(b, "expected the second argument to be a number");
1804
+ };
1805
+ const plus = (a, b) => {
1806
+ return toNumber(a, "expected the first argument to be a number") + toNumber(b, "expected the second argument to be a number");
1807
+ };
1808
+ const random = (min, max) => {
1809
+ const minNum = toNumber(min, "expected minimum to be a number");
1810
+ const maxNum = toNumber(max, "expected maximum to be a number");
1811
+ return minNum + Math.floor(Math.random() * (maxNum - minNum + 1));
1812
+ };
1813
+ const remainder = (a, b) => a % b;
1814
+ const round = (value) => {
1815
+ const num = toNumber(value);
1816
+ return Math.round(num);
1817
+ };
1818
+ const subtract = (a, b) => {
1819
+ return toNumber(a, "expected the first argument to be a number") - toNumber(b, "expected the second argument to be a number");
1820
+ };
1821
+ const sum = (...values) => {
1822
+ const flat = values.flat();
1823
+ let total = 0;
1824
+ for (const value of flat) if (isNumeric$1(value)) total += Number(value);
1825
+ return total;
1826
+ };
1827
+ const times = (a, b) => multiply(a, b);
1828
+ const helpers$10 = [
1829
+ {
1830
+ name: "abs",
1831
+ category: "math",
1832
+ compatibility: ["browser", "nodejs"],
1833
+ fn: abs
1834
+ },
1835
+ {
1836
+ name: "add",
1837
+ category: "math",
1838
+ compatibility: ["browser", "nodejs"],
1839
+ fn: add
1840
+ },
1841
+ {
1842
+ name: "avg",
1843
+ category: "math",
1844
+ compatibility: ["browser", "nodejs"],
1845
+ fn: avg
1846
+ },
1847
+ {
1848
+ name: "ceil",
1849
+ category: "math",
1850
+ compatibility: ["browser", "nodejs"],
1851
+ fn: ceil
1852
+ },
1853
+ {
1854
+ name: "divide",
1855
+ category: "math",
1856
+ compatibility: ["browser", "nodejs"],
1857
+ fn: divide
1858
+ },
1859
+ {
1860
+ name: "floor",
1861
+ category: "math",
1862
+ compatibility: ["browser", "nodejs"],
1863
+ fn: floor
1864
+ },
1865
+ {
1866
+ name: "minus",
1867
+ category: "math",
1868
+ compatibility: ["browser", "nodejs"],
1869
+ fn: minus
1870
+ },
1871
+ {
1872
+ name: "modulo",
1873
+ category: "math",
1874
+ compatibility: ["browser", "nodejs"],
1875
+ fn: modulo
1876
+ },
1877
+ {
1878
+ name: "multiply",
1879
+ category: "math",
1880
+ compatibility: ["browser", "nodejs"],
1881
+ fn: multiply
1882
+ },
1883
+ {
1884
+ name: "plus",
1885
+ category: "math",
1886
+ compatibility: ["browser", "nodejs"],
1887
+ fn: plus
1888
+ },
1889
+ {
1890
+ name: "random",
1891
+ category: "math",
1892
+ compatibility: ["browser", "nodejs"],
1893
+ fn: random
1894
+ },
1895
+ {
1896
+ name: "remainder",
1897
+ category: "math",
1898
+ compatibility: ["browser", "nodejs"],
1899
+ fn: remainder
1900
+ },
1901
+ {
1902
+ name: "round",
1903
+ category: "math",
1904
+ compatibility: ["browser", "nodejs"],
1905
+ fn: round
1906
+ },
1907
+ {
1908
+ name: "subtract",
1909
+ category: "math",
1910
+ compatibility: ["browser", "nodejs"],
1911
+ fn: subtract
1912
+ },
1913
+ {
1914
+ name: "sum",
1915
+ category: "math",
1916
+ compatibility: ["browser", "nodejs"],
1917
+ fn: sum
1918
+ },
1919
+ {
1920
+ name: "times",
1921
+ category: "math",
1922
+ compatibility: ["browser", "nodejs"],
1923
+ fn: times
1924
+ }
1925
+ ];
1926
+ //#endregion
1927
+ //#region src/helpers/md.ts
1928
+ const md = new markdown_it.default({
1929
+ breaks: true,
1930
+ html: true,
1931
+ langPrefix: "lang-",
1932
+ typographer: false,
1933
+ xhtmlOut: false
1934
+ });
1935
+ function renderString(input) {
1936
+ return new handlebars.default.SafeString(ent.default.decode(md.render(input)));
1937
+ }
1938
+ //#endregion
1939
+ //#region src/helpers/md.node.ts
1940
+ const renderMarkdown = function(input, options) {
1941
+ if (typeof input === "object" && input && "fn" in input && typeof input.fn === "function") {
1942
+ options = input;
1943
+ input = input.fn(this);
1944
+ } else if (typeof input !== "string") input = "";
1945
+ const options_ = {
1946
+ cwd: node_process.default.cwd(),
1947
+ ...options
1948
+ };
1949
+ let string_ = input;
1950
+ if (string_.length > 0) {
1951
+ const filepath = node_path.default.resolve(options_.cwd, string_);
1952
+ if (node_fs.default.existsSync(filepath) && node_fs.default.statSync(filepath).isFile()) string_ = node_fs.default.readFileSync(filepath, "utf8");
1953
+ }
1954
+ return renderString(string_);
1955
+ };
1956
+ const helpers$9 = [{
1957
+ name: "md",
1958
+ category: "markdown",
1959
+ compatibility: ["nodejs"],
1960
+ fn: renderMarkdown
1961
+ }, {
1962
+ name: "markdown",
1963
+ category: "markdown",
1964
+ compatibility: ["nodejs"],
1965
+ fn: renderMarkdown
1966
+ }];
1967
+ //#endregion
1968
+ //#region src/helpers/misc.ts
1969
+ const objectToString = Object.prototype.toString;
1970
+ function ctorName(val) {
1971
+ return typeof val.constructor === "function" ? val.constructor.name : null;
1972
+ }
1973
+ function isGeneratorFn(val) {
1974
+ return ctorName(val) === "GeneratorFunction";
1975
+ }
1976
+ function isGeneratorObj(val) {
1977
+ return typeof val.throw === "function" && typeof val.return === "function" && typeof val.next === "function";
1978
+ }
1979
+ function isDateLike(val) {
1980
+ return typeof val.toDateString === "function" && typeof val.getDate === "function" && typeof val.setDate === "function";
1981
+ }
1982
+ function isErrorLike(val) {
1983
+ return typeof val.message === "string" && val.constructor && typeof val.constructor.stackTraceLimit === "number";
1984
+ }
1985
+ function isRegexpLike(val) {
1986
+ return typeof val.flags === "string" && typeof val.ignoreCase === "boolean" && typeof val.multiline === "boolean" && typeof val.global === "boolean";
1987
+ }
1988
+ function kindOf(val) {
1989
+ if (val === void 0) return "undefined";
1990
+ if (val === null) return "null";
1991
+ const type = typeof val;
1992
+ if (type === "boolean") return "boolean";
1993
+ if (type === "string") return "string";
1994
+ if (type === "number") return "number";
1995
+ if (type === "symbol") return "symbol";
1996
+ if (type === "bigint") return "bigint";
1997
+ if (type === "function") return isGeneratorFn(val) ? "generatorfunction" : "function";
1998
+ if (Array.isArray(val)) return "array";
1999
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer?.(val)) return "buffer";
2000
+ if (typeof val.length === "number" && objectToString.call(val) === "[object Arguments]") return "arguments";
2001
+ if (val instanceof Date || isDateLike(val)) return "date";
2002
+ if (val instanceof Error || isErrorLike(val)) return "error";
2003
+ if (val instanceof RegExp || isRegexpLike(val)) return "regexp";
2004
+ switch (ctorName(val)) {
2005
+ case "Promise": return "promise";
2006
+ case "WeakMap": return "weakmap";
2007
+ case "WeakSet": return "weakset";
2008
+ case "Map": return "map";
2009
+ case "Set": return "set";
2010
+ case "Int8Array": return "int8array";
2011
+ case "Uint8Array": return "uint8array";
2012
+ case "Uint8ClampedArray": return "uint8clampedarray";
2013
+ case "Int16Array": return "int16array";
2014
+ case "Uint16Array": return "uint16array";
2015
+ case "Int32Array": return "int32array";
2016
+ case "Uint32Array": return "uint32array";
2017
+ case "Float32Array": return "float32array";
2018
+ case "Float64Array": return "float64array";
2019
+ }
2020
+ if (isGeneratorObj(val)) return "generator";
2021
+ const tag = objectToString.call(val);
2022
+ switch (tag) {
2023
+ case "[object Object]": return "object";
2024
+ case "[object Map Iterator]": return "mapiterator";
2025
+ case "[object Set Iterator]": return "setiterator";
2026
+ case "[object String Iterator]": return "stringiterator";
2027
+ case "[object Array Iterator]": return "arrayiterator";
2028
+ }
2029
+ return tag.slice(8, -1).toLowerCase().replace(/\s/g, "");
2030
+ }
2031
+ /**
2032
+ * Block helper for exposing private `@` variables on the context
2033
+ * Replaces the external handlebars-helper-create-frame package
2034
+ */
2035
+ function frame(context, options) {
2036
+ if (typeof context === "object" && context !== null && "hash" in context) {
2037
+ options = context;
2038
+ context = options.data;
2039
+ }
2040
+ const data = handlebars.default.createFrame(context || {});
2041
+ if (typeof options !== "object" || options === null) options = {};
2042
+ if (options.hash && typeof options.hash === "object") Object.assign(data, options.hash);
2043
+ return options.fn(this, { data });
2044
+ }
2045
+ function option(prop, locals, opts) {
2046
+ return get(options(this, locals, opts), prop);
2047
+ }
2048
+ function noop(options) {
2049
+ return options.fn(this);
2050
+ }
2051
+ const typeOf = kindOf;
2052
+ function withHash(options) {
2053
+ if (options.hash && Object.keys(options.hash).length) return options.fn(options.hash);
2054
+ return options.inverse(this);
2055
+ }
2056
+ const helpers$8 = [
2057
+ {
2058
+ name: "frame",
2059
+ category: "misc",
2060
+ compatibility: ["browser", "nodejs"],
2061
+ fn: frame
2062
+ },
2063
+ {
2064
+ name: "option",
2065
+ category: "misc",
2066
+ compatibility: ["browser", "nodejs"],
2067
+ fn: option
2068
+ },
2069
+ {
2070
+ name: "noop",
2071
+ category: "misc",
2072
+ compatibility: ["browser", "nodejs"],
2073
+ fn: noop
2074
+ },
2075
+ {
2076
+ name: "typeOf",
2077
+ category: "misc",
2078
+ compatibility: ["browser", "nodejs"],
2079
+ fn: typeOf
2080
+ },
2081
+ {
2082
+ name: "withHash",
2083
+ category: "misc",
2084
+ compatibility: ["browser", "nodejs"],
2085
+ fn: withHash
2086
+ }
2087
+ ];
2088
+ //#endregion
2089
+ //#region src/helpers/number.ts
2090
+ const isNumeric = (value) => typeof value === "number" && !Number.isNaN(value);
2091
+ const bytes = (value, precision) => {
2092
+ if (value == null) return "0 B";
2093
+ let num;
2094
+ if (typeof value === "string") {
2095
+ num = value.length;
2096
+ if (!num) return "0 B";
2097
+ } else if (isNumeric(value)) num = Number(value);
2098
+ else if (typeof value.length === "number") {
2099
+ num = value.length;
2100
+ if (!num) return "0 B";
2101
+ } else return "0 B";
2102
+ const prec = typeof precision === "number" && !Number.isNaN(precision) ? precision : 2;
2103
+ const abbr = [
2104
+ "B",
2105
+ "kB",
2106
+ "MB",
2107
+ "GB",
2108
+ "TB",
2109
+ "PB",
2110
+ "EB",
2111
+ "ZB",
2112
+ "YB"
2113
+ ];
2114
+ const factor = 10 ** prec;
2115
+ for (let i = abbr.length - 1; i >= 0; i--) {
2116
+ const size = 10 ** (i * 3);
2117
+ if (size <= num + 1) return `${Math.round(num * factor / size) / factor} ${abbr[i]}`;
2118
+ }
2119
+ return `${num}`;
2120
+ };
2121
+ const addCommas = (num) => num.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
2122
+ const phoneNumber = (num) => {
2123
+ const str = num.toString();
2124
+ return `(${str.substr(0, 3)}) ${str.substr(3, 3)}-${str.substr(6, 4)}`;
2125
+ };
2126
+ const toAbbr = (value, precision) => {
2127
+ const num = isNumeric(value) ? Number(value) : 0;
2128
+ const factor = 10 ** (typeof precision === "number" && !Number.isNaN(precision) ? precision : 2);
2129
+ const abbr = [
2130
+ "k",
2131
+ "m",
2132
+ "b",
2133
+ "t",
2134
+ "q"
2135
+ ];
2136
+ for (let i = abbr.length - 1; i >= 0; i--) {
2137
+ const size = 10 ** ((i + 1) * 3);
2138
+ if (size <= num + 1) return `${Math.round(num * factor / size) / factor}${abbr[i]}`;
2139
+ }
2140
+ return `${num}`;
2141
+ };
2142
+ const toExponential = (value, digits) => {
2143
+ const num = isNumeric(value) ? Number(value) : 0;
2144
+ const d = typeof digits === "number" && !Number.isNaN(digits) ? digits : 0;
2145
+ return Number(num).toExponential(d);
2146
+ };
2147
+ const toFixed = (value, digits) => {
2148
+ const num = isNumeric(value) ? Number(value) : 0;
2149
+ const d = typeof digits === "number" && !Number.isNaN(digits) ? digits : 0;
2150
+ return Number(num).toFixed(d);
2151
+ };
2152
+ const toFloat = (value) => parseFloat(String(value));
2153
+ const toInt = (value) => parseInt(String(value), 10);
2154
+ const toPrecision = (value, precision) => {
2155
+ const num = isNumeric(value) ? Number(value) : 0;
2156
+ const prec = typeof precision === "number" && !Number.isNaN(precision) ? precision : 1;
2157
+ return Number(num).toPrecision(prec);
2158
+ };
2159
+ const helpers$7 = [
2160
+ {
2161
+ name: "bytes",
2162
+ category: "number",
2163
+ compatibility: ["browser", "nodejs"],
2164
+ fn: bytes
2165
+ },
2166
+ {
2167
+ name: "addCommas",
2168
+ category: "number",
2169
+ compatibility: ["browser", "nodejs"],
2170
+ fn: addCommas
2171
+ },
2172
+ {
2173
+ name: "phoneNumber",
2174
+ category: "number",
2175
+ compatibility: ["browser", "nodejs"],
2176
+ fn: phoneNumber
2177
+ },
2178
+ {
2179
+ name: "toAbbr",
2180
+ category: "number",
2181
+ compatibility: ["browser", "nodejs"],
2182
+ fn: toAbbr
2183
+ },
2184
+ {
2185
+ name: "toExponential",
2186
+ category: "number",
2187
+ compatibility: ["browser", "nodejs"],
2188
+ fn: toExponential
2189
+ },
2190
+ {
2191
+ name: "toFixed",
2192
+ category: "number",
2193
+ compatibility: ["browser", "nodejs"],
2194
+ fn: toFixed
2195
+ },
2196
+ {
2197
+ name: "toFloat",
2198
+ category: "number",
2199
+ compatibility: ["browser", "nodejs"],
2200
+ fn: toFloat
2201
+ },
2202
+ {
2203
+ name: "toInt",
2204
+ category: "number",
2205
+ compatibility: ["browser", "nodejs"],
2206
+ fn: toInt
2207
+ },
2208
+ {
2209
+ name: "toPrecision",
2210
+ category: "number",
2211
+ compatibility: ["browser", "nodejs"],
2212
+ fn: toPrecision
2213
+ }
2214
+ ];
2215
+ //#endregion
2216
+ //#region src/helpers/object.ts
2217
+ const isOptions = (value) => {
2218
+ return Boolean(value && typeof value === "object" && "hash" in value);
2219
+ };
2220
+ const createFrame = (options, hash) => ({
2221
+ ...options?.data || {},
2222
+ ...hash
2223
+ });
2224
+ const extend = (...objects) => {
2225
+ const args = [...objects];
2226
+ if (args.length && isOptions(args[args.length - 1])) {
2227
+ const opts = args.pop();
2228
+ args.push(opts.hash);
2229
+ }
2230
+ const result = {};
2231
+ for (const obj of args) if (obj && typeof obj === "object" && !Array.isArray(obj)) Object.assign(result, obj);
2232
+ return result;
2233
+ };
2234
+ const forIn = (obj, options) => {
2235
+ if (!isOptions(options)) return options?.inverse?.(obj) ?? "";
2236
+ const data = createFrame(options, options.hash || {});
2237
+ let result = "";
2238
+ for (const key in obj) {
2239
+ data.key = key;
2240
+ result += options.fn(obj[key], { data });
2241
+ }
2242
+ return result;
2243
+ };
2244
+ const forOwn = (obj, options) => {
2245
+ if (!isOptions(options)) return options?.inverse?.(obj) ?? "";
2246
+ const data = createFrame(options, options.hash || {});
2247
+ let result = "";
2248
+ for (const key in obj) if (Object.hasOwn(obj, key)) {
2249
+ data.key = key;
2250
+ result += options.fn(obj[key], { data });
2251
+ }
2252
+ return result;
2253
+ };
2254
+ const toPath = (...prop) => {
2255
+ const parts = [];
2256
+ for (const p of prop) if (typeof p === "string" || typeof p === "number") parts.push(p);
2257
+ return parts.join(".");
2258
+ };
2259
+ const getHelper = (prop, context, options) => {
2260
+ const val = get(context, prop);
2261
+ if (options && typeof options.fn === "function") return val ? options.fn(val) : options.inverse?.(context);
2262
+ return val;
2263
+ };
2264
+ const getObjectHelper = (prop, context) => {
2265
+ return getObject(context, prop);
2266
+ };
2267
+ const hasOwn = (context, key) => {
2268
+ return Object.hasOwn(context, key);
2269
+ };
2270
+ const isObject = (value) => {
2271
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2272
+ };
2273
+ const JSONparse = (str) => {
2274
+ return JSON.parse(str);
2275
+ };
2276
+ const JSONstringify = (obj, indent) => {
2277
+ return JSON.stringify(obj, null, typeof indent === "number" ? indent : 0);
2278
+ };
2279
+ const merge = (context, ...objects) => {
2280
+ const args = [context, ...objects];
2281
+ if (args.length && isOptions(args[args.length - 1])) {
2282
+ const opts = args.pop();
2283
+ args.push(opts.hash);
2284
+ }
2285
+ return Object.assign(args[0], ...args.slice(1));
2286
+ };
2287
+ const parseJSON = JSONparse;
2288
+ const stringify = JSONstringify;
2289
+ const pick = (props, context, options) => {
2290
+ const keys = arrayify(props);
2291
+ let result = {};
2292
+ for (const key of keys) result = Object.assign({}, result, getObject(context, key));
2293
+ if (options && typeof options.fn === "function") {
2294
+ if (Object.keys(result).length) return options.fn(result);
2295
+ return options.inverse?.(context);
2296
+ }
2297
+ return result;
2298
+ };
2299
+ const helpers$6 = [
2300
+ {
2301
+ name: "extend",
2302
+ category: "object",
2303
+ compatibility: ["browser", "nodejs"],
2304
+ fn: extend
2305
+ },
2306
+ {
2307
+ name: "forIn",
2308
+ category: "object",
2309
+ compatibility: ["browser", "nodejs"],
2310
+ fn: forIn
2311
+ },
2312
+ {
2313
+ name: "forOwn",
2314
+ category: "object",
2315
+ compatibility: ["browser", "nodejs"],
2316
+ fn: forOwn
2317
+ },
2318
+ {
2319
+ name: "toPath",
2320
+ category: "object",
2321
+ compatibility: ["browser", "nodejs"],
2322
+ fn: toPath
2323
+ },
2324
+ {
2325
+ name: "get",
2326
+ category: "object",
2327
+ compatibility: ["browser", "nodejs"],
2328
+ fn: getHelper
2329
+ },
2330
+ {
2331
+ name: "getObject",
2332
+ category: "object",
2333
+ compatibility: ["browser", "nodejs"],
2334
+ fn: getObjectHelper
2335
+ },
2336
+ {
2337
+ name: "hasOwn",
2338
+ category: "object",
2339
+ compatibility: ["browser", "nodejs"],
2340
+ fn: hasOwn
2341
+ },
2342
+ {
2343
+ name: "isObject",
2344
+ category: "object",
2345
+ compatibility: ["browser", "nodejs"],
2346
+ fn: isObject
2347
+ },
2348
+ {
2349
+ name: "JSONparse",
2350
+ category: "object",
2351
+ compatibility: ["browser", "nodejs"],
2352
+ fn: JSONparse
2353
+ },
2354
+ {
2355
+ name: "JSONstringify",
2356
+ category: "object",
2357
+ compatibility: ["browser", "nodejs"],
2358
+ fn: JSONstringify
2359
+ },
2360
+ {
2361
+ name: "merge",
2362
+ category: "object",
2363
+ compatibility: ["browser", "nodejs"],
2364
+ fn: merge
2365
+ },
2366
+ {
2367
+ name: "parseJSON",
2368
+ category: "object",
2369
+ compatibility: ["browser", "nodejs"],
2370
+ fn: parseJSON
2371
+ },
2372
+ {
2373
+ name: "pick",
2374
+ category: "object",
2375
+ compatibility: ["browser", "nodejs"],
2376
+ fn: pick
2377
+ },
2378
+ {
2379
+ name: "stringify",
2380
+ category: "object",
2381
+ compatibility: ["browser", "nodejs"],
2382
+ fn: stringify
2383
+ }
2384
+ ];
2385
+ //#endregion
2386
+ //#region src/helpers/path.ts
2387
+ const expectedType = (variableName, expectedType, variableValue) => {
2388
+ return `Expected ${variableName} to be of type ${expectedType}, but got ${Object.prototype.toString.call(variableValue).slice(8, -1).toLowerCase()}`;
2389
+ };
2390
+ const assertString = (name, value) => {
2391
+ if (typeof value !== "string") throw new TypeError(expectedType(name, "string", value));
2392
+ return value;
2393
+ };
2394
+ const absolute = function(filepath, options) {
2395
+ const fp = assertString("filepath", filepath);
2396
+ const cwd = options?.data?.root?.cwd ?? this?.cwd ?? process.cwd();
2397
+ return node_path.default.resolve(cwd, fp);
2398
+ };
2399
+ const dirname = (filepath) => {
2400
+ const fp = assertString("filepath", filepath);
2401
+ return node_path.default.dirname(fp);
2402
+ };
2403
+ const relative = (a, b) => {
2404
+ const from = assertString("first path", a);
2405
+ const to = assertString("second path", b);
2406
+ return node_path.default.relative(node_path.default.dirname(from), to);
2407
+ };
2408
+ const basename = (filepath) => {
2409
+ const fp = assertString("filepath", filepath);
2410
+ return node_path.default.basename(fp);
2411
+ };
2412
+ const stem = (filepath) => {
2413
+ const fp = assertString("filepath", filepath);
2414
+ return node_path.default.basename(fp, node_path.default.extname(fp));
2415
+ };
2416
+ const extname = (filepath) => {
2417
+ const fp = assertString("filepath", filepath);
2418
+ return node_path.default.extname(fp);
2419
+ };
2420
+ const resolveFn = function(filepath, ...paths) {
2421
+ let options;
2422
+ const last = paths[paths.length - 1];
2423
+ if (typeof last === "object" && last && "data" in last) options = paths.pop();
2424
+ const all = [
2425
+ options?.data?.root?.cwd ?? this?.cwd ?? process.cwd(),
2426
+ assertString("filepath", filepath),
2427
+ ...paths.map((p, i) => assertString(`path${i}`, p))
2428
+ ];
2429
+ return node_path.default.resolve(...all);
2430
+ };
2431
+ const segments = (filepath, a, b) => {
2432
+ const fp = assertString("filepath", filepath);
2433
+ const start = Number(a);
2434
+ const end = Number(b);
2435
+ return fp.split(/[\\/]+/).slice(start, end).join("/");
2436
+ };
2437
+ const helpers$5 = [
2438
+ {
2439
+ name: "absolute",
2440
+ category: "path",
2441
+ compatibility: ["nodejs"],
2442
+ fn: absolute
2443
+ },
2444
+ {
2445
+ name: "dirname",
2446
+ category: "path",
2447
+ compatibility: ["nodejs"],
2448
+ fn: dirname
2449
+ },
2450
+ {
2451
+ name: "relative",
2452
+ category: "path",
2453
+ compatibility: ["nodejs"],
2454
+ fn: relative
2455
+ },
2456
+ {
2457
+ name: "basename",
2458
+ category: "path",
2459
+ compatibility: ["nodejs"],
2460
+ fn: basename
2461
+ },
2462
+ {
2463
+ name: "stem",
2464
+ category: "path",
2465
+ compatibility: ["nodejs"],
2466
+ fn: stem
2467
+ },
2468
+ {
2469
+ name: "extname",
2470
+ category: "path",
2471
+ compatibility: ["nodejs"],
2472
+ fn: extname
2473
+ },
2474
+ {
2475
+ name: "resolve",
2476
+ category: "path",
2477
+ compatibility: ["nodejs"],
2478
+ fn: resolveFn
2479
+ },
2480
+ {
2481
+ name: "segments",
2482
+ category: "path",
2483
+ compatibility: ["nodejs"],
2484
+ fn: segments
2485
+ }
2486
+ ];
2487
+ //#endregion
2488
+ //#region src/helpers/regex.ts
2489
+ const toRegex = (str, locals, opts) => {
2490
+ const mergedOpts = options({}, locals, opts);
2491
+ return new RegExp(str, mergedOpts.flags);
2492
+ };
2493
+ const test = (str, regex) => {
2494
+ if (typeof str !== "string") return false;
2495
+ if (!(regex instanceof RegExp)) throw new TypeError("expected a regular expression");
2496
+ return regex.test(str);
2497
+ };
2498
+ const helpers$4 = [{
2499
+ name: "toRegex",
2500
+ category: "regex",
2501
+ compatibility: ["browser", "nodejs"],
2502
+ fn: toRegex
2503
+ }, {
2504
+ name: "test",
2505
+ category: "regex",
2506
+ compatibility: ["browser", "nodejs"],
2507
+ fn: test
2508
+ }];
2509
+ //#endregion
2510
+ //#region src/helpers/string.ts
2511
+ const chop = (str) => str.trim().replace(/^[-_.\W\s]+|[-_.\W\s]+$/g, "");
2512
+ const changecase = (str, fn) => {
2513
+ if (str.length === 1) return str.toLowerCase();
2514
+ return chop(str).toLowerCase().replace(/[-_.\W\s]+(\w|$)/g, (_, ch) => fn(ch));
2515
+ };
2516
+ const append = (str, suffix) => {
2517
+ if (typeof str === "string" && typeof suffix === "string") return str + suffix;
2518
+ return str;
2519
+ };
2520
+ const camelcase = (str) => typeof str === "string" ? changecase(str, (ch) => ch.toUpperCase()) : "";
2521
+ const capitalize = (str) => {
2522
+ if (typeof str !== "string" || str.length === 0) return "";
2523
+ return str.charAt(0).toUpperCase() + str.slice(1);
2524
+ };
2525
+ const capitalizeAll = (str) => {
2526
+ if (typeof str !== "string") return "";
2527
+ return str.replace(/\w\S*/g, (word) => capitalize(word));
2528
+ };
2529
+ const center = (str, spaces) => {
2530
+ if (typeof str !== "string") return "";
2531
+ let space = "";
2532
+ for (let i = 0; i < spaces; i++) space += "&nbsp;";
2533
+ return space + str + space;
2534
+ };
2535
+ const chopStr = (str) => typeof str === "string" ? chop(str) : "";
2536
+ const dashcase = (str) => typeof str === "string" ? changecase(str, (ch) => `-${ch}`) : "";
2537
+ const dotcase = (str) => typeof str === "string" ? changecase(str, (ch) => `.${ch}`) : "";
2538
+ const truncate = (str, limit, suffix) => {
2539
+ if (typeof str === "string") {
2540
+ if (typeof suffix !== "string") suffix = "";
2541
+ if (str.length > limit) return str.slice(0, limit - suffix.length) + suffix;
2542
+ return str;
2543
+ }
2544
+ return "";
2545
+ };
2546
+ const ellipsis = (str, limit) => {
2547
+ if (typeof str === "string") {
2548
+ if (str.length <= limit) return str;
2549
+ return `${truncate(str, limit)}…`;
2550
+ }
2551
+ return "";
2552
+ };
2553
+ const hyphenate = (str) => typeof str === "string" ? str.split(" ").join("-") : "";
2554
+ const isString = (value) => typeof value === "string";
2555
+ const lowercase = (str) => {
2556
+ if (typeof str === "object" && str !== null && "fn" in str && typeof str.fn === "function") return String(str.fn()).toLowerCase();
2557
+ if (typeof str !== "string") return "";
2558
+ return str.toLowerCase();
2559
+ };
2560
+ const downcase = (str) => lowercase(str);
2561
+ const occurrences = (str, substring) => {
2562
+ if (typeof str !== "string") return "";
2563
+ const len = substring.length;
2564
+ let pos = str.indexOf(substring, 0);
2565
+ let n = 0;
2566
+ while (pos > -1) {
2567
+ n++;
2568
+ pos = str.indexOf(substring, pos + len);
2569
+ }
2570
+ return n;
2571
+ };
2572
+ const pascalcase = (str) => {
2573
+ if (typeof str !== "string") return "";
2574
+ const res = changecase(str, (ch) => ch.toUpperCase());
2575
+ return res.charAt(0).toUpperCase() + res.slice(1);
2576
+ };
2577
+ const pathcase = (str) => typeof str === "string" ? changecase(str, (ch) => `/${ch}`) : "";
2578
+ const plusify = (str, ch) => {
2579
+ if (typeof str !== "string") return "";
2580
+ if (typeof ch !== "string") ch = " ";
2581
+ return str.split(ch).join("+");
2582
+ };
2583
+ const prepend = (str, prefix) => {
2584
+ return typeof str === "string" && typeof prefix === "string" ? prefix + str : str;
2585
+ };
2586
+ const remove = (str, ch) => {
2587
+ if (typeof str !== "string") return "";
2588
+ if (typeof ch !== "string") return str;
2589
+ return str.split(ch).join("");
2590
+ };
2591
+ const removeFirst = (str, ch) => {
2592
+ if (typeof str !== "string") return "";
2593
+ if (typeof ch !== "string") return str;
2594
+ return str.replace(ch, "");
2595
+ };
2596
+ const replace = (str, a, b) => {
2597
+ if (typeof str !== "string") return "";
2598
+ if (typeof a !== "string") return str;
2599
+ if (typeof b !== "string") b = "";
2600
+ return str.split(a).join(b);
2601
+ };
2602
+ const replaceFirst = (str, a, b) => {
2603
+ if (typeof str !== "string") return "";
2604
+ if (typeof a !== "string") return str;
2605
+ if (typeof b !== "string") b = "";
2606
+ return str.replace(a, b);
2607
+ };
2608
+ const reverse = (str) => typeof str === "string" ? str.split("").reverse().join("") : "";
2609
+ const sentence = (str) => {
2610
+ if (typeof str !== "string") return "";
2611
+ return str.replace(/((?:\S[^.?!]*)[.?!]*)/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
2612
+ };
2613
+ const snakecase = (str) => typeof str === "string" ? changecase(str, (ch) => `_${ch}`) : "";
2614
+ const trim = (str) => typeof str === "string" ? str.trim() : "";
2615
+ const trimLeft = (str) => typeof str === "string" ? str.replace(/^\s+/, "") : "";
2616
+ const trimRight = (str) => typeof str === "string" ? str.replace(/\s+$/, "") : "";
2617
+ const truncateWords = (str, count, suffix) => {
2618
+ if (typeof str === "string" && typeof count === "number" && Number.isFinite(count)) {
2619
+ /* c8 ignore next -- @preserve */
2620
+ if (typeof suffix !== "string") suffix = "...";
2621
+ const num = Math.trunc(count);
2622
+ let arr = str.split(" ");
2623
+ /* c8 ignore next -- @preserve */
2624
+ if (num < arr.length) arr = arr.slice(0, num);
2625
+ return arr.join(" ").trim() + suffix;
2626
+ }
2627
+ return "";
2628
+ };
2629
+ const truncateWordsAlias = truncateWords;
2630
+ const uppercase = (str) => {
2631
+ if (typeof str === "object" && str !== null && "fn" in str && typeof str.fn === "function") return String(str.fn()).toUpperCase();
2632
+ if (typeof str !== "string") return "";
2633
+ return str.toUpperCase();
2634
+ };
2635
+ const upcase = (str) => uppercase(str);
2636
+ const split = (str, character) => {
2637
+ if (typeof str !== "string") return "";
2638
+ if (typeof character !== "string") character = "";
2639
+ return str.split(character);
2640
+ };
2641
+ const startsWith = (prefix, testString, _options) => {
2642
+ if (typeof prefix !== "string" || typeof testString !== "string") return false;
2643
+ return testString.startsWith(prefix);
2644
+ };
2645
+ const titleize = (str) => {
2646
+ if (typeof str !== "string") return "";
2647
+ return str.replace(/\w\S*/g, (word) => {
2648
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
2649
+ });
2650
+ };
2651
+ const raw = (options) => {
2652
+ if (options && typeof options.fn === "function") return options.fn();
2653
+ return "";
2654
+ };
2655
+ const helpers$3 = [
2656
+ {
2657
+ name: "append",
2658
+ category: "string",
2659
+ compatibility: ["browser", "nodejs"],
2660
+ fn: append
2661
+ },
2662
+ {
2663
+ name: "camelcase",
2664
+ category: "string",
2665
+ compatibility: ["browser", "nodejs"],
2666
+ fn: camelcase
2667
+ },
2668
+ {
2669
+ name: "capitalize",
2670
+ category: "string",
2671
+ compatibility: ["browser", "nodejs"],
2672
+ fn: capitalize
2673
+ },
2674
+ {
2675
+ name: "capitalizeAll",
2676
+ category: "string",
2677
+ compatibility: ["browser", "nodejs"],
2678
+ fn: capitalizeAll
2679
+ },
2680
+ {
2681
+ name: "center",
2682
+ category: "string",
2683
+ compatibility: ["browser", "nodejs"],
2684
+ fn: center
2685
+ },
2686
+ {
2687
+ name: "chop",
2688
+ category: "string",
2689
+ compatibility: ["browser", "nodejs"],
2690
+ fn: chopStr
2691
+ },
2692
+ {
2693
+ name: "dashcase",
2694
+ category: "string",
2695
+ compatibility: ["browser", "nodejs"],
2696
+ fn: dashcase
2697
+ },
2698
+ {
2699
+ name: "dotcase",
2700
+ category: "string",
2701
+ compatibility: ["browser", "nodejs"],
2702
+ fn: dotcase
2703
+ },
2704
+ {
2705
+ name: "ellipsis",
2706
+ category: "string",
2707
+ compatibility: ["browser", "nodejs"],
2708
+ fn: ellipsis
2709
+ },
2710
+ {
2711
+ name: "hyphenate",
2712
+ category: "string",
2713
+ compatibility: ["browser", "nodejs"],
2714
+ fn: hyphenate
2715
+ },
2716
+ {
2717
+ name: "isString",
2718
+ category: "string",
2719
+ compatibility: ["browser", "nodejs"],
2720
+ fn: isString
2721
+ },
2722
+ {
2723
+ name: "lowercase",
2724
+ category: "string",
2725
+ compatibility: ["browser", "nodejs"],
2726
+ fn: lowercase
2727
+ },
2728
+ {
2729
+ name: "downcase",
2730
+ category: "string",
2731
+ compatibility: ["browser", "nodejs"],
2732
+ fn: downcase
2733
+ },
2734
+ {
2735
+ name: "occurrences",
2736
+ category: "string",
2737
+ compatibility: ["browser", "nodejs"],
2738
+ fn: occurrences
2739
+ },
2740
+ {
2741
+ name: "pascalcase",
2742
+ category: "string",
2743
+ compatibility: ["browser", "nodejs"],
2744
+ fn: pascalcase
2745
+ },
2746
+ {
2747
+ name: "pathcase",
2748
+ category: "string",
2749
+ compatibility: ["browser", "nodejs"],
2750
+ fn: pathcase
2751
+ },
2752
+ {
2753
+ name: "plusify",
2754
+ category: "string",
2755
+ compatibility: ["browser", "nodejs"],
2756
+ fn: plusify
2757
+ },
2758
+ {
2759
+ name: "prepend",
2760
+ category: "string",
2761
+ compatibility: ["browser", "nodejs"],
2762
+ fn: prepend
2763
+ },
2764
+ {
2765
+ name: "remove",
2766
+ category: "string",
2767
+ compatibility: ["browser", "nodejs"],
2768
+ fn: remove
2769
+ },
2770
+ {
2771
+ name: "removeFirst",
2772
+ category: "string",
2773
+ compatibility: ["browser", "nodejs"],
2774
+ fn: removeFirst
2775
+ },
2776
+ {
2777
+ name: "replace",
2778
+ category: "string",
2779
+ compatibility: ["browser", "nodejs"],
2780
+ fn: replace
2781
+ },
2782
+ {
2783
+ name: "replaceFirst",
2784
+ category: "string",
2785
+ compatibility: ["browser", "nodejs"],
2786
+ fn: replaceFirst
2787
+ },
2788
+ {
2789
+ name: "reverse",
2790
+ category: "string",
2791
+ compatibility: ["browser", "nodejs"],
2792
+ fn: reverse
2793
+ },
2794
+ {
2795
+ name: "sentence",
2796
+ category: "string",
2797
+ compatibility: ["browser", "nodejs"],
2798
+ fn: sentence
2799
+ },
2800
+ {
2801
+ name: "snakecase",
2802
+ category: "string",
2803
+ compatibility: ["browser", "nodejs"],
2804
+ fn: snakecase
2805
+ },
2806
+ {
2807
+ name: "trim",
2808
+ category: "string",
2809
+ compatibility: ["browser", "nodejs"],
2810
+ fn: trim
2811
+ },
2812
+ {
2813
+ name: "trimLeft",
2814
+ category: "string",
2815
+ compatibility: ["browser", "nodejs"],
2816
+ fn: trimLeft
2817
+ },
2818
+ {
2819
+ name: "trimRight",
2820
+ category: "string",
2821
+ compatibility: ["browser", "nodejs"],
2822
+ fn: trimRight
2823
+ },
2824
+ {
2825
+ name: "truncate",
2826
+ category: "string",
2827
+ compatibility: ["browser", "nodejs"],
2828
+ fn: truncate
2829
+ },
2830
+ {
2831
+ name: "truncateWords",
2832
+ category: "string",
2833
+ compatibility: ["browser", "nodejs"],
2834
+ fn: truncateWordsAlias
2835
+ },
2836
+ {
2837
+ name: "uppercase",
2838
+ category: "string",
2839
+ compatibility: ["browser", "nodejs"],
2840
+ fn: uppercase
2841
+ },
2842
+ {
2843
+ name: "upcase",
2844
+ category: "string",
2845
+ compatibility: ["browser", "nodejs"],
2846
+ fn: upcase
2847
+ },
2848
+ {
2849
+ name: "split",
2850
+ category: "string",
2851
+ compatibility: ["browser", "nodejs"],
2852
+ fn: split
2853
+ },
2854
+ {
2855
+ name: "startsWith",
2856
+ category: "string",
2857
+ compatibility: ["browser", "nodejs"],
2858
+ fn: startsWith
2859
+ },
2860
+ {
2861
+ name: "titleize",
2862
+ category: "string",
2863
+ compatibility: ["browser", "nodejs"],
2864
+ fn: titleize
2865
+ },
2866
+ {
2867
+ name: "raw",
2868
+ category: "string",
2869
+ compatibility: ["browser", "nodejs"],
2870
+ fn: raw
2871
+ }
2872
+ ];
2873
+ //#endregion
2874
+ //#region src/helpers/url.ts
2875
+ const all = ["browser", "nodejs"];
2876
+ const encodeUri = (str) => {
2877
+ if (typeof str === "string") return encodeURIComponent(str);
2878
+ };
2879
+ const decodeUri = (str) => {
2880
+ if (typeof str === "string") return decodeURIComponent(str);
2881
+ };
2882
+ function urlEncode(...args) {
2883
+ return encodeUri.apply(this, args);
2884
+ }
2885
+ function urlDecode(...args) {
2886
+ return decodeUri.apply(this, args);
2887
+ }
2888
+ const stripQuerystring = (str) => {
2889
+ if (typeof str === "string") return str.split("?")[0];
2890
+ };
2891
+ const helpers$2 = [
2892
+ {
2893
+ name: "encodeURI",
2894
+ category: "url",
2895
+ compatibility: all,
2896
+ fn: encodeUri
2897
+ },
2898
+ {
2899
+ name: "decodeURI",
2900
+ category: "url",
2901
+ compatibility: all,
2902
+ fn: decodeUri
2903
+ },
2904
+ {
2905
+ name: "url_encode",
2906
+ category: "url",
2907
+ compatibility: all,
2908
+ fn: urlEncode
2909
+ },
2910
+ {
2911
+ name: "url_decode",
2912
+ category: "url",
2913
+ compatibility: all,
2914
+ fn: urlDecode
2915
+ },
2916
+ {
2917
+ name: "stripQuerystring",
2918
+ category: "url",
2919
+ compatibility: all,
2920
+ fn: stripQuerystring
2921
+ }
2922
+ ];
2923
+ //#endregion
2924
+ //#region src/helpers/url.node.ts
2925
+ const escapeFn = (str) => {
2926
+ if (typeof str === "string") return (0, node_querystring.escape)(str);
2927
+ };
2928
+ const urlResolve = (base, href) => (0, node_url.resolve)(String(base), String(href));
2929
+ const urlParse = (str) => (0, node_url.parse)(String(str));
2930
+ const stripProtocol = (str) => {
2931
+ if (typeof str === "string") {
2932
+ const parsed = (0, node_url.parse)(str);
2933
+ parsed.protocol = "";
2934
+ return (0, node_url.format)(parsed);
2935
+ }
2936
+ };
2937
+ const helpers$1 = [
2938
+ {
2939
+ name: "escape",
2940
+ category: "url",
2941
+ compatibility: ["nodejs"],
2942
+ fn: escapeFn
2943
+ },
2944
+ {
2945
+ name: "urlResolve",
2946
+ category: "url",
2947
+ compatibility: ["nodejs"],
2948
+ fn: urlResolve
2949
+ },
2950
+ {
2951
+ name: "urlParse",
2952
+ category: "url",
2953
+ compatibility: ["nodejs"],
2954
+ fn: urlParse
2955
+ },
2956
+ {
2957
+ name: "stripProtocol",
2958
+ category: "url",
2959
+ compatibility: ["nodejs"],
2960
+ fn: stripProtocol
2961
+ }
2962
+ ];
2963
+ //#endregion
2964
+ //#region src/helper-registry.ts
2965
+ var HelperRegistry = class extends HelperRegistryBase {
2966
+ init() {
2967
+ this.registerHelpers(helpers$23);
2968
+ this.registerHelpers(helpers$19);
2969
+ this.registerHelpers(helpers$17);
2970
+ this.registerHelpers(helpers$16);
2971
+ this.registerHelpers(helpers$21);
2972
+ this.registerHelpers(helpers$20);
2973
+ this.registerHelpers(helpers$9);
2974
+ this.registerHelpers(helpers$22);
2975
+ this.registerHelpers(helpers$15);
2976
+ this.registerHelpers(helpers$18);
2977
+ this.registerHelpers(helpers$14);
2978
+ this.registerHelpers(helpers$13);
2979
+ this.registerHelpers(helpers$12);
2980
+ this.registerHelpers(helpers$11);
2981
+ this.registerHelpers(helpers$10);
2982
+ this.registerHelpers(helpers$8);
2983
+ this.registerHelpers(helpers$7);
2984
+ this.registerHelpers(helpers$5);
2985
+ this.registerHelpers(helpers$4);
2986
+ this.registerHelpers(helpers$3);
2987
+ this.registerHelpers(helpers$2);
2988
+ this.registerHelpers(helpers$1);
2989
+ this.registerHelpers(helpers$6);
2990
+ }
2991
+ };
2992
+ //#endregion
2993
+ //#region src/index.node.ts
2994
+ /**
2995
+ * Handlebars library not initiated with helpers
2996
+ * @type {Handlebars}
2997
+ */
2998
+ const Handlebars = handlebars.default;
2999
+ /**
3000
+ * Fumanchu Handlebars instance not initiated with helpers
3001
+ * @type {Handlebars}
3002
+ */
3003
+ const handlebars$1 = handlebars.default.create();
3004
+ /**
3005
+ * Register Handlebars helpers
3006
+ * @param {HelpersOptions} options - Options for Fumanchu helpers
3007
+ */
3008
+ function helpers(options) {
3009
+ new HelperRegistry().load(options.handlebars ?? options.hbs);
3010
+ }
3011
+ /**
3012
+ * Create a new Handlebars instance with Fumanchu helpers
3013
+ * @returns {Promise<Handlebars>}
3014
+ * @deprecated Will be deprecated in future versions, use `fumanchu()` instead.
3015
+ */
3016
+ async function createHandlebars() {
3017
+ const registry = new HelperRegistry();
3018
+ const handlebars$2 = handlebars.default.create();
3019
+ if (Object.keys(handlebars.default.partials).length > 0) handlebars$2.registerPartial(handlebars.default.partials);
3020
+ registry.load(handlebars$2);
3021
+ /* c8 ignore next -- @preserve */
3022
+ if (process.env.NODE_ENV === "development") console.warn("createHandlebars will be deprecated in future versions, use `fumanchu` instead.");
3023
+ return handlebars$2;
3024
+ }
3025
+ /**
3026
+ * Will return a Handlebars instance with Fumanchu helpers (experimental)
3027
+ * @param {FumanchuOptions} [options] - Options for Fumanchu
3028
+ * @returns {Handlebars} Handlebars instance with helpers
3029
+ */
3030
+ function fumanchu(options) {
3031
+ const registry = new HelperRegistry();
3032
+ let handlebars$3 = handlebars.default.create();
3033
+ /* c8 ignore next -- @preserve */
3034
+ if (options?.handlebars) handlebars$3 = options.handlebars;
3035
+ else if (Object.keys(handlebars.default.partials).length > 0) handlebars$3.registerPartial(handlebars.default.partials);
3036
+ registry.load(handlebars$3);
3037
+ if (options?.caching) {
3038
+ let cache;
3039
+ if (options.caching instanceof _cacheable_memory.CacheableMemory) cache = options.caching;
3040
+ else if (typeof options.caching === "object") cache = new _cacheable_memory.CacheableMemory({
3041
+ useClone: false,
3042
+ ...options.caching
3043
+ });
3044
+ else cache = new _cacheable_memory.CacheableMemory({ useClone: false });
3045
+ const originalCompile = handlebars$3.compile.bind(handlebars$3);
3046
+ handlebars$3.compile = (input, compileOptions) => {
3047
+ const key = compileOptions ? `${input}\0${JSON.stringify(compileOptions)}` : input;
3048
+ const cached = cache.get(key);
3049
+ if (cached) return cached;
3050
+ const compiled = originalCompile(input, compileOptions);
3051
+ cache.set(key, compiled);
3052
+ return compiled;
3053
+ };
3054
+ }
3055
+ return handlebars$3;
3056
+ }
3057
+ //#endregion
3058
+ exports.CacheableMemory = _cacheable_memory.CacheableMemory;
3059
+ exports.Handlebars = Handlebars;
3060
+ exports.HelperRegistry = HelperRegistry;
3061
+ exports.createHandlebars = createHandlebars;
3062
+ exports.fumanchu = fumanchu;
3063
+ exports.handlebars = handlebars$1;
3064
+ exports.helpers = helpers;