@anydigital/eleventy-bricks 0.24.0 → 0.26.0
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/.prettierrc.json +1 -10
- package/README.md +289 -330
- package/package.json +3 -3
- package/src/eleventy.config.js +15 -2
- package/src/filters/{where_in.js → attr_includes.js} +4 -4
- package/src/filters/attr_includes.test.js +145 -0
- package/src/filters/attr_set.js +27 -0
- package/src/filters/attr_set.test.js +71 -0
- package/src/index.cjs +32 -7
- package/src/index.js +16 -16
- package/src/{markdown.js → transforms/autoLinkFavicons.js} +3 -62
- package/src/{markdown.test.js → transforms/autoLinkFavicons.test.js} +29 -161
- package/src/transforms/markdown.js +58 -0
- package/src/transforms/markdown.test.js +145 -0
- package/src/filters/attr.js +0 -16
- package/src/filters/where_in.test.js +0 -148
|
@@ -1,156 +1,12 @@
|
|
|
1
1
|
import { describe, it } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import {
|
|
4
|
-
transformAutoRaw,
|
|
5
|
-
transformNl2br,
|
|
6
4
|
isPlainUrlText,
|
|
7
5
|
cleanLinkText,
|
|
8
6
|
buildFaviconLink,
|
|
9
7
|
transformLink,
|
|
10
8
|
replaceLinksInHtml,
|
|
11
|
-
} from "./
|
|
12
|
-
|
|
13
|
-
describe("transformAutoRaw", () => {
|
|
14
|
-
it("should wrap opening double curly braces with raw tags", () => {
|
|
15
|
-
const input = "Use {{ variable }} to output.";
|
|
16
|
-
const expected = "Use {% raw %}{{{% endraw %} variable {% raw %}}}{% endraw %} to output.";
|
|
17
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("should wrap closing double curly braces with raw tags", () => {
|
|
21
|
-
const input = "{{ name }}";
|
|
22
|
-
const expected = "{% raw %}{{{% endraw %} name {% raw %}}}{% endraw %}";
|
|
23
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("should wrap opening template tags with raw tags", () => {
|
|
27
|
-
const input = "{% if condition %}";
|
|
28
|
-
const expected = "{% raw %}{%{% endraw %} if condition {% raw %}%}{% endraw %}";
|
|
29
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("should wrap closing template tags with raw tags", () => {
|
|
33
|
-
const input = "{% endif %}";
|
|
34
|
-
const expected = "{% raw %}{%{% endraw %} endif {% raw %}%}{% endraw %}";
|
|
35
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("should handle multiple Nunjucks patterns in one string", () => {
|
|
39
|
-
const input = "{{ var1 }} and {% if test %} something {% endif %}";
|
|
40
|
-
const expected =
|
|
41
|
-
"{% raw %}{{{% endraw %} var1 {% raw %}}}{% endraw %} and {% raw %}{%{% endraw %} if test {% raw %}%}{% endraw %} something {% raw %}{%{% endraw %} endif {% raw %}%}{% endraw %}";
|
|
42
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should handle multiline content with Nunjucks syntax", () => {
|
|
46
|
-
const input = `# Title
|
|
47
|
-
{{ variable }}
|
|
48
|
-
Some text
|
|
49
|
-
{% for item in items %}
|
|
50
|
-
{{ item }}
|
|
51
|
-
{% endfor %}`;
|
|
52
|
-
const expected = `# Title
|
|
53
|
-
{% raw %}{{{% endraw %} variable {% raw %}}}{% endraw %}
|
|
54
|
-
Some text
|
|
55
|
-
{% raw %}{%{% endraw %} for item in items {% raw %}%}{% endraw %}
|
|
56
|
-
{% raw %}{{{% endraw %} item {% raw %}}}{% endraw %}
|
|
57
|
-
{% raw %}{%{% endraw %} endfor {% raw %}%}{% endraw %}`;
|
|
58
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("should return unchanged content when no Nunjucks syntax is present", () => {
|
|
62
|
-
const input = "This is just plain text with no templates.";
|
|
63
|
-
assert.equal(transformAutoRaw(input), input);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("should handle empty string", () => {
|
|
67
|
-
assert.equal(transformAutoRaw(""), "");
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("should handle content with only Nunjucks syntax", () => {
|
|
71
|
-
const input = "{{}}";
|
|
72
|
-
const expected = "{% raw %}{{{% endraw %}{% raw %}}}{% endraw %}";
|
|
73
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("should handle consecutive Nunjucks patterns", () => {
|
|
77
|
-
const input = "{{{{}}}}";
|
|
78
|
-
const expected = "{% raw %}{{{% endraw %}{% raw %}{{{% endraw %}{% raw %}}}{% endraw %}{% raw %}}}{% endraw %}";
|
|
79
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("should wrap each delimiter individually", () => {
|
|
83
|
-
const input = "Show {{ and }} and {% and %}";
|
|
84
|
-
const expected =
|
|
85
|
-
"Show {% raw %}{{{% endraw %} and {% raw %}}}{% endraw %} and {% raw %}{%{% endraw %} and {% raw %}%}{% endraw %}";
|
|
86
|
-
assert.equal(transformAutoRaw(input), expected);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
describe("transformNl2br", () => {
|
|
91
|
-
it("should convert single \\n to <br>", () => {
|
|
92
|
-
const input = "Line 1\\nLine 2";
|
|
93
|
-
const expected = "Line 1<br>Line 2";
|
|
94
|
-
assert.equal(transformNl2br(input), expected);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("should convert double \\n\\n to <br>", () => {
|
|
98
|
-
const input = "Line 1\\n\\nLine 2";
|
|
99
|
-
const expected = "Line 1<br>Line 2";
|
|
100
|
-
assert.equal(transformNl2br(input), expected);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("should convert multiple \\n sequences", () => {
|
|
104
|
-
const input = "Line 1\\nLine 2\\nLine 3";
|
|
105
|
-
const expected = "Line 1<br>Line 2<br>Line 3";
|
|
106
|
-
assert.equal(transformNl2br(input), expected);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("should handle mixed single and double \\n", () => {
|
|
110
|
-
const input = "Line 1\\n\\nLine 2\\nLine 3";
|
|
111
|
-
const expected = "Line 1<br>Line 2<br>Line 3";
|
|
112
|
-
assert.equal(transformNl2br(input), expected);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("should handle text without \\n", () => {
|
|
116
|
-
const input = "Just plain text";
|
|
117
|
-
assert.equal(transformNl2br(input), input);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it("should handle empty content", () => {
|
|
121
|
-
assert.equal(transformNl2br(""), "");
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("should handle content with only \\n", () => {
|
|
125
|
-
const input = "\\n\\n\\n";
|
|
126
|
-
const expected = "<br><br>";
|
|
127
|
-
assert.equal(transformNl2br(input), expected);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it("should handle markdown table cell content with \\n", () => {
|
|
131
|
-
const input = "Cell 1\\nCell 1 Line 2\\n\\nCell 1 Line 3";
|
|
132
|
-
const expected = "Cell 1<br>Cell 1 Line 2<br>Cell 1 Line 3";
|
|
133
|
-
assert.equal(transformNl2br(input), expected);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it("should handle multiple consecutive double \\n\\n", () => {
|
|
137
|
-
const input = "Line 1\\n\\n\\n\\nLine 2";
|
|
138
|
-
const expected = "Line 1<br><br>Line 2";
|
|
139
|
-
assert.equal(transformNl2br(input), expected);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it("should preserve actual newlines (not literal \\n)", () => {
|
|
143
|
-
const input = "Line 1\nLine 2";
|
|
144
|
-
const expected = "Line 1\nLine 2";
|
|
145
|
-
assert.equal(transformNl2br(input), expected);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it("should only convert literal backslash-n sequences", () => {
|
|
149
|
-
const input = "Text with\\nbackslash-n and\nreal newline";
|
|
150
|
-
const expected = "Text with<br>backslash-n and\nreal newline";
|
|
151
|
-
assert.equal(transformNl2br(input), expected);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
9
|
+
} from "./autoLinkFavicons.js";
|
|
154
10
|
|
|
155
11
|
describe("isPlainUrlText", () => {
|
|
156
12
|
it("should return true when linkText contains domain", () => {
|
|
@@ -202,10 +58,11 @@ describe("cleanLinkText", () => {
|
|
|
202
58
|
assert.equal(cleanLinkText("example.com/docs", "example.com"), "/docs");
|
|
203
59
|
});
|
|
204
60
|
|
|
205
|
-
it("should return
|
|
206
|
-
|
|
207
|
-
assert.equal(cleanLinkText("example.com", "example.com"), "");
|
|
208
|
-
assert.equal(cleanLinkText("
|
|
61
|
+
it("should return cleaned domain for root domain (no long path)", () => {
|
|
62
|
+
// When path is too short (<=2 chars), returns cleanedText instead of withoutDomain
|
|
63
|
+
assert.equal(cleanLinkText("example.com/", "example.com"), "example.com");
|
|
64
|
+
assert.equal(cleanLinkText("example.com", "example.com"), "example.com");
|
|
65
|
+
assert.equal(cleanLinkText("https://example.com", "example.com"), "example.com");
|
|
209
66
|
});
|
|
210
67
|
|
|
211
68
|
it("should handle whitespace", () => {
|
|
@@ -283,15 +140,16 @@ describe("transformLink", () => {
|
|
|
283
140
|
);
|
|
284
141
|
});
|
|
285
142
|
|
|
286
|
-
it("should
|
|
287
|
-
|
|
143
|
+
it("should transform links with short paths (shows domain)", () => {
|
|
144
|
+
// When path is short (<=2 chars), cleanLinkText returns cleanedText (with domain)
|
|
145
|
+
// The link still gets transformed and shows the domain
|
|
288
146
|
const result = transformLink(
|
|
289
|
-
|
|
147
|
+
'<a href="https://example.com/a">https://example.com/a</a>',
|
|
290
148
|
'href="https://example.com/a"',
|
|
291
149
|
"https://example.com/a",
|
|
292
150
|
"https://example.com/a",
|
|
293
151
|
);
|
|
294
|
-
assert.
|
|
152
|
+
assert.match(result, /<i><img[^>]*><\/i><span>example\.com\/a<\/span>/);
|
|
295
153
|
});
|
|
296
154
|
|
|
297
155
|
it("should not transform custom link text without URL", () => {
|
|
@@ -300,16 +158,26 @@ describe("transformLink", () => {
|
|
|
300
158
|
assert.equal(result, match);
|
|
301
159
|
});
|
|
302
160
|
|
|
303
|
-
it("should
|
|
304
|
-
|
|
305
|
-
const result = transformLink(
|
|
306
|
-
|
|
161
|
+
it("should transform root domain links (shows domain)", () => {
|
|
162
|
+
// Root domains are transformed and display the domain name
|
|
163
|
+
const result = transformLink(
|
|
164
|
+
'<a href="https://example.com">example.com</a>',
|
|
165
|
+
'href="https://example.com"',
|
|
166
|
+
"https://example.com",
|
|
167
|
+
"example.com",
|
|
168
|
+
);
|
|
169
|
+
assert.match(result, /<i><img[^>]*><\/i><span>example\.com<\/span>/);
|
|
307
170
|
});
|
|
308
171
|
|
|
309
|
-
it("should
|
|
310
|
-
|
|
311
|
-
const result = transformLink(
|
|
312
|
-
|
|
172
|
+
it("should transform links ending with slash only (shows domain)", () => {
|
|
173
|
+
// Links with trailing slash are transformed and display the domain name
|
|
174
|
+
const result = transformLink(
|
|
175
|
+
'<a href="https://example.com/">https://example.com/</a>',
|
|
176
|
+
'href="https://example.com/"',
|
|
177
|
+
"https://example.com/",
|
|
178
|
+
"https://example.com/",
|
|
179
|
+
);
|
|
180
|
+
assert.match(result, /<i><img[^>]*><\/i><span>example\.com<\/span>/);
|
|
313
181
|
});
|
|
314
182
|
|
|
315
183
|
it("should handle invalid URLs gracefully", () => {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform Nunjucks syntax in content by wrapping it with raw tags
|
|
3
|
+
*
|
|
4
|
+
* This function wraps Nunjucks syntax ({{, }}, {%, %}) with {% raw %} tags
|
|
5
|
+
* to prevent them from being processed by the template engine.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} content - The content to transform
|
|
8
|
+
* @returns {string} The transformed content with Nunjucks syntax wrapped
|
|
9
|
+
*/
|
|
10
|
+
export function transformAutoRaw(content) {
|
|
11
|
+
// This regex looks for {{, }}, {%, or %} individually and wraps them
|
|
12
|
+
return content.replace(/({{|}}|{%|%})/g, "{% raw %}$1{% endraw %}");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* mdAutoRawTags - Forbid Nunjucks processing in Markdown files
|
|
17
|
+
*
|
|
18
|
+
* This preprocessor wraps Nunjucks syntax ({{, }}, {%, %}) with {% raw %} tags
|
|
19
|
+
* to prevent them from being processed by the template engine in Markdown files.
|
|
20
|
+
*
|
|
21
|
+
* @param {Object} eleventyConfig - The Eleventy configuration object
|
|
22
|
+
*/
|
|
23
|
+
export function mdAutoRawTags(eleventyConfig) {
|
|
24
|
+
eleventyConfig.addPreprocessor("mdAutoRawTags", "md", (data, content) => {
|
|
25
|
+
return transformAutoRaw(content);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Transform \n sequences to <br> tags
|
|
31
|
+
*
|
|
32
|
+
* This function converts literal \n sequences (double backslash + n) to HTML <br> tags.
|
|
33
|
+
* It handles both double \n\n and single \n sequences, processing double ones first.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} content - The content to transform
|
|
36
|
+
* @returns {string} The transformed content with \n converted to <br>
|
|
37
|
+
*/
|
|
38
|
+
export function transformNl2br(content) {
|
|
39
|
+
// Replace double \n\n first, then single \n to avoid double conversion
|
|
40
|
+
return content.replace(/\\n\\n/g, "<br>").replace(/\\n/g, "<br>");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* mdAutoNl2br - Auto convert \\n to <br> in markdown (especially tables)
|
|
45
|
+
*
|
|
46
|
+
* This function amends the markdown library to automatically convert \\n
|
|
47
|
+
* to <br> tags in text content, which is particularly useful for line breaks
|
|
48
|
+
* inside markdown tables where standard newlines don't work.
|
|
49
|
+
*
|
|
50
|
+
* @param {Object} eleventyConfig - The Eleventy configuration object
|
|
51
|
+
*/
|
|
52
|
+
export function mdAutoNl2br(eleventyConfig) {
|
|
53
|
+
eleventyConfig.amendLibrary("md", (mdLib) => {
|
|
54
|
+
mdLib.renderer.rules.text = (tokens, idx) => {
|
|
55
|
+
return transformNl2br(tokens[idx].content);
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { transformAutoRaw, transformNl2br } from "./markdown.js";
|
|
4
|
+
|
|
5
|
+
describe("transformAutoRaw", () => {
|
|
6
|
+
it("should wrap opening double curly braces with raw tags", () => {
|
|
7
|
+
const input = "Use {{ variable }} to output.";
|
|
8
|
+
const expected = "Use {% raw %}{{{% endraw %} variable {% raw %}}}{% endraw %} to output.";
|
|
9
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should wrap closing double curly braces with raw tags", () => {
|
|
13
|
+
const input = "{{ name }}";
|
|
14
|
+
const expected = "{% raw %}{{{% endraw %} name {% raw %}}}{% endraw %}";
|
|
15
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should wrap opening template tags with raw tags", () => {
|
|
19
|
+
const input = "{% if condition %}";
|
|
20
|
+
const expected = "{% raw %}{%{% endraw %} if condition {% raw %}%}{% endraw %}";
|
|
21
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should wrap closing template tags with raw tags", () => {
|
|
25
|
+
const input = "{% endif %}";
|
|
26
|
+
const expected = "{% raw %}{%{% endraw %} endif {% raw %}%}{% endraw %}";
|
|
27
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should handle multiple Nunjucks patterns in one string", () => {
|
|
31
|
+
const input = "{{ var1 }} and {% if test %} something {% endif %}";
|
|
32
|
+
const expected =
|
|
33
|
+
"{% raw %}{{{% endraw %} var1 {% raw %}}}{% endraw %} and {% raw %}{%{% endraw %} if test {% raw %}%}{% endraw %} something {% raw %}{%{% endraw %} endif {% raw %}%}{% endraw %}";
|
|
34
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should handle multiline content with Nunjucks syntax", () => {
|
|
38
|
+
const input = `# Title
|
|
39
|
+
{{ variable }}
|
|
40
|
+
Some text
|
|
41
|
+
{% for item in items %}
|
|
42
|
+
{{ item }}
|
|
43
|
+
{% endfor %}`;
|
|
44
|
+
const expected = `# Title
|
|
45
|
+
{% raw %}{{{% endraw %} variable {% raw %}}}{% endraw %}
|
|
46
|
+
Some text
|
|
47
|
+
{% raw %}{%{% endraw %} for item in items {% raw %}%}{% endraw %}
|
|
48
|
+
{% raw %}{{{% endraw %} item {% raw %}}}{% endraw %}
|
|
49
|
+
{% raw %}{%{% endraw %} endfor {% raw %}%}{% endraw %}`;
|
|
50
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should return unchanged content when no Nunjucks syntax is present", () => {
|
|
54
|
+
const input = "This is just plain text with no templates.";
|
|
55
|
+
assert.equal(transformAutoRaw(input), input);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should handle empty string", () => {
|
|
59
|
+
assert.equal(transformAutoRaw(""), "");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should handle content with only Nunjucks syntax", () => {
|
|
63
|
+
const input = "{{}}";
|
|
64
|
+
const expected = "{% raw %}{{{% endraw %}{% raw %}}}{% endraw %}";
|
|
65
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should handle consecutive Nunjucks patterns", () => {
|
|
69
|
+
const input = "{{{{}}}}";
|
|
70
|
+
const expected = "{% raw %}{{{% endraw %}{% raw %}{{{% endraw %}{% raw %}}}{% endraw %}{% raw %}}}{% endraw %}";
|
|
71
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should wrap each delimiter individually", () => {
|
|
75
|
+
const input = "Show {{ and }} and {% and %}";
|
|
76
|
+
const expected =
|
|
77
|
+
"Show {% raw %}{{{% endraw %} and {% raw %}}}{% endraw %} and {% raw %}{%{% endraw %} and {% raw %}%}{% endraw %}";
|
|
78
|
+
assert.equal(transformAutoRaw(input), expected);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("transformNl2br", () => {
|
|
83
|
+
it("should convert single \\n to <br>", () => {
|
|
84
|
+
const input = "Line 1\\nLine 2";
|
|
85
|
+
const expected = "Line 1<br>Line 2";
|
|
86
|
+
assert.equal(transformNl2br(input), expected);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should convert double \\n\\n to <br>", () => {
|
|
90
|
+
const input = "Line 1\\n\\nLine 2";
|
|
91
|
+
const expected = "Line 1<br>Line 2";
|
|
92
|
+
assert.equal(transformNl2br(input), expected);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should convert multiple \\n sequences", () => {
|
|
96
|
+
const input = "Line 1\\nLine 2\\nLine 3";
|
|
97
|
+
const expected = "Line 1<br>Line 2<br>Line 3";
|
|
98
|
+
assert.equal(transformNl2br(input), expected);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should handle mixed single and double \\n", () => {
|
|
102
|
+
const input = "Line 1\\n\\nLine 2\\nLine 3";
|
|
103
|
+
const expected = "Line 1<br>Line 2<br>Line 3";
|
|
104
|
+
assert.equal(transformNl2br(input), expected);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should handle text without \\n", () => {
|
|
108
|
+
const input = "Just plain text";
|
|
109
|
+
assert.equal(transformNl2br(input), input);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should handle empty content", () => {
|
|
113
|
+
assert.equal(transformNl2br(""), "");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should handle content with only \\n", () => {
|
|
117
|
+
const input = "\\n\\n\\n";
|
|
118
|
+
const expected = "<br><br>";
|
|
119
|
+
assert.equal(transformNl2br(input), expected);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should handle markdown table cell content with \\n", () => {
|
|
123
|
+
const input = "Cell 1\\nCell 1 Line 2\\n\\nCell 1 Line 3";
|
|
124
|
+
const expected = "Cell 1<br>Cell 1 Line 2<br>Cell 1 Line 3";
|
|
125
|
+
assert.equal(transformNl2br(input), expected);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should handle multiple consecutive double \\n\\n", () => {
|
|
129
|
+
const input = "Line 1\\n\\n\\n\\nLine 2";
|
|
130
|
+
const expected = "Line 1<br><br>Line 2";
|
|
131
|
+
assert.equal(transformNl2br(input), expected);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should preserve actual newlines (not literal \\n)", () => {
|
|
135
|
+
const input = "Line 1\nLine 2";
|
|
136
|
+
const expected = "Line 1\nLine 2";
|
|
137
|
+
assert.equal(transformNl2br(input), expected);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should only convert literal backslash-n sequences", () => {
|
|
141
|
+
const input = "Text with\\nbackslash-n and\nreal newline";
|
|
142
|
+
const expected = "Text with<br>backslash-n and\nreal newline";
|
|
143
|
+
assert.equal(transformNl2br(input), expected);
|
|
144
|
+
});
|
|
145
|
+
});
|
package/src/filters/attr.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* attr filter - Override an attribute and return the object
|
|
3
|
-
*
|
|
4
|
-
* This filter takes an object, a key, and a value, and returns a new object
|
|
5
|
-
* with the specified attribute set to the given value.
|
|
6
|
-
*
|
|
7
|
-
* @param {Object} eleventyConfig - The Eleventy configuration object
|
|
8
|
-
*/
|
|
9
|
-
export function setAttrFilter(eleventyConfig) {
|
|
10
|
-
eleventyConfig.addFilter("attr", function (obj, key, value) {
|
|
11
|
-
return {
|
|
12
|
-
...obj,
|
|
13
|
-
[key]: value,
|
|
14
|
-
};
|
|
15
|
-
});
|
|
16
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
3
|
-
import { whereIn, whereInFilter } from "./where_in.js";
|
|
4
|
-
|
|
5
|
-
describe("whereIn (core logic)", () => {
|
|
6
|
-
it("should filter items by exact attribute match", () => {
|
|
7
|
-
const collection = [
|
|
8
|
-
{ category: "blog", title: "Post 1" },
|
|
9
|
-
{ category: "news", title: "Post 2" },
|
|
10
|
-
{ category: "blog", title: "Post 3" },
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
const result = whereIn(collection, "category", "blog");
|
|
14
|
-
assert.strictEqual(result.length, 2);
|
|
15
|
-
assert.strictEqual(result[0].title, "Post 1");
|
|
16
|
-
assert.strictEqual(result[1].title, "Post 3");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("should filter items when attribute is an array (includes check)", () => {
|
|
20
|
-
const collection = [
|
|
21
|
-
{ tags: ["javascript", "tutorial"], title: "Post 1" },
|
|
22
|
-
{ tags: ["python", "tutorial"], title: "Post 2" },
|
|
23
|
-
{ tags: ["javascript", "advanced"], title: "Post 3" },
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
const result = whereIn(collection, "tags", "javascript");
|
|
27
|
-
assert.strictEqual(result.length, 2);
|
|
28
|
-
assert.strictEqual(result[0].title, "Post 1");
|
|
29
|
-
assert.strictEqual(result[1].title, "Post 3");
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("should return empty array when collection is not an array", () => {
|
|
33
|
-
const result = whereIn(null, "category", "blog");
|
|
34
|
-
assert.strictEqual(result.length, 0);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("should filter out items without the specified attribute", () => {
|
|
38
|
-
const collection = [
|
|
39
|
-
{ category: "blog", title: "Post 1" },
|
|
40
|
-
{ title: "Post 2" },
|
|
41
|
-
{ category: "blog", title: "Post 3" },
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
const result = whereIn(collection, "category", "blog");
|
|
45
|
-
assert.strictEqual(result.length, 2);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("should work with attribute directly on item (not in data)", () => {
|
|
49
|
-
const collection = [
|
|
50
|
-
{ category: "blog", title: "Post 1" },
|
|
51
|
-
{ category: "news", title: "Post 2" },
|
|
52
|
-
{ category: "blog", title: "Post 3" },
|
|
53
|
-
];
|
|
54
|
-
|
|
55
|
-
const result = whereIn(collection, "category", "blog");
|
|
56
|
-
assert.strictEqual(result.length, 2);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("should handle array that does not include target value", () => {
|
|
60
|
-
const collection = [
|
|
61
|
-
{ tags: ["python", "tutorial"], title: "Post 1" },
|
|
62
|
-
{ tags: ["ruby", "guide"], title: "Post 2" },
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
const result = whereIn(collection, "tags", "javascript");
|
|
66
|
-
assert.strictEqual(result.length, 0);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("should handle different value types", () => {
|
|
70
|
-
const collection = [
|
|
71
|
-
{ priority: 1, title: "Post 1" },
|
|
72
|
-
{ priority: 2, title: "Post 2" },
|
|
73
|
-
{ priority: 1, title: "Post 3" },
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
const result = whereIn(collection, "priority", 1);
|
|
77
|
-
assert.strictEqual(result.length, 2);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("should support nested attribute names with dot notation", () => {
|
|
81
|
-
const collection = [
|
|
82
|
-
{ data: { category: "blog" }, title: "Post 1" },
|
|
83
|
-
{ data: { category: "news" }, title: "Post 2" },
|
|
84
|
-
{ data: { category: "blog" }, title: "Post 3" },
|
|
85
|
-
];
|
|
86
|
-
|
|
87
|
-
const result = whereIn(collection, "data.category", "blog");
|
|
88
|
-
assert.strictEqual(result.length, 2);
|
|
89
|
-
assert.strictEqual(result[0].title, "Post 1");
|
|
90
|
-
assert.strictEqual(result[1].title, "Post 3");
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("should support nested arrays with dot notation", () => {
|
|
94
|
-
const collection = [
|
|
95
|
-
{ data: { tags: ["javascript", "tutorial"] }, title: "Post 1" },
|
|
96
|
-
{ data: { tags: ["python", "tutorial"] }, title: "Post 2" },
|
|
97
|
-
{ data: { tags: ["javascript", "advanced"] }, title: "Post 3" },
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
const result = whereIn(collection, "data.tags", "javascript");
|
|
101
|
-
assert.strictEqual(result.length, 2);
|
|
102
|
-
assert.strictEqual(result[0].title, "Post 1");
|
|
103
|
-
assert.strictEqual(result[1].title, "Post 3");
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it("should handle deeply nested paths", () => {
|
|
107
|
-
const collection = [
|
|
108
|
-
{ data: { meta: { status: "published" } }, title: "Post 1" },
|
|
109
|
-
{ data: { meta: { status: "draft" } }, title: "Post 2" },
|
|
110
|
-
{ data: { meta: { status: "published" } }, title: "Post 3" },
|
|
111
|
-
];
|
|
112
|
-
|
|
113
|
-
const result = whereIn(collection, "data.meta.status", "published");
|
|
114
|
-
assert.strictEqual(result.length, 2);
|
|
115
|
-
assert.strictEqual(result[0].title, "Post 1");
|
|
116
|
-
assert.strictEqual(result[1].title, "Post 3");
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it("should return empty array when nested path does not exist", () => {
|
|
120
|
-
const collection = [
|
|
121
|
-
{ data: { category: "blog" }, title: "Post 1" },
|
|
122
|
-
{ title: "Post 2" },
|
|
123
|
-
];
|
|
124
|
-
|
|
125
|
-
const result = whereIn(collection, "data.nonexistent.path", "value");
|
|
126
|
-
assert.strictEqual(result.length, 0);
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
describe("whereInFilter (Eleventy integration)", () => {
|
|
131
|
-
it("should register the filter with eleventyConfig", () => {
|
|
132
|
-
let registeredName;
|
|
133
|
-
let registeredFn;
|
|
134
|
-
|
|
135
|
-
const mockEleventyConfig = {
|
|
136
|
-
addFilter(name, fn) {
|
|
137
|
-
registeredName = name;
|
|
138
|
-
registeredFn = fn;
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
whereInFilter(mockEleventyConfig);
|
|
143
|
-
|
|
144
|
-
assert.strictEqual(registeredName, "where_in");
|
|
145
|
-
assert.strictEqual(typeof registeredFn, "function");
|
|
146
|
-
assert.strictEqual(registeredFn, whereIn);
|
|
147
|
-
});
|
|
148
|
-
});
|