@arsedizioni/ars-utils 20.0.34 → 20.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/index.d.ts CHANGED
@@ -174,20 +174,20 @@ declare class SystemUtils {
174
174
  * @param b : string b
175
175
  * @returns : 0 if equals, 1 if bigger, -1 if lower
176
176
  */
177
- static compareString(a: string, b: string): number;
177
+ static compareString(a?: string, b?: string): number;
178
178
  /**
179
179
  * Capitalize a string
180
180
  * @param s : the string to capitalize
181
181
  * @returns : the capitalized string
182
182
  */
183
- static capitalize(s: string): string | undefined;
183
+ static capitalize(s?: string): string | undefined;
184
184
  /**
185
185
  * Truncate a string
186
186
  * @param s : the string to truncate
187
187
  * @param max : the max number of chars
188
188
  * @returns : the truncated string
189
189
  */
190
- static truncate(s: string, max?: number): string | undefined;
190
+ static truncate(s?: string, max?: number): string | undefined;
191
191
  /**
192
192
  * Join a list of strings
193
193
  * @param items : the list of strings
@@ -195,26 +195,58 @@ declare class SystemUtils {
195
195
  * @param max : the maximum resulting string
196
196
  * @returns : the joined string
197
197
  */
198
- static join(items: string[], sep?: string, max?: number): string | undefined;
198
+ static join(items?: string[], sep?: string, max?: number): string | undefined;
199
199
  /**
200
200
  * Replace stuff in text html
201
201
  * @param s : the string to process
202
202
  * @returns : the replaced string
203
203
  */
204
- static replaceAsHtml(s: string): string;
204
+ static replaceAsHtml(s?: string): string;
205
205
  /**
206
- * Convert a markdown string to html
207
- * @param markdown : the markdown string
208
- * @returns
206
+ * Convert markdown to html
207
+ * @param markdown : the markdown data
208
+ * @returns the html
209
209
  */
210
210
  static markdownToHtml(markdown: string): string;
211
+ /**
212
+ * Convert markdown table to html
213
+ * @param markdown: the markdown string
214
+ * @returns : the html
215
+ */
216
+ private static markdownConvertTables;
217
+ /**
218
+ * Convert a markdown table row to html
219
+ * @param row : the markdown row
220
+ * @param isHeader : true if is header
221
+ * @returns the html
222
+ */
223
+ private static markdownConvertTableRow;
224
+ /**
225
+ * Convert a markdown list to html
226
+ * @param markdown : the markdown list
227
+ * @returns the html
228
+ */
229
+ private static markdownConvertLists;
230
+ /**
231
+ * Wrap a list
232
+ * @param type: the list type
233
+ * @param items : the item list
234
+ * @returns the html
235
+ */
236
+ private static markdownWrapList;
237
+ /**
238
+ * Convert markdown paragraphs to html
239
+ * @param markdown : the markdown paragraphs
240
+ * @returns the html
241
+ */
242
+ private static markdownConvertParagraphs;
211
243
  /**
212
244
  * Compare two names
213
245
  * @param a : name a
214
246
  * @param b : name b
215
247
  * @returns : true if a equals b
216
248
  */
217
- static compareNames(a: string, b: string): boolean;
249
+ static compareNames(a?: string, b?: string): boolean;
218
250
  /**
219
251
  * Cipher a text
220
252
  * @param text : the text
@@ -222,7 +254,7 @@ declare class SystemUtils {
222
254
  * @param reverse : true to decode, false to encode
223
255
  * @returns :the ciphered text
224
256
  */
225
- static cipher(text: string, key: string, reverse?: boolean): string;
257
+ static cipher(text: string, key: string, reverse?: boolean): string | undefined;
226
258
  /**
227
259
  * Clone an object using JSON
228
260
  * @param obj : the oblect to clone
@@ -240,13 +272,13 @@ declare class SystemUtils {
240
272
  * @param value : the value to parse
241
273
  * @returns : true if is a valid UUID
242
274
  */
243
- static parseUUID(value: string): boolean;
275
+ static parseUUID(value?: string): boolean;
244
276
  /**
245
277
  * Parse and ensure that UUID is not empty
246
278
  * @param value : the value to parse
247
279
  * @returns : true if valid and not empty
248
280
  */
249
- static parseUUIDNotEmpty(value: string): boolean;
281
+ static parseUUIDNotEmpty(value?: string): boolean;
250
282
  /**
251
283
  * Return an empty UUID
252
284
  * @returns : the empty UUID
@@ -262,26 +294,26 @@ declare class SystemUtils {
262
294
  * @param value : email
263
295
  * @returns : true if the email is valid or empty
264
296
  */
265
- static parseEmail(value: string): boolean;
297
+ static parseEmail(value?: string): boolean;
266
298
  /**
267
299
  * Parse a text and return true if is a valid url or null
268
300
  * @param value : the url to parse
269
301
  * @returns : true if the url is valid or empty
270
302
  */
271
- static parseUrl(value: string): boolean;
303
+ static parseUrl(value?: string): boolean;
272
304
  /**
273
305
  * Get date parts from a string value
274
306
  * @param value : the string to parse
275
307
  * @returns : an array of numbers with year, month, day
276
308
  */
277
- static getDateParts(value: string): number[] | undefined;
309
+ static getDateParts(value?: string): number[] | undefined;
278
310
  /**
279
311
  * Parse a date
280
312
  * @param value : the value to check
281
313
  * @param locale : the locale to use
282
314
  * @returns : a valid Date object or null
283
315
  */
284
- static parseDate(value: string | Date, locale?: any): Date | undefined;
316
+ static parseDate(value?: string | Date, locale?: any): Date | undefined;
285
317
  /**
286
318
  * Format a date
287
319
  * @param value : the date or string to format
@@ -289,13 +321,13 @@ declare class SystemUtils {
289
321
  * @param locale : the locale to use (default is IT)
290
322
  * @returns : the formatted string
291
323
  */
292
- static formatDate(value: Date | string, fmt?: DateFormat | string, locale?: any): string;
324
+ static formatDate(value?: Date | string, fmt?: DateFormat | string, locale?: any): string;
293
325
  /**
294
326
  * Return an italian local date
295
327
  * @param value : the date
296
328
  * @returns : the new date
297
329
  */
298
- static toLocalDate(value: Date | string): Date;
330
+ static toLocalDate(value?: Date | string): Date;
299
331
  /**
300
332
  * Update a DateInterval object according to a string
301
333
  * @param value : string value
@@ -309,13 +341,13 @@ declare class SystemUtils {
309
341
  * @param value : the value to encode
310
342
  * @returns : the url encoded string
311
343
  */
312
- static urlEncode(value: string): string;
344
+ static urlEncode(value: string): string | undefined;
313
345
  /**
314
346
  * Decode url
315
347
  * @param value : the url to decode
316
348
  * @returns : the decode url string
317
349
  */
318
- static urlDecode(value: string): string;
350
+ static urlDecode(value?: string): string | undefined;
319
351
  /**
320
352
  * Get a querystring parameter value
321
353
  * @param name : the parameter name
@@ -332,7 +364,7 @@ declare class SystemUtils {
332
364
  * @param password: the password to evaluate
333
365
  * @returns the password strength info
334
366
  */
335
- static calculatePasswordStrength(password: string): PasswordStrength;
367
+ static calculatePasswordStrength(password?: string): PasswordStrength;
336
368
  /**
337
369
  * Check if current browser supports touch
338
370
  * @returns : true if the display is touchable
@@ -307,6 +307,8 @@ class SystemUtils {
307
307
  * @returns : the replaced string
308
308
  */
309
309
  static replaceAsHtml(s) {
310
+ if (!s)
311
+ return undefined;
310
312
  const regex = /https?:\/\/.*[^\s]/ig;
311
313
  const m = regex.exec(s);
312
314
  if (m && m.length > 0) {
@@ -319,87 +321,203 @@ class SystemUtils {
319
321
  return s;
320
322
  }
321
323
  /**
322
- * Convert a markdown string to html
323
- * @param markdown : the markdown string
324
- * @returns
324
+ * Convert markdown to html
325
+ * @param markdown : the markdown data
326
+ * @returns the html
325
327
  */
326
328
  static markdownToHtml(markdown) {
327
329
  let html = markdown;
328
- // Headers
330
+ //1. Escape HTML entities
331
+ html = html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
332
+ // 2. Code blocks
333
+ html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (_match, lang, code) => {
334
+ const langClass = lang ? ` class="language-${lang}"` : '';
335
+ return `<pre><code${langClass}>${code.trim()}</code></pre>`;
336
+ });
337
+ // 3. Inline code
338
+ html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
339
+ // 4. Headers
340
+ html = html.replace(/^##### (.*$)/gim, '<h5>$1</h5>');
341
+ html = html.replace(/^#### (.*$)/gim, '<h4>$1</h4>');
329
342
  html = html.replace(/^### (.*$)/gim, '<h3>$1</h3>');
330
343
  html = html.replace(/^## (.*$)/gim, '<h2>$1</h2>');
331
344
  html = html.replace(/^# (.*$)/gim, '<h1>$1</h1>');
332
- // Bold
333
- html = html.replace(/\*\*(.*)\*\*/gim, '<strong>$1</strong>');
334
- html = html.replace(/__(.*?)__/gim, '<strong>$1</strong>');
335
- // Italic
336
- html = html.replace(/\*(.*?)\*/gim, '<em>$1</em>');
337
- html = html.replace(/_(.*?)_/gim, '<em>$1</em>');
338
- // Code blocks
339
- html = html.replace(/```([\s\S]*?)```/gim, '<pre><code>$1</code></pre>');
340
- // Inline code
341
- html = html.replace(/`(.*?)`/gim, '<code>$1</code>');
342
- // Links
343
- html = html.replace(/\[([^\]]*)\]\(([^)]*)\)/gim, '<a href="$2">$1</a>');
344
- // Images
345
- html = html.replace(/!\[([^\]]*)\]\(([^)]*)\)/gim, '<img alt="$1" src="$2" />');
346
- // Blockquotes
347
- html = html.replace(/^\> (.*$)/gim, '<blockquote>$1</blockquote>');
348
- // Unordered lists
349
- html = html.replace(/^\* (.*$)/gim, '<li>$1</li>');
350
- html = html.replace(/^- (.*$)/gim, '<li>$1</li>');
351
- // Ordered lists
352
- html = html.replace(/^\d+\. (.*$)/gim, '<li>$1</li>');
353
- // Wrap list items in ul/ol tags
354
- html = html.replace(/(<li>.*<\/li>)/gims, function (match) {
355
- return '<ul>' + match + '</ul>';
356
- });
357
- // Tables
358
- html = html.replace(/\|(.+)\|/g, function (_match, content) {
359
- const cells = content.split('|').map((cell) => cell.trim());
360
- return '<tr>' + cells.map((cell) => {
361
- // Check if this is a header separator row
362
- if (cell.match(/^[\s\-\:]+$/)) {
363
- return null;
345
+ // 5. Horizontal rules
346
+ html = html.replace(/^---+$/gim, '<hr>');
347
+ html = html.replace(/^\*\*\*+$/gim, '<hr>');
348
+ // 6. Links
349
+ html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
350
+ // 7. Images
351
+ html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">');
352
+ // 8. Bold e Italic
353
+ html = html.replace(/\*\*\*([^*]+)\*\*\*/gim, '<strong><em>$1</em></strong>');
354
+ html = html.replace(/___([^_]+)___/gim, '<strong><em>$1</em></strong>');
355
+ html = html.replace(/\*\*([^*]+)\*\*/gim, '<strong>$1</strong>');
356
+ html = html.replace(/__([^_]+)__/gim, '<strong>$1</strong>');
357
+ html = html.replace(/\*([^*]+)\*/gim, '<em>$1</em>');
358
+ html = html.replace(/_([^_]+)_/gim, '<em>$1</em>');
359
+ // 9. Strikethrough
360
+ html = html.replace(/~~([^~]+)~~/gim, '<del>$1</del>');
361
+ // 10. Blockquotes
362
+ html = html.replace(/^> (.*$)/gim, '<blockquote>$1</blockquote>');
363
+ // 11. Tables
364
+ html = this.markdownConvertTables(html);
365
+ // 12. Lists
366
+ html = this.markdownConvertLists(html);
367
+ // 13. Line breaks
368
+ html = html.replace(/ $/gm, '<br>');
369
+ // 14. Paragrafi (ultimo step per non interferire con altri elementi)
370
+ html = this.markdownConvertParagraphs(html);
371
+ // 15. Clean up extra newlines
372
+ html = html.replace(/\n{3,}/g, '\n\n');
373
+ return html.trim();
374
+ }
375
+ /**
376
+ * Convert markdown table to html
377
+ * @param markdown: the markdown string
378
+ * @returns : the html
379
+ */
380
+ static markdownConvertTables(markdown) {
381
+ const lines = markdown.split('\n');
382
+ const result = [];
383
+ let inTable = false;
384
+ let tableRows = [];
385
+ let headerProcessed = false;
386
+ for (let i = 0; i < lines.length; i++) {
387
+ const line = lines[i].trim();
388
+ if (line.includes('|') && line.length > 1) {
389
+ const nextLine = i + 1 < lines.length ? lines[i + 1].trim() : '';
390
+ const isHeaderSeparator = /^\|?[\s\-:|]+\|?$/.test(nextLine);
391
+ if (!inTable) {
392
+ inTable = true;
393
+ headerProcessed = false;
394
+ tableRows = [];
395
+ }
396
+ if (isHeaderSeparator && !headerProcessed) {
397
+ tableRows.push(this.markdownConvertTableRow(line, true));
398
+ headerProcessed = true;
399
+ i++;
400
+ }
401
+ else if (!isHeaderSeparator) {
402
+ tableRows.push(this.markdownConvertTableRow(line, false));
364
403
  }
365
- return '<td>' + cell + '</td>';
366
- }).filter((cell) => cell !== null).join('') + '</tr>';
367
- });
368
- // Convert table rows to proper table structure
369
- html = html.replace(/(<tr>.*?<\/tr>)\s*\n*(<tr>.*?<\/tr>)/gs, function (match, firstRow, rest) {
370
- // Check if the second row is a separator (contains only dashes, colons, spaces)
371
- const secondRowContent = rest.replace(/<\/?t[rd]>/g, '');
372
- if (secondRowContent.match(/^[\s\-\:\|]+$/)) {
373
- // This is a header separator, make first row a header
374
- const headerRow = firstRow.replace(/<td>/g, '<th>').replace(/<\/td>/g, '</th>');
375
- return headerRow;
376
404
  }
377
- return match;
378
- });
379
- // Wrap table rows in table tags
380
- html = html.replace(/(<tr>.*?<\/tr>(?:\s*<tr>.*?<\/tr>)*)/gs, '<table>$1</table>');
381
- // Horizontal rules
382
- html = html.replace(/^\-\-\-$/gim, '<hr>');
383
- html = html.replace(/^\*\*\*$/gim, '<hr>');
384
- // Line breaks
385
- html = html.replace(/\n\n/gim, '</p><p>');
386
- html = html.replace(/\n/gim, '<br>');
387
- // Wrap in paragraphs
388
- html = '<p>' + html + '</p>';
389
- // Clean up empty paragraphs
390
- html = html.replace(/<p><\/p>/gim, '');
391
- html = html.replace(/<p>(<h[1-6]>)/gim, '$1');
392
- html = html.replace(/(<\/h[1-6]>)<\/p>/gim, '$1');
393
- html = html.replace(/<p>(<ul>)/gim, '$1');
394
- html = html.replace(/(<\/ul>)<\/p>/gim, '$1');
395
- html = html.replace(/<p>(<blockquote>)/gim, '$1');
396
- html = html.replace(/(<\/blockquote>)<\/p>/gim, '$1');
397
- html = html.replace(/<p>(<pre>)/gim, '$1');
398
- html = html.replace(/(<\/pre>)<\/p>/gim, '$1');
399
- html = html.replace(/<p>(<table>)/gim, '$1');
400
- html = html.replace(/(<\/table>)<\/p>/gim, '$1');
401
- html = html.replace(/<p>(<hr>)<\/p>/gim, '$1');
402
- return html;
405
+ else {
406
+ if (inTable && tableRows.length > 0) {
407
+ result.push('<table>');
408
+ result.push(...tableRows);
409
+ result.push('</table>');
410
+ tableRows = [];
411
+ inTable = false;
412
+ }
413
+ result.push(line);
414
+ }
415
+ }
416
+ if (inTable && tableRows.length > 0) {
417
+ result.push('<table>');
418
+ result.push(...tableRows);
419
+ result.push('</table>');
420
+ }
421
+ return result.join('\n');
422
+ }
423
+ /**
424
+ * Convert a markdown table row to html
425
+ * @param row : the markdown row
426
+ * @param isHeader : true if is header
427
+ * @returns the html
428
+ */
429
+ static markdownConvertTableRow(row, isHeader) {
430
+ const cells = row.split('|').map(cell => cell.trim()).filter(cell => cell !== '');
431
+ const tag = isHeader ? 'th' : 'td';
432
+ const cellsHtml = cells.map(cell => ` <${tag}>${cell}</${tag}>`).join('\n');
433
+ return ` <tr>\n${cellsHtml}\n </tr>`;
434
+ }
435
+ /**
436
+ * Convert a markdown list to html
437
+ * @param markdown : the markdown list
438
+ * @returns the html
439
+ */
440
+ static markdownConvertLists(markdown) {
441
+ markdown = markdown.replace(/^\* (.*$)/gim, '<li data-type="ul">$1</li>');
442
+ markdown = markdown.replace(/^- (.*$)/gim, '<li data-type="ul">$1</li>');
443
+ markdown = markdown.replace(/^\+ (.*$)/gim, '<li data-type="ul">$1</li>');
444
+ markdown = markdown.replace(/^\d+\. (.*$)/gim, '<li data-type="ol">$1</li>');
445
+ const lines = markdown.split('\n');
446
+ const result = [];
447
+ let currentList = { type: null, items: [] };
448
+ for (const line of lines) {
449
+ const ulMatch = line.match(/^<li data-type="ul">(.*)<\/li>$/);
450
+ const olMatch = line.match(/^<li data-type="ol">(.*)<\/li>$/);
451
+ if (ulMatch) {
452
+ if (currentList.type !== 'ul') {
453
+ if (currentList.type && currentList.items.length > 0) {
454
+ result.push(this.markdownWrapList(currentList.type, currentList.items));
455
+ }
456
+ currentList = { type: 'ul', items: [ulMatch[1]] };
457
+ }
458
+ else {
459
+ currentList.items.push(ulMatch[1]);
460
+ }
461
+ }
462
+ else if (olMatch) {
463
+ if (currentList.type !== 'ol') {
464
+ if (currentList.type && currentList.items.length > 0) {
465
+ result.push(this.markdownWrapList(currentList.type, currentList.items));
466
+ }
467
+ currentList = { type: 'ol', items: [olMatch[1]] };
468
+ }
469
+ else {
470
+ currentList.items.push(olMatch[1]);
471
+ }
472
+ }
473
+ else {
474
+ if (currentList.type && currentList.items.length > 0) {
475
+ result.push(this.markdownWrapList(currentList.type, currentList.items));
476
+ currentList = { type: null, items: [] };
477
+ }
478
+ result.push(line);
479
+ }
480
+ }
481
+ if (currentList.type && currentList.items.length > 0) {
482
+ result.push(this.markdownWrapList(currentList.type, currentList.items));
483
+ }
484
+ return result.join('\n');
485
+ }
486
+ /**
487
+ * Wrap a list
488
+ * @param type: the list type
489
+ * @param items : the item list
490
+ * @returns the html
491
+ */
492
+ static markdownWrapList(type, items) {
493
+ const listItems = items.map(item => ` <li>${item}</li>`).join('\n');
494
+ return `<${type}>\n${listItems}\n</${type}>`;
495
+ }
496
+ /**
497
+ * Convert markdown paragraphs to html
498
+ * @param markdown : the markdown paragraphs
499
+ * @returns the html
500
+ */
501
+ static markdownConvertParagraphs(markdown) {
502
+ const lines = markdown.split('\n');
503
+ const result = [];
504
+ for (const line of lines) {
505
+ const trimmed = line.trim();
506
+ if (!trimmed) {
507
+ result.push('');
508
+ continue;
509
+ }
510
+ if (trimmed.startsWith('<') && trimmed.endsWith('>')) {
511
+ result.push(line);
512
+ continue;
513
+ }
514
+ if (trimmed.startsWith('<') || trimmed.endsWith('>')) {
515
+ result.push(line);
516
+ continue;
517
+ }
518
+ result.push(`<p>${trimmed}</p>`);
519
+ }
520
+ return result.join('\n');
403
521
  }
404
522
  /**
405
523
  * Compare two names
@@ -490,7 +608,7 @@ class SystemUtils {
490
608
  */
491
609
  static parseUUID(value) {
492
610
  const regex = /^({|()?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(}|))?$/;
493
- return regex.test(value);
611
+ return value?.length > 0 && regex.test(value);
494
612
  }
495
613
  /**
496
614
  * Parse and ensure that UUID is not empty
@@ -699,7 +817,9 @@ class SystemUtils {
699
817
  * @returns : the url encoded string
700
818
  */
701
819
  static urlEncode(value) {
702
- return encodeURIComponent(value);
820
+ return value?.length > 0
821
+ ? encodeURIComponent(value)
822
+ : undefined;
703
823
  }
704
824
  /**
705
825
  * Decode url
@@ -708,7 +828,9 @@ class SystemUtils {
708
828
  */
709
829
  static urlDecode(value) {
710
830
  const regex = /\+/g;
711
- return decodeURIComponent((value + "").replace(regex, "%20"));
831
+ return value?.length > 0
832
+ ? decodeURIComponent((value + "").replace(regex, "%20"))
833
+ : undefined;
712
834
  }
713
835
  /**
714
836
  * Get a querystring parameter value