@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anydigital/eleventy-bricks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "A collection of helpful utilities and filters for Eleventy (11ty)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
14
|
+
"test": "node --test src/**/*.test.js",
|
|
15
|
+
"prepublishOnly": "npm run test"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"11ty",
|
package/src/eleventy.config.js
CHANGED
|
@@ -4,6 +4,13 @@ import minimist from "minimist";
|
|
|
4
4
|
import { RenderPlugin } from "@11ty/eleventy";
|
|
5
5
|
import eleventyNavigationPlugin from "@11ty/eleventy-navigation";
|
|
6
6
|
import eleventyBricksPlugin from "@anydigital/eleventy-bricks";
|
|
7
|
+
/* Conditional imports */
|
|
8
|
+
let pluginTOC;
|
|
9
|
+
try {
|
|
10
|
+
pluginTOC = (await import("@uncenter/eleventy-plugin-toc")).default;
|
|
11
|
+
} catch (e) {
|
|
12
|
+
// @uncenter/eleventy-plugin-toc not installed
|
|
13
|
+
}
|
|
7
14
|
/* Libraries */
|
|
8
15
|
import markdownIt from "markdown-it";
|
|
9
16
|
import markdownItAnchor from "markdown-it-anchor";
|
|
@@ -27,10 +34,16 @@ export default function (eleventyConfig) {
|
|
|
27
34
|
eleventyConfig.addPlugin(eleventyBricksPlugin, {
|
|
28
35
|
mdAutoNl2br: true,
|
|
29
36
|
mdAutoRawTags: true,
|
|
30
|
-
|
|
37
|
+
autoLinkFavicons: true,
|
|
31
38
|
siteData: true,
|
|
32
|
-
filters: ["
|
|
39
|
+
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "fetch"],
|
|
33
40
|
});
|
|
41
|
+
if (pluginTOC) {
|
|
42
|
+
eleventyConfig.addPlugin(pluginTOC, {
|
|
43
|
+
ignoredElements: ["sub", ".header-anchor"],
|
|
44
|
+
ul: true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
34
47
|
|
|
35
48
|
/* Libraries */
|
|
36
49
|
eleventyConfig.setLibrary(
|
|
@@ -15,7 +15,7 @@ const { get } = lodash;
|
|
|
15
15
|
* @param {*} targetValue - The value to match against
|
|
16
16
|
* @returns {Array} Filtered collection
|
|
17
17
|
*/
|
|
18
|
-
export function
|
|
18
|
+
export function attrIncludes(collection, attrName, targetValue) {
|
|
19
19
|
// If no targetValue, return original collection
|
|
20
20
|
if (!targetValue) {
|
|
21
21
|
return collection;
|
|
@@ -36,10 +36,10 @@ export function whereIn(collection, attrName, targetValue) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Registers the
|
|
39
|
+
* Registers the attr_includes filter with Eleventy
|
|
40
40
|
*
|
|
41
41
|
* @param {Object} eleventyConfig - The Eleventy configuration object
|
|
42
42
|
*/
|
|
43
|
-
export function
|
|
44
|
-
eleventyConfig.addFilter("
|
|
43
|
+
export function attrIncludesFilter(eleventyConfig) {
|
|
44
|
+
eleventyConfig.addFilter("attr_includes", attrIncludes);
|
|
45
45
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { attrIncludes, attrIncludesFilter } from "./attr_includes.js";
|
|
4
|
+
|
|
5
|
+
describe("attrIncludes (core logic)", () => {
|
|
6
|
+
it("should only work with array attributes, not exact matches", () => {
|
|
7
|
+
const collection = [
|
|
8
|
+
{ category: "blog", title: "Post 1" },
|
|
9
|
+
{ category: "news", title: "Post 2" },
|
|
10
|
+
{ category: "blog", title: "Post 3" },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
// Non-array attributes are skipped
|
|
14
|
+
const result = attrIncludes(collection, "category", "blog");
|
|
15
|
+
assert.strictEqual(result.length, 0);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should filter items when attribute is an array (includes check)", () => {
|
|
19
|
+
const collection = [
|
|
20
|
+
{ tags: ["javascript", "tutorial"], title: "Post 1" },
|
|
21
|
+
{ tags: ["python", "tutorial"], title: "Post 2" },
|
|
22
|
+
{ tags: ["javascript", "advanced"], title: "Post 3" },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const result = attrIncludes(collection, "tags", "javascript");
|
|
26
|
+
assert.strictEqual(result.length, 2);
|
|
27
|
+
assert.strictEqual(result[0].title, "Post 1");
|
|
28
|
+
assert.strictEqual(result[1].title, "Post 3");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should throw error when collection is not an array", () => {
|
|
32
|
+
assert.throws(() => {
|
|
33
|
+
attrIncludes(null, "category", "blog");
|
|
34
|
+
}, TypeError);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should filter out items without array attributes", () => {
|
|
38
|
+
const collection = [
|
|
39
|
+
{ tags: ["javascript"], title: "Post 1" },
|
|
40
|
+
{ title: "Post 2" },
|
|
41
|
+
{ tags: ["javascript"], title: "Post 3" },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const result = attrIncludes(collection, "tags", "javascript");
|
|
45
|
+
assert.strictEqual(result.length, 2);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should work with array attribute directly on item (not in data)", () => {
|
|
49
|
+
const collection = [
|
|
50
|
+
{ tags: ["blog"], title: "Post 1" },
|
|
51
|
+
{ tags: ["news"], title: "Post 2" },
|
|
52
|
+
{ tags: ["blog"], title: "Post 3" },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
const result = attrIncludes(collection, "tags", "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 = attrIncludes(collection, "tags", "javascript");
|
|
66
|
+
assert.strictEqual(result.length, 0);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should handle different value types in arrays", () => {
|
|
70
|
+
const collection = [
|
|
71
|
+
{ priorities: [1, 3], title: "Post 1" },
|
|
72
|
+
{ priorities: [2, 4], title: "Post 2" },
|
|
73
|
+
{ priorities: [1, 5], title: "Post 3" },
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const result = attrIncludes(collection, "priorities", 1);
|
|
77
|
+
assert.strictEqual(result.length, 2);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should support nested array attributes with dot notation", () => {
|
|
81
|
+
const collection = [
|
|
82
|
+
{ data: { categories: ["blog"] }, title: "Post 1" },
|
|
83
|
+
{ data: { categories: ["news"] }, title: "Post 2" },
|
|
84
|
+
{ data: { categories: ["blog"] }, title: "Post 3" },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
const result = attrIncludes(collection, "data.categories", "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 = attrIncludes(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 array paths", () => {
|
|
107
|
+
const collection = [
|
|
108
|
+
{ data: { meta: { statuses: ["published"] } }, title: "Post 1" },
|
|
109
|
+
{ data: { meta: { statuses: ["draft"] } }, title: "Post 2" },
|
|
110
|
+
{ data: { meta: { statuses: ["published"] } }, title: "Post 3" },
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
const result = attrIncludes(collection, "data.meta.statuses", "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 array path does not exist", () => {
|
|
120
|
+
const collection = [{ data: { tags: ["blog"] }, title: "Post 1" }, { title: "Post 2" }];
|
|
121
|
+
|
|
122
|
+
const result = attrIncludes(collection, "data.nonexistent.path", "value");
|
|
123
|
+
assert.strictEqual(result.length, 0);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe("attrIncludesFilter (Eleventy integration)", () => {
|
|
128
|
+
it("should register the filter with eleventyConfig", () => {
|
|
129
|
+
let registeredName;
|
|
130
|
+
let registeredFn;
|
|
131
|
+
|
|
132
|
+
const mockEleventyConfig = {
|
|
133
|
+
addFilter(name, fn) {
|
|
134
|
+
registeredName = name;
|
|
135
|
+
registeredFn = fn;
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
attrIncludesFilter(mockEleventyConfig);
|
|
140
|
+
|
|
141
|
+
assert.strictEqual(registeredName, "attr_includes");
|
|
142
|
+
assert.strictEqual(typeof registeredFn, "function");
|
|
143
|
+
assert.strictEqual(registeredFn, attrIncludes);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* attr_set 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
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Core attr_set function - Override an attribute and return a new object
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} obj - The object to modify
|
|
14
|
+
* @param {string} key - The attribute name to set
|
|
15
|
+
* @param {*} value - The value to set for the attribute
|
|
16
|
+
* @returns {Object} A new object with the specified attribute set to the given value
|
|
17
|
+
*/
|
|
18
|
+
export function attrSet(obj, key, value) {
|
|
19
|
+
return {
|
|
20
|
+
...obj,
|
|
21
|
+
[key]: value,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function attrSetFilter(eleventyConfig) {
|
|
26
|
+
eleventyConfig.addFilter("attr_set", attrSet);
|
|
27
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { attrSet } from "./attr_set.js";
|
|
4
|
+
|
|
5
|
+
test("attrSet - sets a single attribute", () => {
|
|
6
|
+
const result = attrSet({ a: 1 }, "b", 2);
|
|
7
|
+
assert.deepStrictEqual(result, { a: 1, b: 2 });
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("attrSet - overrides an existing attribute", () => {
|
|
11
|
+
const result = attrSet({ a: 1, b: 2 }, "b", 3);
|
|
12
|
+
assert.deepStrictEqual(result, { a: 1, b: 3 });
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("attrSet - sets attribute on empty object", () => {
|
|
16
|
+
const result = attrSet({}, "key", "value");
|
|
17
|
+
assert.deepStrictEqual(result, { key: "value" });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("attrSet - does not modify original object", () => {
|
|
21
|
+
const original = { a: 1, b: 2 };
|
|
22
|
+
const result = attrSet(original, "c", 3);
|
|
23
|
+
|
|
24
|
+
assert.deepStrictEqual(original, { a: 1, b: 2 });
|
|
25
|
+
assert.deepStrictEqual(result, { a: 1, b: 2, c: 3 });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("attrSet - works with different value types", () => {
|
|
29
|
+
const obj = { name: "test" };
|
|
30
|
+
|
|
31
|
+
// String
|
|
32
|
+
assert.deepStrictEqual(attrSet(obj, "str", "value"), { name: "test", str: "value" });
|
|
33
|
+
|
|
34
|
+
// Number
|
|
35
|
+
assert.deepStrictEqual(attrSet(obj, "num", 42), { name: "test", num: 42 });
|
|
36
|
+
|
|
37
|
+
// Boolean
|
|
38
|
+
assert.deepStrictEqual(attrSet(obj, "bool", true), { name: "test", bool: true });
|
|
39
|
+
|
|
40
|
+
// Array
|
|
41
|
+
assert.deepStrictEqual(attrSet(obj, "arr", [1, 2, 3]), { name: "test", arr: [1, 2, 3] });
|
|
42
|
+
|
|
43
|
+
// Object
|
|
44
|
+
assert.deepStrictEqual(attrSet(obj, "nested", { x: 1 }), { name: "test", nested: { x: 1 } });
|
|
45
|
+
|
|
46
|
+
// Null
|
|
47
|
+
assert.deepStrictEqual(attrSet(obj, "nil", null), { name: "test", nil: null });
|
|
48
|
+
|
|
49
|
+
// Undefined
|
|
50
|
+
assert.deepStrictEqual(attrSet(obj, "undef", undefined), { name: "test", undef: undefined });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("attrSet - can chain multiple calls", () => {
|
|
54
|
+
const original = { a: 1 };
|
|
55
|
+
const step1 = attrSet(original, "b", 2);
|
|
56
|
+
const step2 = attrSet(step1, "c", 3);
|
|
57
|
+
const step3 = attrSet(step2, "d", 4);
|
|
58
|
+
|
|
59
|
+
assert.deepStrictEqual(original, { a: 1 });
|
|
60
|
+
assert.deepStrictEqual(step3, { a: 1, b: 2, c: 3, d: 4 });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("attrSet - handles special characters in keys", () => {
|
|
64
|
+
const result = attrSet({}, "data-id", 123);
|
|
65
|
+
assert.deepStrictEqual(result, { "data-id": 123 });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("attrSet - works with numeric keys", () => {
|
|
69
|
+
const result = attrSet({ a: 1 }, "0", "zero");
|
|
70
|
+
assert.deepStrictEqual(result, { a: 1, 0: "zero" });
|
|
71
|
+
});
|
package/src/index.cjs
CHANGED
|
@@ -5,22 +5,47 @@
|
|
|
5
5
|
|
|
6
6
|
// Dynamic import for ES modules
|
|
7
7
|
module.exports = async function eleventyBricksPlugin(eleventyConfig, options) {
|
|
8
|
-
const { default: plugin } = await import(
|
|
8
|
+
const { default: plugin } = await import("./index.js");
|
|
9
9
|
return plugin(eleventyConfig, options);
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// Export individual helpers for granular usage
|
|
13
|
-
[
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
[
|
|
14
|
+
"mdAutoRawTags",
|
|
15
|
+
"mdAutoNl2br",
|
|
16
|
+
"autoLinkFavicons",
|
|
17
|
+
"attrSetFilter",
|
|
18
|
+
"attrIncludesFilter",
|
|
19
|
+
"mergeFilter",
|
|
20
|
+
"removeTagFilter",
|
|
21
|
+
"ifFilter",
|
|
22
|
+
"attrConcatFilter",
|
|
23
|
+
"fetchFilter",
|
|
24
|
+
"siteData",
|
|
25
|
+
].forEach((name) => {
|
|
26
|
+
module.exports[name] = async (...args) => {
|
|
27
|
+
const module = await import("./index.js");
|
|
28
|
+
return module[name](...args);
|
|
17
29
|
};
|
|
18
30
|
});
|
|
19
31
|
|
|
20
32
|
// Export transform/utility functions for advanced usage
|
|
21
|
-
[
|
|
33
|
+
[
|
|
34
|
+
"transformAutoRaw",
|
|
35
|
+
"transformNl2br",
|
|
36
|
+
"isPlainUrlText",
|
|
37
|
+
"cleanLinkText",
|
|
38
|
+
"buildFaviconLink",
|
|
39
|
+
"transformLink",
|
|
40
|
+
"replaceLinksInHtml",
|
|
41
|
+
"merge",
|
|
42
|
+
"removeTag",
|
|
43
|
+
"iff",
|
|
44
|
+
"attrConcat",
|
|
45
|
+
"attrSet",
|
|
46
|
+
].forEach((name) => {
|
|
22
47
|
module.exports[name] = async (...args) => {
|
|
23
|
-
const module = await import(
|
|
48
|
+
const module = await import("./index.js");
|
|
24
49
|
return module[name](...args);
|
|
25
50
|
};
|
|
26
51
|
});
|
package/src/index.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
+
import { mdAutoRawTags, mdAutoNl2br, transformAutoRaw, transformNl2br } from "./transforms/markdown.js";
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
-
mdAutoNl2br,
|
|
4
|
-
mdAutoLinkFavicons,
|
|
5
|
-
transformAutoRaw,
|
|
6
|
-
transformNl2br,
|
|
3
|
+
autoLinkFavicons,
|
|
7
4
|
isPlainUrlText,
|
|
8
5
|
cleanLinkText,
|
|
9
6
|
buildFaviconLink,
|
|
10
7
|
transformLink,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import {
|
|
8
|
+
replaceLinksInHtml,
|
|
9
|
+
} from "./transforms/autoLinkFavicons.js";
|
|
10
|
+
import { attrSetFilter, attrSet } from "./filters/attr_set.js";
|
|
11
|
+
import { attrIncludesFilter } from "./filters/attr_includes.js";
|
|
14
12
|
import { mergeFilter, merge } from "./filters/merge.js";
|
|
15
13
|
import { removeTagFilter, removeTag } from "./filters/remove_tag.js";
|
|
16
14
|
import { ifFilter, iff } from "./filters/if.js";
|
|
@@ -37,21 +35,21 @@ try {
|
|
|
37
35
|
* @param {Object} options - Plugin options
|
|
38
36
|
* @param {boolean} options.mdAutoRawTags - Enable mdAutoRawTags preprocessor (default: false)
|
|
39
37
|
* @param {boolean} options.mdAutoNl2br - Enable mdAutoNl2br for \n to <br> conversion (default: false)
|
|
40
|
-
* @param {boolean} options.
|
|
41
|
-
* @param {Array<string>} options.filters - Array of filter names to enable: '
|
|
38
|
+
* @param {boolean} options.autoLinkFavicons - Enable autoLinkFavicons to add favicons to plain text links (default: false)
|
|
39
|
+
* @param {Array<string>} options.filters - Array of filter names to enable: 'attr_set', 'attr_includes', 'merge', 'remove_tag', 'if', 'attr_concat', 'fetch' (default: [])
|
|
42
40
|
* @param {boolean} options.siteData - Enable site.year and site.prod global data (default: false)
|
|
43
41
|
*/
|
|
44
42
|
export default function eleventyBricksPlugin(eleventyConfig, options = {}) {
|
|
45
43
|
const plugins = {
|
|
46
44
|
mdAutoRawTags,
|
|
47
45
|
mdAutoNl2br,
|
|
48
|
-
|
|
46
|
+
autoLinkFavicons,
|
|
49
47
|
siteData,
|
|
50
48
|
};
|
|
51
49
|
|
|
52
50
|
const filters = {
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
attr_set: attrSetFilter,
|
|
52
|
+
attr_includes: attrIncludesFilter,
|
|
55
53
|
merge: mergeFilter,
|
|
56
54
|
remove_tag: removeTagFilter,
|
|
57
55
|
if: ifFilter,
|
|
@@ -81,9 +79,9 @@ export default function eleventyBricksPlugin(eleventyConfig, options = {}) {
|
|
|
81
79
|
export {
|
|
82
80
|
mdAutoRawTags,
|
|
83
81
|
mdAutoNl2br,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
autoLinkFavicons,
|
|
83
|
+
attrSetFilter,
|
|
84
|
+
attrIncludesFilter,
|
|
87
85
|
mergeFilter,
|
|
88
86
|
removeTagFilter,
|
|
89
87
|
ifFilter,
|
|
@@ -100,8 +98,10 @@ export {
|
|
|
100
98
|
cleanLinkText,
|
|
101
99
|
buildFaviconLink,
|
|
102
100
|
transformLink,
|
|
101
|
+
replaceLinksInHtml,
|
|
103
102
|
merge,
|
|
104
103
|
removeTag,
|
|
105
104
|
iff,
|
|
106
105
|
attrConcat,
|
|
106
|
+
attrSet,
|
|
107
107
|
};
|
|
@@ -1,62 +1,3 @@
|
|
|
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
|
-
}
|
|
59
|
-
|
|
60
1
|
/**
|
|
61
2
|
* Check if link text looks like a plain URL or domain
|
|
62
3
|
*
|
|
@@ -157,7 +98,7 @@ export function replaceLinksInHtml(content, transformer) {
|
|
|
157
98
|
}
|
|
158
99
|
|
|
159
100
|
/**
|
|
160
|
-
*
|
|
101
|
+
* autoLinkFavicons - Add favicon images to plain text links
|
|
161
102
|
*
|
|
162
103
|
* This transform automatically adds favicon images from Google's favicon service
|
|
163
104
|
* to links that display plain URLs or domain names. It processes all HTML output
|
|
@@ -165,8 +106,8 @@ export function replaceLinksInHtml(content, transformer) {
|
|
|
165
106
|
*
|
|
166
107
|
* @param {Object} eleventyConfig - The Eleventy configuration object
|
|
167
108
|
*/
|
|
168
|
-
export function
|
|
169
|
-
eleventyConfig.addTransform("
|
|
109
|
+
export function autoLinkFavicons(eleventyConfig) {
|
|
110
|
+
eleventyConfig.addTransform("autoLinkFavicons", function (content) {
|
|
170
111
|
if (this.page.outputPath && this.page.outputPath.endsWith(".html")) {
|
|
171
112
|
return replaceLinksInHtml(content, transformLink);
|
|
172
113
|
}
|