@schukai/monster 3.101.2 → 3.101.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.
@@ -12,28 +12,28 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import {getLocaleOfDocument} from "../dom/locale.mjs";
16
- import {Base} from "../types/base.mjs";
17
- import {getGlobal, getGlobalObject} from "../types/global.mjs";
18
- import {ID} from "../types/id.mjs";
19
- import {isArray, isObject, isString, isPrimitive} from "../types/is.mjs";
15
+ import { getLocaleOfDocument } from "../dom/locale.mjs";
16
+ import { Base } from "../types/base.mjs";
17
+ import { getGlobal, getGlobalObject } from "../types/global.mjs";
18
+ import { ID } from "../types/id.mjs";
19
+ import { isArray, isObject, isString, isPrimitive } from "../types/is.mjs";
20
20
  import {
21
- getDocumentTranslations,
22
- Translations,
21
+ getDocumentTranslations,
22
+ Translations,
23
23
  } from "../i18n/translations.mjs";
24
24
  import {
25
- validateFunction,
26
- validateInteger,
27
- validateObject,
28
- validatePrimitive,
29
- validateString,
30
- validateBoolean,
25
+ validateFunction,
26
+ validateInteger,
27
+ validateObject,
28
+ validatePrimitive,
29
+ validateString,
30
+ validateBoolean,
31
31
  } from "../types/validate.mjs";
32
- import {clone} from "../util/clone.mjs";
33
- import {Pathfinder} from "./pathfinder.mjs";
34
- import {formatTimeAgo} from "../i18n/time-ago.mjs";
32
+ import { clone } from "../util/clone.mjs";
33
+ import { Pathfinder } from "./pathfinder.mjs";
34
+ import { formatTimeAgo } from "../i18n/time-ago.mjs";
35
35
 
36
- export {Transformer};
36
+ export { Transformer };
37
37
 
38
38
  /**
39
39
  * The transformer class is a swiss army knife for manipulating values.
@@ -53,53 +53,53 @@ export {Transformer};
53
53
  * @summary The transformer class is a swiss army knife for manipulating values. especially in combination with the pipe, processing chains can be built up.
54
54
  */
55
55
  class Transformer extends Base {
56
- /**
57
- *
58
- * @param {string} definition
59
- */
60
- constructor(definition) {
61
- super();
62
- this.args = disassemble(definition);
63
- this.command = this.args.shift();
64
- this.callbacks = new Map();
65
- }
66
-
67
- /**
68
- *
69
- * @param {string} name
70
- * @param {function} callback
71
- * @param {object} context
72
- * @return {Transformer}
73
- * @throws {TypeError} value is not a string
74
- * @throws {TypeError} value is not a function
75
- */
76
- setCallback(name, callback, context) {
77
- validateString(name);
78
- validateFunction(callback);
79
-
80
- if (context !== undefined) {
81
- validateObject(context);
82
- }
83
-
84
- this.callbacks.set(name, {
85
- callback: callback,
86
- context: context,
87
- });
88
-
89
- return this;
90
- }
91
-
92
- /**
93
- *
94
- * @param {*} value
95
- * @return {*}
96
- * @throws {Error} unknown command
97
- * @throws {TypeError} unsupported type
98
- * @throws {Error} type not supported
99
- */
100
- run(value) {
101
- return transform.apply(this, [value]);
102
- }
56
+ /**
57
+ *
58
+ * @param {string} definition
59
+ */
60
+ constructor(definition) {
61
+ super();
62
+ this.args = disassemble(definition);
63
+ this.command = this.args.shift();
64
+ this.callbacks = new Map();
65
+ }
66
+
67
+ /**
68
+ *
69
+ * @param {string} name
70
+ * @param {function} callback
71
+ * @param {object} context
72
+ * @return {Transformer}
73
+ * @throws {TypeError} value is not a string
74
+ * @throws {TypeError} value is not a function
75
+ */
76
+ setCallback(name, callback, context) {
77
+ validateString(name);
78
+ validateFunction(callback);
79
+
80
+ if (context !== undefined) {
81
+ validateObject(context);
82
+ }
83
+
84
+ this.callbacks.set(name, {
85
+ callback: callback,
86
+ context: context,
87
+ });
88
+
89
+ return this;
90
+ }
91
+
92
+ /**
93
+ *
94
+ * @param {*} value
95
+ * @return {*}
96
+ * @throws {Error} unknown command
97
+ * @throws {TypeError} unsupported type
98
+ * @throws {Error} type not supported
99
+ */
100
+ run(value) {
101
+ return transform.apply(this, [value]);
102
+ }
103
103
  }
104
104
 
105
105
  /**
@@ -109,41 +109,41 @@ class Transformer extends Base {
109
109
  * @private
110
110
  */
111
111
  function disassemble(command) {
112
- validateString(command);
113
-
114
- const placeholder = new Map();
115
- const regex = /((?<pattern>\\(?<char>.)){1})/gim;
116
-
117
- // The separator for args must be escaped
118
- // undefined string which should not occur normally and is also not a regex
119
- const result = command.matchAll(regex);
120
-
121
- for (const m of result) {
122
- const g = m?.["groups"];
123
- if (!isObject(g)) {
124
- continue;
125
- }
126
-
127
- const p = g?.["pattern"];
128
- const c = g?.["char"];
129
-
130
- if (p && c) {
131
- const r = `__${new ID().toString()}__`;
132
- placeholder.set(r, c);
133
- command = command.replace(p, r);
134
- }
135
- }
136
- let parts = command.split(":");
137
-
138
- parts = parts.map(function (value) {
139
- let v = value.trim();
140
- for (const k of placeholder) {
141
- v = v.replace(k[0], k[1]);
142
- }
143
- return v;
144
- });
145
-
146
- return parts;
112
+ validateString(command);
113
+
114
+ const placeholder = new Map();
115
+ const regex = /((?<pattern>\\(?<char>.)){1})/gim;
116
+
117
+ // The separator for args must be escaped
118
+ // undefined string which should not occur normally and is also not a regex
119
+ const result = command.matchAll(regex);
120
+
121
+ for (const m of result) {
122
+ const g = m?.["groups"];
123
+ if (!isObject(g)) {
124
+ continue;
125
+ }
126
+
127
+ const p = g?.["pattern"];
128
+ const c = g?.["char"];
129
+
130
+ if (p && c) {
131
+ const r = `__${new ID().toString()}__`;
132
+ placeholder.set(r, c);
133
+ command = command.replace(p, r);
134
+ }
135
+ }
136
+ let parts = command.split(":");
137
+
138
+ parts = parts.map(function (value) {
139
+ let v = value.trim();
140
+ for (const k of placeholder) {
141
+ v = v.replace(k[0], k[1]);
142
+ }
143
+ return v;
144
+ });
145
+
146
+ return parts;
147
147
  }
148
148
 
149
149
  /**
@@ -154,12 +154,12 @@ function disassemble(command) {
154
154
  * @private
155
155
  */
156
156
  function convertToString(value) {
157
- if (isObject(value) && value.hasOwnProperty("toString")) {
158
- value = value.toString();
159
- }
157
+ if (isObject(value) && value.hasOwnProperty("toString")) {
158
+ value = value.toString();
159
+ }
160
160
 
161
- validateString(value);
162
- return value;
161
+ validateString(value);
162
+ return value;
163
163
  }
164
164
 
165
165
  /**
@@ -173,706 +173,704 @@ function convertToString(value) {
173
173
  * @throws {Error} missing key parameter
174
174
  */
175
175
  function transform(value) {
176
- const console = getGlobalObject("console");
177
-
178
- const args = clone(this.args);
179
- let key;
180
- let defaultValue;
181
-
182
- let translations;
183
- let date;
184
- let locale;
185
- let timestamp;
186
- let map;
187
- let keyValue;
188
-
189
- switch (this.command) {
190
- case "static":
191
- return this.args.join(":");
192
-
193
- case "tolower":
194
- case "strtolower":
195
- case "tolowercase":
196
- validateString(value);
197
- return value.toLowerCase();
198
-
199
- case "escape-html":
200
- case "escapehtml":
201
- validateString(value);
202
-
203
- return value.replace(/&/g, "&amp;").
204
- replace(/</g, "&lt;").
205
- replace(/>/g, "&gt;").
206
- replace(/"/g, "&quot;").
207
- replace(/'/g, '&#39;');
208
-
209
-
210
- case "contains":
211
- if (isString(value)) {
212
- return value.includes(args[0]);
213
- }
214
-
215
- if (isArray(value)) {
216
- return value.includes(args[0]);
217
- }
218
-
219
- if (isObject(value)) {
220
- return value.hasOwnProperty(args[0]);
221
- }
222
-
223
- return false;
224
-
225
- case "has-entries":
226
- case "hasentries":
227
- if (isObject(value)) {
228
- return Object.keys(value).length > 0;
229
- }
230
-
231
- if (isArray(value)) {
232
- return value.length > 0;
233
- }
234
-
235
- return false;
236
-
237
- case "isundefined":
238
- case "is-undefined":
239
- return value === undefined;
240
-
241
- case "isnull":
242
- case "is-null":
243
- return value === null;
244
-
245
- case "isset":
246
- case "is-set":
247
- return value !== undefined && value !== null;
248
-
249
- case "isnumber":
250
- case "is-number":
251
- return isPrimitive(value) && !isNaN(value);
252
-
253
- case "isinteger":
254
- case "is-integer":
255
- return isPrimitive(value) && !isNaN(value) && value % 1 === 0;
256
-
257
- case "isfloat":
258
- case "is-float":
259
- return isPrimitive(value) && !isNaN(value) && value % 1 !== 0;
260
-
261
- case "isobject":
262
- case "is-object":
263
- return isObject(value);
264
-
265
- case "isarray":
266
- case "is-array":
267
- return Array.isArray(value);
268
-
269
- case "not":
270
- validateBoolean(value);
271
- return !value;
272
-
273
- case "toupper":
274
- case "strtoupper":
275
- case "touppercase":
276
- validateString(value);
277
- return value.toUpperCase();
278
-
279
- case "to-string":
280
- case "tostring":
281
- return `${value}`;
282
-
283
- case "to-integer":
284
- case "tointeger":
285
- const n = parseInt(value);
286
- validateInteger(n);
287
- return n;
288
-
289
- case "to-json":
290
- case "tojson":
291
- return JSON.stringify(value);
292
-
293
- case "from-json":
294
- case "fromjson":
295
- return JSON.parse(value);
296
-
297
- case "trim":
298
- validateString(value);
299
- return value.trim();
300
-
301
- case "rawurlencode":
302
- validateString(value);
303
- return encodeURIComponent(value)
304
- .replace(/!/g, "%21")
305
- .replace(/'/g, "%27")
306
- .replace(/\(/g, "%28")
307
- .replace(/\)/g, "%29")
308
- .replace(/\*/g, "%2A");
309
-
310
- case "call":
311
- /**
312
- * callback-definition
313
- * function callback(value, ...args) {
314
- * return value;
315
- * }
316
- */
317
-
318
- let callback;
319
- const callbackName = args.shift();
320
- let context = getGlobal();
321
-
322
- if (isObject(value) && value.hasOwnProperty(callbackName)) {
323
- callback = value[callbackName];
324
- } else if (this.callbacks.has(callbackName)) {
325
- const s = this.callbacks.get(callbackName);
326
- callback = s?.["callback"];
327
- context = s?.["context"];
328
- } else if (
329
- typeof window === "object" &&
330
- window.hasOwnProperty(callbackName)
331
- ) {
332
- callback = window[callbackName];
333
- }
334
- validateFunction(callback);
335
-
336
- args.unshift(value);
337
- return callback.call(context, ...args);
338
-
339
- case "plain":
340
- case "plaintext":
341
- validateString(value);
342
- const doc = new DOMParser().parseFromString(value, "text/html");
343
- return doc.body.textContent || "";
344
-
345
- case "if":
346
- case "?":
347
- validatePrimitive(value);
348
-
349
- let trueStatement = args.shift() || undefined;
350
- let falseStatement = args.shift() || undefined;
351
-
352
- trueStatement = convertSpecialStrings(trueStatement, value);
353
- falseStatement = convertSpecialStrings(falseStatement, value);
354
-
355
- const condition = evaluateCondition(value);
356
- return condition ? trueStatement : falseStatement;
357
-
358
- case "ucfirst":
359
- validateString(value);
360
-
361
- const firstchar = value.charAt(0).toUpperCase();
362
- return firstchar + value.substr(1);
363
- case "ucwords":
364
- validateString(value);
365
-
366
- return value.replace(
367
- /^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g,
368
- function (v) {
369
- return v.toUpperCase();
370
- },
371
- );
372
-
373
- case "count":
374
- case "length":
375
- if (
376
- (isString(value) || isObject(value) || isArray(value)) &&
377
- value.hasOwnProperty("length")
378
- ) {
379
- return value.length;
380
- }
381
-
382
- throw new TypeError(`unsupported type ${typeof value}`);
383
-
384
- case "to-base64":
385
- case "btoa":
386
- case "base64":
387
- return btoa(convertToString(value));
388
-
389
- case "atob":
390
- case "from-base64":
391
- return atob(convertToString(value));
392
-
393
- case "empty":
394
- return "";
395
-
396
- case "undefined":
397
- return undefined;
398
-
399
- case "debug":
400
- if (isObject(console)) {
401
- console.log(value);
402
- }
403
-
404
- return value;
405
-
406
- case "prefix":
407
- validateString(value);
408
- const prefix = args?.[0];
409
- return prefix + value;
410
-
411
- case "suffix":
412
- validateString(value);
413
- const suffix = args?.[0];
414
- return value + suffix;
415
-
416
- case "uniqid":
417
- return new ID().toString();
418
-
419
- case "first-key":
420
- case "last-key":
421
- case "nth-last-key":
422
- case "nth-key":
423
- if (!isObject(value)) {
424
- throw new Error("type not supported");
425
- }
426
-
427
- const keys = Object.keys(value).sort();
428
-
429
- if (this.command === "first-key") {
430
- key = 0;
431
- } else if (this.command === "last-key") {
432
- key = keys.length - 1;
433
- } else {
434
- key = validateInteger(parseInt(args.shift()));
435
-
436
- if (this.command === "nth-last-key") {
437
- key = keys.length - key - 1;
438
- }
439
- }
440
-
441
- defaultValue = args.shift() || "";
442
-
443
- const useKey = keys?.[key];
444
-
445
- if (value?.[useKey]) {
446
- return value?.[useKey];
447
- }
448
-
449
- return defaultValue;
450
-
451
- case "key":
452
- case "property":
453
- case "index":
454
- key = args.shift() || undefined;
455
-
456
- if (key === undefined) {
457
- throw new Error("missing key parameter");
458
- }
459
-
460
- defaultValue = args.shift() || undefined;
461
-
462
- if (value instanceof Map) {
463
- if (!value.has(key)) {
464
- return defaultValue;
465
- }
466
- return value.get(key);
467
- }
468
-
469
- if (isObject(value) || isArray(value)) {
470
- if (value?.[key]) {
471
- return value?.[key];
472
- }
473
-
474
- return defaultValue;
475
- }
476
-
477
- throw new Error("type not supported");
478
-
479
- case "path-exists":
480
- key = args.shift();
481
- if (key === undefined) {
482
- throw new Error("missing key parameter");
483
- }
484
-
485
- return new Pathfinder(value).exists(key);
486
-
487
- case "concat":
488
- const pf2 = new Pathfinder(value);
489
- let concat = "";
490
- while (args.length > 0) {
491
- key = args.shift();
492
- if (key === undefined) {
493
- throw new Error("missing key parameter");
494
- }
495
-
496
- // add empty strings
497
- if (isString(key) && key.trim() === "") {
498
- concat += key;
499
- continue;
500
- }
501
-
502
- if (!pf2.exists(key)) {
503
- concat += key;
504
- continue;
505
- }
506
- const v = pf2.getVia(key);
507
- if (!isPrimitive(v)) {
508
- throw new Error("value is not primitive");
509
- }
510
-
511
- concat += v;
512
- }
513
-
514
- return concat;
515
- case "path":
516
- key = args.shift();
517
- if (key === undefined) {
518
- throw new Error("missing key parameter");
519
- }
520
-
521
- const pf = new Pathfinder(value);
522
-
523
- if (!pf.exists(key)) {
524
- return undefined;
525
- }
526
-
527
- return pf.getVia(key);
528
-
529
- case 'ellipsize':
530
- case 'ellipsis':
531
- case 'ellipse':
532
-
533
- validateString(value);
534
- const length = parseInt(args[0]) || 0;
535
- const ellipsis = args[1] || '…';
536
- if (value.length <= length) {
537
- return value;
538
- }
539
- return value.substring(0, length) + ellipsis;
540
-
541
-
542
- case "substring":
543
- validateString(value);
544
-
545
- const start = parseInt(args[0]) || 0;
546
- const end = (parseInt(args[1]) || 0) + start;
547
-
548
- return value.substring(start, end);
549
-
550
- case "nop":
551
- return value;
552
-
553
- case "??":
554
- case "default":
555
- if (value !== undefined && value !== null) {
556
- return value;
557
- }
558
-
559
- defaultValue = args.shift();
560
- let defaultType = args.shift();
561
- if (defaultType === undefined) {
562
- defaultType = "string";
563
- }
564
-
565
- switch (defaultType) {
566
- case "int":
567
- case "integer":
568
- return parseInt(defaultValue);
569
- case "float":
570
- return parseFloat(defaultValue);
571
- case "undefined":
572
- return undefined;
573
- case "bool":
574
- case "boolean":
575
- defaultValue = defaultValue.toLowerCase();
576
- return (
577
- (defaultValue !== "undefined" &&
578
- defaultValue !== "" &&
579
- defaultValue !== "off" &&
580
- defaultValue !== "false" &&
581
- defaultValue !== "false") ||
582
- defaultValue === "on" ||
583
- defaultValue === "true" ||
584
- defaultValue === "true"
585
- );
586
- case "string":
587
- return `${defaultValue}`;
588
- case "object":
589
- return JSON.parse(atob(defaultValue));
590
- }
591
-
592
- throw new Error("type not supported");
593
-
594
- case "map":
595
- map = new Map();
596
- while (args.length > 0) {
597
- keyValue = args.shift();
598
- if (keyValue === undefined) {
599
- throw new Error("missing key parameter");
600
- }
601
-
602
- keyValue = keyValue.split("=");
603
- map.set(keyValue[0], keyValue[1]);
604
- }
605
-
606
- return map.get(value);
607
-
608
- case "equals":
609
- if (args.length === 0) {
610
- throw new Error("missing value parameter");
611
- }
612
-
613
- validatePrimitive(value);
614
-
615
- const equalsValue = args.shift();
616
-
617
- /**
618
- * The history of “typeof null
619
- * https://2ality.com/2013/10/typeof-null.html
620
- * In JavaScript, typeof null is 'object', which incorrectly suggests
621
- * that null is an object.
622
- */
623
- if (value === null) {
624
- return equalsValue === "null";
625
- }
626
-
627
- const typeOfValue = typeof value;
628
-
629
- switch (typeOfValue) {
630
- case "string":
631
- return value === equalsValue;
632
- case "number":
633
- return value === parseFloat(equalsValue);
634
- case "boolean":
635
- return value === (equalsValue === "true" || equalsValue === "on");
636
- case "undefined":
637
- return equalsValue === "undefined";
638
- default:
639
- throw new Error("type not supported");
640
- }
641
-
642
- case "money":
643
- case "currency":
644
- try {
645
- locale = getLocaleOfDocument();
646
- } catch (e) {
647
- throw new Error(`unsupported locale or missing format (${e.message})`);
648
- }
649
-
650
- // Verwenden von RegExp, um Währung und Betrag zu extrahieren
651
- const match = value.match(/^([A-Z]{3})[\s-]*(\d+(\.\d+)?)$/);
652
- if (!match) {
653
- throw new Error("invalid currency format");
654
- }
655
-
656
- const currency = match[1];
657
- const amount = match[2];
658
-
659
- const maximumFractionDigits = args?.[0] || 2;
660
- const roundingIncrement = args?.[1] || 5;
661
-
662
- const nf = new Intl.NumberFormat(locale.toString(), {
663
- style: "currency",
664
- currency: currency,
665
- maximumFractionDigits: maximumFractionDigits,
666
- roundingIncrement: roundingIncrement,
667
- });
668
-
669
- return nf.format(amount);
670
-
671
- case "timestamp":
672
- date = new Date(value);
673
- timestamp = date.getTime();
674
- if (isNaN(timestamp)) {
675
- throw new Error("invalid date");
676
- }
677
- return timestamp;
678
-
679
- case "time":
680
- date = new Date(value);
681
- if (isNaN(date.getTime())) {
682
- throw new Error("invalid date");
683
- }
684
-
685
- try {
686
- locale = getLocaleOfDocument();
687
- return date.toLocaleTimeString(locale.toString(), {
688
- hour12: false,
689
- });
690
- } catch (e) {
691
- throw new Error(`unsupported locale or missing format (${e.message})`);
692
- }
693
-
694
- case "datetimeformat":
695
- date = new Date(value);
696
- if (isNaN(date.getTime())) {
697
- throw new Error("invalid date");
698
- }
699
-
700
- const options = {
701
- dateStyle: "medium",
702
- timeStyle: "medium",
703
- hour12: false,
704
- };
705
-
706
- if (args.length > 0) {
707
- options.dateStyle = args.shift();
708
- }
709
-
710
- if (args.length > 0) {
711
- options.timeStyle = args.shift();
712
- }
713
-
714
- try {
715
- locale = getLocaleOfDocument().toString();
716
- return new Intl.DateTimeFormat(locale, options).format(date);
717
- } catch (e) {
718
- throw new Error(`unsupported locale or missing format (${e.message})`);
719
- }
720
-
721
- case "datetime":
722
- date = new Date(value);
723
- if (isNaN(date.getTime())) {
724
- throw new Error("invalid date");
725
- }
726
-
727
- try {
728
- locale = getLocaleOfDocument();
729
- return date.toLocaleString(locale.toString(), {
730
- hour12: false,
731
- });
732
- } catch (e) {
733
- throw new Error(`unsupported locale or missing format (${e.message})`);
734
- }
735
-
736
- case "date":
737
- date = new Date(value);
738
- if (isNaN(date.getTime())) {
739
- throw new Error("invalid date");
740
- }
741
-
742
- try {
743
- locale = getLocaleOfDocument();
744
- return date.toLocaleDateString(locale.toString(), {
745
- year: "numeric",
746
- month: "2-digit",
747
- day: "2-digit",
748
- });
749
- } catch (e) {
750
- throw new Error(`unsupported locale or missing format (${e.message})`);
751
- }
752
-
753
- case "time-ago":
754
- date = new Date(value);
755
- if (isNaN(date.getTime())) {
756
- throw new Error("invalid date");
757
- }
758
-
759
- try {
760
- locale = getLocaleOfDocument();
761
- return formatTimeAgo(date, locale.toString());
762
- } catch (e) {
763
- throw new Error(`unsupported locale or missing format (${e.message})`);
764
- }
765
-
766
- case "year":
767
- date = new Date(value);
768
- if (isNaN(date.getTime())) {
769
- throw new Error("invalid date");
770
- }
771
-
772
- return date.getFullYear();
773
-
774
- case "month":
775
- date = new Date(value);
776
- if (isNaN(date.getTime())) {
777
- throw new Error("invalid date");
778
- }
779
-
780
- return date.getMonth() + 1;
781
-
782
- case "day":
783
- date = new Date(value);
784
- if (isNaN(date.getTime())) {
785
- throw new Error("invalid date");
786
- }
787
-
788
- return date.getDate();
789
-
790
- case "weekday":
791
- date = new Date(value);
792
- if (isNaN(date.getTime())) {
793
- throw new Error("invalid date");
794
- }
795
-
796
- return date.getDay();
797
-
798
- case "hour":
799
- case "hours":
800
- date = new Date(value);
801
- if (isNaN(date.getTime())) {
802
- throw new Error("invalid date");
803
- }
804
-
805
- return date.getHours();
806
-
807
- case "minute":
808
- case "minutes":
809
- date = new Date(value);
810
- if (isNaN(date.getTime())) {
811
- throw new Error("invalid date");
812
- }
813
-
814
- return date.getMinutes();
815
-
816
- case "second":
817
- case "seconds":
818
- date = new Date(value);
819
- if (isNaN(date.getTime())) {
820
- throw new Error("invalid date");
821
- }
822
-
823
- return date.getSeconds();
824
-
825
- case "i18n":
826
- case "translation":
827
- translations = getDocumentTranslations();
828
- if (!(translations instanceof Translations)) {
829
- throw new Error("missing translations");
830
- }
831
-
832
- key = args.shift() || undefined;
833
- if (key === undefined) {
834
- key = value;
835
- }
836
-
837
- defaultValue = args.shift() || undefined;
838
-
839
- defaultValue = convertSpecialStrings(defaultValue, value);
840
-
841
- return translations.getText(key, defaultValue);
842
-
843
- case "set-toggle":
844
- case "set-set":
845
- case "set-remove":
846
- const modifier = args.shift();
847
- let delimiter = args.shift();
848
- if (delimiter === undefined) {
849
- delimiter = " ";
850
- }
851
-
852
- const set = new Set(value.split(delimiter));
853
- const toggle = new Set(modifier.split(delimiter));
854
- if (this.command === "set-toggle") {
855
- for (const t of toggle) {
856
- if (set.has(t)) {
857
- set.delete(t);
858
- } else {
859
- set.add(t);
860
- }
861
- }
862
- } else if (this.command === "set-set") {
863
- for (const t of toggle) {
864
- set.add(t);
865
- }
866
- } else if (this.command === "set-remove") {
867
- for (const t of toggle) {
868
- set.delete(t);
869
- }
870
- }
871
- return Array.from(set).join(delimiter);
872
-
873
- default:
874
- throw new Error(`unknown command ${this.command}`);
875
- }
176
+ const console = getGlobalObject("console");
177
+
178
+ const args = clone(this.args);
179
+ let key;
180
+ let defaultValue;
181
+
182
+ let translations;
183
+ let date;
184
+ let locale;
185
+ let timestamp;
186
+ let map;
187
+ let keyValue;
188
+
189
+ switch (this.command) {
190
+ case "static":
191
+ return this.args.join(":");
192
+
193
+ case "tolower":
194
+ case "strtolower":
195
+ case "tolowercase":
196
+ validateString(value);
197
+ return value.toLowerCase();
198
+
199
+ case "escape-html":
200
+ case "escapehtml":
201
+ validateString(value);
202
+
203
+ return value
204
+ .replace(/&/g, "&amp;")
205
+ .replace(/</g, "&lt;")
206
+ .replace(/>/g, "&gt;")
207
+ .replace(/"/g, "&quot;")
208
+ .replace(/'/g, "&#39;");
209
+
210
+ case "contains":
211
+ if (isString(value)) {
212
+ return value.includes(args[0]);
213
+ }
214
+
215
+ if (isArray(value)) {
216
+ return value.includes(args[0]);
217
+ }
218
+
219
+ if (isObject(value)) {
220
+ return value.hasOwnProperty(args[0]);
221
+ }
222
+
223
+ return false;
224
+
225
+ case "has-entries":
226
+ case "hasentries":
227
+ if (isObject(value)) {
228
+ return Object.keys(value).length > 0;
229
+ }
230
+
231
+ if (isArray(value)) {
232
+ return value.length > 0;
233
+ }
234
+
235
+ return false;
236
+
237
+ case "isundefined":
238
+ case "is-undefined":
239
+ return value === undefined;
240
+
241
+ case "isnull":
242
+ case "is-null":
243
+ return value === null;
244
+
245
+ case "isset":
246
+ case "is-set":
247
+ return value !== undefined && value !== null;
248
+
249
+ case "isnumber":
250
+ case "is-number":
251
+ return isPrimitive(value) && !isNaN(value);
252
+
253
+ case "isinteger":
254
+ case "is-integer":
255
+ return isPrimitive(value) && !isNaN(value) && value % 1 === 0;
256
+
257
+ case "isfloat":
258
+ case "is-float":
259
+ return isPrimitive(value) && !isNaN(value) && value % 1 !== 0;
260
+
261
+ case "isobject":
262
+ case "is-object":
263
+ return isObject(value);
264
+
265
+ case "isarray":
266
+ case "is-array":
267
+ return Array.isArray(value);
268
+
269
+ case "not":
270
+ validateBoolean(value);
271
+ return !value;
272
+
273
+ case "toupper":
274
+ case "strtoupper":
275
+ case "touppercase":
276
+ validateString(value);
277
+ return value.toUpperCase();
278
+
279
+ case "to-string":
280
+ case "tostring":
281
+ return `${value}`;
282
+
283
+ case "to-integer":
284
+ case "tointeger":
285
+ const n = parseInt(value);
286
+ validateInteger(n);
287
+ return n;
288
+
289
+ case "to-json":
290
+ case "tojson":
291
+ return JSON.stringify(value);
292
+
293
+ case "from-json":
294
+ case "fromjson":
295
+ return JSON.parse(value);
296
+
297
+ case "trim":
298
+ validateString(value);
299
+ return value.trim();
300
+
301
+ case "rawurlencode":
302
+ validateString(value);
303
+ return encodeURIComponent(value)
304
+ .replace(/!/g, "%21")
305
+ .replace(/'/g, "%27")
306
+ .replace(/\(/g, "%28")
307
+ .replace(/\)/g, "%29")
308
+ .replace(/\*/g, "%2A");
309
+
310
+ case "call":
311
+ /**
312
+ * callback-definition
313
+ * function callback(value, ...args) {
314
+ * return value;
315
+ * }
316
+ */
317
+
318
+ let callback;
319
+ const callbackName = args.shift();
320
+ let context = getGlobal();
321
+
322
+ if (isObject(value) && value.hasOwnProperty(callbackName)) {
323
+ callback = value[callbackName];
324
+ } else if (this.callbacks.has(callbackName)) {
325
+ const s = this.callbacks.get(callbackName);
326
+ callback = s?.["callback"];
327
+ context = s?.["context"];
328
+ } else if (
329
+ typeof window === "object" &&
330
+ window.hasOwnProperty(callbackName)
331
+ ) {
332
+ callback = window[callbackName];
333
+ }
334
+ validateFunction(callback);
335
+
336
+ args.unshift(value);
337
+ return callback.call(context, ...args);
338
+
339
+ case "plain":
340
+ case "plaintext":
341
+ validateString(value);
342
+ const doc = new DOMParser().parseFromString(value, "text/html");
343
+ return doc.body.textContent || "";
344
+
345
+ case "if":
346
+ case "?":
347
+ validatePrimitive(value);
348
+
349
+ let trueStatement = args.shift() || undefined;
350
+ let falseStatement = args.shift() || undefined;
351
+
352
+ trueStatement = convertSpecialStrings(trueStatement, value);
353
+ falseStatement = convertSpecialStrings(falseStatement, value);
354
+
355
+ const condition = evaluateCondition(value);
356
+ return condition ? trueStatement : falseStatement;
357
+
358
+ case "ucfirst":
359
+ validateString(value);
360
+
361
+ const firstchar = value.charAt(0).toUpperCase();
362
+ return firstchar + value.substr(1);
363
+ case "ucwords":
364
+ validateString(value);
365
+
366
+ return value.replace(
367
+ /^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g,
368
+ function (v) {
369
+ return v.toUpperCase();
370
+ },
371
+ );
372
+
373
+ case "count":
374
+ case "length":
375
+ if (
376
+ (isString(value) || isObject(value) || isArray(value)) &&
377
+ value.hasOwnProperty("length")
378
+ ) {
379
+ return value.length;
380
+ }
381
+
382
+ throw new TypeError(`unsupported type ${typeof value}`);
383
+
384
+ case "to-base64":
385
+ case "btoa":
386
+ case "base64":
387
+ return btoa(convertToString(value));
388
+
389
+ case "atob":
390
+ case "from-base64":
391
+ return atob(convertToString(value));
392
+
393
+ case "empty":
394
+ return "";
395
+
396
+ case "undefined":
397
+ return undefined;
398
+
399
+ case "debug":
400
+ if (isObject(console)) {
401
+ console.log(value);
402
+ }
403
+
404
+ return value;
405
+
406
+ case "prefix":
407
+ validateString(value);
408
+ const prefix = args?.[0];
409
+ return prefix + value;
410
+
411
+ case "suffix":
412
+ validateString(value);
413
+ const suffix = args?.[0];
414
+ return value + suffix;
415
+
416
+ case "uniqid":
417
+ return new ID().toString();
418
+
419
+ case "first-key":
420
+ case "last-key":
421
+ case "nth-last-key":
422
+ case "nth-key":
423
+ if (!isObject(value)) {
424
+ throw new Error("type not supported");
425
+ }
426
+
427
+ const keys = Object.keys(value).sort();
428
+
429
+ if (this.command === "first-key") {
430
+ key = 0;
431
+ } else if (this.command === "last-key") {
432
+ key = keys.length - 1;
433
+ } else {
434
+ key = validateInteger(parseInt(args.shift()));
435
+
436
+ if (this.command === "nth-last-key") {
437
+ key = keys.length - key - 1;
438
+ }
439
+ }
440
+
441
+ defaultValue = args.shift() || "";
442
+
443
+ const useKey = keys?.[key];
444
+
445
+ if (value?.[useKey]) {
446
+ return value?.[useKey];
447
+ }
448
+
449
+ return defaultValue;
450
+
451
+ case "key":
452
+ case "property":
453
+ case "index":
454
+ key = args.shift() || undefined;
455
+
456
+ if (key === undefined) {
457
+ throw new Error("missing key parameter");
458
+ }
459
+
460
+ defaultValue = args.shift() || undefined;
461
+
462
+ if (value instanceof Map) {
463
+ if (!value.has(key)) {
464
+ return defaultValue;
465
+ }
466
+ return value.get(key);
467
+ }
468
+
469
+ if (isObject(value) || isArray(value)) {
470
+ if (value?.[key]) {
471
+ return value?.[key];
472
+ }
473
+
474
+ return defaultValue;
475
+ }
476
+
477
+ throw new Error("type not supported");
478
+
479
+ case "path-exists":
480
+ key = args.shift();
481
+ if (key === undefined) {
482
+ throw new Error("missing key parameter");
483
+ }
484
+
485
+ return new Pathfinder(value).exists(key);
486
+
487
+ case "concat":
488
+ const pf2 = new Pathfinder(value);
489
+ let concat = "";
490
+ while (args.length > 0) {
491
+ key = args.shift();
492
+ if (key === undefined) {
493
+ throw new Error("missing key parameter");
494
+ }
495
+
496
+ // add empty strings
497
+ if (isString(key) && key.trim() === "") {
498
+ concat += key;
499
+ continue;
500
+ }
501
+
502
+ if (!pf2.exists(key)) {
503
+ concat += key;
504
+ continue;
505
+ }
506
+ const v = pf2.getVia(key);
507
+ if (!isPrimitive(v)) {
508
+ throw new Error("value is not primitive");
509
+ }
510
+
511
+ concat += v;
512
+ }
513
+
514
+ return concat;
515
+ case "path":
516
+ key = args.shift();
517
+ if (key === undefined) {
518
+ throw new Error("missing key parameter");
519
+ }
520
+
521
+ const pf = new Pathfinder(value);
522
+
523
+ if (!pf.exists(key)) {
524
+ return undefined;
525
+ }
526
+
527
+ return pf.getVia(key);
528
+
529
+ case "ellipsize":
530
+ case "ellipsis":
531
+ case "ellipse":
532
+ validateString(value);
533
+ const length = parseInt(args[0]) || 0;
534
+ const ellipsis = args[1] || "…";
535
+ if (value.length <= length) {
536
+ return value;
537
+ }
538
+ return value.substring(0, length) + ellipsis;
539
+
540
+ case "substring":
541
+ validateString(value);
542
+
543
+ const start = parseInt(args[0]) || 0;
544
+ const end = (parseInt(args[1]) || 0) + start;
545
+
546
+ return value.substring(start, end);
547
+
548
+ case "nop":
549
+ return value;
550
+
551
+ case "??":
552
+ case "default":
553
+ if (value !== undefined && value !== null) {
554
+ return value;
555
+ }
556
+
557
+ defaultValue = args.shift();
558
+ let defaultType = args.shift();
559
+ if (defaultType === undefined) {
560
+ defaultType = "string";
561
+ }
562
+
563
+ switch (defaultType) {
564
+ case "int":
565
+ case "integer":
566
+ return parseInt(defaultValue);
567
+ case "float":
568
+ return parseFloat(defaultValue);
569
+ case "undefined":
570
+ return undefined;
571
+ case "bool":
572
+ case "boolean":
573
+ defaultValue = defaultValue.toLowerCase();
574
+ return (
575
+ (defaultValue !== "undefined" &&
576
+ defaultValue !== "" &&
577
+ defaultValue !== "off" &&
578
+ defaultValue !== "false" &&
579
+ defaultValue !== "false") ||
580
+ defaultValue === "on" ||
581
+ defaultValue === "true" ||
582
+ defaultValue === "true"
583
+ );
584
+ case "string":
585
+ return `${defaultValue}`;
586
+ case "object":
587
+ return JSON.parse(atob(defaultValue));
588
+ }
589
+
590
+ throw new Error("type not supported");
591
+
592
+ case "map":
593
+ map = new Map();
594
+ while (args.length > 0) {
595
+ keyValue = args.shift();
596
+ if (keyValue === undefined) {
597
+ throw new Error("missing key parameter");
598
+ }
599
+
600
+ keyValue = keyValue.split("=");
601
+ map.set(keyValue[0], keyValue[1]);
602
+ }
603
+
604
+ return map.get(value);
605
+
606
+ case "equals":
607
+ if (args.length === 0) {
608
+ throw new Error("missing value parameter");
609
+ }
610
+
611
+ validatePrimitive(value);
612
+
613
+ const equalsValue = args.shift();
614
+
615
+ /**
616
+ * The history of “typeof null”
617
+ * https://2ality.com/2013/10/typeof-null.html
618
+ * In JavaScript, typeof null is 'object', which incorrectly suggests
619
+ * that null is an object.
620
+ */
621
+ if (value === null) {
622
+ return equalsValue === "null";
623
+ }
624
+
625
+ const typeOfValue = typeof value;
626
+
627
+ switch (typeOfValue) {
628
+ case "string":
629
+ return value === equalsValue;
630
+ case "number":
631
+ return value === parseFloat(equalsValue);
632
+ case "boolean":
633
+ return value === (equalsValue === "true" || equalsValue === "on");
634
+ case "undefined":
635
+ return equalsValue === "undefined";
636
+ default:
637
+ throw new Error("type not supported");
638
+ }
639
+
640
+ case "money":
641
+ case "currency":
642
+ try {
643
+ locale = getLocaleOfDocument();
644
+ } catch (e) {
645
+ throw new Error(`unsupported locale or missing format (${e.message})`);
646
+ }
647
+
648
+ // Verwenden von RegExp, um Währung und Betrag zu extrahieren
649
+ const match = value.match(/^([A-Z]{3})[\s-]*(\d+(\.\d+)?)$/);
650
+ if (!match) {
651
+ throw new Error("invalid currency format");
652
+ }
653
+
654
+ const currency = match[1];
655
+ const amount = match[2];
656
+
657
+ const maximumFractionDigits = args?.[0] || 2;
658
+ const roundingIncrement = args?.[1] || 5;
659
+
660
+ const nf = new Intl.NumberFormat(locale.toString(), {
661
+ style: "currency",
662
+ currency: currency,
663
+ maximumFractionDigits: maximumFractionDigits,
664
+ roundingIncrement: roundingIncrement,
665
+ });
666
+
667
+ return nf.format(amount);
668
+
669
+ case "timestamp":
670
+ date = new Date(value);
671
+ timestamp = date.getTime();
672
+ if (isNaN(timestamp)) {
673
+ throw new Error("invalid date");
674
+ }
675
+ return timestamp;
676
+
677
+ case "time":
678
+ date = new Date(value);
679
+ if (isNaN(date.getTime())) {
680
+ throw new Error("invalid date");
681
+ }
682
+
683
+ try {
684
+ locale = getLocaleOfDocument();
685
+ return date.toLocaleTimeString(locale.toString(), {
686
+ hour12: false,
687
+ });
688
+ } catch (e) {
689
+ throw new Error(`unsupported locale or missing format (${e.message})`);
690
+ }
691
+
692
+ case "datetimeformat":
693
+ date = new Date(value);
694
+ if (isNaN(date.getTime())) {
695
+ throw new Error("invalid date");
696
+ }
697
+
698
+ const options = {
699
+ dateStyle: "medium",
700
+ timeStyle: "medium",
701
+ hour12: false,
702
+ };
703
+
704
+ if (args.length > 0) {
705
+ options.dateStyle = args.shift();
706
+ }
707
+
708
+ if (args.length > 0) {
709
+ options.timeStyle = args.shift();
710
+ }
711
+
712
+ try {
713
+ locale = getLocaleOfDocument().toString();
714
+ return new Intl.DateTimeFormat(locale, options).format(date);
715
+ } catch (e) {
716
+ throw new Error(`unsupported locale or missing format (${e.message})`);
717
+ }
718
+
719
+ case "datetime":
720
+ date = new Date(value);
721
+ if (isNaN(date.getTime())) {
722
+ throw new Error("invalid date");
723
+ }
724
+
725
+ try {
726
+ locale = getLocaleOfDocument();
727
+ return date.toLocaleString(locale.toString(), {
728
+ hour12: false,
729
+ });
730
+ } catch (e) {
731
+ throw new Error(`unsupported locale or missing format (${e.message})`);
732
+ }
733
+
734
+ case "date":
735
+ date = new Date(value);
736
+ if (isNaN(date.getTime())) {
737
+ throw new Error("invalid date");
738
+ }
739
+
740
+ try {
741
+ locale = getLocaleOfDocument();
742
+ return date.toLocaleDateString(locale.toString(), {
743
+ year: "numeric",
744
+ month: "2-digit",
745
+ day: "2-digit",
746
+ });
747
+ } catch (e) {
748
+ throw new Error(`unsupported locale or missing format (${e.message})`);
749
+ }
750
+
751
+ case "time-ago":
752
+ date = new Date(value);
753
+ if (isNaN(date.getTime())) {
754
+ throw new Error("invalid date");
755
+ }
756
+
757
+ try {
758
+ locale = getLocaleOfDocument();
759
+ return formatTimeAgo(date, locale.toString());
760
+ } catch (e) {
761
+ throw new Error(`unsupported locale or missing format (${e.message})`);
762
+ }
763
+
764
+ case "year":
765
+ date = new Date(value);
766
+ if (isNaN(date.getTime())) {
767
+ throw new Error("invalid date");
768
+ }
769
+
770
+ return date.getFullYear();
771
+
772
+ case "month":
773
+ date = new Date(value);
774
+ if (isNaN(date.getTime())) {
775
+ throw new Error("invalid date");
776
+ }
777
+
778
+ return date.getMonth() + 1;
779
+
780
+ case "day":
781
+ date = new Date(value);
782
+ if (isNaN(date.getTime())) {
783
+ throw new Error("invalid date");
784
+ }
785
+
786
+ return date.getDate();
787
+
788
+ case "weekday":
789
+ date = new Date(value);
790
+ if (isNaN(date.getTime())) {
791
+ throw new Error("invalid date");
792
+ }
793
+
794
+ return date.getDay();
795
+
796
+ case "hour":
797
+ case "hours":
798
+ date = new Date(value);
799
+ if (isNaN(date.getTime())) {
800
+ throw new Error("invalid date");
801
+ }
802
+
803
+ return date.getHours();
804
+
805
+ case "minute":
806
+ case "minutes":
807
+ date = new Date(value);
808
+ if (isNaN(date.getTime())) {
809
+ throw new Error("invalid date");
810
+ }
811
+
812
+ return date.getMinutes();
813
+
814
+ case "second":
815
+ case "seconds":
816
+ date = new Date(value);
817
+ if (isNaN(date.getTime())) {
818
+ throw new Error("invalid date");
819
+ }
820
+
821
+ return date.getSeconds();
822
+
823
+ case "i18n":
824
+ case "translation":
825
+ translations = getDocumentTranslations();
826
+ if (!(translations instanceof Translations)) {
827
+ throw new Error("missing translations");
828
+ }
829
+
830
+ key = args.shift() || undefined;
831
+ if (key === undefined) {
832
+ key = value;
833
+ }
834
+
835
+ defaultValue = args.shift() || undefined;
836
+
837
+ defaultValue = convertSpecialStrings(defaultValue, value);
838
+
839
+ return translations.getText(key, defaultValue);
840
+
841
+ case "set-toggle":
842
+ case "set-set":
843
+ case "set-remove":
844
+ const modifier = args.shift();
845
+ let delimiter = args.shift();
846
+ if (delimiter === undefined) {
847
+ delimiter = " ";
848
+ }
849
+
850
+ const set = new Set(value.split(delimiter));
851
+ const toggle = new Set(modifier.split(delimiter));
852
+ if (this.command === "set-toggle") {
853
+ for (const t of toggle) {
854
+ if (set.has(t)) {
855
+ set.delete(t);
856
+ } else {
857
+ set.add(t);
858
+ }
859
+ }
860
+ } else if (this.command === "set-set") {
861
+ for (const t of toggle) {
862
+ set.add(t);
863
+ }
864
+ } else if (this.command === "set-remove") {
865
+ for (const t of toggle) {
866
+ set.delete(t);
867
+ }
868
+ }
869
+ return Array.from(set).join(delimiter);
870
+
871
+ default:
872
+ throw new Error(`unknown command ${this.command}`);
873
+ }
876
874
  }
877
875
 
878
876
  /**
@@ -883,18 +881,18 @@ function transform(value) {
883
881
  * @return {undefined|*|null|string}
884
882
  */
885
883
  function convertSpecialStrings(input, value) {
886
- switch (input) {
887
- case "value":
888
- return value;
889
- case "\\value":
890
- return "value";
891
- case "\\undefined":
892
- return undefined;
893
- case "\\null":
894
- return null;
895
- default:
896
- return input;
897
- }
884
+ switch (input) {
885
+ case "value":
886
+ return value;
887
+ case "\\value":
888
+ return "value";
889
+ case "\\undefined":
890
+ return undefined;
891
+ case "\\null":
892
+ return null;
893
+ default:
894
+ return input;
895
+ }
898
896
  }
899
897
 
900
898
  /**
@@ -903,17 +901,17 @@ function convertSpecialStrings(input, value) {
903
901
  * @return {boolean}
904
902
  */
905
903
  function evaluateCondition(value) {
906
- const lowerValue = typeof value === "string" ? value.toLowerCase() : value;
907
-
908
- return (
909
- (value !== undefined &&
910
- value !== null &&
911
- value !== "" &&
912
- lowerValue !== "off" &&
913
- lowerValue !== "false" &&
914
- value !== false) ||
915
- lowerValue === "on" ||
916
- lowerValue === "true" ||
917
- value === true
918
- );
904
+ const lowerValue = typeof value === "string" ? value.toLowerCase() : value;
905
+
906
+ return (
907
+ (value !== undefined &&
908
+ value !== null &&
909
+ value !== "" &&
910
+ lowerValue !== "off" &&
911
+ lowerValue !== "false" &&
912
+ value !== false) ||
913
+ lowerValue === "on" ||
914
+ lowerValue === "true" ||
915
+ value === true
916
+ );
919
917
  }