@samuelbines/nunjucks 0.0.3
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/LICENSE +26 -0
- package/README.md +55 -0
- package/dist/scripts/smoke.d.ts +1 -0
- package/dist/scripts/smoke.js +95 -0
- package/dist/src/compiler.d.ts +12 -0
- package/dist/src/compiler.js +1050 -0
- package/dist/src/environment.d.ts +103 -0
- package/dist/src/environment.js +621 -0
- package/dist/src/express-app.d.ts +2 -0
- package/dist/src/express-app.js +33 -0
- package/dist/src/filters.d.ts +44 -0
- package/dist/src/filters.js +424 -0
- package/dist/src/globals.d.ts +14 -0
- package/dist/src/globals.js +342 -0
- package/dist/src/index.d.ts +28 -0
- package/dist/src/index.js +116 -0
- package/dist/src/interpreter.d.ts +16 -0
- package/dist/src/interpreter.js +489 -0
- package/dist/src/lexer.d.ts +72 -0
- package/dist/src/lexer.js +480 -0
- package/dist/src/lib.d.ts +74 -0
- package/dist/src/lib.js +237 -0
- package/dist/src/loader.d.ts +80 -0
- package/dist/src/loader.js +175 -0
- package/dist/src/nodes.d.ts +362 -0
- package/dist/src/nodes.js +894 -0
- package/dist/src/parser.d.ts +66 -0
- package/dist/src/parser.js +1068 -0
- package/dist/src/precompile.d.ts +15 -0
- package/dist/src/precompile.js +108 -0
- package/dist/src/runtime.d.ts +33 -0
- package/dist/src/runtime.js +314 -0
- package/dist/src/transformer.d.ts +3 -0
- package/dist/src/transformer.js +161 -0
- package/dist/src/types.d.ts +27 -0
- package/dist/src/types.js +2 -0
- package/dist/tests/compiler.test.d.ts +1 -0
- package/dist/tests/compiler.test.js +201 -0
- package/dist/tests/enviornment.test.d.ts +1 -0
- package/dist/tests/enviornment.test.js +279 -0
- package/dist/tests/express.test.d.ts +1 -0
- package/dist/tests/express.test.js +86 -0
- package/dist/tests/filters.test.d.ts +13 -0
- package/dist/tests/filters.test.js +286 -0
- package/dist/tests/globals.test.d.ts +1 -0
- package/dist/tests/globals.test.js +579 -0
- package/dist/tests/interpreter.test.d.ts +1 -0
- package/dist/tests/interpreter.test.js +208 -0
- package/dist/tests/lexer.test.d.ts +1 -0
- package/dist/tests/lexer.test.js +249 -0
- package/dist/tests/lib.test.d.ts +1 -0
- package/dist/tests/lib.test.js +236 -0
- package/dist/tests/loader.test.d.ts +1 -0
- package/dist/tests/loader.test.js +301 -0
- package/dist/tests/nodes.test.d.ts +1 -0
- package/dist/tests/nodes.test.js +137 -0
- package/dist/tests/parser.test.d.ts +1 -0
- package/dist/tests/parser.test.js +294 -0
- package/dist/tests/precompile.test.d.ts +1 -0
- package/dist/tests/precompile.test.js +224 -0
- package/dist/tests/runtime.test.d.ts +1 -0
- package/dist/tests/runtime.test.js +237 -0
- package/dist/tests/transformer.test.d.ts +1 -0
- package/dist/tests/transformer.test.js +125 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nl2br = exports.lower = exports.last = exports.first = exports.trim = exports.int = exports.isFloat = exports.isInt = exports.wordcount = exports.isUpper = exports.upper = exports.capitalize = exports.title = exports.string = exports.sort = exports.select = exports.reject = exports.random = exports.safe = exports.e = exports._escape = exports.d = void 0;
|
|
4
|
+
exports.batch = batch;
|
|
5
|
+
exports.center = center;
|
|
6
|
+
exports.default_ = default_;
|
|
7
|
+
exports.dictsort = dictsort;
|
|
8
|
+
exports.forceescape = forceescape;
|
|
9
|
+
exports.groupby = groupby;
|
|
10
|
+
exports.indent = indent;
|
|
11
|
+
exports.join = join;
|
|
12
|
+
exports.length = length;
|
|
13
|
+
exports.list = list;
|
|
14
|
+
exports.rejectattr = rejectattr;
|
|
15
|
+
exports.selectattr = selectattr;
|
|
16
|
+
exports.replace = replace;
|
|
17
|
+
exports.reverse = reverse;
|
|
18
|
+
exports.round = round;
|
|
19
|
+
exports.slice = slice;
|
|
20
|
+
exports.sum = sum;
|
|
21
|
+
exports.striptags = striptags;
|
|
22
|
+
exports.truncate = truncate;
|
|
23
|
+
exports.urlencode = urlencode;
|
|
24
|
+
exports.urlize = urlize;
|
|
25
|
+
exports.float = float;
|
|
26
|
+
//TODO: Sun 4th Jan 2026 [Improve this code]
|
|
27
|
+
const lib_1 = require("./lib");
|
|
28
|
+
const runtime_1 = require("./runtime");
|
|
29
|
+
const normalize = (value, defaultValue = '') => !value ? defaultValue : value;
|
|
30
|
+
function batch(arr, lineCount, fillWith) {
|
|
31
|
+
let i = 0;
|
|
32
|
+
const res = [];
|
|
33
|
+
let tmp = [];
|
|
34
|
+
for (i < arr?.length; i++;) {
|
|
35
|
+
if (i % lineCount === 0 && tmp?.length) {
|
|
36
|
+
res?.push(tmp);
|
|
37
|
+
tmp = [];
|
|
38
|
+
}
|
|
39
|
+
tmp?.push(arr[i]);
|
|
40
|
+
}
|
|
41
|
+
if (tmp?.length) {
|
|
42
|
+
if (fillWith) {
|
|
43
|
+
for (i = tmp?.length; i < lineCount; i++) {
|
|
44
|
+
tmp?.push(fillWith);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
res?.push(tmp);
|
|
48
|
+
}
|
|
49
|
+
return res;
|
|
50
|
+
}
|
|
51
|
+
function center(str = '', width = 80) {
|
|
52
|
+
if (str?.length >= width)
|
|
53
|
+
return str;
|
|
54
|
+
const spaces = width - str?.length;
|
|
55
|
+
const pre = (0, lib_1.repeat)(' ', spaces / 2 - (spaces % 2));
|
|
56
|
+
const post = (0, lib_1.repeat)(' ', spaces / 2);
|
|
57
|
+
return (0, runtime_1.copySafeness)(str, pre + str + post);
|
|
58
|
+
}
|
|
59
|
+
function default_(val, def, bool = false) {
|
|
60
|
+
if (bool)
|
|
61
|
+
return def || val;
|
|
62
|
+
return val || def;
|
|
63
|
+
}
|
|
64
|
+
exports.d = default_;
|
|
65
|
+
function dictsort(val, caseSensitive, by = 'value') {
|
|
66
|
+
if (!(0, lib_1.isObject)(val)) {
|
|
67
|
+
throw (0, lib_1.TemplateError)('dictsort filter: val must be an object');
|
|
68
|
+
}
|
|
69
|
+
let array = [];
|
|
70
|
+
// deliberately include properties from the object's prototype
|
|
71
|
+
for (let k in val) {
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
array?.push([k, val[k]]);
|
|
74
|
+
}
|
|
75
|
+
let si;
|
|
76
|
+
if (by === undefined || by === 'key') {
|
|
77
|
+
si = 0;
|
|
78
|
+
}
|
|
79
|
+
else if (by === 'value') {
|
|
80
|
+
si = 1;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw (0, lib_1.TemplateError)('dictsort filter: You can only sort by either key or value');
|
|
84
|
+
}
|
|
85
|
+
array.sort((t1, t2) => {
|
|
86
|
+
var a = t1[si];
|
|
87
|
+
var b = t2[si];
|
|
88
|
+
if (!caseSensitive) {
|
|
89
|
+
if ((0, lib_1.isString)(a)) {
|
|
90
|
+
a = a.toUpperCase();
|
|
91
|
+
}
|
|
92
|
+
if ((0, lib_1.isString)(b)) {
|
|
93
|
+
b = b.toUpperCase();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return a > b ? 1 : a === b ? 0 : -1; // eslint-disable-line no-nested-ternary
|
|
97
|
+
});
|
|
98
|
+
return array;
|
|
99
|
+
}
|
|
100
|
+
const _escape = (str) => (0, runtime_1.markSafe)((0, lib_1.escape)(str.toString()));
|
|
101
|
+
exports._escape = _escape;
|
|
102
|
+
exports.e = lib_1.escape;
|
|
103
|
+
const safe = (str = '') => (0, runtime_1.markSafe)(str.toString());
|
|
104
|
+
exports.safe = safe;
|
|
105
|
+
function forceescape(str) {
|
|
106
|
+
str = str === null || str === undefined ? '' : str;
|
|
107
|
+
return (0, runtime_1.markSafe)((0, lib_1.escape)(str.toString()));
|
|
108
|
+
}
|
|
109
|
+
function groupby(arr, attr) {
|
|
110
|
+
return (0, lib_1.groupBy)(arr, attr, this.env.throwOnUndefined);
|
|
111
|
+
}
|
|
112
|
+
function indent(str = '', width = 4, indentfirst) {
|
|
113
|
+
if (str === '') {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
// let res = '';
|
|
117
|
+
const lines = str.split('\n');
|
|
118
|
+
const sp = (0, lib_1.repeat)(' ', width);
|
|
119
|
+
const res = lines
|
|
120
|
+
.map((l, i) => {
|
|
121
|
+
return i === 0 && !indentfirst ? l : `${sp}${l}`;
|
|
122
|
+
})
|
|
123
|
+
.join('\n');
|
|
124
|
+
return (0, runtime_1.copySafeness)(str, res);
|
|
125
|
+
}
|
|
126
|
+
function join(arr, del = '', attr) {
|
|
127
|
+
if (attr)
|
|
128
|
+
arr = arr.map((v) => v[attr]);
|
|
129
|
+
return arr.join(del);
|
|
130
|
+
}
|
|
131
|
+
function length(str) {
|
|
132
|
+
if (Array.isArray(str) || (0, lib_1.isString)(str))
|
|
133
|
+
return str?.length;
|
|
134
|
+
if ((0, lib_1.isObject)(str))
|
|
135
|
+
Object.keys(str)?.length;
|
|
136
|
+
if (str instanceof Map || str instanceof Set)
|
|
137
|
+
return str.size;
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
function list(val) {
|
|
141
|
+
if ((0, lib_1.isString)(val)) {
|
|
142
|
+
return val.split('');
|
|
143
|
+
}
|
|
144
|
+
else if ((0, lib_1.isObject)(val)) {
|
|
145
|
+
return Object.entries(val || {}).map(([key, value]) => ({ key, value }));
|
|
146
|
+
}
|
|
147
|
+
else if (Array.isArray(val)) {
|
|
148
|
+
return val;
|
|
149
|
+
}
|
|
150
|
+
throw (0, lib_1.TemplateError)('list filter: type not iterable'); //TODO: maybe error isn't useful here
|
|
151
|
+
}
|
|
152
|
+
const random = (arr) => arr[Math.floor(Math.random() * arr?.length)];
|
|
153
|
+
exports.random = random;
|
|
154
|
+
function getSelectOrReject(expectedTestResult = false) {
|
|
155
|
+
return function filter(arr, testName = 'truthy', secondArg) {
|
|
156
|
+
const context = this;
|
|
157
|
+
const test = context.env.getTest(testName);
|
|
158
|
+
return (0, lib_1.toArray)(arr).filter(function examineTestResult(item) {
|
|
159
|
+
return test.call(context, item, secondArg) === expectedTestResult;
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
exports.reject = getSelectOrReject();
|
|
164
|
+
exports.select = getSelectOrReject(true);
|
|
165
|
+
function rejectattr(arr, attr) {
|
|
166
|
+
return arr.filter((item) => !item[attr]);
|
|
167
|
+
}
|
|
168
|
+
function selectattr(arr, attr) {
|
|
169
|
+
return arr.filter((item) => !!item[attr]);
|
|
170
|
+
}
|
|
171
|
+
function replace(str, old, new_, maxCount) {
|
|
172
|
+
var originalStr = str;
|
|
173
|
+
if (old instanceof RegExp) {
|
|
174
|
+
if ((0, lib_1.isString)(str))
|
|
175
|
+
return str.replace(old, new_);
|
|
176
|
+
}
|
|
177
|
+
if (typeof maxCount === 'undefined') {
|
|
178
|
+
maxCount = -1;
|
|
179
|
+
}
|
|
180
|
+
let res = ''; // Output
|
|
181
|
+
if ((0, exports.isFloat)(old)) {
|
|
182
|
+
old = '' + old;
|
|
183
|
+
}
|
|
184
|
+
else if (!(0, lib_1.isString)(old)) {
|
|
185
|
+
return str;
|
|
186
|
+
}
|
|
187
|
+
if ((0, exports.isFloat)(str)) {
|
|
188
|
+
str = '' + str;
|
|
189
|
+
}
|
|
190
|
+
if (!(0, lib_1.isString)(str)) {
|
|
191
|
+
return str;
|
|
192
|
+
}
|
|
193
|
+
// ShortCircuits
|
|
194
|
+
if (old === '') {
|
|
195
|
+
res = new_ + str.split('').join(new_) + new_;
|
|
196
|
+
return (0, runtime_1.copySafeness)(str, res);
|
|
197
|
+
}
|
|
198
|
+
let nextIndex = str.indexOf(old);
|
|
199
|
+
if (maxCount === 0 || nextIndex === -1) {
|
|
200
|
+
return str;
|
|
201
|
+
}
|
|
202
|
+
let pos = 0;
|
|
203
|
+
let count = 0; // # of replacements made
|
|
204
|
+
while (nextIndex > -1 && (maxCount === -1 || count < maxCount)) {
|
|
205
|
+
// Grab the next chunk of src string and add it with the
|
|
206
|
+
// replacement, to the result
|
|
207
|
+
res += str.substring(pos, nextIndex) + new_;
|
|
208
|
+
// Increment our pointer in the src string
|
|
209
|
+
pos = nextIndex + old?.length;
|
|
210
|
+
count++;
|
|
211
|
+
// See if there are any more replacements to be made
|
|
212
|
+
nextIndex = str.indexOf(old, pos);
|
|
213
|
+
}
|
|
214
|
+
// We've either reached the end, or done the max # of
|
|
215
|
+
// replacements, tack on any remaining string
|
|
216
|
+
if (pos < str?.length) {
|
|
217
|
+
res += str.substring(pos);
|
|
218
|
+
}
|
|
219
|
+
return (0, runtime_1.copySafeness)(originalStr, res);
|
|
220
|
+
}
|
|
221
|
+
function reverse(val = []) {
|
|
222
|
+
let arr = val;
|
|
223
|
+
if ((0, lib_1.isString)(val)) {
|
|
224
|
+
arr = list(val);
|
|
225
|
+
arr.reverse();
|
|
226
|
+
return (0, runtime_1.copySafeness)(val, arr.join(''));
|
|
227
|
+
}
|
|
228
|
+
arr.reverse();
|
|
229
|
+
return arr;
|
|
230
|
+
}
|
|
231
|
+
function round(val, precision = 0, method = 'round') {
|
|
232
|
+
const factor = Math.pow(10, precision);
|
|
233
|
+
return ((() => {
|
|
234
|
+
if (method === 'ceil') {
|
|
235
|
+
return Math.ceil;
|
|
236
|
+
}
|
|
237
|
+
else if (method === 'floor') {
|
|
238
|
+
return Math.floor;
|
|
239
|
+
}
|
|
240
|
+
return Math.round;
|
|
241
|
+
})()(val * factor) / factor);
|
|
242
|
+
}
|
|
243
|
+
function slice(arr, slices, fillWith = false) {
|
|
244
|
+
const sliceLength = Math.floor(arr?.length / slices);
|
|
245
|
+
const extra = arr?.length % slices;
|
|
246
|
+
const res = [];
|
|
247
|
+
let offset = 0;
|
|
248
|
+
for (let i = 0; i < slices; i++) {
|
|
249
|
+
const start = offset + i * sliceLength;
|
|
250
|
+
if (i < extra) {
|
|
251
|
+
offset++;
|
|
252
|
+
}
|
|
253
|
+
const end = offset + (i + 1) * sliceLength;
|
|
254
|
+
const currSlice = arr.slice(start, end);
|
|
255
|
+
if (fillWith && i >= extra) {
|
|
256
|
+
currSlice?.push(fillWith);
|
|
257
|
+
}
|
|
258
|
+
res?.push(currSlice);
|
|
259
|
+
}
|
|
260
|
+
return res;
|
|
261
|
+
}
|
|
262
|
+
function sum(arr, attr, start = 0) {
|
|
263
|
+
if (attr) {
|
|
264
|
+
arr = arr.map((v) => v[attr]);
|
|
265
|
+
}
|
|
266
|
+
return start + arr.reduce((a, b) => a + b, 0);
|
|
267
|
+
}
|
|
268
|
+
exports.sort = (0, runtime_1.makeMacro)(['value', 'reverse', 'case_sensitive', 'attribute'], [], function sortFilter(arr, reversed = false, caseSens = false, attr) {
|
|
269
|
+
// Copy it
|
|
270
|
+
let array = arr.map((v) => v);
|
|
271
|
+
let getAttribute = (0, lib_1.getAttrGetter)(attr);
|
|
272
|
+
array.sort((a, b) => {
|
|
273
|
+
let x = attr ? getAttribute(a) : a;
|
|
274
|
+
let y = attr ? getAttribute(b) : b;
|
|
275
|
+
if (this.env.throwOnUndefined &&
|
|
276
|
+
attr &&
|
|
277
|
+
(x === undefined || y === undefined)) {
|
|
278
|
+
throw new TypeError(`sort: attribute "${attr}" resolved to undefined`);
|
|
279
|
+
}
|
|
280
|
+
if (!caseSens && (0, lib_1.isString)(x) && (0, lib_1.isString)(y)) {
|
|
281
|
+
x = (0, exports.lower)(x);
|
|
282
|
+
y = (0, exports.lower)(y);
|
|
283
|
+
}
|
|
284
|
+
if (x < y) {
|
|
285
|
+
return reversed ? 1 : -1;
|
|
286
|
+
}
|
|
287
|
+
else if (x > y) {
|
|
288
|
+
return reversed ? -1 : 1;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
return 0;
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
return array;
|
|
295
|
+
});
|
|
296
|
+
const string = (obj) => (0, runtime_1.copySafeness)(obj, obj);
|
|
297
|
+
exports.string = string;
|
|
298
|
+
function striptags(input = '', preserveLinebreaks = true) {
|
|
299
|
+
let tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>|<!--[\s\S]*?-->/gi;
|
|
300
|
+
let trimmedInput = (0, exports.trim)(input.replace(tags, ''));
|
|
301
|
+
let res = '';
|
|
302
|
+
if (preserveLinebreaks) {
|
|
303
|
+
res = trimmedInput
|
|
304
|
+
.replace(/^ +| +$/gm, '') // remove leading and trailing spaces
|
|
305
|
+
.replace(/ +/g, ' ') // squash adjacent spaces
|
|
306
|
+
.replace(/(\r\n)/g, '\n') // normalize linebreaks (CRLF -> LF)
|
|
307
|
+
.replace(/\n\n\n+/g, '\n\n'); // squash abnormal adjacent linebreaks
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
res = trimmedInput.replace(/\s+/gi, ' ');
|
|
311
|
+
}
|
|
312
|
+
return (0, runtime_1.copySafeness)(input, res);
|
|
313
|
+
}
|
|
314
|
+
const title = (str = '') => {
|
|
315
|
+
let words = str.split(' ').map((word) => (0, exports.capitalize)(word));
|
|
316
|
+
return (0, runtime_1.copySafeness)(str, words.join(' '));
|
|
317
|
+
};
|
|
318
|
+
exports.title = title;
|
|
319
|
+
function truncate(input = '', length = 255, killwords = false, end) {
|
|
320
|
+
let orig = input;
|
|
321
|
+
if (input?.length <= length) {
|
|
322
|
+
return input;
|
|
323
|
+
}
|
|
324
|
+
if (killwords) {
|
|
325
|
+
input = input.substring(0, length);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
let idx = input.lastIndexOf(' ', length);
|
|
329
|
+
if (idx === -1) {
|
|
330
|
+
idx = length;
|
|
331
|
+
}
|
|
332
|
+
input = input.substring(0, idx);
|
|
333
|
+
}
|
|
334
|
+
input += end || '...';
|
|
335
|
+
return (0, runtime_1.copySafeness)(orig, input);
|
|
336
|
+
}
|
|
337
|
+
// TODO: Pretty sure I don't need this
|
|
338
|
+
const capitalize = (str = '') => {
|
|
339
|
+
const ret = (0, exports.lower)(str);
|
|
340
|
+
return (0, runtime_1.copySafeness)(str, ret.charAt(0).toUpperCase() + ret.slice(1));
|
|
341
|
+
};
|
|
342
|
+
exports.capitalize = capitalize;
|
|
343
|
+
const upper = (str = '') => str.toUpperCase();
|
|
344
|
+
exports.upper = upper;
|
|
345
|
+
const isUpper = (str) => str.toUpperCase() === str;
|
|
346
|
+
exports.isUpper = isUpper;
|
|
347
|
+
function urlencode(obj) {
|
|
348
|
+
var enc = encodeURIComponent;
|
|
349
|
+
if ((0, lib_1.isString)(obj)) {
|
|
350
|
+
return enc(obj);
|
|
351
|
+
}
|
|
352
|
+
let keyvals = Array.isArray(obj) ? obj : Object.keys(obj);
|
|
353
|
+
lib_1.p.log(keyvals);
|
|
354
|
+
return keyvals.map(([k, v]) => `${enc(k)}=${enc(v)}`).join('&');
|
|
355
|
+
}
|
|
356
|
+
// For the jinja regexp, see
|
|
357
|
+
// https://github.com/mitsuhiko/jinja2/blob/f15b814dcba6aa12bc74d1f7d0c881d55f7126be/jinja2/utils.py#L20-L23
|
|
358
|
+
const puncRe = /^(?:\(|<|<)?(.*?)(?:\.|,|\)|\n|>)?$/;
|
|
359
|
+
// from http://blog.gerv.net/2011/05/html5_email_address_regexp/
|
|
360
|
+
const emailRe = /^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i;
|
|
361
|
+
const httpHttpsRe = /^https?:\/\/.*$/;
|
|
362
|
+
const wwwRe = /^www\./;
|
|
363
|
+
const tldRe = /\.(?:org|net|com)(?:\:|\/|$)/;
|
|
364
|
+
function urlize(str, length, nofollow) {
|
|
365
|
+
if (isNaN(length)) {
|
|
366
|
+
length = Infinity;
|
|
367
|
+
}
|
|
368
|
+
const noFollowAttr = nofollow === true ? ' rel="nofollow"' : '';
|
|
369
|
+
const words = str
|
|
370
|
+
.split(/(\s+)/)
|
|
371
|
+
.filter((word) => {
|
|
372
|
+
// If the word has no length, bail. This can happen for str with
|
|
373
|
+
// trailing whitespace.
|
|
374
|
+
return word && word?.length;
|
|
375
|
+
})
|
|
376
|
+
.map((word) => {
|
|
377
|
+
var matches = word.match(puncRe);
|
|
378
|
+
var possibleUrl = matches ? matches[1] : word;
|
|
379
|
+
var shortUrl = possibleUrl.substr(0, length);
|
|
380
|
+
// url that starts with http or https
|
|
381
|
+
if (httpHttpsRe.test(possibleUrl)) {
|
|
382
|
+
return `<a href="${possibleUrl}"${noFollowAttr}>${shortUrl}</a>`;
|
|
383
|
+
}
|
|
384
|
+
// url that starts with www.
|
|
385
|
+
if (wwwRe.test(possibleUrl)) {
|
|
386
|
+
return `<a href="http://${possibleUrl}"${noFollowAttr}>${shortUrl}</a>`;
|
|
387
|
+
}
|
|
388
|
+
// an email address of the form username@domain.tld
|
|
389
|
+
if (emailRe.test(possibleUrl)) {
|
|
390
|
+
return `<a href="mailto:${possibleUrl}">${possibleUrl}</a>`;
|
|
391
|
+
}
|
|
392
|
+
// url that ends in .com, .org or .net that is not an email address
|
|
393
|
+
if (tldRe.test(possibleUrl)) {
|
|
394
|
+
return `<a href="http://${possibleUrl}"${noFollowAttr}>${shortUrl}</a>`;
|
|
395
|
+
}
|
|
396
|
+
return word;
|
|
397
|
+
});
|
|
398
|
+
return words.join('');
|
|
399
|
+
}
|
|
400
|
+
const wordcount = (str = '') => str.match(/\w+/g)?.length || null;
|
|
401
|
+
exports.wordcount = wordcount;
|
|
402
|
+
function float(val, def) {
|
|
403
|
+
const res = parseFloat(val);
|
|
404
|
+
return isNaN(res) ? def : res;
|
|
405
|
+
}
|
|
406
|
+
const isInt = (n) => Number(n) === n && n % 1 === 0;
|
|
407
|
+
exports.isInt = isInt;
|
|
408
|
+
const isFloat = (n) => Number(n) === n && n % 1 !== 0;
|
|
409
|
+
exports.isFloat = isFloat;
|
|
410
|
+
exports.int = (0, runtime_1.makeMacro)(['value', 'default', 'base'], [], function doInt(value, defaultValue = 0, base = 10) {
|
|
411
|
+
var res = parseInt(value, base);
|
|
412
|
+
return isNaN(res) ? defaultValue : res;
|
|
413
|
+
});
|
|
414
|
+
const trim = (str) => (0, runtime_1.copySafeness)(str, str.replace(/^\s*|\s*$/g, ''));
|
|
415
|
+
exports.trim = trim;
|
|
416
|
+
// Aliases
|
|
417
|
+
const first = (arr = []) => arr[0];
|
|
418
|
+
exports.first = first;
|
|
419
|
+
const last = (arr = []) => arr[arr?.length - 1];
|
|
420
|
+
exports.last = last;
|
|
421
|
+
const lower = (str) => normalize(str).toLowerCase();
|
|
422
|
+
exports.lower = lower;
|
|
423
|
+
const nl2br = (str = '') => str ? (0, runtime_1.copySafeness)(str, str.replace(/\r\n|\n/g, '<br />\n')) : '';
|
|
424
|
+
exports.nl2br = nl2br;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface IGlobals {
|
|
2
|
+
range(start: number, stop: number, step?: number): any[];
|
|
3
|
+
cycler(...items: any[]): {
|
|
4
|
+
readonly current: any;
|
|
5
|
+
reset(): void;
|
|
6
|
+
next(): any;
|
|
7
|
+
};
|
|
8
|
+
joiner(sep?: string): () => string;
|
|
9
|
+
}
|
|
10
|
+
export declare function globals(): IGlobals;
|
|
11
|
+
export declare function precompileGlobal(templates: any[], opts?: {
|
|
12
|
+
isFunction: boolean;
|
|
13
|
+
}): string;
|
|
14
|
+
export declare function installCompat(): () => void;
|