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