@mdfriday/foundry 25.9.2 → 25.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/internal/application/ssg.d.ts.map +1 -1
- package/dist/internal/application/ssg.js +12 -0
- package/dist/internal/application/ssg.js.map +1 -1
- package/dist/internal/domain/config/entity/config.d.ts +8 -2
- package/dist/internal/domain/config/entity/config.d.ts.map +1 -1
- package/dist/internal/domain/config/entity/config.js +10 -3
- package/dist/internal/domain/config/entity/config.js.map +1 -1
- package/dist/internal/domain/config/entity/social.d.ts +66 -0
- package/dist/internal/domain/config/entity/social.d.ts.map +1 -0
- package/dist/internal/domain/config/entity/social.js +126 -0
- package/dist/internal/domain/config/entity/social.js.map +1 -0
- package/dist/internal/domain/config/factory/config.d.ts.map +1 -1
- package/dist/internal/domain/config/factory/config.js +2 -1
- package/dist/internal/domain/config/factory/config.js.map +1 -1
- package/dist/internal/domain/config/index.d.ts +2 -0
- package/dist/internal/domain/config/index.d.ts.map +1 -1
- package/dist/internal/domain/config/index.js +5 -1
- package/dist/internal/domain/config/index.js.map +1 -1
- package/dist/internal/domain/config/tests/entity-config.test.js +16 -12
- package/dist/internal/domain/config/tests/entity-config.test.js.map +1 -1
- package/dist/internal/domain/config/tests/social.test.d.ts +2 -0
- package/dist/internal/domain/config/tests/social.test.d.ts.map +1 -0
- package/dist/internal/domain/config/tests/social.test.js +164 -0
- package/dist/internal/domain/config/tests/social.test.js.map +1 -0
- package/dist/internal/domain/config/type.d.ts +22 -0
- package/dist/internal/domain/config/type.d.ts.map +1 -1
- package/dist/internal/domain/config/type.js.map +1 -1
- package/dist/internal/domain/config/vo/root.d.ts.map +1 -1
- package/dist/internal/domain/config/vo/root.js +2 -1
- package/dist/internal/domain/config/vo/root.js.map +1 -1
- package/dist/internal/domain/config/vo/social.d.ts +23 -0
- package/dist/internal/domain/config/vo/social.d.ts.map +1 -0
- package/dist/internal/domain/config/vo/social.js +212 -0
- package/dist/internal/domain/config/vo/social.js.map +1 -0
- package/dist/internal/domain/content/entity/page.d.ts +7 -1
- package/dist/internal/domain/content/entity/page.d.ts.map +1 -1
- package/dist/internal/domain/content/entity/page.js +36 -3
- package/dist/internal/domain/content/entity/page.js.map +1 -1
- package/dist/internal/domain/content/entity/pagebuilder.d.ts +3 -2
- package/dist/internal/domain/content/entity/pagebuilder.d.ts.map +1 -1
- package/dist/internal/domain/content/entity/pagebuilder.js +16 -5
- package/dist/internal/domain/content/entity/pagebuilder.js.map +1 -1
- package/dist/internal/domain/content/entity/pagemeta.d.ts +10 -2
- package/dist/internal/domain/content/entity/pagemeta.d.ts.map +1 -1
- package/dist/internal/domain/content/entity/pagemeta.js +17 -1
- package/dist/internal/domain/content/entity/pagemeta.js.map +1 -1
- package/dist/internal/domain/content/entity/paginator.d.ts +6 -0
- package/dist/internal/domain/content/entity/paginator.d.ts.map +1 -1
- package/dist/internal/domain/content/entity/paginator.js +26 -2
- package/dist/internal/domain/content/entity/paginator.js.map +1 -1
- package/dist/internal/domain/content/entity/section.js +5 -5
- package/dist/internal/domain/content/entity/section.js.map +1 -1
- package/dist/internal/domain/content/factory/hub.d.ts.map +1 -1
- package/dist/internal/domain/content/factory/hub.js +2 -1
- package/dist/internal/domain/content/factory/hub.js.map +1 -1
- package/dist/internal/domain/content/type.d.ts +59 -1
- package/dist/internal/domain/content/type.d.ts.map +1 -1
- package/dist/internal/domain/content/type.js.map +1 -1
- package/dist/internal/domain/content/vo/frontmatter.d.ts +29 -1
- package/dist/internal/domain/content/vo/frontmatter.d.ts.map +1 -1
- package/dist/internal/domain/content/vo/frontmatter.js +242 -1
- package/dist/internal/domain/content/vo/frontmatter.js.map +1 -1
- package/dist/internal/domain/markdown/entity/markdown.d.ts.map +1 -1
- package/dist/internal/domain/markdown/entity/markdown.js +5 -4
- package/dist/internal/domain/markdown/entity/markdown.js.map +1 -1
- package/dist/internal/domain/markdown/vo/content.d.ts +3 -6
- package/dist/internal/domain/markdown/vo/content.d.ts.map +1 -1
- package/dist/internal/domain/markdown/vo/content.js +32 -31
- package/dist/internal/domain/markdown/vo/content.js.map +1 -1
- package/dist/internal/domain/module/entity/module.d.ts.map +1 -1
- package/dist/internal/domain/module/entity/module.js +10 -6
- package/dist/internal/domain/module/entity/module.js.map +1 -1
- package/dist/internal/domain/module/vo/themes.test.js +12 -8
- package/dist/internal/domain/module/vo/themes.test.js.map +1 -1
- package/dist/internal/domain/site/entity/language.d.ts.map +1 -1
- package/dist/internal/domain/site/entity/language.js +2 -0
- package/dist/internal/domain/site/entity/language.js.map +1 -1
- package/dist/internal/domain/site/entity/menu-builder.d.ts +39 -21
- package/dist/internal/domain/site/entity/menu-builder.d.ts.map +1 -1
- package/dist/internal/domain/site/entity/menu-builder.js +264 -107
- package/dist/internal/domain/site/entity/menu-builder.js.map +1 -1
- package/dist/internal/domain/site/entity/page.d.ts +22 -8
- package/dist/internal/domain/site/entity/page.d.ts.map +1 -1
- package/dist/internal/domain/site/entity/page.js +67 -6
- package/dist/internal/domain/site/entity/page.js.map +1 -1
- package/dist/internal/domain/site/entity/pager.d.ts +2 -0
- package/dist/internal/domain/site/entity/pager.d.ts.map +1 -1
- package/dist/internal/domain/site/entity/pager.js +11 -0
- package/dist/internal/domain/site/entity/pager.js.map +1 -1
- package/dist/internal/domain/site/entity/site.d.ts +14 -8
- package/dist/internal/domain/site/entity/site.d.ts.map +1 -1
- package/dist/internal/domain/site/entity/site.js +35 -8
- package/dist/internal/domain/site/entity/site.js.map +1 -1
- package/dist/internal/domain/site/entity/url.d.ts.map +1 -1
- package/dist/internal/domain/site/entity/url.js +3 -1
- package/dist/internal/domain/site/entity/url.js.map +1 -1
- package/dist/internal/domain/site/factory/navigation-factory.d.ts +4 -2
- package/dist/internal/domain/site/factory/navigation-factory.d.ts.map +1 -1
- package/dist/internal/domain/site/factory/navigation-factory.js +5 -4
- package/dist/internal/domain/site/factory/navigation-factory.js.map +1 -1
- package/dist/internal/domain/site/factory/site.d.ts.map +1 -1
- package/dist/internal/domain/site/factory/site.js +7 -9
- package/dist/internal/domain/site/factory/site.js.map +1 -1
- package/dist/internal/domain/site/type.d.ts +11 -0
- package/dist/internal/domain/site/type.d.ts.map +1 -1
- package/dist/internal/domain/site/valueobject/author.d.ts +14 -2
- package/dist/internal/domain/site/valueobject/author.d.ts.map +1 -1
- package/dist/internal/domain/site/valueobject/author.js +29 -4
- package/dist/internal/domain/site/valueobject/author.js.map +1 -1
- package/dist/internal/domain/site/valueobject/menu.d.ts +28 -115
- package/dist/internal/domain/site/valueobject/menu.d.ts.map +1 -1
- package/dist/internal/domain/site/valueobject/menu.js +44 -192
- package/dist/internal/domain/site/valueobject/menu.js.map +1 -1
- package/dist/internal/domain/site/valueobject/organization.d.ts +66 -0
- package/dist/internal/domain/site/valueobject/organization.d.ts.map +1 -0
- package/dist/internal/domain/site/valueobject/organization.js +115 -0
- package/dist/internal/domain/site/valueobject/organization.js.map +1 -0
- package/dist/internal/domain/site/valueobject/organization.test.d.ts +2 -0
- package/dist/internal/domain/site/valueobject/organization.test.d.ts.map +1 -0
- package/dist/internal/domain/site/valueobject/organization.test.js +78 -0
- package/dist/internal/domain/site/valueobject/organization.test.js.map +1 -0
- package/dist/internal/domain/template/vo/namespace.d.ts.map +1 -1
- package/dist/internal/domain/template/vo/namespace.js +8 -0
- package/dist/internal/domain/template/vo/namespace.js.map +1 -1
- package/dist/internal/domain/template/vo/registry.d.ts +18 -0
- package/dist/internal/domain/template/vo/registry.d.ts.map +1 -1
- package/dist/internal/domain/template/vo/registry.js +387 -9
- package/dist/internal/domain/template/vo/registry.js.map +1 -1
- package/dist/pkg/maps/scratch.d.ts +1 -0
- package/dist/pkg/maps/scratch.d.ts.map +1 -1
- package/dist/pkg/maps/scratch.js +4 -0
- package/dist/pkg/maps/scratch.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,8 @@ exports.newPartialTemplateNamespace = newPartialTemplateNamespace;
|
|
|
9
9
|
exports.newShortcodeTemplateNamespace = newShortcodeTemplateNamespace;
|
|
10
10
|
const type_1 = require("../type");
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const log_1 = require("../../../../pkg/log");
|
|
13
|
+
const log = (0, log_1.getDomainLogger)('template', { component: 'namespace' });
|
|
12
14
|
/**
|
|
13
15
|
* Base namespace for template storage with common functionality
|
|
14
16
|
* Abstract base class for different template namespace types
|
|
@@ -34,6 +36,12 @@ class BaseNamespace {
|
|
|
34
36
|
if (this.templates.has(name)) {
|
|
35
37
|
return this.templates.get(name) || null;
|
|
36
38
|
}
|
|
39
|
+
if (!name.endsWith(".html")) {
|
|
40
|
+
const htmlName = name + '.html';
|
|
41
|
+
if (this.templates.has(htmlName)) {
|
|
42
|
+
return this.templates.get(htmlName) || null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
37
45
|
for (const [key, template] of this.templates.entries()) {
|
|
38
46
|
if (key.includes(name)) {
|
|
39
47
|
return template;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../../../internal/domain/template/vo/namespace.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../../../internal/domain/template/vo/namespace.ts"],"names":[],"mappings":"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"}
|
|
@@ -70,6 +70,18 @@ export declare class DefaultTemplateRegistry implements TemplateRegistry {
|
|
|
70
70
|
* Equivalent to Go's registerStrings()
|
|
71
71
|
*/
|
|
72
72
|
private registerStringFunctions;
|
|
73
|
+
/**
|
|
74
|
+
* HTML escape utility function
|
|
75
|
+
*/
|
|
76
|
+
private escapeHTML;
|
|
77
|
+
/**
|
|
78
|
+
* Truncate plain text, breaking at word boundaries when possible
|
|
79
|
+
*/
|
|
80
|
+
private truncateText;
|
|
81
|
+
/**
|
|
82
|
+
* Truncate HTML text while preserving tag structure
|
|
83
|
+
*/
|
|
84
|
+
private truncateHTML;
|
|
73
85
|
/**
|
|
74
86
|
* Register math functions
|
|
75
87
|
* Equivalent to Go's registerMath()
|
|
@@ -140,6 +152,12 @@ export declare class DefaultTemplateRegistry implements TemplateRegistry {
|
|
|
140
152
|
* Equivalent to Go's transform package functions
|
|
141
153
|
*/
|
|
142
154
|
private registerTransformFunctions;
|
|
155
|
+
/**
|
|
156
|
+
* Strip HTML tags from a string
|
|
157
|
+
* Equivalent to Go's helpers.StripHTML function
|
|
158
|
+
* Preserves line breaks from block elements and normalizes whitespace
|
|
159
|
+
*/
|
|
160
|
+
private stripHTML;
|
|
143
161
|
/**
|
|
144
162
|
* Unmarshal content from string based on format
|
|
145
163
|
* Supports JSON, YAML, TOML, CSV formats
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../../../internal/domain/template/vo/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,mBAAmB,EAAE,eAAe,EAAC,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAsFlD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IACtD,yBAAyB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACzF,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACtF;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAE9D;;;OAGG;IACH,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAgCrD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;;OAGG;IACH,yBAAyB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAgBxF;;;OAGG;IACH,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,IAAI;IAiBpF;;;OAGG;IACH,OAAO,CAAC,gCAAgC;IAOxC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAgL5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,0BAA0B;IAWlC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAuDjC;;;OAGG;IACH,OAAO,CAAC,uBAAuB;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../../../internal/domain/template/vo/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,mBAAmB,EAAE,eAAe,EAAC,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAsFlD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IACtD,yBAAyB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACzF,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACtF;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAE9D;;;OAGG;IACH,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAgCrD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;;OAGG;IACH,yBAAyB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAgBxF;;;OAGG;IACH,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,IAAI;IAiBpF;;;OAGG;IACH,OAAO,CAAC,gCAAgC;IAOxC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAgL5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,0BAA0B;IAWlC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAuDjC;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAma/B;;OAEG;IACH,OAAO,CAAC,UAAU;IASlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAgCpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAoGpB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAmO7B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAgM7B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA2ZnC;;;OAGG;IACH,OAAO,CAAC,OAAO;IAuCf;;OAEG;IACH,OAAO,CAAC,UAAU;IAelB;;OAEG;IACH,OAAO,CAAC,WAAW;IAenB;;OAEG;IACH,OAAO,CAAC,WAAW;IAkCnB;;OAEG;IACH,OAAO,CAAC,SAAS;IAoBjB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAmEtB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkC9B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA+I7B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAiI5B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAgDhC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAqH7B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IA4ElC;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAuCjB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAmCxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAiCpB;;;OAGG;IACH,OAAO,CAAC,SAAS;IA0CjB;;;OAGG;IACH,OAAO,CAAC,SAAS;IA4DjB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAuChB;;OAEG;IACH,OAAO,CAAC,YAAY;IAgCpB;;;OAGG;IACH,OAAO,CAAC,cAAc;CAwDvB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAEtD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,eAAe,CAKnD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,eAAe,CAKpF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAQ3E"}
|
|
@@ -454,7 +454,36 @@ class DefaultTemplateRegistry {
|
|
|
454
454
|
funcMap.set('lower', (str) => str.toLowerCase());
|
|
455
455
|
funcMap.set('title', (str) => str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()));
|
|
456
456
|
funcMap.set('trim', (str) => str.trim());
|
|
457
|
-
funcMap.set('replace', (
|
|
457
|
+
funcMap.set('replace', (...args) => {
|
|
458
|
+
if (args.length < 3) {
|
|
459
|
+
throw new Error('replace requires at least 3 arguments: string, old, new');
|
|
460
|
+
}
|
|
461
|
+
const str = String(args[0]);
|
|
462
|
+
const old = String(args[1]);
|
|
463
|
+
const newStr = String(args[2]);
|
|
464
|
+
// Handle optional limit parameter like Go's implementation
|
|
465
|
+
if (args.length >= 4) {
|
|
466
|
+
const limit = Number(args[3]);
|
|
467
|
+
if (isNaN(limit)) {
|
|
468
|
+
throw new Error('replace limit must be a number');
|
|
469
|
+
}
|
|
470
|
+
// Implement limited replacement like Go's strings.Replace
|
|
471
|
+
let result = str;
|
|
472
|
+
let count = 0;
|
|
473
|
+
let startIndex = 0;
|
|
474
|
+
while (count < limit && startIndex < result.length) {
|
|
475
|
+
const index = result.indexOf(old, startIndex);
|
|
476
|
+
if (index === -1)
|
|
477
|
+
break;
|
|
478
|
+
result = result.substring(0, index) + newStr + result.substring(index + old.length);
|
|
479
|
+
startIndex = index + newStr.length;
|
|
480
|
+
count++;
|
|
481
|
+
}
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
// Default behavior: replace all occurrences (like Go's strings.ReplaceAll)
|
|
485
|
+
return str.split(old).join(newStr);
|
|
486
|
+
});
|
|
458
487
|
// Split function - ensure first parameter is the string to split
|
|
459
488
|
funcMap.set('split', (str, sep) => {
|
|
460
489
|
// Handle null and undefined cases first
|
|
@@ -570,16 +599,22 @@ class DefaultTemplateRegistry {
|
|
|
570
599
|
Replace: (s, old, newStr, limit) => {
|
|
571
600
|
const str = String(s);
|
|
572
601
|
if (limit === undefined) {
|
|
573
|
-
|
|
602
|
+
// Replace all occurrences (like Go's strings.ReplaceAll)
|
|
603
|
+
return str.split(old).join(newStr);
|
|
574
604
|
}
|
|
605
|
+
// Implement limited replacement like Go's strings.Replace
|
|
606
|
+
let result = str;
|
|
575
607
|
let count = 0;
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
608
|
+
let startIndex = 0;
|
|
609
|
+
while (count < limit && startIndex < result.length) {
|
|
610
|
+
const index = result.indexOf(old, startIndex);
|
|
611
|
+
if (index === -1)
|
|
612
|
+
break;
|
|
613
|
+
result = result.substring(0, index) + newStr + result.substring(index + old.length);
|
|
614
|
+
startIndex = index + newStr.length;
|
|
615
|
+
count++;
|
|
616
|
+
}
|
|
617
|
+
return result;
|
|
583
618
|
},
|
|
584
619
|
// Splitting and slicing
|
|
585
620
|
Split: (s, delimiter) => String(s).split(delimiter),
|
|
@@ -629,6 +664,265 @@ class DefaultTemplateRegistry {
|
|
|
629
664
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
630
665
|
}
|
|
631
666
|
}));
|
|
667
|
+
// Substr extracts parts of a string, beginning at the character at the specified
|
|
668
|
+
// position, and returns the specified number of characters.
|
|
669
|
+
// It normally takes two parameters: start and length.
|
|
670
|
+
// It can also take one parameter: start, i.e. length is omitted, in which case
|
|
671
|
+
// the substring starting from start until the end of the string will be returned.
|
|
672
|
+
// To extract characters from the end of the string, use a negative start number.
|
|
673
|
+
// If length is given and is negative, then that many characters will be omitted from
|
|
674
|
+
// the end of string.
|
|
675
|
+
// Equivalent to Go's Substr function in strings namespace
|
|
676
|
+
// Usage: {{ substr "hello world" 0 5 }} -> "hello"
|
|
677
|
+
// Usage: {{ substr "hello world" 6 }} -> "world"
|
|
678
|
+
// Usage: {{ substr "hello world" -5 }} -> "world"
|
|
679
|
+
// Usage: {{ substr "hello world" 0 -6 }} -> "hello"
|
|
680
|
+
funcMap.set('substr', (a, ...nums) => {
|
|
681
|
+
// Convert input to string
|
|
682
|
+
const s = String(a);
|
|
683
|
+
// Convert string to array of characters to handle Unicode properly
|
|
684
|
+
const chars = Array.from(s);
|
|
685
|
+
const rlen = chars.length;
|
|
686
|
+
let start;
|
|
687
|
+
let length;
|
|
688
|
+
// Parse arguments
|
|
689
|
+
switch (nums.length) {
|
|
690
|
+
case 0:
|
|
691
|
+
throw new Error('too few arguments');
|
|
692
|
+
case 1:
|
|
693
|
+
// Only start parameter provided
|
|
694
|
+
const startNum = Number(nums[0]);
|
|
695
|
+
if (isNaN(startNum) || !Number.isInteger(startNum)) {
|
|
696
|
+
throw new Error('start argument must be an integer');
|
|
697
|
+
}
|
|
698
|
+
start = startNum;
|
|
699
|
+
length = rlen;
|
|
700
|
+
break;
|
|
701
|
+
case 2:
|
|
702
|
+
// Both start and length parameters provided
|
|
703
|
+
const startNum2 = Number(nums[0]);
|
|
704
|
+
const lengthNum = Number(nums[1]);
|
|
705
|
+
if (isNaN(startNum2) || !Number.isInteger(startNum2)) {
|
|
706
|
+
throw new Error('start argument must be an integer');
|
|
707
|
+
}
|
|
708
|
+
if (isNaN(lengthNum) || !Number.isInteger(lengthNum)) {
|
|
709
|
+
throw new Error('length argument must be an integer');
|
|
710
|
+
}
|
|
711
|
+
start = startNum2;
|
|
712
|
+
length = lengthNum;
|
|
713
|
+
break;
|
|
714
|
+
default:
|
|
715
|
+
throw new Error('too many arguments');
|
|
716
|
+
}
|
|
717
|
+
// Handle empty string
|
|
718
|
+
if (rlen === 0) {
|
|
719
|
+
return '';
|
|
720
|
+
}
|
|
721
|
+
// Handle negative start (count from end)
|
|
722
|
+
if (start < 0) {
|
|
723
|
+
start += rlen;
|
|
724
|
+
}
|
|
725
|
+
// If start was originally negative beyond rlen, set to 0
|
|
726
|
+
if (start < 0) {
|
|
727
|
+
start = 0;
|
|
728
|
+
}
|
|
729
|
+
// If start is beyond the string length, return empty
|
|
730
|
+
if (start > rlen - 1) {
|
|
731
|
+
return '';
|
|
732
|
+
}
|
|
733
|
+
let end = rlen;
|
|
734
|
+
// Handle different length cases
|
|
735
|
+
if (length === 0) {
|
|
736
|
+
return '';
|
|
737
|
+
}
|
|
738
|
+
else if (length < 0) {
|
|
739
|
+
// Negative length: omit that many characters from end
|
|
740
|
+
end += length;
|
|
741
|
+
}
|
|
742
|
+
else if (length > 0) {
|
|
743
|
+
// Positive length: take that many characters from start
|
|
744
|
+
end = start + length;
|
|
745
|
+
}
|
|
746
|
+
// Validate bounds
|
|
747
|
+
if (start >= end) {
|
|
748
|
+
return '';
|
|
749
|
+
}
|
|
750
|
+
if (end < 0) {
|
|
751
|
+
return '';
|
|
752
|
+
}
|
|
753
|
+
// Clamp end to string length
|
|
754
|
+
if (end > rlen) {
|
|
755
|
+
end = rlen;
|
|
756
|
+
}
|
|
757
|
+
// Extract substring
|
|
758
|
+
return chars.slice(start, end).join('');
|
|
759
|
+
});
|
|
760
|
+
// Truncate truncates the string to the specified length
|
|
761
|
+
// Equivalent to Go's Truncate function in strings namespace
|
|
762
|
+
// Usage: {{ truncate 10 "hello world" }} -> "hello …"
|
|
763
|
+
// Usage: {{ truncate 10 "..." "hello world" }} -> "hello..."
|
|
764
|
+
// Supports HTML-aware truncation
|
|
765
|
+
funcMap.set('truncate', (lengthParam, ...options) => {
|
|
766
|
+
// Parse length parameter
|
|
767
|
+
const length = Number(lengthParam);
|
|
768
|
+
if (isNaN(length) || !Number.isInteger(length)) {
|
|
769
|
+
throw new Error('truncate length must be an integer');
|
|
770
|
+
}
|
|
771
|
+
let textParam;
|
|
772
|
+
let ellipsis = ' …';
|
|
773
|
+
// Parse options
|
|
774
|
+
switch (options.length) {
|
|
775
|
+
case 0:
|
|
776
|
+
throw new Error('truncate requires a length and a string');
|
|
777
|
+
case 1:
|
|
778
|
+
textParam = options[0];
|
|
779
|
+
ellipsis = ' …';
|
|
780
|
+
break;
|
|
781
|
+
case 2:
|
|
782
|
+
ellipsis = String(options[0]);
|
|
783
|
+
textParam = options[1];
|
|
784
|
+
break;
|
|
785
|
+
default:
|
|
786
|
+
throw new Error('too many arguments passed to truncate');
|
|
787
|
+
}
|
|
788
|
+
// Convert text to string
|
|
789
|
+
const text = String(textParam);
|
|
790
|
+
// Check if input is HTML (simple heuristic: contains HTML tags)
|
|
791
|
+
const isHTML = /<[^>]+>/.test(text);
|
|
792
|
+
// Convert to array of characters for proper Unicode handling
|
|
793
|
+
const chars = Array.from(text);
|
|
794
|
+
// If text is already shorter than or equal to length, return as-is
|
|
795
|
+
if (chars.length <= length) {
|
|
796
|
+
if (isHTML) {
|
|
797
|
+
return text; // Return as HTML
|
|
798
|
+
}
|
|
799
|
+
return this.escapeHTML(text);
|
|
800
|
+
}
|
|
801
|
+
if (isHTML) {
|
|
802
|
+
return this.truncateHTML(text, length, ellipsis);
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
return this.truncateText(text, length, ellipsis);
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* HTML escape utility function
|
|
811
|
+
*/
|
|
812
|
+
escapeHTML(text) {
|
|
813
|
+
return text
|
|
814
|
+
.replace(/&/g, '&')
|
|
815
|
+
.replace(/</g, '<')
|
|
816
|
+
.replace(/>/g, '>')
|
|
817
|
+
.replace(/"/g, '"')
|
|
818
|
+
.replace(/'/g, ''');
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Truncate plain text, breaking at word boundaries when possible
|
|
822
|
+
*/
|
|
823
|
+
truncateText(text, length, ellipsis) {
|
|
824
|
+
const chars = Array.from(text);
|
|
825
|
+
if (chars.length <= length) {
|
|
826
|
+
return this.escapeHTML(text);
|
|
827
|
+
}
|
|
828
|
+
let lastWordIndex = 0;
|
|
829
|
+
let currentLen = 0;
|
|
830
|
+
// Find the best truncation point (word boundary)
|
|
831
|
+
for (let i = 0; i < chars.length && currentLen < length; i++) {
|
|
832
|
+
const char = chars[i];
|
|
833
|
+
currentLen++;
|
|
834
|
+
if (/\s/.test(char)) {
|
|
835
|
+
lastWordIndex = i;
|
|
836
|
+
}
|
|
837
|
+
// For CJK characters, each character can be a word boundary
|
|
838
|
+
if (/[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/.test(char)) {
|
|
839
|
+
lastWordIndex = i;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
// Determine truncation point
|
|
843
|
+
let endPos = currentLen >= length ? (lastWordIndex > 0 ? lastWordIndex : length) : chars.length;
|
|
844
|
+
const truncated = chars.slice(0, endPos).join('');
|
|
845
|
+
return this.escapeHTML(truncated) + ellipsis;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Truncate HTML text while preserving tag structure
|
|
849
|
+
*/
|
|
850
|
+
truncateHTML(text, length, ellipsis) {
|
|
851
|
+
const tagRegex = /^<(\/)?([^ ]+?)(?:(\s*\/)| .*?)?>/;
|
|
852
|
+
const htmlSinglets = new Set(['br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input']);
|
|
853
|
+
const tags = [];
|
|
854
|
+
let lastWordIndex = 0;
|
|
855
|
+
let lastNonSpace = 0;
|
|
856
|
+
let currentLen = 0;
|
|
857
|
+
let endTextPos = 0;
|
|
858
|
+
let i = 0;
|
|
859
|
+
const chars = Array.from(text);
|
|
860
|
+
while (i < chars.length) {
|
|
861
|
+
const currentChar = chars[i];
|
|
862
|
+
// Check for HTML tag
|
|
863
|
+
if (currentChar === '<') {
|
|
864
|
+
const remainingText = chars.slice(i).join('');
|
|
865
|
+
const match = remainingText.match(tagRegex);
|
|
866
|
+
if (match) {
|
|
867
|
+
const fullMatch = match[0];
|
|
868
|
+
const isClosing = match[1] === '/';
|
|
869
|
+
const tagName = match[2].toLowerCase();
|
|
870
|
+
const isSelfClosing = match[3] === '/';
|
|
871
|
+
// Skip the entire tag
|
|
872
|
+
i += fullMatch.length;
|
|
873
|
+
lastWordIndex = lastNonSpace;
|
|
874
|
+
// Track non-singlet tags for proper closing
|
|
875
|
+
const isSinglet = htmlSinglets.has(tagName);
|
|
876
|
+
if (!isSinglet && !isSelfClosing) {
|
|
877
|
+
tags.push({
|
|
878
|
+
name: tagName,
|
|
879
|
+
pos: i - fullMatch.length,
|
|
880
|
+
openTag: !isClosing
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
// Count actual text characters
|
|
887
|
+
currentLen++;
|
|
888
|
+
if (/\s/.test(currentChar)) {
|
|
889
|
+
lastWordIndex = lastNonSpace;
|
|
890
|
+
}
|
|
891
|
+
else if (/[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/.test(currentChar)) {
|
|
892
|
+
// CJK characters can break at any character
|
|
893
|
+
lastWordIndex = i;
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
lastNonSpace = i + 1;
|
|
897
|
+
}
|
|
898
|
+
if (currentLen > length) {
|
|
899
|
+
endTextPos = lastWordIndex > 0 ? lastWordIndex : i;
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
i++;
|
|
903
|
+
}
|
|
904
|
+
if (currentLen <= length) {
|
|
905
|
+
return text; // No truncation needed
|
|
906
|
+
}
|
|
907
|
+
let output = chars.slice(0, endTextPos).join('') + ellipsis;
|
|
908
|
+
// Close any open HTML tags
|
|
909
|
+
let currentTag = null;
|
|
910
|
+
for (let j = tags.length - 1; j >= 0; j--) {
|
|
911
|
+
const tag = tags[j];
|
|
912
|
+
if (tag.pos >= endTextPos || currentTag !== null) {
|
|
913
|
+
if (currentTag !== null && currentTag.name === tag.name) {
|
|
914
|
+
currentTag = null;
|
|
915
|
+
}
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
if (tag.openTag) {
|
|
919
|
+
output += `</${tag.name}>`;
|
|
920
|
+
}
|
|
921
|
+
else {
|
|
922
|
+
currentTag = tag;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
return output;
|
|
632
926
|
}
|
|
633
927
|
/**
|
|
634
928
|
* Register math functions
|
|
@@ -1355,6 +1649,42 @@ class DefaultTemplateRegistry {
|
|
|
1355
1649
|
.join('&');
|
|
1356
1650
|
return queryString;
|
|
1357
1651
|
});
|
|
1652
|
+
// IsSet returns whether a given array, slice, or map has the given key defined
|
|
1653
|
+
// Equivalent to Go's IsSet function in collections namespace
|
|
1654
|
+
// Usage: {{ isset .array 0 }} or {{ isset .object "key" }}
|
|
1655
|
+
funcMap.set('isset', (c, key) => {
|
|
1656
|
+
if (c === null || c === undefined) {
|
|
1657
|
+
return false;
|
|
1658
|
+
}
|
|
1659
|
+
// Handle arrays and slices
|
|
1660
|
+
if (Array.isArray(c)) {
|
|
1661
|
+
// Convert key to integer for array indexing
|
|
1662
|
+
const k = Number(key);
|
|
1663
|
+
if (isNaN(k) || !Number.isInteger(k)) {
|
|
1664
|
+
console.warn(`isset unable to use key of type ${typeof key} as index`);
|
|
1665
|
+
return false;
|
|
1666
|
+
}
|
|
1667
|
+
// Check if index is valid (within bounds)
|
|
1668
|
+
return c.length > k && k >= 0;
|
|
1669
|
+
}
|
|
1670
|
+
// Handle objects/maps
|
|
1671
|
+
if (typeof c === 'object') {
|
|
1672
|
+
// For objects, check if the key exists as a property
|
|
1673
|
+
return key in c;
|
|
1674
|
+
}
|
|
1675
|
+
// Handle strings (similar to arrays, but for character indexing)
|
|
1676
|
+
if (typeof c === 'string') {
|
|
1677
|
+
const k = Number(key);
|
|
1678
|
+
if (isNaN(k) || !Number.isInteger(k)) {
|
|
1679
|
+
console.warn(`isset unable to use key of type ${typeof key} as index`);
|
|
1680
|
+
return false;
|
|
1681
|
+
}
|
|
1682
|
+
return c.length > k && k >= 0;
|
|
1683
|
+
}
|
|
1684
|
+
// Unsupported types
|
|
1685
|
+
console.warn(`calling isset with unsupported type "${typeof c}" (${c.constructor?.name || typeof c}) will always return false.`);
|
|
1686
|
+
return false;
|
|
1687
|
+
});
|
|
1358
1688
|
}
|
|
1359
1689
|
/**
|
|
1360
1690
|
* Core indexing implementation following Go's doIndex logic
|
|
@@ -2023,6 +2353,14 @@ class DefaultTemplateRegistry {
|
|
|
2023
2353
|
return null;
|
|
2024
2354
|
}
|
|
2025
2355
|
return this.unmarshalContent(dataStr, options);
|
|
2356
|
+
},
|
|
2357
|
+
// Plainify returns a copy of s with all HTML tags removed
|
|
2358
|
+
// Equivalent to Go's Plainify function in transform namespace
|
|
2359
|
+
// Usage: {{ "Hello <strong>world</strong>!" | transform.Plainify }} -> "Hello world!"
|
|
2360
|
+
// Usage: {{ transform.Plainify "<p>Text with <br> tags</p>" }} -> "Text with tags"
|
|
2361
|
+
Plainify: (s) => {
|
|
2362
|
+
const str = String(s);
|
|
2363
|
+
return this.stripHTML(str);
|
|
2026
2364
|
}
|
|
2027
2365
|
}));
|
|
2028
2366
|
// Also register unmarshal as a standalone function for backward compatibility
|
|
@@ -2030,6 +2368,46 @@ class DefaultTemplateRegistry {
|
|
|
2030
2368
|
const transform = funcMap.get('transform')();
|
|
2031
2369
|
return transform.Unmarshal(...args);
|
|
2032
2370
|
});
|
|
2371
|
+
// Register plainify as a standalone function for convenience
|
|
2372
|
+
funcMap.set('plainify', (s) => {
|
|
2373
|
+
const str = String(s);
|
|
2374
|
+
return this.stripHTML(str);
|
|
2375
|
+
});
|
|
2376
|
+
}
|
|
2377
|
+
/**
|
|
2378
|
+
* Strip HTML tags from a string
|
|
2379
|
+
* Equivalent to Go's helpers.StripHTML function
|
|
2380
|
+
* Preserves line breaks from block elements and normalizes whitespace
|
|
2381
|
+
*/
|
|
2382
|
+
stripHTML(html) {
|
|
2383
|
+
// Shortcut for strings with no HTML tags
|
|
2384
|
+
if (!html.includes('<') && !html.includes('>')) {
|
|
2385
|
+
return html;
|
|
2386
|
+
}
|
|
2387
|
+
// First pass: Replace block elements that should create line breaks
|
|
2388
|
+
let result = html
|
|
2389
|
+
.replace(/\n/g, ' ') // Convert newlines to spaces first
|
|
2390
|
+
.replace(/<\/p>/gi, '\n') // </p> creates line break
|
|
2391
|
+
.replace(/<br\s*\/?>/gi, '\n') // <br> and <br/> create line breaks
|
|
2392
|
+
.replace(/<\/div>/gi, '\n') // </div> creates line break
|
|
2393
|
+
.replace(/<\/h[1-6]>/gi, '\n') // Heading end tags create line breaks
|
|
2394
|
+
.replace(/<\/li>/gi, '\n') // List items create line breaks
|
|
2395
|
+
.replace(/<\/tr>/gi, '\n') // Table rows create line breaks
|
|
2396
|
+
.replace(/<\/blockquote>/gi, '\n'); // Blockquotes create line breaks
|
|
2397
|
+
// Second pass: Remove all HTML tags
|
|
2398
|
+
result = result.replace(/<[^>]*>/g, '');
|
|
2399
|
+
// Third pass: Normalize whitespace
|
|
2400
|
+
// Convert multiple spaces to single spaces, but preserve intentional line breaks
|
|
2401
|
+
const lines = result.split('\n');
|
|
2402
|
+
const normalizedLines = lines.map(line => line.trim().replace(/\s+/g, ' '));
|
|
2403
|
+
// Join lines back together, removing empty lines but preserving intentional breaks
|
|
2404
|
+
result = normalizedLines
|
|
2405
|
+
.filter(line => line.length > 0)
|
|
2406
|
+
.join('\n')
|
|
2407
|
+
.trim();
|
|
2408
|
+
// Final cleanup: ensure we don't have multiple consecutive newlines
|
|
2409
|
+
result = result.replace(/\n\s*\n/g, '\n');
|
|
2410
|
+
return result;
|
|
2033
2411
|
}
|
|
2034
2412
|
/**
|
|
2035
2413
|
* Unmarshal content from string based on format
|