@pacem/pacem 1.0.0-abel

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.
Files changed (67) hide show
  1. package/LICENSE +191 -0
  2. package/NOTICE +4 -0
  3. package/dist/browser/pacem-2d.js +2755 -0
  4. package/dist/browser/pacem-2d.js.map +6 -0
  5. package/dist/browser/pacem-2d.min.js +7 -0
  6. package/dist/browser/pacem-2d.min.js.map +6 -0
  7. package/dist/browser/pacem-3d.js +7723 -0
  8. package/dist/browser/pacem-3d.js.map +6 -0
  9. package/dist/browser/pacem-3d.min.js +7 -0
  10. package/dist/browser/pacem-3d.min.js.map +6 -0
  11. package/dist/browser/pacem-charts.js +1628 -0
  12. package/dist/browser/pacem-charts.js.map +6 -0
  13. package/dist/browser/pacem-charts.min.js +7 -0
  14. package/dist/browser/pacem-charts.min.js.map +6 -0
  15. package/dist/browser/pacem-cms.js +2220 -0
  16. package/dist/browser/pacem-cms.js.map +6 -0
  17. package/dist/browser/pacem-cms.min.js +7 -0
  18. package/dist/browser/pacem-cms.min.js.map +6 -0
  19. package/dist/browser/pacem-core.js +9104 -0
  20. package/dist/browser/pacem-core.js.map +6 -0
  21. package/dist/browser/pacem-core.min.js +7 -0
  22. package/dist/browser/pacem-core.min.js.map +6 -0
  23. package/dist/browser/pacem-foundation.js +2138 -0
  24. package/dist/browser/pacem-foundation.js.map +6 -0
  25. package/dist/browser/pacem-foundation.min.js +7 -0
  26. package/dist/browser/pacem-foundation.min.js.map +6 -0
  27. package/dist/browser/pacem-fx.js +870 -0
  28. package/dist/browser/pacem-fx.js.map +6 -0
  29. package/dist/browser/pacem-fx.min.js +7 -0
  30. package/dist/browser/pacem-fx.min.js.map +6 -0
  31. package/dist/browser/pacem-logging.js +175 -0
  32. package/dist/browser/pacem-logging.js.map +6 -0
  33. package/dist/browser/pacem-logging.min.js +7 -0
  34. package/dist/browser/pacem-logging.min.js.map +6 -0
  35. package/dist/browser/pacem-maps.js +3642 -0
  36. package/dist/browser/pacem-maps.js.map +6 -0
  37. package/dist/browser/pacem-maps.min.js +7 -0
  38. package/dist/browser/pacem-maps.min.js.map +6 -0
  39. package/dist/browser/pacem-media.js +284 -0
  40. package/dist/browser/pacem-media.js.map +6 -0
  41. package/dist/browser/pacem-media.min.js +7 -0
  42. package/dist/browser/pacem-media.min.js.map +6 -0
  43. package/dist/browser/pacem-networking.js +434 -0
  44. package/dist/browser/pacem-networking.js.map +6 -0
  45. package/dist/browser/pacem-networking.min.js +7 -0
  46. package/dist/browser/pacem-networking.min.js.map +6 -0
  47. package/dist/browser/pacem-numerical.js +2627 -0
  48. package/dist/browser/pacem-numerical.js.map +6 -0
  49. package/dist/browser/pacem-numerical.min.js +7 -0
  50. package/dist/browser/pacem-numerical.min.js.map +6 -0
  51. package/dist/browser/pacem-plus.js +2373 -0
  52. package/dist/browser/pacem-plus.js.map +6 -0
  53. package/dist/browser/pacem-plus.min.js +7 -0
  54. package/dist/browser/pacem-plus.min.js.map +6 -0
  55. package/dist/browser/pacem-scaffolding.js +10435 -0
  56. package/dist/browser/pacem-scaffolding.js.map +6 -0
  57. package/dist/browser/pacem-scaffolding.min.js +7 -0
  58. package/dist/browser/pacem-scaffolding.min.js.map +6 -0
  59. package/dist/browser/pacem-ui.js +6348 -0
  60. package/dist/browser/pacem-ui.js.map +6 -0
  61. package/dist/browser/pacem-ui.min.js +7 -0
  62. package/dist/browser/pacem-ui.min.js.map +6 -0
  63. package/dist/bundle/pacem.min.mjs +997 -0
  64. package/dist/bundle/pacem.mjs +47067 -0
  65. package/dist/bundle/pacem.mjs.map +12 -0
  66. package/dist/typings/index.d.ts +9757 -0
  67. package/package.json +130 -0
@@ -0,0 +1,2138 @@
1
+ /**
2
+ * @pacem/pacem v1.0.0-abel (https://js.pacem.it)
3
+ * Copyright 2026 Pacem (https://pacem.it)
4
+ * Licensed under Apache-2.0
5
+ */
6
+ (function () {
7
+ 'use strict';
8
+
9
+ Number.prototype.isCloseTo = function (other, precision = 14) {
10
+ const delta = Number(`1e-${precision}`);
11
+ return this > (other - delta) && this < (other + delta);
12
+ //return this.toFixed(precision) === other.toFixed(precision);
13
+ };
14
+ Number.prototype.roundoff = function (precision = 14) {
15
+ return parseFloat(this.toFixed(precision));
16
+ };
17
+ Number.prototype.clamp = function (min, max) {
18
+ let value = this;
19
+ if (min != null && !isNaN(min)) {
20
+ value = Math.max(value, min);
21
+ }
22
+ if (max != null && !isNaN(max)) {
23
+ value = Math.min(value, max);
24
+ }
25
+ return value;
26
+ };
27
+ Number.prototype.toBase62 = function () {
28
+ var alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
29
+ var temp = this;
30
+ var sb = '';
31
+ while (temp != 0) {
32
+ var mod = temp % 62;
33
+ sb = alphabet.charAt(mod) + sb;
34
+ temp = Math.floor(temp / 62);
35
+ }
36
+ return sb;
37
+ };
38
+ Number.prototype.toBase36 = function () {
39
+ return this.toString(36);
40
+ };
41
+
42
+ //namespace Pacem {
43
+ const JSON_DATE_PATTERN = /^\/Date\([\d]+\)\/$/i;
44
+ class Dates {
45
+ static parse(input) {
46
+ let d;
47
+ if (typeof input === 'string') {
48
+ if (JSON_DATE_PATTERN.test(input))
49
+ d = parseInt(input.substring(6));
50
+ else
51
+ d = Date.parse(input);
52
+ return new Date(d);
53
+ }
54
+ else if (typeof input === 'number') {
55
+ return new Date(input);
56
+ }
57
+ else
58
+ return input;
59
+ }
60
+ static isLeapYear(year) {
61
+ return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
62
+ }
63
+ static daysInMonth(year, month) {
64
+ return [31, (Dates.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
65
+ }
66
+ /**
67
+ * Gets whether a date is an `Invalid Date` or not.
68
+ * @param date
69
+ */
70
+ static isDate(date) {
71
+ return date instanceof Date && !isNaN(date.valueOf());
72
+ }
73
+ /**
74
+ * Returns the date-only equaivalent of a provided datetime.
75
+ * @param datetime
76
+ */
77
+ static dateOnly(datetime) {
78
+ return new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate());
79
+ }
80
+ static addMonths(input, value) {
81
+ let n = input.getDate(), i = new Date(input), month = i.getMonth() + value, years = 0;
82
+ while (month < 0) {
83
+ month += 12;
84
+ years--;
85
+ }
86
+ i.setDate(1);
87
+ i.setMonth(month % 12);
88
+ i.setFullYear(i.getFullYear() + years + Math.floor(month / 12));
89
+ i.setDate(Math.min(n, Dates.daysInMonth(i.getFullYear(), i.getMonth())));
90
+ return i;
91
+ }
92
+ static addDays(input, value) {
93
+ return new Date(input.valueOf() + value * 86400000);
94
+ }
95
+ static daysBetween(start, end) {
96
+ return (end.valueOf() - start.valueOf()) / 86400000;
97
+ }
98
+ }
99
+ //}
100
+
101
+ /// <reference path="dates.ts" />
102
+ // namespace Pacem {
103
+ class NullChecker {
104
+ static isNull(o) {
105
+ return o === null || o === void 0;
106
+ }
107
+ static isEmpty(o) {
108
+ try {
109
+ return (Array.isArray(o) && o.length === 0)
110
+ || (typeof o === 'string' && o === '')
111
+ || (typeof o === 'object' && Object.keys(o).length === 0 && !Dates.isDate(o) && !(o instanceof RegExp) && !(o instanceof FileSystemDirectoryHandle) && !(o instanceof FileSystemFileHandle));
112
+ }
113
+ catch (e) {
114
+ // Object.keys(null) would throw...
115
+ return false;
116
+ }
117
+ }
118
+ static isNullOrEmpty(o) {
119
+ return NullChecker.isNull(o) || NullChecker.isEmpty(o);
120
+ }
121
+ }
122
+ //}
123
+
124
+ Array.prototype.distinct = function () {
125
+ return Array.from(new Set(this));
126
+ };
127
+ Array.prototype.union = function (other) {
128
+ const thisEmpty = NullChecker.isNullOrEmpty(this), thatEmpty = NullChecker.isNullOrEmpty(other);
129
+ if (thisEmpty && thatEmpty) {
130
+ return [];
131
+ }
132
+ if (thatEmpty) {
133
+ return this.slice();
134
+ }
135
+ if (thisEmpty) {
136
+ return other.slice();
137
+ }
138
+ return this.concat(other).distinct();
139
+ };
140
+ Array.prototype.moveWithin = function (from, to) {
141
+ const OUT_OF_RANGE = 'Index must be greater or equal than 0 and less or equal than the length of the array.';
142
+ var arr = this;
143
+ if (from < 0 || from > arr.length)
144
+ throw new Error(OUT_OF_RANGE);
145
+ if (to < 0 || to > arr.length)
146
+ throw new Error(OUT_OF_RANGE);
147
+ arr.splice(to, 0, /* avoid to trigger a double change on a single command */ Array.prototype.splice.apply(arr, [from, 1])[0]);
148
+ };
149
+ Array.prototype.equalsContent = function (other) {
150
+ if (other == null || this.length !== other.length) {
151
+ return false;
152
+ }
153
+ for (let j = 0; j < this.length; j++) {
154
+ if (this[j] !== other[j]) {
155
+ return false;
156
+ }
157
+ }
158
+ return true;
159
+ };
160
+ Array.prototype.cloneFrom = function (other) {
161
+ if (other == null) {
162
+ throw 'Cannot clone array from null object.';
163
+ }
164
+ const length = other.length;
165
+ var changes = this.length !== other.length;
166
+ for (let j = 0; j < length; j++) {
167
+ const item = other[j];
168
+ if (this.length > j) {
169
+ if (this[j] !== item) {
170
+ this[j] = item;
171
+ changes = true;
172
+ }
173
+ }
174
+ else {
175
+ Array.prototype.push.apply(this, [item]);
176
+ changes = true;
177
+ }
178
+ }
179
+ if (changes) {
180
+ // trigger change just in case
181
+ this.splice(length);
182
+ }
183
+ };
184
+
185
+ function isPlainObject(value) {
186
+ return (value != null &&
187
+ typeof value === 'object' &&
188
+ !Array.isArray(value) &&
189
+ (value.constructor === Object || value.constructor === undefined));
190
+ }
191
+ function deepMerge(target, source) {
192
+ const output = target;
193
+ for (const key of Object.keys(source)) {
194
+ const sourceValue = source[key];
195
+ const targetValue = output[key];
196
+ if (isPlainObject(sourceValue)) {
197
+ // never adopt the source's object by reference: bundlers emit frozen
198
+ // namespace objects (`export * as X`), so a later merge into the same
199
+ // slot would throw ("object is not extensible"). Always merge into a
200
+ // fresh, extensible object instead.
201
+ output[key] = deepMerge(isPlainObject(targetValue) ? targetValue : {}, sourceValue);
202
+ }
203
+ else if (Array.isArray(sourceValue)) {
204
+ output[key] = sourceValue.slice();
205
+ }
206
+ else {
207
+ output[key] = sourceValue;
208
+ }
209
+ }
210
+ return output;
211
+ }
212
+ class DeepMerger {
213
+ constructor() {
214
+ }
215
+ static merge(source, target) {
216
+ target ??= (globalThis['Pacem'] ??= {});
217
+ return deepMerge(target, source);
218
+ }
219
+ }
220
+
221
+ //namespace Pacem {
222
+ class Arrays {
223
+ static range(min, max, items = 2) {
224
+ let x = min;
225
+ if (NullChecker.isNull(max)) {
226
+ max = items = min;
227
+ min = 1;
228
+ }
229
+ const step = (max - min) / (items - 1);
230
+ const output = [];
231
+ if (step > 0) {
232
+ //while (x <= max) {
233
+ while (output.length < items) {
234
+ output.push(x.roundoff());
235
+ x += step;
236
+ }
237
+ }
238
+ return output;
239
+ }
240
+ static chunkify(source, size) {
241
+ if (NullChecker.isNullOrEmpty(source)) {
242
+ return [];
243
+ }
244
+ if (size <= 0 || size % 1 !== 0) {
245
+ throw new Error('Provide a positive integer number.');
246
+ }
247
+ const length = Math.ceil(source.length / size);
248
+ return Array.from({ length }, (_, index) => {
249
+ const start = index * size, end = start + size;
250
+ return source.slice(start, end);
251
+ });
252
+ }
253
+ }
254
+ //}
255
+
256
+ //namespace Pacem {
257
+ class Blobs {
258
+ static blobToDataURL(blob) {
259
+ return new Promise((resolve, _) => {
260
+ const a = new FileReader();
261
+ a.onload = (e) => { resolve(e.target.result); };
262
+ a.readAsDataURL(blob);
263
+ });
264
+ }
265
+ static _b64ToUint8Array(bstr) {
266
+ let n = bstr.length;
267
+ const u8arr = new Uint8Array(n);
268
+ while (n--) {
269
+ u8arr[n] = bstr.charCodeAt(n);
270
+ }
271
+ return u8arr;
272
+ }
273
+ static base64ToBlob(bstr, options) {
274
+ const u8arr = Blobs._b64ToUint8Array(atob(bstr));
275
+ return new Blob([u8arr], options);
276
+ }
277
+ static dataURLToBlob(dataurl) {
278
+ const coma = dataurl.indexOf(',');
279
+ if (coma === -1) {
280
+ return Blobs.base64ToBlob(dataurl);
281
+ }
282
+ else {
283
+ const bstr = dataurl.substring(coma + 1), data = dataurl.substring(0, coma);
284
+ const mime = data.match(/:(.*?);/)[1];
285
+ return Blobs.base64ToBlob(bstr, { type: mime });
286
+ }
287
+ }
288
+ static async blobToText(blob, encoding) {
289
+ const buffer = await blob.arrayBuffer();
290
+ const decoder = new TextDecoder(encoding, { fatal: false });
291
+ return decoder.decode(buffer);
292
+ }
293
+ static textToBlob(content, type = 'text/plain', charset = 'utf-8', bom, lossyChar = 0x3F) {
294
+ let charsetLower = charset.toLowerCase();
295
+ const fullType = () => `${type};charset=${charsetLower}`;
296
+ switch (charsetLower) {
297
+ // -------------------------
298
+ // UTF-8 (native, safe)
299
+ // -------------------------
300
+ case 'utf-8': {
301
+ const encoder = new TextEncoder();
302
+ const bytes = encoder.encode(content);
303
+ const parts = bom
304
+ ? [new Uint8Array([0xEF, 0xBB, 0xBF]), bytes]
305
+ : [bytes];
306
+ return new Blob(parts, { type: fullType() });
307
+ }
308
+ // -------------------------
309
+ // UTF-16 (explicit LE/BE)
310
+ // -------------------------
311
+ case 'utf-16':
312
+ // Treat as UTF-16LE with BOM (common convention)
313
+ charsetLower = 'utf-16le';
314
+ bom ??= true;
315
+ case 'utf-16le':
316
+ case 'utf-16be': {
317
+ const littleEndian = charsetLower !== 'utf-16be';
318
+ const offset = bom ? 1 : 0;
319
+ const buffer = new ArrayBuffer((content.length + offset) * 2);
320
+ const view = new DataView(buffer);
321
+ if (bom) {
322
+ view.setUint16(0, 0xFEFF, littleEndian);
323
+ }
324
+ for (let i = 0; i < content.length; i++) {
325
+ view.setUint16((i + offset) * 2, content.charCodeAt(i), littleEndian);
326
+ }
327
+ return new Blob([buffer], {
328
+ type: fullType()
329
+ });
330
+ }
331
+ // -------------------------
332
+ // Latin-1 (ISO-8859-1)
333
+ // -------------------------
334
+ case 'ascii':
335
+ case 'iso-8859-1':
336
+ case 'latin1': {
337
+ const boundary = charsetLower === 'ascii' ? 0x7F : 0xFF;
338
+ const buffer = new Uint8Array(content.length);
339
+ const lossy = lossyChar > 0;
340
+ for (let i = 0; i < content.length; i++) {
341
+ const code = content.charCodeAt(i);
342
+ if (code > boundary) {
343
+ if (lossy) {
344
+ buffer[i] = lossyChar; // ? char
345
+ }
346
+ else {
347
+ throw new Error(`Character "${content[i]}" cannot be encoded in ${charset}.`);
348
+ }
349
+ }
350
+ else {
351
+ buffer[i] = code;
352
+ }
353
+ }
354
+ return new Blob([buffer], { type: fullType() });
355
+ }
356
+ // -------------------------
357
+ // Explicitly unsupported
358
+ // -------------------------
359
+ default:
360
+ throw new Error(`Encoding "${charset}" is not supported safely in the browser. ` +
361
+ `Use UTF-8 or any supported encoding.`);
362
+ }
363
+ }
364
+ }
365
+ //}
366
+
367
+ //namespace Pacem.Browsers {
368
+ // Function to extract browser version using regex
369
+ const browserVersion = (userAgent, regex) => {
370
+ const match = userAgent.match(regex);
371
+ return match ? match[2] : null;
372
+ };
373
+ // https://stackoverflow.com/77095874
374
+ function detect(userAgent = navigator.userAgent) {
375
+ let browser = 'unknown';
376
+ let version = null;
377
+ // Detect browser name
378
+ if (/ucbrowser/i.test(userAgent)) {
379
+ browser = 'UCBrowser';
380
+ }
381
+ else if (/edg/i.test(userAgent)) {
382
+ browser = 'Edge';
383
+ }
384
+ else if (/googlebot/i.test(userAgent)) {
385
+ browser = 'GoogleBot';
386
+ }
387
+ else if (/chromium/i.test(userAgent)) {
388
+ browser = 'Chromium';
389
+ }
390
+ else if (/firefox|fxios/i.test(userAgent) && !/seamonkey/i.test(userAgent)) {
391
+ browser = 'Firefox';
392
+ }
393
+ else if (/; msie|trident/i.test(userAgent) && !/ucbrowser/i.test(userAgent)) {
394
+ browser = 'IE';
395
+ }
396
+ else if (/chrome|crios/i.test(userAgent) && !/opr|opera|chromium|edg|ucbrowser|googlebot/i.test(userAgent)) {
397
+ browser = 'Chrome';
398
+ }
399
+ else if (/safari/i.test(userAgent) && !/chromium|edg|ucbrowser|chrome|crios|opr|opera|fxios|firefox/i.test(userAgent)) {
400
+ browser = 'Safari';
401
+ }
402
+ else if (/opr|opera/i.test(userAgent)) {
403
+ browser = 'Opera';
404
+ }
405
+ // Detect browser version
406
+ switch (browser) {
407
+ case 'UCBrowser':
408
+ version = browserVersion(userAgent, /(ucbrowser)\/([\d\.]+)/i);
409
+ break;
410
+ case 'Edge':
411
+ version = browserVersion(userAgent, /(edge|edga|edgios|edg)\/([\d\.]+)/i);
412
+ break;
413
+ case 'GoogleBot':
414
+ version = browserVersion(userAgent, /(googlebot)\/([\d\.]+)/i);
415
+ break;
416
+ case 'Chromium':
417
+ version = browserVersion(userAgent, /(chromium)\/([\d\.]+)/i);
418
+ break;
419
+ case 'Firefox':
420
+ version = browserVersion(userAgent, /(firefox|fxios)\/([\d\.]+)/i);
421
+ break;
422
+ case 'Chrome':
423
+ version = browserVersion(userAgent, /(chrome|crios)\/([\d\.]+)/i);
424
+ break;
425
+ case 'Safari':
426
+ version = browserVersion(userAgent, /(safari)\/([\d\.]+)/i);
427
+ break;
428
+ case 'Opera':
429
+ version = browserVersion(userAgent, /(opera|opr)\/([\d\.]+)/i);
430
+ break;
431
+ case 'IE': {
432
+ const tridentVersion = browserVersion(userAgent, /(trident)\/([\d\.]+)/i);
433
+ // IE version is mapped using Trident version
434
+ // IE/8.0 = Trident/4.0, IE/9.0 = Trident/5.0
435
+ version = tridentVersion ? `${parseFloat(tridentVersion) + 4.0}` : '7.0';
436
+ break;
437
+ }
438
+ default:
439
+ version = '0.0.0.0';
440
+ break;
441
+ }
442
+ return { name: browser, version };
443
+ }
444
+ //}
445
+
446
+ //namespace Pacem {
447
+ const HSL_PATTERN = /^hsl\s*\(\s*([\d\.]+)\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)%\s*\)$/;
448
+ const HSLA_PATTERN = /^hsla\s*\(\s*([\d\.]+)\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)\)$/;
449
+ const RGB_PATTERN = /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/;
450
+ const RGBA_PATTERN = /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\)$/;
451
+ const HEX_PATTERN = /^#[a-f0-9]{6}$/;
452
+ const HEX_SHORT_PATTERN = /^#[a-f0-9]{3}$/;
453
+ function isRgb(clr) {
454
+ const base = !NullChecker.isNullOrEmpty(clr) && typeof clr === 'object' && 'r' in clr && 'g' in clr && 'b' in clr // && 'a' in clr
455
+ && typeof clr.r === 'number' && typeof clr.b === 'number' && typeof clr.g === 'number' // && typeof clr.a === 'number'
456
+ ;
457
+ if (!base) {
458
+ return false;
459
+ }
460
+ clr.a ??= 1;
461
+ return clr.r >= 0 && clr.r <= 1
462
+ && clr.g >= 0 && clr.g <= 1
463
+ && clr.b >= 0 && clr.b <= 1
464
+ && clr.a >= 0 && clr.a <= 1;
465
+ }
466
+ function isHsl(clr) {
467
+ const base = !NullChecker.isNullOrEmpty(clr) && typeof clr === 'object' && 'h' in clr && 's' in clr && 'l' in clr // && 'a' in clr
468
+ && typeof clr.h === 'number' && typeof clr.s === 'number' && typeof clr.l === 'number' // && typeof clr.a === 'number'
469
+ ;
470
+ if (!base) {
471
+ return false;
472
+ }
473
+ clr.a ??= 1;
474
+ return clr.h >= 0 && clr.h <= 360
475
+ && clr.s >= 0 && clr.s <= 1
476
+ && clr.l >= 0 && clr.l <= 1
477
+ && clr.a >= 0 && clr.a <= 1;
478
+ }
479
+ function luminance(rgb) {
480
+ const r = rgb.r, g = rgb.g, b = rgb.b;
481
+ const l = .5 * (Math.max(r, g, b) + Math.min(r, g, b));
482
+ return l.clamp(0, 1);
483
+ }
484
+ const cieUtils = {
485
+ adjustRgbChannel: (v) => {
486
+ // sRGB => sR'G'B'
487
+ return v <= .03928 ? (v / 12.92) : Math.pow((v + .055) / 1.055, 2.4);
488
+ },
489
+ adjustRgbChannelInv: (v) => {
490
+ // sR'G'B' => sRGB
491
+ return v <= .00304 ? (v * 12.92) : 1.055 * (Math.pow(v, 1 / 2.4) - .055);
492
+ },
493
+ adjustRgb: (rgb) => {
494
+ const rgbOut = { r: cieUtils.adjustRgbChannel(rgb.r), g: cieUtils.adjustRgbChannel(rgb.g), b: cieUtils.adjustRgbChannel(rgb.b), a: rgb.a };
495
+ return rgbOut;
496
+ },
497
+ adjustRgbInv: (rgb) => {
498
+ const rgbOut = { r: cieUtils.adjustRgbChannelInv(rgb.r), g: cieUtils.adjustRgbChannelInv(rgb.g), b: cieUtils.adjustRgbChannelInv(rgb.b), a: rgb.a };
499
+ return rgbOut;
500
+ },
501
+ X: (adjustedRgb) => {
502
+ return .4125 * adjustedRgb.r + .3576 * adjustedRgb.g + .1804 * adjustedRgb.b;
503
+ },
504
+ Y: (adjustedRgb) => {
505
+ // https://www.w3.org/TR/WCAG20/#relativeluminancedef
506
+ return .2126 * adjustedRgb.r + .7152 * adjustedRgb.g + .0722 * adjustedRgb.b;
507
+ },
508
+ Z: (adjustedRgb) => {
509
+ return .0193 * adjustedRgb.r + .1191 * adjustedRgb.g + .9503 * adjustedRgb.b;
510
+ },
511
+ relativeLuminance: (rgb) => {
512
+ const adjRgb = cieUtils.adjustRgb(rgb);
513
+ return cieUtils.Y(adjRgb);
514
+ },
515
+ rgbToCieXYZ: (rgb) => {
516
+ const adjRgb = cieUtils.adjustRgb(rgb);
517
+ const xyz = { x: cieUtils.X(adjRgb), y: cieUtils.Y(adjRgb), z: cieUtils.Z(adjRgb), a: rgb.a };
518
+ return xyz;
519
+ },
520
+ cieXYZToRgb: (xyz) => {
521
+ const r = 3.2410 * xyz.x - 1.5374 * xyz.y - .4986 * xyz.z, g = -0.9692 * xyz.x + 1.8760 * xyz.y + .0416 * xyz.z, b = .0556 * xyz.x - .2040 * xyz.y + 1.0570 * xyz.z;
522
+ return cieUtils.adjustRgbInv({ r, g, b, a: xyz.a });
523
+ },
524
+ /**
525
+ * Returns the contrast ratio between two colors.
526
+ * @param rgb1 Color 1
527
+ * @param rgb2 Color 2
528
+ * @returns A numeric value between 1 and 21.
529
+ */
530
+ contrastRatio: (rgb1, rgb2) => {
531
+ // https://www.w3.org/TR/WCAG20/#contrast-ratiodef
532
+ const l1 = cieUtils.relativeLuminance(rgb1) + .05, l2 = cieUtils.relativeLuminance(rgb2) + .05;
533
+ return l1 > l2 ?
534
+ l1 / l2
535
+ :
536
+ l2 / l1;
537
+ }
538
+ };
539
+ function saturation(rgb, l) {
540
+ const r = rgb.r, g = rgb.g, b = rgb.b;
541
+ const max = Math.max(r, g, b);
542
+ const min = Math.min(r, g, b);
543
+ const s = (l === 0 || l === 1) ? 0 : (max - min) / (1 - Math.abs(2 * l - 1));
544
+ return s.clamp(0, 1);
545
+ }
546
+ /**
547
+ * Preucil 'circle' algorithm.
548
+ * @param rgb
549
+ */
550
+ function hueCircle(rgb) {
551
+ const r = rgb.r, g = rgb.g, b = rgb.b;
552
+ const max = Math.max(r, g, b);
553
+ const min = Math.min(r, g, b);
554
+ let hue = 0;
555
+ if (max !== min) {
556
+ if (max === r) {
557
+ hue = (60 * ((g - b) / (max - min)) + 360) % 360;
558
+ }
559
+ else if (max === g) {
560
+ hue = (60 * ((b - r) / (max - min)) + 120) % 360;
561
+ }
562
+ else {
563
+ hue = (60 * ((r - g) / (max - min)) + 240) % 360;
564
+ }
565
+ }
566
+ return hue.clamp(0, 360);
567
+ }
568
+ function hexify(v) {
569
+ return v.toString(16).padStart(2, '0');
570
+ //return Pacem.Strings.leftPad(v.toString(16), 2, '0');
571
+ }
572
+ class Colors {
573
+ static { this.WCAG_MINIMUM_CONTRAST = 3.0; }
574
+ static { this.WCAG_NORMAL_TEXT_CONTRAST = 4.5; }
575
+ static { this.WCAG_SAFE_CONTRAST = 7.0; }
576
+ static _clampRGB(rgb) {
577
+ const clmp = (n) => Math.min(1.0, Math.max(0, n));
578
+ if (rgb[3] == null) {
579
+ rgb[3] = 1.0;
580
+ }
581
+ return { r: clmp(rgb[0]), g: clmp(rgb[1]), b: clmp(rgb[2]), a: Math.min(1, Math.max(0, rgb[3])) };
582
+ }
583
+ static _normalize(rgb) {
584
+ return [rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0, rgb[3]];
585
+ }
586
+ static parse(clr) {
587
+ clr = (clr || '').toLowerCase();
588
+ /* rgb(255,255,255) */
589
+ if (RGB_PATTERN.test(clr)) {
590
+ let rgbArr = RGB_PATTERN.exec(clr);
591
+ return this._clampRGB(this._normalize([parseInt(rgbArr[1]), parseInt(rgbArr[2]), parseInt(rgbArr[3]), 1]));
592
+ }
593
+ /* rgba(255,255,255,.5) */
594
+ if (RGBA_PATTERN.test(clr)) {
595
+ let rgbArr = RGBA_PATTERN.exec(clr);
596
+ return this._clampRGB(this._normalize([parseInt(rgbArr[1]), parseInt(rgbArr[2]), parseInt(rgbArr[3]), parseFloat(rgbArr[4])]));
597
+ }
598
+ /* #ffffff */
599
+ if (HEX_PATTERN.test(clr)) {
600
+ let hex = HEX_PATTERN.exec(clr)[0];
601
+ return this._clampRGB(this._normalize([parseInt('0x' + hex.substr(1, 2)), parseInt('0x' + hex.substr(3, 2)), parseInt('0x' + hex.substr(5, 2)), 1]));
602
+ }
603
+ /* #fff */
604
+ if (HEX_SHORT_PATTERN.test(clr)) {
605
+ let hex = HEX_SHORT_PATTERN.exec(clr)[0];
606
+ let r = hex.substr(1, 1), g = hex.substr(2, 1), b = hex.substr(3, 1);
607
+ return this._clampRGB(this._normalize([parseInt('0x' + r + r), parseInt('0x' + g + g), parseInt('0x' + b + b), 1]));
608
+ }
609
+ /* hsl(0,60%,100%) */
610
+ if (HSL_PATTERN.test(clr)) {
611
+ let hslArr = HSL_PATTERN.exec(clr);
612
+ const hsl = { h: parseFloat(hslArr[1]), s: parseFloat(hslArr[2]) * .01, l: parseFloat(hslArr[3]) * .01 };
613
+ return this.rgb(hsl);
614
+ }
615
+ /* hsla(0,40%,50%,.5) */
616
+ if (HSLA_PATTERN.test(clr)) {
617
+ let hslaArr = HSLA_PATTERN.exec(clr);
618
+ const hsla = { h: parseFloat(hslaArr[1]), s: parseFloat(hslaArr[2]) * .01, l: parseFloat(hslaArr[3]) * .01, a: parseFloat(hslaArr[4]) };
619
+ return this.rgb(hsla);
620
+ }
621
+ }
622
+ static hsl(rgb) {
623
+ const l = luminance(rgb), s = saturation(rgb, l), h = hueCircle(rgb);
624
+ return { h, s, l, a: rgb.a };
625
+ }
626
+ static cieXYZ(clr) {
627
+ if (isHsl(clr)) {
628
+ clr = this.rgb(clr);
629
+ }
630
+ return cieUtils.rgbToCieXYZ(clr);
631
+ }
632
+ static rgb(clr) {
633
+ if (isHsl(clr)) {
634
+ // hsl
635
+ const h = clr.h, s = clr.s, l = clr.l, h6 = h / 60.0;
636
+ const C = (1 - Math.abs(2 * l - 1)) * s;
637
+ const X = C * (1 - Math.abs(h6 % 2 - 1));
638
+ const m = l - C / 2;
639
+ const compose = (r, g, b) => this._clampRGB([r + m, g + m, b + m, clr.a]);
640
+ if (h6 <= 1) {
641
+ return compose(C, X, 0);
642
+ }
643
+ else if (h6 <= 2) {
644
+ return compose(X, C, 0);
645
+ }
646
+ else if (h6 <= 3) {
647
+ return compose(0, C, X);
648
+ }
649
+ else if (h6 <= 4) {
650
+ return compose(0, X, C);
651
+ }
652
+ else if (h6 <= 5) {
653
+ return compose(X, 0, C);
654
+ }
655
+ else if (h6 <= 6) {
656
+ return compose(C, 0, X);
657
+ }
658
+ }
659
+ else {
660
+ // cie XYZ
661
+ const rgb = cieUtils.cieXYZToRgb(clr);
662
+ return this._clampRGB([rgb.r, rgb.g, rgb.b, rgb.a]);
663
+ }
664
+ }
665
+ static stringify(clr, arg1 = 1) {
666
+ if (isHsl(clr)) {
667
+ arg1 ??= 1;
668
+ clr.a ??= 1;
669
+ const precision = typeof arg1 === 'number' ? arg1 : 1;
670
+ return `hsla(${clr.h.roundoff(precision)},${(clr.s * 100).roundoff(precision)}%,${(clr.l * 100).roundoff(precision)}%,${clr.a.roundoff()})`;
671
+ }
672
+ else if (isRgb(clr)) {
673
+ arg1 ??= true;
674
+ clr.a ??= 1;
675
+ const hex = typeof arg1 === 'boolean' ? arg1 : !!arg1, r = Math.round(clr.r * 255), g = Math.round(clr.g * 255), b = Math.round(clr.b * 255), a = clr.a.roundoff();
676
+ if (a === 1) {
677
+ if (hex) {
678
+ return ('#' + hexify(r) + hexify(g) + hexify(b)).toUpperCase();
679
+ }
680
+ return `rgb(${r},${g},${b})`;
681
+ }
682
+ return `rgba(${r},${g},${b},${a})`;
683
+ }
684
+ return undefined;
685
+ }
686
+ /**
687
+ * Contrast ratio betwen two colors (useful for accessibility assessments). Output range: 1 (no-contrast) to 21 (maximum contrast)
688
+ */
689
+ static contrastRatio(clr1, clr2) {
690
+ if (isHsl(clr1)) {
691
+ clr1 = this.rgb(clr1);
692
+ }
693
+ if (isHsl(clr2)) {
694
+ clr2 = this.rgb(clr2);
695
+ }
696
+ return cieUtils.contrastRatio(clr1, clr2);
697
+ }
698
+ /**
699
+ * Returns the relative luminance as of WCAG specs.
700
+ */
701
+ static luminance(clr) {
702
+ if (isHsl(clr)) {
703
+ clr = Colors.rgb(clr);
704
+ }
705
+ return cieUtils.relativeLuminance(clr);
706
+ }
707
+ static lighten(clr, amount = 0.1) {
708
+ amount ||= 0;
709
+ if (isHsl(clr)) {
710
+ const l = Math.min(1, Math.max(0, clr.l + amount));
711
+ return Object.assign({}, clr, { l });
712
+ }
713
+ if (isRgb(clr)) {
714
+ const hsl = this.lighten(this.hsl(clr), amount);
715
+ return this.rgb(hsl);
716
+ }
717
+ return clr;
718
+ }
719
+ static darken(clr, amount = 0.1) {
720
+ return this.lighten(clr, -amount);
721
+ }
722
+ static saturate(clr, amount = 0.1) {
723
+ amount ||= 0;
724
+ if (isHsl(clr)) {
725
+ const s = Math.min(1, Math.max(0, clr.s + amount));
726
+ return Object.assign({}, clr, { s });
727
+ }
728
+ if (isRgb(clr)) {
729
+ const hsl = this.saturate(this.hsl(clr), amount);
730
+ return this.rgb(hsl);
731
+ }
732
+ return clr;
733
+ }
734
+ static desaturate(clr, amount = 0.1) {
735
+ return this.saturate(clr, -amount);
736
+ }
737
+ static interpolate(clr1, clr2, weight1, weight2) {
738
+ weight1 ??= .5;
739
+ weight2 ??= weight1;
740
+ const weight = (weight1 + weight2).roundoff();
741
+ const ratio1 = (weight1 / weight).roundoff(), ratio2 = (weight2 / weight).roundoff();
742
+ const rgb = isRgb(clr1), hsl = isHsl(clr1);
743
+ const toCieXYZ = (c) => {
744
+ if (isRgb(c) || isHsl(c)) {
745
+ return Colors.cieXYZ(c);
746
+ }
747
+ return c;
748
+ };
749
+ clr1 = toCieXYZ(clr1);
750
+ clr2 = toCieXYZ(clr2);
751
+ const clr = {
752
+ x: (clr1.x * ratio1 + clr2.x * ratio2).roundoff(),
753
+ y: (clr1.y * ratio1 + clr2.y * ratio2).roundoff(),
754
+ z: (clr1.z * ratio1 + clr2.z * ratio2).roundoff(),
755
+ a: (clr1.a * ratio1 + clr2.a * ratio2).roundoff(),
756
+ };
757
+ if (rgb) {
758
+ return Colors.rgb(clr);
759
+ }
760
+ if (hsl) {
761
+ return Colors.hsl(Colors.rgb(clr));
762
+ }
763
+ return clr;
764
+ }
765
+ }
766
+ //}
767
+
768
+ // 1.7763568394002505e-15 -20.4551920341394 40 40
769
+ const FLOAT_PATTERN = /[-+]?([\d]+(\.[\d]+(e-[\d]+)?)?|[\d]*(\.[\d]+(e-[\d]+)?))/g;
770
+ function parseAsNumericalArray(input) {
771
+ const arr = [];
772
+ let reg = input.match(FLOAT_PATTERN);
773
+ if (reg && reg.length > 0) {
774
+ reg.forEach(i => arr.push(parseFloat(i)));
775
+ }
776
+ return arr;
777
+ }
778
+ class Angle {
779
+ static isAngle(obj) {
780
+ return typeof obj === 'object'
781
+ && 'vertex' in obj && Point.isPoint(obj['vertex'])
782
+ && 'start' in obj && Point.isPoint(obj['start'])
783
+ && 'end' in obj && Point.isPoint(obj['end']);
784
+ }
785
+ /**
786
+ * Returns the angle span in radians.
787
+ * Clockwise angles are positive, counterclockwise angles are negative.
788
+ */
789
+ static value(angle) {
790
+ if (NullChecker.isNullOrEmpty(angle) || !Angle.isAngle(angle)) {
791
+ return Number.NaN;
792
+ }
793
+ const { vertex, start, end } = angle;
794
+ return Angle.angleBetween(vertex, start, end);
795
+ }
796
+ /**
797
+ * Returns the angle (in radians) given the angle vertex and two points belonging to the rays that combine to build the angle sides.
798
+ * Clockwise angles are positive, counterclockwise angles are negative.
799
+ * @param vertex Angle vertex
800
+ * @param start Point belonging to the start side
801
+ * @param end Point belonging to the end side
802
+ * @returns Angle span in radians [-pi, pi]
803
+ */
804
+ static angleBetween(vertex, start, end) {
805
+ const v1 = { x: start.x - vertex.x, y: start.y - vertex.y }, v2 = { x: end.x - vertex.x, y: end.y - vertex.y };
806
+ const dot = v1.x * v2.x + v1.y * v2.y;
807
+ const cross = v1.x * v2.y - v1.y * v2.x;
808
+ // clockwise positive, ccw negative
809
+ return -Math.atan2(cross, dot);
810
+ }
811
+ }
812
+ class Size {
813
+ static parse(sz) {
814
+ let arr = parseAsNumericalArray(sz);
815
+ if (arr && arr.length === 2) {
816
+ return { width: arr[0], height: arr[1] };
817
+ }
818
+ throw new Error(`Cannot parse "${sz}" as a valid Size.`);
819
+ }
820
+ static isSize(obj) {
821
+ return typeof obj === 'object'
822
+ && 'width' in obj && typeof obj['width'] === 'number'
823
+ && 'height' in obj && typeof obj['height'] === 'number';
824
+ }
825
+ }
826
+ class Point {
827
+ static parse(pt) {
828
+ let arr = parseAsNumericalArray(pt);
829
+ if (arr && arr.length === 2) {
830
+ return { x: arr[0], y: arr[1] };
831
+ }
832
+ throw new Error(`Cannot parse "${pt}" as a valid Point.`);
833
+ }
834
+ static isPoint(obj) {
835
+ return typeof obj === 'object'
836
+ && 'x' in obj && typeof obj['x'] === 'number'
837
+ && 'y' in obj && typeof obj['y'] === 'number';
838
+ }
839
+ /**
840
+ * Computes the distance between two points.
841
+ * @param p1 Point 1
842
+ * @param p2 Point 2
843
+ */
844
+ static distance(p1, p2) {
845
+ return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
846
+ }
847
+ /**
848
+ * Subtracts a point p from another and returns the resulting vector.
849
+ * @param p Point to subtract
850
+ * @param from Point to be subtracted from
851
+ */
852
+ static subtract(p, from) {
853
+ return { x: from.x - p.x, y: from.y - p.y };
854
+ }
855
+ /**
856
+ * Adds a set of points together and returns the resulting vector.
857
+ * @param points Points to add
858
+ */
859
+ static add(...points) {
860
+ var point = { x: 0, y: 0 };
861
+ for (var p of points) {
862
+ point.x += p.x;
863
+ point.y += p.y;
864
+ }
865
+ return point;
866
+ }
867
+ /**
868
+ * Memberwise multiplication.
869
+ * @param p Original Point object
870
+ * @param f Factor
871
+ * @returns New Point object.
872
+ */
873
+ static multiply(p, f) {
874
+ return { x: p.x * f, y: p.y * f };
875
+ }
876
+ }
877
+ //}
878
+
879
+ /// <reference path="geom.ts" />
880
+ class Matrix2D {
881
+ static isIdentity(m) {
882
+ return m.a === 1 && m.d === 1 && m.b === 0 && m.f === 0 && m.c === 0 && m.e === 0;
883
+ }
884
+ static get identity() {
885
+ return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
886
+ }
887
+ static copy(m) {
888
+ return { a: m.a, b: m.b, c: m.c, d: m.d, e: m.e, f: m.f };
889
+ }
890
+ static scale(m, sx, sy = sx) {
891
+ return { a: m.a * sx, b: m.b, c: m.c, d: m.d * sy, e: m.e, f: m.f };
892
+ }
893
+ static translate(m, t) {
894
+ return { a: m.a, b: m.b, c: m.c, d: m.d, e: m.e + t.x, f: m.f + t.y };
895
+ }
896
+ static rotate(m, rad) {
897
+ const cos = Math.cos(rad), sin = Math.sin(rad);
898
+ return Matrix2D.multiply(m, { a: cos, b: sin, c: -sin, d: cos, e: 0, f: 0 });
899
+ }
900
+ static multiply(m1, m2) {
901
+ if ("x" in m1 && "y" in m1) {
902
+ if (typeof m2 === 'number') {
903
+ return { x: m1.x * m2, y: m1.y * m2 };
904
+ }
905
+ else {
906
+ return { x: m1.x * m2.a + m1.y * m2.c + m2.e, y: m1.x * m2.b + m1.y * m2.d + m2.f };
907
+ }
908
+ }
909
+ if (typeof m2 === 'number') {
910
+ return {
911
+ a: m1.a * m2, b: m1.b * m2, c: m1.c * m2, d: m1.d * m2, e: m1.e * m2, f: m1.f * m2
912
+ };
913
+ }
914
+ return {
915
+ a: m1.a * m2.a + m1.b * m2.c,
916
+ b: m1.a * m2.b + m1.b * m2.d,
917
+ c: m1.c * m2.a + m1.d * m2.c,
918
+ d: m1.c * m2.b + m1.d * m2.d,
919
+ e: m1.e * m2.a + m1.f * m2.c + m2.e,
920
+ f: m1.e * m2.b + m1.f * m2.d + m2.f
921
+ };
922
+ }
923
+ static det(m) {
924
+ return m.a * m.d - m.c * m.b;
925
+ }
926
+ static invert(m) {
927
+ const det = this.det(m);
928
+ if (det === 0) {
929
+ // NaM(2D) ?
930
+ return null;
931
+ }
932
+ const invdet = 1 / det;
933
+ /*
934
+ * 1. swap a, d
935
+ * 2. swap c, b and change signs
936
+ * 3. e := -e*d + f*c
937
+ * 4. f := e*b - f*a
938
+ * 5. divide everything by [det]
939
+ */
940
+ return this.multiply({
941
+ a: m.d,
942
+ b: -m.b,
943
+ c: -m.c,
944
+ d: m.a,
945
+ e: -m.e * m.d + m.c * m.f,
946
+ f: m.e * m.b - m.a * m.f
947
+ }, invdet);
948
+ }
949
+ static toComponents(m, transformOrigin = { x: 0, y: 0 }) {
950
+ const scaleX = Math.sqrt(m.a * m.a + m.c * m.c);
951
+ const scaleY = Math.sqrt(m.b * m.b + m.d * m.d);
952
+ const cos = scaleX != 0 ? m.a / scaleX : 0;
953
+ const sin = scaleX != 0 ? m.c / scaleX : 0;
954
+ const rotation = Math.atan2(sin, cos);
955
+ const { x: px, y: py } = transformOrigin;
956
+ const translation = {
957
+ x: m.e - px * (scaleX * cos - 1) + py * scaleX * sin,
958
+ y: m.f - py * (scaleY * cos - 1) - px * scaleY * sin,
959
+ };
960
+ return {
961
+ scaleX, scaleY, rotation,
962
+ translation
963
+ };
964
+ }
965
+ /**
966
+ * Returns the matrix that transforms the triangle defined by the points p0, p1, p2 into the triangle defined by the points q0, q1, q2.
967
+ * @param param0 Triangle defined by the points p0, p1, p2 (before transformation).
968
+ * @param param1 Triangle defined by the points q0, q1, q2 (after transformation).
969
+ * @returns Transformation matrix.
970
+ */
971
+ static fromTransform([p0, p1, p2], [q0, q1, q2]) {
972
+ const det = p0.x * (p1.y - p2.y) -
973
+ p0.y * (p1.x - p2.x) +
974
+ (p1.x * p2.y - p2.x * p1.y);
975
+ if (Math.abs(det) < 1e-10) {
976
+ throw new Error("Points are collinear; matrix is singular and cannot be solved.");
977
+ }
978
+ const idet = 1 / det;
979
+ // Matrix inversion of the 3x3 augmented source points
980
+ // then multiplied by the destination points to get rows 1 and 2
981
+ return {
982
+ a: idet * (q0.x * (p1.y - p2.y) + q1.x * (p2.y - p0.y) + q2.x * (p0.y - p1.y)),
983
+ b: idet * (q0.y * (p1.y - p2.y) + q1.y * (p2.y - p0.y) + q2.y * (p0.y - p1.y)),
984
+ c: idet * (q0.x * (p2.x - p1.x) + q1.x * (p0.x - p2.x) + q2.x * (p1.x - p0.x)),
985
+ d: idet * (q0.y * (p2.x - p1.x) + q1.y * (p0.x - p2.x) + q2.y * (p1.x - p0.x)),
986
+ e: idet * (q0.x * (p1.x * p2.y - p2.x * p1.y) +
987
+ q1.x * (p2.x * p0.y - p0.x * p2.y) +
988
+ q2.x * (p0.x * p1.y - p1.x * p0.y)),
989
+ f: idet * (q0.y * (p1.x * p2.y - p2.x * p1.y) +
990
+ q1.y * (p2.x * p0.y - p0.x * p2.y) +
991
+ q2.y * (p0.x * p1.y - p1.x * p0.y))
992
+ };
993
+ }
994
+ /**
995
+ * Returns whether two matrices are equal to each other, within a certain precision (number of decimal digits).
996
+ * @param m1
997
+ * @param m2
998
+ * @param precision
999
+ * @returns
1000
+ */
1001
+ static areClose(m1, m2, precision = 12) {
1002
+ return m1.a.isCloseTo(m2.a, precision)
1003
+ && m1.b.isCloseTo(m2.b, precision)
1004
+ && m1.c.isCloseTo(m2.c, precision)
1005
+ && m1.d.isCloseTo(m2.d, precision)
1006
+ && m1.e.isCloseTo(m2.e, precision)
1007
+ && m1.f.isCloseTo(m2.f, precision);
1008
+ }
1009
+ }
1010
+ // }
1011
+
1012
+ class Rect {
1013
+ static parse(rect) {
1014
+ let arr = parseAsNumericalArray(rect);
1015
+ if (arr && arr.length === 4) {
1016
+ return { x: arr[0], y: arr[1], width: arr[2], height: arr[3] };
1017
+ }
1018
+ throw new Error(`Cannot parse "${rect}" as a valid Rect.`);
1019
+ }
1020
+ static isRect(obj) {
1021
+ return Point.isPoint(obj) && Size.isSize(obj);
1022
+ }
1023
+ static _stretch(from, to) {
1024
+ return { a: to.width / from.width, b: 0, c: 0, d: to.height / from.height, e: to.x - from.x, f: to.y - from.y };
1025
+ }
1026
+ static _contain(from, to, align, valign) {
1027
+ let scale = 1;
1028
+ const fromRatio = from.width / from.height, toRatio = to.width / to.height;
1029
+ if (fromRatio >= toRatio) {
1030
+ // constraining width
1031
+ scale = to.width / from.width;
1032
+ }
1033
+ else {
1034
+ // constraining height
1035
+ scale = to.height / from.height;
1036
+ }
1037
+ const w = from.width * scale, h = from.height * scale;
1038
+ const translation = this._align({ x: from.x, y: from.y, width: w, height: h }, to, align, valign);
1039
+ return Matrix2D.translate({ a: scale, b: 0, c: 0, d: scale, e: 0, f: 0 }, translation);
1040
+ }
1041
+ static _cover(from, to, align, valign) {
1042
+ let scale = 1;
1043
+ const fromRatio = from.width / from.height, toRatio = to.width / to.height;
1044
+ if (fromRatio < toRatio) {
1045
+ // constraining width
1046
+ scale = to.width / from.width;
1047
+ }
1048
+ else {
1049
+ // constraining height
1050
+ scale = to.height / from.height;
1051
+ }
1052
+ const w = from.width * scale, h = from.height * scale;
1053
+ const translation = this._align({ x: from.x, y: from.y, width: w, height: h }, to, align, valign);
1054
+ return Matrix2D.translate({ a: scale, b: 0, c: 0, d: scale, e: 0, f: 0 }, translation);
1055
+ }
1056
+ static _align(from, to, align, valign) {
1057
+ let x = 0, y = 0;
1058
+ switch (align) {
1059
+ case 'left':
1060
+ x = to.x - from.x;
1061
+ break;
1062
+ case 'right':
1063
+ x = (to.x + to.width - from.width) - from.x;
1064
+ break;
1065
+ default:
1066
+ x = (to.x + to.width * .5 - from.width * .5) - from.x;
1067
+ break;
1068
+ }
1069
+ switch (valign) {
1070
+ case 'top':
1071
+ y = to.y - from.y;
1072
+ break;
1073
+ case 'bottom':
1074
+ y = (to.y + to.height - from.height) - from.y;
1075
+ break;
1076
+ default:
1077
+ y = (to.y + to.height * .5 - from.height * .5) - from.y;
1078
+ break;
1079
+ }
1080
+ return { x, y };
1081
+ }
1082
+ /**
1083
+ * Computes the 2D matrix that transforms one rect into another.
1084
+ * @param a Rect from
1085
+ * @param b Rect to
1086
+ * @param mode Transformation mode
1087
+ * @param align Horizontal alignment
1088
+ * @param valign Vertical alignment
1089
+ */
1090
+ static findTransform(a, b, mode = 'stretch', align = 'center', valign = 'middle') {
1091
+ switch (mode) {
1092
+ case 'contain':
1093
+ return this._contain(a, b, align, valign);
1094
+ case 'cover':
1095
+ return this._cover(a, b, align, valign);
1096
+ default:
1097
+ return this._stretch(a, b);
1098
+ }
1099
+ }
1100
+ /**
1101
+ * Computes the intersection rect among a set of provided rects.
1102
+ * @param rects Rects to intersect
1103
+ */
1104
+ static intersect(...rects) {
1105
+ const empty = { x: 0, y: 0, height: 0, width: 0 }, arr = Array.from(rects || []);
1106
+ if (arr.length <= 0) {
1107
+ return empty;
1108
+ }
1109
+ var rect = arr[0];
1110
+ for (var i = 1; i < arr.length; i++) {
1111
+ const r = arr[i];
1112
+ const x = Math.max(r.x, rect.x), y = Math.max(r.y, rect.y), xw = Math.min(r.x + r.width, rect.x + rect.width), xh = Math.min(r.y + r.height, rect.y + rect.height), w = xw - x, h = xh - y;
1113
+ if (w < 0 || h <= 0) {
1114
+ // no intersection
1115
+ return empty;
1116
+ }
1117
+ rect = { x: x, y: y, width: w, height: h };
1118
+ }
1119
+ return rect;
1120
+ }
1121
+ static expand(rect, ...args) {
1122
+ const arr = Array.from(args || []);
1123
+ let x0 = rect.x, y0 = rect.y, x1 = x0, y1 = y0;
1124
+ if (Rect.isRect(rect)) {
1125
+ x1 += rect.width;
1126
+ y1 += rect.height;
1127
+ }
1128
+ for (let p of arr) {
1129
+ x0 = Math.min(p.x, x0);
1130
+ y0 = Math.min(p.y, y0);
1131
+ x1 = Math.max(p.x, x1);
1132
+ y1 = Math.max(p.y, y1);
1133
+ }
1134
+ return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
1135
+ }
1136
+ }
1137
+ //}
1138
+
1139
+ // namespace Pacem {
1140
+ /** Grants undo/redo functionalities for given state. */
1141
+ class HistoryService {
1142
+ constructor(state, maxlength) {
1143
+ this.#current = state;
1144
+ this.#maxlength = maxlength;
1145
+ }
1146
+ // it's a queue
1147
+ #backwards = [];
1148
+ // it's a stack
1149
+ #forwards = [];
1150
+ // max number of items (queue + stack)
1151
+ #maxlength;
1152
+ #current;
1153
+ /**
1154
+ * Gets the current state.
1155
+ */
1156
+ get current() {
1157
+ return this.#current;
1158
+ }
1159
+ get canUndo() {
1160
+ return this.#backwards.length > 0;
1161
+ }
1162
+ get canRedo() {
1163
+ return this.#forwards.length > 0;
1164
+ }
1165
+ /** Sets the maximum number of stored states, queue + stack.
1166
+ */
1167
+ set maxlength(v) {
1168
+ this.#maxlength = v;
1169
+ }
1170
+ undo() {
1171
+ if (this.canUndo) {
1172
+ const back = this.#backwards, fore = this.#forwards, current = this.#current;
1173
+ fore.unshift(current);
1174
+ this.#current = back.pop();
1175
+ }
1176
+ }
1177
+ redo() {
1178
+ if (this.canRedo) {
1179
+ const back = this.#backwards, fore = this.#forwards, current = this.#current;
1180
+ back.push(current);
1181
+ this.#current = fore.shift();
1182
+ }
1183
+ }
1184
+ push(state) {
1185
+ this.#forwards.splice(0);
1186
+ this.#backwards.push(this.#current);
1187
+ this.#current = state;
1188
+ const max = this.#maxlength, queue = this.#backwards;
1189
+ if (max > 0 && queue.length > max) {
1190
+ queue.splice(0, queue.length - max);
1191
+ }
1192
+ }
1193
+ reset() {
1194
+ this.#forwards.splice(0);
1195
+ this.#backwards.splice(0);
1196
+ }
1197
+ }
1198
+ // }
1199
+
1200
+ // namespace Pacem {
1201
+ const DefaultImagingResizeOptions = {
1202
+ mode: 'stretch',
1203
+ align: 'center',
1204
+ valign: 'middle',
1205
+ quality: 1,
1206
+ type: 'image/jpeg'
1207
+ };
1208
+ class Imaging {
1209
+ static async loadImage(url) {
1210
+ const response = await fetch(url);
1211
+ if (!response.ok) {
1212
+ return null;
1213
+ }
1214
+ const blob = await response.blob();
1215
+ return blob;
1216
+ }
1217
+ static async resizeImage(img, width, height, options) {
1218
+ if (width <= 0 || height <= 0 || isNaN(width) || isNaN(height)) {
1219
+ throw new Error('Invalid target size');
1220
+ }
1221
+ if (typeof img === 'string') {
1222
+ img = await Imaging.loadImage(img);
1223
+ }
1224
+ const el = await self.createImageBitmap(img);
1225
+ const origWidth = el.width, origHeight = el.height;
1226
+ const cnv = new OffscreenCanvas(origWidth, origHeight);
1227
+ const ctx = cnv.getContext('2d');
1228
+ ctx.imageSmoothingEnabled =
1229
+ ctx['mozImageSmoothingEnabled'] =
1230
+ ctx['oImageSmoothingEnabled'] =
1231
+ ctx['webkitImageSmoothingEnabled'] =
1232
+ true;
1233
+ const { quality, type, mode, align, valign, background } = Object.assign({}, DefaultImagingResizeOptions, options ?? {});
1234
+ const from = { width: origWidth, height: origHeight, x: 0, y: 0 }, to = { x: 0, y: 0, width, height };
1235
+ const transformMatrix = Rect.findTransform(from, to, mode, align, valign);
1236
+ cnv.width = width;
1237
+ cnv.height = height;
1238
+ if (background) {
1239
+ ctx.fillStyle = background;
1240
+ ctx.fillRect(0, 0, cnv.width, cnv.height);
1241
+ }
1242
+ ctx.setTransform(transformMatrix);
1243
+ ctx.drawImage(el, 0, 0);
1244
+ const retval = await cnv.convertToBlob({ quality, type });
1245
+ return retval;
1246
+ }
1247
+ }
1248
+ // }
1249
+
1250
+ // namespace Pacem {
1251
+ class Keys {
1252
+ static #seed;
1253
+ static uniqueId() {
1254
+ let seed = Keys.#seed || Date.now();
1255
+ return Keys.#seed = ++seed;
1256
+ }
1257
+ static uniqueCode() {
1258
+ const newid = Keys.uniqueId();
1259
+ return newid.toBase62();
1260
+ }
1261
+ static randomString(length) {
1262
+ let retval = '';
1263
+ do {
1264
+ retval += (Math.random() * 62).toBase62();
1265
+ } while (retval.length < length);
1266
+ return retval;
1267
+ }
1268
+ }
1269
+ // }
1270
+
1271
+ // namespace Pacem {
1272
+ class Numbers {
1273
+ static round(x, step = 1.0) {
1274
+ return Math.round(x / step) * step;
1275
+ }
1276
+ static log(x, base) {
1277
+ return Math.log10(x) / Math.log10(base);
1278
+ }
1279
+ static rebase(v, from, to) {
1280
+ const vStr = v.toString();
1281
+ const firstPass = parseInt(vStr, from);
1282
+ if (!vStr.endsWith(firstPass.toString(from))) {
1283
+ return Number.NaN.toString();
1284
+ }
1285
+ return parseInt(v.toString(), from).toString(to);
1286
+ }
1287
+ }
1288
+ //}
1289
+
1290
+ // namespace Pacem {
1291
+ /**
1292
+ * Computes the Longest Common Subsequence (LCS) table for two arrays of strings.
1293
+ * @param aTokens Array of strings from the first input.
1294
+ * @param bTokens Array of strings from the second input.
1295
+ * @returns The DP table for LCS lengths.
1296
+ */
1297
+ function lcs(aTokens, bTokens) {
1298
+ const m = aTokens.length;
1299
+ const n = bTokens.length;
1300
+ // Initialize DP table with zeros
1301
+ const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
1302
+ // Fill DP table
1303
+ for (let i = 1; i <= m; i++) {
1304
+ for (let j = 1; j <= n; j++) {
1305
+ if (aTokens[i - 1] === bTokens[j - 1]) {
1306
+ // Tokens match, increment LCS length
1307
+ dp[i][j] = dp[i - 1][j - 1] + 1;
1308
+ }
1309
+ else {
1310
+ // Tokens don't match, take max length from previous states
1311
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
1312
+ }
1313
+ }
1314
+ }
1315
+ return dp;
1316
+ }
1317
+ /**
1318
+ * Internal diff implementation using backtracking on the LCS DP table.
1319
+ * Works on token arrays (characters, words, lines).
1320
+ * @param aTokens Array of strings from the first input.
1321
+ * @param bTokens Array of strings from the second input.
1322
+ * @param dp The precomputed LCS DP table.
1323
+ * @param joiner The string to use when joining tokens of the same type (e.g., "" for chars, "\n" for lines).
1324
+ * For word diffing, joiner is effectively "" because whitespace is part of the tokens.
1325
+ * @returns An array of DiffTokens representing the differences.
1326
+ */
1327
+ function diffInternal(aTokens, bTokens, dp, joiner = '') {
1328
+ const m = aTokens.length;
1329
+ const n = bTokens.length;
1330
+ const result = [];
1331
+ let i = m, j = n;
1332
+ let currentToken = null;
1333
+ const finalizeToken = () => {
1334
+ if (currentToken) {
1335
+ result.push(currentToken);
1336
+ currentToken = null;
1337
+ }
1338
+ };
1339
+ // Backtrack through the DP table
1340
+ while (i > 0 || j > 0) { // Continue until both sequences are fully processed
1341
+ var currentType = null;
1342
+ let currentValue = null;
1343
+ if (i > 0 && j > 0 && aTokens[i - 1] === bTokens[j - 1]) {
1344
+ // Common token
1345
+ currentType = '=';
1346
+ currentValue = aTokens[i - 1];
1347
+ i--;
1348
+ j--;
1349
+ }
1350
+ else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
1351
+ // Token added in b
1352
+ currentType = '+';
1353
+ currentValue = bTokens[j - 1];
1354
+ j--;
1355
+ }
1356
+ else if (i > 0 && (j === 0 || dp[i - 1][j] > dp[i][j - 1])) {
1357
+ // Token removed from a
1358
+ currentType = '-';
1359
+ currentValue = aTokens[i - 1];
1360
+ i--;
1361
+ }
1362
+ if (currentType && currentValue !== null) {
1363
+ if (currentToken && currentToken.type === currentType) {
1364
+ // Prepend the value to the existing token
1365
+ currentToken.value = currentValue + (currentToken.value ? joiner : '') + currentToken.value;
1366
+ }
1367
+ else {
1368
+ // Finalize the previous token (if different type) and start a new one
1369
+ finalizeToken();
1370
+ currentToken = { type: currentType, value: currentValue };
1371
+ }
1372
+ }
1373
+ else {
1374
+ // Should not happen in standard LCS backtracking, but finalize just in case
1375
+ finalizeToken();
1376
+ }
1377
+ }
1378
+ finalizeToken(); // Add the last accumulated token
1379
+ return result.reverse(); // Reverse to get the correct order
1380
+ }
1381
+ /**
1382
+ * Performs character-level diffing.
1383
+ * @param a The first string.
1384
+ * @param b The second string.
1385
+ * @returns An array of DiffTokens.
1386
+ */
1387
+ function diffChars(a, b) {
1388
+ const aTokens = a.split(''); // Split into characters
1389
+ const bTokens = b.split(''); // Split into characters
1390
+ const dp = lcs(aTokens, bTokens);
1391
+ // No joiner needed as characters are concatenated directly
1392
+ return diffInternal(aTokens, bTokens, dp, '');
1393
+ }
1394
+ /**
1395
+ * Performs word-level diffing, preserving whitespace and line breaks.
1396
+ * It tokenizes based on sequences of non-whitespace (\S+) or whitespace (\s+).
1397
+ * @param a The first string.
1398
+ * @param b The second string.
1399
+ * @returns An array of DiffTokens.
1400
+ */
1401
+ function diffWords(a, b) {
1402
+ // Tokenize into words (\S+) and whitespace/newlines (\s+)
1403
+ // This preserves the original spacing and line breaks.
1404
+ const wordRegex = /(\S+|\s+)/g;
1405
+ const aTokens = a.match(wordRegex) || [];
1406
+ const bTokens = b.match(wordRegex) || [];
1407
+ const dp = lcs(aTokens, bTokens);
1408
+ // No joiner needed; whitespace tokens handle spacing.
1409
+ return diffInternal(aTokens, bTokens, dp, '');
1410
+ }
1411
+ /**
1412
+ * Performs line-level diffing.
1413
+ * @param a The first string.
1414
+ * @param b The second string.
1415
+ * @returns An array of DiffTokens where each token's value can contain multiple lines.
1416
+ */
1417
+ function diffLines(a, b) {
1418
+ // Split by newline characters, keeping the EOL character concept separate
1419
+ // The result of split does not contain the separators themselves.
1420
+ const lineRegex = /\r?\n/;
1421
+ const aTokens = a.split(lineRegex);
1422
+ const bTokens = b.split(lineRegex);
1423
+ // Handle potential empty string added by split if text ends with a newline
1424
+ // (This behavior is often desired, representing an empty line after the last newline)
1425
+ // Example: "a\nb\n".split(/\n/) -> ["a", "b", ""]
1426
+ const dp = lcs(aTokens, bTokens);
1427
+ // Join consecutive lines of the same type with newline characters
1428
+ return diffInternal(aTokens, bTokens, dp, '\n');
1429
+ }
1430
+ //#endregion
1431
+ class Strings {
1432
+ /** @deprecated Use String.prototype.padStart() instead. */
1433
+ static leftPad(v, targetLength, padChar) {
1434
+ let retval = v.toString();
1435
+ return retval.padStart(targetLength, padChar);
1436
+ //while (retval.length < targetLength)
1437
+ // retval = padChar + retval;
1438
+ //return retval;
1439
+ }
1440
+ static format(template, ...args) {
1441
+ const array = Array.from(args);
1442
+ let retval = template;
1443
+ for (let j = 0; j < array.length; j++) {
1444
+ const regex = new RegExp('(^|[^\\{])\\{' + j + '\\}($|[^\\}])', 'g');
1445
+ retval = retval.replaceAll(regex, (match, ...args0) => {
1446
+ return match.replace('{' + j + '}', array[j]);
1447
+ });
1448
+ }
1449
+ const check = /(^|[^\{}])\{(\d+)\}($|[^\}])/.exec(retval);
1450
+ if (!NullChecker.isNullOrEmpty(check)) {
1451
+ throw new Error(`Missing argument at index ${check[2]}.`);
1452
+ }
1453
+ return retval;
1454
+ }
1455
+ static diff(a, b, mode = 'char') {
1456
+ switch (mode) {
1457
+ case 'line':
1458
+ return diffLines(a, b);
1459
+ case 'word':
1460
+ return diffWords(a, b);
1461
+ default:
1462
+ return diffChars(a, b);
1463
+ }
1464
+ }
1465
+ static async hash(input, algo = 'SHA-256') {
1466
+ const hashBuffer = await crypto.subtle.digest(algo, new TextEncoder().encode(input));
1467
+ return Array.from(new Uint8Array(hashBuffer))
1468
+ .map(byte => byte.toString(16).padStart(2, '0'))
1469
+ .join('');
1470
+ }
1471
+ }
1472
+ // }
1473
+
1474
+ //namespace Pacem.Compile {
1475
+ class LexerClass {
1476
+ tokenize(input, grammar) {
1477
+ const tokens = [];
1478
+ while (input) {
1479
+ const start = input.length;
1480
+ for (let rule of grammar) {
1481
+ const newTokens = rule.exec(input, /* arguments that ease recursion when needed */ this), length = newTokens?.length;
1482
+ if (length > 0) {
1483
+ Array.prototype.push.apply(tokens, newTokens);
1484
+ const last = newTokens[length - 1];
1485
+ input = input.substr((last.index || 0) + last.raw.length);
1486
+ break;
1487
+ }
1488
+ }
1489
+ if (input.length >= start) {
1490
+ // break infinite loop
1491
+ throw new Error(`Cannot parse\n"${input}"\n using the provided grammar.`);
1492
+ }
1493
+ }
1494
+ return tokens;
1495
+ }
1496
+ }
1497
+ let Parser$1 = class Parser {
1498
+ constructor(_lexer = new LexerClass()) {
1499
+ this._lexer = _lexer;
1500
+ }
1501
+ parse(input, grammar, renderer) {
1502
+ const tokens = this._lexer.tokenize(input, grammar);
1503
+ return renderer.render(tokens);
1504
+ }
1505
+ };
1506
+ //}
1507
+
1508
+ //namespace Pacem.Compile.Markdown {
1509
+ // #region HELPERS
1510
+ function htmlEncode(input) {
1511
+ return (input ?? '').replace(/</g, '&lt;');
1512
+ }
1513
+ function extractReference(input) {
1514
+ if (NullChecker.isNullOrEmpty(input)) {
1515
+ return void 0;
1516
+ }
1517
+ if (/^\(/.test(input) && /\)$/.test(input)) {
1518
+ return void 0;
1519
+ }
1520
+ if (/^\[/.test(input) && /\]$/.test(input)) {
1521
+ input = input.substr(1, input.length - 2);
1522
+ }
1523
+ return input;
1524
+ }
1525
+ function regexMatchIndex(arr) {
1526
+ return arr?.index || void 0;
1527
+ }
1528
+ function extractUrl(input) {
1529
+ if (NullChecker.isNullOrEmpty(input)) {
1530
+ return void 0;
1531
+ }
1532
+ if (/^\[/.test(input) && /\]$/.test(input)) {
1533
+ return void 0;
1534
+ }
1535
+ if (/^\(/.test(input) && /\)$/.test(input)) {
1536
+ input = input.substr(1, input.length - 2);
1537
+ }
1538
+ return input;
1539
+ }
1540
+ function normalizeReference(input) {
1541
+ return input?.replace(/[^\w]+/g, ' ').trim().replace(/ +/g, '-').toLowerCase();
1542
+ }
1543
+ function match(input, pattern, fn) {
1544
+ const arr = pattern.exec(input);
1545
+ if (arr && arr.length) {
1546
+ return fn(arr);
1547
+ }
1548
+ return null;
1549
+ }
1550
+ // #endregion
1551
+ const COMMENT = /(<!--)([\s\S]*?)(-->|$)/;
1552
+ const HR = /^ {0,3}(={3,}|_{3,}|-{3,})(\r?\n|$)/;
1553
+ const HEADING = /^ {0,3}(#{1,6})\s+([^\n]+)(\r?\n|$)+/;
1554
+ const HEADING1 = /^ {0,3}([^\n]+)(\r?\n=+(\r?\n|$))+/;
1555
+ const HEADING2 = /^ {0,3}([^\n]+)(\r?\n-+(\r?\n|$))+/;
1556
+ const CODEBLOCK = /^ {4,}.+(\r?\n {4,}.+)*(\r?\n|$)+/;
1557
+ const FENCES = /^ {0,3}``` *([^\n]*)\r?\n(([\s\S](?!\r?\n {0,3}```))*.(\r?\n)+) {0,3}```(\r?\n|$)+/;
1558
+ const BLOCKQUOTE = /^ {0,3}> *([^\n]+)(\r?\n {0,3}> *([^\n]*))*(\r?\n|$)+/;
1559
+ const ULIST = /^( {0,3}([-+]).*\r?\n|$)((?!(?: {0,3}(?:\d+[.\)]|\r?\n\S))).*(\r?\n|$))*/;
1560
+ const OLIST = /^( {0,3}(\d+[.\)]).*\r?\n|$)((?!(?: {0,3}(?:[+-]|\r?\n\S))).*(\r?\n|$))*/;
1561
+ const LISTITEM = /^(?:[-+*]|\d+[.\)])/m;
1562
+ const PARAGRAPH = /^(?! {4,})(.+(\n(?! {0,3}```)(?! {0,3}([-+]|\d+[.\)]))(?! {4,})(?! {0,3}>).+)*)/;
1563
+ const REF = /^ {0,3}(!?)\[([^\]]+)\]: +(\S+)(?: +['"\(](.+)['"\)])?(\r?\n|$)+/;
1564
+ const IMAGE_OR_LINK = /!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?(\[[^\[\]]*\]|\([^\(\)]*\))?/;
1565
+ const EMPHASIZED_LINK = /(\*\*?|__?)(\[[^\]]*]\([^\)]+\))\1/;
1566
+ const CODE = /(?:(?<!\\)`)(.+?)(?:(?<!\\)`)/;
1567
+ const EMPHASIZE = /(\*\*?|__?)((?!\1\s?)(?:(?!\1)[\S\s])*[^\s])\1/;
1568
+ const STRIKE = /(~~?|__?)(?!\1\s?)([^\s][\s\S]*?(?!\1)[^\s])\1/;
1569
+ const QUOTE = /(:")(?!":\s?)([^\s][\s\S]*?(?!":)[^\s])":/;
1570
+ const SPACE = /^\s+/;
1571
+ const LINEBREAK = / {2,}\r?\n/;
1572
+ const TEXT = /^[^\r\n]+/;
1573
+ var MARKDOWN_TYPES;
1574
+ (function (MARKDOWN_TYPES) {
1575
+ MARKDOWN_TYPES["Html"] = "html";
1576
+ MARKDOWN_TYPES["Text"] = "text";
1577
+ MARKDOWN_TYPES["Paragraph"] = "paragraph";
1578
+ MARKDOWN_TYPES["BlockQuote"] = "blockquote";
1579
+ MARKDOWN_TYPES["Space"] = "space";
1580
+ MARKDOWN_TYPES["Heading"] = "heading";
1581
+ MARKDOWN_TYPES["Bold"] = "bold";
1582
+ MARKDOWN_TYPES["Italic"] = "italic";
1583
+ MARKDOWN_TYPES["CodeBlock"] = "codeblock";
1584
+ MARKDOWN_TYPES["Code"] = "code";
1585
+ MARKDOWN_TYPES["Image"] = "img";
1586
+ MARKDOWN_TYPES["ImageLike"] = "imglike";
1587
+ MARKDOWN_TYPES["Link"] = "link";
1588
+ MARKDOWN_TYPES["LinkLike"] = "linklike";
1589
+ MARKDOWN_TYPES["LineBreak"] = "br";
1590
+ MARKDOWN_TYPES["StrikeThrough"] = "strike";
1591
+ MARKDOWN_TYPES["Quote"] = "quote";
1592
+ MARKDOWN_TYPES["HorizontalRule"] = "hr";
1593
+ MARKDOWN_TYPES["OrderedList"] = "ol";
1594
+ MARKDOWN_TYPES["UnorderedList"] = "ul";
1595
+ MARKDOWN_TYPES["ListItem"] = "listitem";
1596
+ MARKDOWN_TYPES["Reference"] = "ref";
1597
+ })(MARKDOWN_TYPES || (MARKDOWN_TYPES = {}));
1598
+ var MARKDOWN_RULES;
1599
+ (function (MARKDOWN_RULES) {
1600
+ MARKDOWN_RULES[MARKDOWN_RULES["Comment"] = 0] = "Comment";
1601
+ MARKDOWN_RULES[MARKDOWN_RULES["Reference"] = 1] = "Reference";
1602
+ MARKDOWN_RULES[MARKDOWN_RULES["HorizontalRule"] = 2] = "HorizontalRule";
1603
+ MARKDOWN_RULES[MARKDOWN_RULES["Heading"] = 3] = "Heading";
1604
+ MARKDOWN_RULES[MARKDOWN_RULES["Heading1"] = 4] = "Heading1";
1605
+ MARKDOWN_RULES[MARKDOWN_RULES["Heading2"] = 5] = "Heading2";
1606
+ MARKDOWN_RULES[MARKDOWN_RULES["CodeBlock"] = 6] = "CodeBlock";
1607
+ MARKDOWN_RULES[MARKDOWN_RULES["Fences"] = 7] = "Fences";
1608
+ MARKDOWN_RULES[MARKDOWN_RULES["BlockQuote"] = 8] = "BlockQuote";
1609
+ MARKDOWN_RULES[MARKDOWN_RULES["OrderedList"] = 9] = "OrderedList";
1610
+ MARKDOWN_RULES[MARKDOWN_RULES["UnorderedList"] = 10] = "UnorderedList";
1611
+ MARKDOWN_RULES[MARKDOWN_RULES["Paragraph"] = 11] = "Paragraph";
1612
+ MARKDOWN_RULES[MARKDOWN_RULES["EmphasizedLink"] = 12] = "EmphasizedLink";
1613
+ MARKDOWN_RULES[MARKDOWN_RULES["ImageOrLink"] = 13] = "ImageOrLink";
1614
+ MARKDOWN_RULES[MARKDOWN_RULES["Emphasize"] = 14] = "Emphasize";
1615
+ MARKDOWN_RULES[MARKDOWN_RULES["StrikeThrough"] = 15] = "StrikeThrough";
1616
+ MARKDOWN_RULES[MARKDOWN_RULES["Quote"] = 16] = "Quote";
1617
+ MARKDOWN_RULES[MARKDOWN_RULES["Code"] = 17] = "Code";
1618
+ MARKDOWN_RULES[MARKDOWN_RULES["LineBreak"] = 18] = "LineBreak";
1619
+ // lowest priority
1620
+ MARKDOWN_RULES[MARKDOWN_RULES["Text"] = 254] = "Text";
1621
+ MARKDOWN_RULES[MARKDOWN_RULES["Space"] = 255] = "Space";
1622
+ })(MARKDOWN_RULES || (MARKDOWN_RULES = {}));
1623
+ function getGrammar(extra = []) {
1624
+ const inert = {
1625
+ // comment
1626
+ [MARKDOWN_RULES.Comment]: {
1627
+ exec: (input, lexer) => match(input, COMMENT, arr => {
1628
+ const index = regexMatchIndex(arr);
1629
+ const output = [{
1630
+ type: MARKDOWN_TYPES.Html, index, raw: arr[0], text: arr[2]
1631
+ }];
1632
+ if (index > 0) {
1633
+ const left = input.substr(0, index), tokens = lexer.tokenize(left, blockRules);
1634
+ Array.prototype.unshift.apply(output, tokens);
1635
+ }
1636
+ return output;
1637
+ })
1638
+ },
1639
+ // reference
1640
+ [MARKDOWN_RULES.Reference]: {
1641
+ exec: (input) => match(input, REF, arr => {
1642
+ const index = regexMatchIndex(arr), raw = arr[0], text = raw, image = arr[1] === '!', id = arr[2], url = arr[3], title = arr[4];
1643
+ return [{
1644
+ type: MARKDOWN_TYPES.Reference, index, raw, text, id, image, url, title
1645
+ }];
1646
+ })
1647
+ },
1648
+ };
1649
+ const blockExtra = [], inlineExtra = [], codeExtra = {};
1650
+ for (let r of extra) {
1651
+ let rule, type = 'inline';
1652
+ if ('type' in r) {
1653
+ type = r.type;
1654
+ rule = r.rule;
1655
+ }
1656
+ else {
1657
+ rule = r;
1658
+ }
1659
+ switch (type) {
1660
+ case 'block':
1661
+ blockExtra.push(rule);
1662
+ break;
1663
+ case 'code':
1664
+ if ('lang' in r) {
1665
+ const key = r.lang.toLowerCase();
1666
+ (codeExtra[key] = codeExtra[key] || []).push(rule);
1667
+ }
1668
+ break;
1669
+ default:
1670
+ const inlineRule = {
1671
+ exec: (input, lexer) => {
1672
+ const output = rule.exec(input, lexer);
1673
+ inPlaceInlineExec(input, output, lexer);
1674
+ return output;
1675
+ }
1676
+ };
1677
+ inlineExtra.push(inlineRule);
1678
+ break;
1679
+ }
1680
+ }
1681
+ // #region INLINE
1682
+ const inlinelowpriority = {
1683
+ // text
1684
+ [MARKDOWN_RULES.Text]: {
1685
+ exec: (input) => match(input, TEXT, arr => {
1686
+ const raw = arr[0], text = raw;
1687
+ return [{
1688
+ index: regexMatchIndex(arr), raw, text, type: MARKDOWN_TYPES.Text
1689
+ }];
1690
+ })
1691
+ },
1692
+ // sparse lines
1693
+ [MARKDOWN_RULES.Space]: {
1694
+ exec: (input) => match(input, SPACE, arr => {
1695
+ const raw = arr[0];
1696
+ return [{
1697
+ type: MARKDOWN_TYPES.Space, raw, text: raw
1698
+ }];
1699
+ })
1700
+ }
1701
+ };
1702
+ const inline = {
1703
+ // link/image
1704
+ [MARKDOWN_RULES.ImageOrLink]: {
1705
+ exec: (input, lexer) => inlineMatch(input, IMAGE_OR_LINK, lexer, arr => {
1706
+ const index = regexMatchIndex(arr), raw = arr[0], image = raw.charAt(0) === '!', text = arr[1], url = extractUrl(arr[2]), ref = normalizeReference(extractReference(arr[2]) ?? text);
1707
+ if (image) {
1708
+ return [{
1709
+ index, type: url ? MARKDOWN_TYPES.Image : MARKDOWN_TYPES.ImageLike,
1710
+ raw, text, src: url, ref,
1711
+ tokens: lexer.tokenize(text, inlineRules)
1712
+ }];
1713
+ }
1714
+ else {
1715
+ return [{
1716
+ index, type: url ? MARKDOWN_TYPES.Link : MARKDOWN_TYPES.LinkLike,
1717
+ raw, text, href: url, ref,
1718
+ tokens: lexer.tokenize(text, inlineRules)
1719
+ }];
1720
+ }
1721
+ })
1722
+ },
1723
+ // code
1724
+ [MARKDOWN_RULES.Code]: {
1725
+ exec: (input, lexer) => inlineMatch(input, CODE, lexer, arr => {
1726
+ const text = htmlEncode(arr[1]);
1727
+ return [{
1728
+ type: MARKDOWN_TYPES.Code, raw: arr[0], text, index: regexMatchIndex(arr)
1729
+ }];
1730
+ })
1731
+ },
1732
+ // italic/bold link
1733
+ [MARKDOWN_RULES.EmphasizedLink]: {
1734
+ exec: (input, lexer) => inlineMatch(input, EMPHASIZED_LINK, lexer, arr => {
1735
+ if (arr.length < 3 || NullChecker.isNullOrEmpty(arr[2])) {
1736
+ return null;
1737
+ }
1738
+ const type = arr[1].length > 1 ? MARKDOWN_TYPES.Bold : MARKDOWN_TYPES.Italic, text = arr[2];
1739
+ return [{
1740
+ index: regexMatchIndex(arr),
1741
+ type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
1742
+ }];
1743
+ })
1744
+ },
1745
+ // italic/bold
1746
+ [MARKDOWN_RULES.Emphasize]: {
1747
+ exec: (input, lexer) => inlineMatch(input, EMPHASIZE, lexer, arr => {
1748
+ if (arr.length < 3 || NullChecker.isNullOrEmpty(arr[2])) {
1749
+ return null;
1750
+ }
1751
+ const type = arr[1].length > 1 ? MARKDOWN_TYPES.Bold : MARKDOWN_TYPES.Italic, text = arr[2];
1752
+ return [{
1753
+ index: regexMatchIndex(arr),
1754
+ type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
1755
+ }];
1756
+ })
1757
+ },
1758
+ // strike
1759
+ [MARKDOWN_RULES.StrikeThrough]: {
1760
+ exec: (input, lexer) => inlineMatch(input, STRIKE, lexer, arr => {
1761
+ if (arr.length < 3 || NullChecker.isNullOrEmpty(arr[2])) {
1762
+ return null;
1763
+ }
1764
+ const type = MARKDOWN_TYPES.StrikeThrough, text = arr[2];
1765
+ return [{
1766
+ index: regexMatchIndex(arr),
1767
+ type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
1768
+ }];
1769
+ })
1770
+ },
1771
+ // quote
1772
+ [MARKDOWN_RULES.Quote]: {
1773
+ exec: (input, lexer) => inlineMatch(input, QUOTE, lexer, arr => {
1774
+ if (arr.length < 3 || NullChecker.isNullOrEmpty(arr[2])) {
1775
+ return null;
1776
+ }
1777
+ const type = MARKDOWN_TYPES.Quote, text = arr[2];
1778
+ return [{
1779
+ index: regexMatchIndex(arr),
1780
+ type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
1781
+ }];
1782
+ })
1783
+ },
1784
+ // line break
1785
+ [MARKDOWN_RULES.LineBreak]: {
1786
+ exec: (input, lexer) => inlineMatch(input, LINEBREAK, lexer, arr => {
1787
+ const raw = arr[0], text = raw;
1788
+ return [{
1789
+ index: regexMatchIndex(arr), raw, text, type: MARKDOWN_TYPES.LineBreak
1790
+ }];
1791
+ })
1792
+ },
1793
+ };
1794
+ const inPlaceInlineExec = (input, output, lexer) => {
1795
+ const index = output?.length > 0 && output[0].index;
1796
+ if (index > 0) {
1797
+ const left = input.substr(0, index);
1798
+ const tokens = lexer.tokenize(left, inlineRules) || [];
1799
+ Array.prototype.unshift.apply(output, tokens);
1800
+ }
1801
+ };
1802
+ const inlineMatch = (input, pattern, lexer, fn) => {
1803
+ const output = match(input, pattern, arr => {
1804
+ if (pattern != CODE) {
1805
+ // prioritize code
1806
+ const codeCheck = CODE.exec(input);
1807
+ if (codeCheck
1808
+ && codeCheck.length
1809
+ && codeCheck.index < arr.index
1810
+ // && (codeCheck.index + codeCheck[0].length) > arr.index
1811
+ ) {
1812
+ return null;
1813
+ }
1814
+ }
1815
+ return fn(arr);
1816
+ });
1817
+ inPlaceInlineExec(input, output, lexer);
1818
+ return output;
1819
+ };
1820
+ const inlineRules = Object.values(inline);
1821
+ Array.prototype.push.apply(inlineRules, inlineExtra);
1822
+ inlineRules.push(inlinelowpriority[MARKDOWN_RULES.Text], inlinelowpriority[MARKDOWN_RULES.Space]);
1823
+ // #endregion
1824
+ // #region CODE
1825
+ const getLangGrammar = (lang) => {
1826
+ const retval = [inlinelowpriority[MARKDOWN_RULES.Text], inlinelowpriority[MARKDOWN_RULES.Space]];
1827
+ const key = lang?.toLowerCase() || '';
1828
+ if (key && key in codeExtra) {
1829
+ Array.prototype.unshift.apply(retval, codeExtra[key]);
1830
+ }
1831
+ return retval;
1832
+ };
1833
+ // #endregion
1834
+ // #region BLOCK
1835
+ const lowpriority = {
1836
+ // paragraph
1837
+ [MARKDOWN_RULES.Paragraph]: {
1838
+ exec: (input, lexer) => match(input, PARAGRAPH, arr => {
1839
+ const raw = arr[0], text = raw;
1840
+ return [{
1841
+ type: MARKDOWN_TYPES.Paragraph, raw, text,
1842
+ // recursion (inline rules only)
1843
+ tokens: lexer.tokenize(text, inlineRules)
1844
+ }];
1845
+ })
1846
+ },
1847
+ // sparse lines
1848
+ [MARKDOWN_RULES.Space]: inlinelowpriority[MARKDOWN_RULES.Space]
1849
+ };
1850
+ const tokenizeListItem = (text, lexer) => {
1851
+ const grammar = !/^ {0,3}(`{3,}|$|>|[+-]\s|\d+[.\)])/m.test(text) ? inlineRules : blockRules;
1852
+ return lexer.tokenize(text, grammar);
1853
+ };
1854
+ const block = {
1855
+ // hr
1856
+ [MARKDOWN_RULES.HorizontalRule]: {
1857
+ exec: (input, lexer) => match(input, HR, arr => {
1858
+ const raw = arr[0], text = raw;
1859
+ return [{
1860
+ type: MARKDOWN_TYPES.HorizontalRule, raw, text
1861
+ }];
1862
+ })
1863
+ },
1864
+ // headings
1865
+ [MARKDOWN_RULES.Heading]: {
1866
+ exec: (input, lexer) => match(input, HEADING, arr => {
1867
+ const text = arr[2];
1868
+ return [{
1869
+ type: MARKDOWN_TYPES.Heading, raw: arr[0], text, level: arr[1].length, ref: normalizeReference(text),
1870
+ tokens: lexer.tokenize(text, inlineRules)
1871
+ }];
1872
+ })
1873
+ },
1874
+ [MARKDOWN_RULES.Heading1]: {
1875
+ exec: (input, lexer) => match(input, HEADING1, arr => {
1876
+ const text = arr[1];
1877
+ return [{
1878
+ type: MARKDOWN_TYPES.Heading, raw: arr[0], text, level: 1, ref: normalizeReference(text),
1879
+ tokens: lexer.tokenize(text, inlineRules)
1880
+ }];
1881
+ })
1882
+ },
1883
+ [MARKDOWN_RULES.Heading2]: {
1884
+ exec: (input, lexer) => match(input, HEADING2, arr => {
1885
+ const text = arr[1];
1886
+ return [{
1887
+ type: MARKDOWN_TYPES.Heading, raw: arr[0], text, level: 2, ref: normalizeReference(text),
1888
+ tokens: lexer.tokenize(text, inlineRules)
1889
+ }];
1890
+ })
1891
+ },
1892
+ // codeblock
1893
+ [MARKDOWN_RULES.CodeBlock]: {
1894
+ exec: (input, lexer) => match(input, CODEBLOCK, arr => {
1895
+ const raw = arr[0], text = htmlEncode(raw);
1896
+ return [{
1897
+ type: MARKDOWN_TYPES.CodeBlock, raw, text,
1898
+ tokens: lexer.tokenize(text, [])
1899
+ }];
1900
+ })
1901
+ },
1902
+ // codeblock
1903
+ [MARKDOWN_RULES.Fences]: {
1904
+ exec: (input, lexer) => match(input, FENCES, arr => {
1905
+ const text = htmlEncode(arr[2]), lang = arr[1]?.toLowerCase();
1906
+ return [{
1907
+ type: MARKDOWN_TYPES.CodeBlock, raw: arr[0], text, lang,
1908
+ tokens: lexer.tokenize(text, getLangGrammar(lang))
1909
+ }];
1910
+ })
1911
+ },
1912
+ // blockquote
1913
+ [MARKDOWN_RULES.BlockQuote]: {
1914
+ exec: (input, lexer) => match(input, BLOCKQUOTE, arr => {
1915
+ const raw = arr[0], text = raw.replace(/^ {0,3}> */gm, '');
1916
+ return [{
1917
+ type: MARKDOWN_TYPES.BlockQuote, raw, text,
1918
+ // recursion
1919
+ tokens: lexer.tokenize(text, [
1920
+ lowpriority[MARKDOWN_RULES.Paragraph],
1921
+ lowpriority[MARKDOWN_RULES.Space]
1922
+ ])
1923
+ }];
1924
+ })
1925
+ },
1926
+ // lists
1927
+ [MARKDOWN_RULES.OrderedList]: {
1928
+ exec: (input, lexer) => match(input, OLIST, arr => {
1929
+ const raw = arr[0], items = raw.replace(/^ {0,3}/gm, '').split(LISTITEM).filter(i => !NullChecker.isNullOrEmpty(i)).map(i => i.trim());
1930
+ return [{
1931
+ type: MARKDOWN_TYPES.OrderedList, start: parseInt(/\d/.exec(arr[0])[0]), raw, text: raw, tokens: items.map(i => {
1932
+ // avoid paragraphs if not strictly needed
1933
+ return {
1934
+ type: MARKDOWN_TYPES.ListItem, raw: i, text: i, tokens: tokenizeListItem(i, lexer)
1935
+ };
1936
+ })
1937
+ }];
1938
+ })
1939
+ },
1940
+ [MARKDOWN_RULES.UnorderedList]: {
1941
+ exec: (input, lexer) => match(input, ULIST, arr => {
1942
+ const raw = arr[0], items = raw.replace(/^ {0,3}/gm, '').split(LISTITEM).filter(i => !NullChecker.isNullOrEmpty(i)).map(i => i.trim());
1943
+ return [{
1944
+ type: MARKDOWN_TYPES.UnorderedList, raw, text: raw, tokens: items.map(i => {
1945
+ return {
1946
+ type: MARKDOWN_TYPES.ListItem, raw: i, text: i, tokens: tokenizeListItem(i, lexer)
1947
+ };
1948
+ })
1949
+ }];
1950
+ })
1951
+ }
1952
+ };
1953
+ const blockRules = Object.values(block);
1954
+ Array.prototype.push.apply(blockRules, blockExtra);
1955
+ blockRules.push(lowpriority[MARKDOWN_RULES.Paragraph], lowpriority[MARKDOWN_RULES.Space]);
1956
+ // #endregion
1957
+ return [
1958
+ // comment first
1959
+ inert[MARKDOWN_RULES.Comment],
1960
+ inert[MARKDOWN_RULES.Reference]
1961
+ ].concat(
1962
+ // block rules contain recursive inline rules (at least)
1963
+ blockRules);
1964
+ }
1965
+ // #region HTML RENDERER HELPER
1966
+ // meant to help in unnecessary spaces replacement.
1967
+ const CARRIAGE_RETURN_PLACEHOLDER = '\0';
1968
+ const TRIM_INSIDE = /[ \r\n]*\0+[ \r\n]*/g;
1969
+ function trim(input) {
1970
+ return input?.replace(TRIM_INSIDE, '\n').trim();
1971
+ }
1972
+ // #endregion
1973
+ class HtmlRenderer {
1974
+ constructor(_extraItemRender = (token, __) => token?.text || '') {
1975
+ this._extraItemRender = _extraItemRender;
1976
+ this._renderContent = (token) => {
1977
+ const children = token.tokens;
1978
+ if (NullChecker.isNullOrEmpty(children)) {
1979
+ return token.text;
1980
+ }
1981
+ return this._render(children);
1982
+ };
1983
+ }
1984
+ _rendeItem(token, allTokens) {
1985
+ const r = this._renderContent, R = CARRIAGE_RETURN_PLACEHOLDER;
1986
+ switch (token?.type) {
1987
+ case MARKDOWN_TYPES.Reference:
1988
+ return '';
1989
+ case MARKDOWN_TYPES.Html:
1990
+ return token.raw;
1991
+ case MARKDOWN_TYPES.BlockQuote:
1992
+ return `<blockquote>\n${r(token)}</blockquote>${R}`;
1993
+ case MARKDOWN_TYPES.Bold:
1994
+ return `<b>${r(token)}</b>`;
1995
+ case MARKDOWN_TYPES.CodeBlock:
1996
+ const lang = token['lang'];
1997
+ return `<pre>${R}<code${(lang ? (' class="' + lang + '"') : '')}>${r(token)}</code>${R}</pre>${R}`;
1998
+ case MARKDOWN_TYPES.Code:
1999
+ return `<code>${r(token)}</code>`;
2000
+ case MARKDOWN_TYPES.HorizontalRule:
2001
+ return `<hr />${R}`;
2002
+ case MARKDOWN_TYPES.Heading:
2003
+ const hlevel = token['level'], hid = token['ref'];
2004
+ return `<h${hlevel} id="${hid}">${r(token)}</h${hlevel}>${R}`;
2005
+ case MARKDOWN_TYPES.Image:
2006
+ case MARKDOWN_TYPES.ImageLike:
2007
+ const itk = token;
2008
+ let isrc = itk.src, ititle = '';
2009
+ const alt = itk.text, iref = itk.ref;
2010
+ if (!isrc && iref) {
2011
+ const ireftk = allTokens.find(t => t.type === MARKDOWN_TYPES.Reference && t['image'] === true && t['id']?.toLowerCase() === iref.toLowerCase());
2012
+ if (ireftk) {
2013
+ isrc = ireftk.url;
2014
+ ititle = ireftk.title ?? '';
2015
+ }
2016
+ }
2017
+ return isrc ? `<img src="${isrc}" alt="${alt}"${(ititle ? (' title="' + ititle + '"') : '')} />` : `![${r(token)}]`;
2018
+ case MARKDOWN_TYPES.Italic:
2019
+ return `<i>${r(token)}</i>`;
2020
+ case MARKDOWN_TYPES.StrikeThrough:
2021
+ return `<s>${r(token)}</s>`;
2022
+ case MARKDOWN_TYPES.Quote:
2023
+ return `<q>${r(token)}</q>`;
2024
+ case MARKDOWN_TYPES.LineBreak:
2025
+ return '<br />' + R;
2026
+ case MARKDOWN_TYPES.OrderedList:
2027
+ return `<ol start="${token['start']}">\n${r(token)}</ol>${R}`;
2028
+ case MARKDOWN_TYPES.UnorderedList:
2029
+ return `<ul>\n${r(token)}</ul>${R}`;
2030
+ case MARKDOWN_TYPES.ListItem:
2031
+ return `\t<li>${r(token)}</li>${R}`;
2032
+ case MARKDOWN_TYPES.Link:
2033
+ case MARKDOWN_TYPES.LinkLike:
2034
+ const atk = token;
2035
+ let ahref = atk.href, atitle = '';
2036
+ const aref = atk.ref;
2037
+ if (!ahref && aref) {
2038
+ const areftk = allTokens.find(t => t.type === MARKDOWN_TYPES.Reference && t['image'] !== true && t['id']?.toLowerCase() === aref.toLowerCase());
2039
+ if (areftk) {
2040
+ ahref = areftk.url;
2041
+ atitle = areftk.title ?? '';
2042
+ }
2043
+ }
2044
+ return ahref ? `<a href="${ahref}"${(atitle ? (' title="' + atitle + '"') : '')}>${r(token)}</a>` : `[${r(token)}]`;
2045
+ case MARKDOWN_TYPES.Paragraph:
2046
+ return `<p>${r(token)}</p>${R}`;
2047
+ case MARKDOWN_TYPES.Text:
2048
+ case MARKDOWN_TYPES.Space:
2049
+ return token.text;
2050
+ }
2051
+ return this._extraItemRender(token, allTokens);
2052
+ }
2053
+ _render(tree) {
2054
+ let acc = '';
2055
+ for (let token of tree || []) {
2056
+ acc += this._rendeItem(token, tree);
2057
+ }
2058
+ return acc;
2059
+ }
2060
+ render(tree) {
2061
+ return trim(this._render(tree));
2062
+ }
2063
+ }
2064
+ class TokenRenderer {
2065
+ _render(token) {
2066
+ return NullChecker.isNullOrEmpty(token) ? '' : JSON.stringify(token);
2067
+ }
2068
+ render(tree) {
2069
+ return '[' + tree.filter(i => !NullChecker.isNullOrEmpty(i)).map(this._render).join(',') + ']';
2070
+ }
2071
+ }
2072
+ function isRenderer(obj) {
2073
+ return obj && typeof obj === 'object' && typeof obj.render === 'function';
2074
+ }
2075
+ class Parser extends Parser$1 {
2076
+ toHtml(input, extraGrammar, extraItemRenderer) {
2077
+ const renderer = new HtmlRenderer(extraItemRenderer);
2078
+ if (NullChecker.isNullOrEmpty(extraGrammar)) {
2079
+ return this.parse(input, renderer);
2080
+ }
2081
+ return this.parse(input, getGrammar(extraGrammar), renderer);
2082
+ }
2083
+ tokenize(input, extraGrammar) {
2084
+ const json = this.parse(input, getGrammar(extraGrammar), new TokenRenderer());
2085
+ return JSON.parse(json);
2086
+ }
2087
+ parse(input, grammarOrRenderer = getGrammar(), renderer = new HtmlRenderer()) {
2088
+ if (isRenderer(grammarOrRenderer)) {
2089
+ return super.parse(input, getGrammar(), grammarOrRenderer);
2090
+ }
2091
+ else {
2092
+ return super.parse(input, grammarOrRenderer, renderer);
2093
+ }
2094
+ }
2095
+ }
2096
+ //}
2097
+
2098
+ var indexCompileMarkdown = /*#__PURE__*/Object.freeze({
2099
+ __proto__: null,
2100
+ Parser: Parser
2101
+ });
2102
+
2103
+ var indexCompile = /*#__PURE__*/Object.freeze({
2104
+ __proto__: null,
2105
+ Markdown: indexCompileMarkdown,
2106
+ Parser: Parser$1
2107
+ });
2108
+
2109
+ // import './number-extensions';
2110
+ // import './array-extensions';
2111
+
2112
+ var Output = /*#__PURE__*/Object.freeze({
2113
+ __proto__: null,
2114
+ Angle: Angle,
2115
+ Arrays: Arrays,
2116
+ Blobs: Blobs,
2117
+ Colors: Colors,
2118
+ Compile: indexCompile,
2119
+ Dates: Dates,
2120
+ DeepMerger: DeepMerger,
2121
+ HistoryService: HistoryService,
2122
+ Imaging: Imaging,
2123
+ Keys: Keys,
2124
+ Matrix2D: Matrix2D,
2125
+ NullChecker: NullChecker,
2126
+ Numbers: Numbers,
2127
+ Point: Point,
2128
+ Rect: Rect,
2129
+ Size: Size,
2130
+ Strings: Strings,
2131
+ detect: detect,
2132
+ parseAsNumericalArray: parseAsNumericalArray
2133
+ });
2134
+
2135
+ DeepMerger.merge(Output);
2136
+
2137
+ })();
2138
+ //# sourceMappingURL=pacem-foundation.js.map