@anydigital/eleventy-bricks 0.26.0 → 0.27.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/README.md +110 -4
- package/examples/section-filter.md +96 -0
- package/package.json +1 -1
- package/src/eleventy.config.js +1 -1
- package/src/filters/section.js +62 -0
- package/src/filters/section.test.js +174 -0
- package/src/index.js +5 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ export default function (eleventyConfig) {
|
|
|
27
27
|
mdAutoNl2br: true,
|
|
28
28
|
autoLinkFavicons: true,
|
|
29
29
|
siteData: true,
|
|
30
|
-
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "fetch"],
|
|
30
|
+
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "section", "fetch"],
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
// Your other configuration...
|
|
@@ -45,7 +45,7 @@ module.exports = function (eleventyConfig) {
|
|
|
45
45
|
mdAutoNl2br: true,
|
|
46
46
|
autoLinkFavicons: true,
|
|
47
47
|
siteData: true,
|
|
48
|
-
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "fetch"],
|
|
48
|
+
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "section", "fetch"],
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
// Your other configuration...
|
|
@@ -71,6 +71,7 @@ import {
|
|
|
71
71
|
removeTagFilter,
|
|
72
72
|
ifFilter,
|
|
73
73
|
attrConcatFilter,
|
|
74
|
+
sectionFilter,
|
|
74
75
|
fetchFilter,
|
|
75
76
|
siteData,
|
|
76
77
|
} from "@anydigital/eleventy-bricks";
|
|
@@ -85,6 +86,7 @@ export default function (eleventyConfig) {
|
|
|
85
86
|
removeTagFilter(eleventyConfig);
|
|
86
87
|
ifFilter(eleventyConfig);
|
|
87
88
|
attrConcatFilter(eleventyConfig);
|
|
89
|
+
sectionFilter(eleventyConfig);
|
|
88
90
|
// fetchFilter is only available if @11ty/eleventy-fetch is installed
|
|
89
91
|
if (fetchFilter) {
|
|
90
92
|
fetchFilter(eleventyConfig);
|
|
@@ -108,6 +110,7 @@ const {
|
|
|
108
110
|
removeTagFilter,
|
|
109
111
|
ifFilter,
|
|
110
112
|
attrConcatFilter,
|
|
113
|
+
sectionFilter,
|
|
111
114
|
fetchFilter,
|
|
112
115
|
siteData,
|
|
113
116
|
} = require("@anydigital/eleventy-bricks");
|
|
@@ -122,6 +125,7 @@ module.exports = async function (eleventyConfig) {
|
|
|
122
125
|
await removeTagFilter(eleventyConfig);
|
|
123
126
|
await ifFilter(eleventyConfig);
|
|
124
127
|
await attrConcatFilter(eleventyConfig);
|
|
128
|
+
await sectionFilter(eleventyConfig);
|
|
125
129
|
// fetchFilter is only available if @11ty/eleventy-fetch is installed
|
|
126
130
|
if (fetchFilter) {
|
|
127
131
|
await fetchFilter(eleventyConfig);
|
|
@@ -154,6 +158,7 @@ When using the plugin (Option 1), you can configure which helpers to enable:
|
|
|
154
158
|
- `'remove_tag'` - Remove HTML elements from content
|
|
155
159
|
- `'if'` - Inline conditional/ternary operator
|
|
156
160
|
- `'attr_concat'` - Concatenate values to an attribute array
|
|
161
|
+
- `'section'` - Extract named sections from content marked with HTML comments
|
|
157
162
|
- `'fetch'` - Fetch remote URLs or local files (requires `@11ty/eleventy-fetch`)
|
|
158
163
|
|
|
159
164
|
**Example:**
|
|
@@ -164,7 +169,7 @@ eleventyConfig.addPlugin(eleventyBricks, {
|
|
|
164
169
|
mdAutoNl2br: true,
|
|
165
170
|
autoLinkFavicons: true,
|
|
166
171
|
siteData: true,
|
|
167
|
-
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "fetch"],
|
|
172
|
+
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "section", "fetch"],
|
|
168
173
|
});
|
|
169
174
|
```
|
|
170
175
|
|
|
@@ -185,8 +190,9 @@ The plugin also exports the following utility functions for advanced usage:
|
|
|
185
190
|
- `iff(trueValue, condition, falseValue)`: The core conditional function used by the `if` filter. Can be used programmatically as a ternary operator.
|
|
186
191
|
- `attrConcat(obj, attr, values)`: The core function used by the `attr_concat` filter. Can be used programmatically to concatenate values to an attribute array.
|
|
187
192
|
- `attrSet(obj, key, value)`: The core function used by the `attr_set` filter. Can be used programmatically to override object attributes.
|
|
193
|
+
- `section(content, sectionName)`: The core function used by the `section` filter. Can be used programmatically to extract named sections from content.
|
|
188
194
|
|
|
189
|
-
<!--
|
|
195
|
+
<!--section:11ty-->
|
|
190
196
|
|
|
191
197
|
## Tricks from [Eleventy Bricks](https://github.com/anydigital/eleventy-bricks) {#eleventy-bricks}
|
|
192
198
|
|
|
@@ -208,6 +214,7 @@ The plugin also exports the following utility functions for advanced usage:
|
|
|
208
214
|
| {.divider} | Textual |
|
|
209
215
|
| `HTML \|` | `striptags` | `strip_html` |
|
|
210
216
|
| `HTML \|` | [`remove_tag(TAG)`](#remove_tag) | [`remove_tag: TAG`](#remove_tag) |
|
|
217
|
+
| `HTML \|` | [`section(NAME)`](#section) | [`section: NAME`](#section) |
|
|
211
218
|
| `STR \|` | `remove: STR2` | `remove: STR2` |
|
|
212
219
|
| {.divider} | Other |
|
|
213
220
|
| `URL \|` | [`fetch`](#fetch) | [`fetch`](#fetch) |
|
|
@@ -520,6 +527,103 @@ export default function (eleventyConfig) {
|
|
|
520
527
|
|
|
521
528
|
While this filter can help sanitize HTML content, it should not be relied upon as the sole security measure. For critical security requirements, use a dedicated HTML sanitization library on the server side before content reaches your templates.
|
|
522
529
|
|
|
530
|
+
#### `section`
|
|
531
|
+
|
|
532
|
+
A filter that extracts a named section from content marked with HTML comments. This is useful for splitting a single content file (like a Markdown post) into multiple parts that can be displayed and styled independently in your templates.
|
|
533
|
+
|
|
534
|
+
**Why use this?**
|
|
535
|
+
|
|
536
|
+
When working with Markdown content in Eleventy, you're usually limited to a single `content` variable. The `section` filter allows you to define multiple named sections within your content using simple HTML comments, giving you granular control over where different parts of your content appear in your layout.
|
|
537
|
+
|
|
538
|
+
**Usage:**
|
|
539
|
+
|
|
540
|
+
1. Enable the `section` filter in your Eleventy config:
|
|
541
|
+
|
|
542
|
+
```javascript
|
|
543
|
+
import { sectionFilter } from "@anydigital/eleventy-bricks";
|
|
544
|
+
|
|
545
|
+
export default function (eleventyConfig) {
|
|
546
|
+
sectionFilter(eleventyConfig);
|
|
547
|
+
// Or use as plugin:
|
|
548
|
+
// eleventyConfig.addPlugin(eleventyBricks, { filters: ['section'] });
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
2. Mark sections in your content file (e.g., `post.md`):
|
|
553
|
+
|
|
554
|
+
```markdown
|
|
555
|
+
# My Post
|
|
556
|
+
|
|
557
|
+
<!--section:intro-->
|
|
558
|
+
|
|
559
|
+
This is the introduction that appears at the top of the page.
|
|
560
|
+
|
|
561
|
+
<!--section:main-->
|
|
562
|
+
|
|
563
|
+
This is the main body of the post with all the details.
|
|
564
|
+
|
|
565
|
+
<!--section:summary,sidebar-->
|
|
566
|
+
|
|
567
|
+
This content appears in both the summary and the sidebar!
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
3. Use the filter in your templates:
|
|
571
|
+
|
|
572
|
+
```njk
|
|
573
|
+
{# Get the intro section #}
|
|
574
|
+
<div class="page-intro">
|
|
575
|
+
{{ content | section('intro') | safe }}
|
|
576
|
+
</div>
|
|
577
|
+
|
|
578
|
+
{# Get the main section #}
|
|
579
|
+
<article>
|
|
580
|
+
{{ content | section('main') | safe }}
|
|
581
|
+
</article>
|
|
582
|
+
|
|
583
|
+
{# Get the sidebar section #}
|
|
584
|
+
<aside>
|
|
585
|
+
{{ content | section('sidebar') | safe }}
|
|
586
|
+
</aside>
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
**Parameters:**
|
|
590
|
+
|
|
591
|
+
- `content`: The string content to process (usually `content` variable)
|
|
592
|
+
- `sectionName`: The name(s) of the section to extract (string)
|
|
593
|
+
|
|
594
|
+
**Features:**
|
|
595
|
+
|
|
596
|
+
- **Multiple names**: A single section can have multiple names separated by commas: `<!--section:name1,name2-->`
|
|
597
|
+
- **Case-insensitive**: Section names are matched without regard to case
|
|
598
|
+
- **Multiple occurrences**: If a section name appears multiple times, the filter concatenates all matching sections
|
|
599
|
+
- **Non-destructive**: Returns extracted content without modifying the original input
|
|
600
|
+
- **EOF support**: Sections continue until the next `<!--section*-->` marker or the end of the file
|
|
601
|
+
|
|
602
|
+
**Examples:**
|
|
603
|
+
|
|
604
|
+
```njk
|
|
605
|
+
{# Extract multiple sections with same name #}
|
|
606
|
+
{# Example content has two <!--section:note--> blocks #}
|
|
607
|
+
<div class="notes-box">
|
|
608
|
+
{{ content | section('note') | safe }}
|
|
609
|
+
</div>
|
|
610
|
+
|
|
611
|
+
{# Use case-insensitive names #}
|
|
612
|
+
{{ content | section('INTRO') | safe }}
|
|
613
|
+
|
|
614
|
+
{# Handle missing sections gracefully (returns empty string) #}
|
|
615
|
+
{% set footer = content | section('non-existent-section') %}
|
|
616
|
+
{% if footer %}
|
|
617
|
+
<footer>{{ footer | safe }}</footer>
|
|
618
|
+
{% endif %}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**Syntax Rules:**
|
|
622
|
+
|
|
623
|
+
- Sections start with: `<!--section:NAME-->` or `<!--section:NAME1,NAME2-->`
|
|
624
|
+
- Sections end at the next `<!--section*-->` marker or end of file
|
|
625
|
+
- Whitespace around names and inside comments is automatically trimmed
|
|
626
|
+
|
|
523
627
|
#### `if`
|
|
524
628
|
|
|
525
629
|
An inline conditional/ternary operator filter that returns one value if a condition is truthy, and another if it's falsy. Similar to Nunjucks' inline if syntax.
|
|
@@ -1101,6 +1205,8 @@ mkdir -p admin
|
|
|
1101
1205
|
ln -s ../node_modules/@anydigital/eleventy-bricks/src/admin/index.html admin/index.html
|
|
1102
1206
|
```
|
|
1103
1207
|
|
|
1208
|
+
<!--section:npm,11ty-->
|
|
1209
|
+
|
|
1104
1210
|
### Using the `do` Folder Pattern
|
|
1105
1211
|
|
|
1106
1212
|
This package provides a pre-configured `do` folder setup that helps organize your development workflow using npm workspaces. The `do` folder contains scripts for building and running your Eleventy project.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Section Filter Examples
|
|
2
|
+
|
|
3
|
+
## Basic Usage
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
<!--section:intro-->
|
|
7
|
+
|
|
8
|
+
This is the introduction section.
|
|
9
|
+
|
|
10
|
+
<!--section:main-->
|
|
11
|
+
|
|
12
|
+
This is the main content.
|
|
13
|
+
|
|
14
|
+
<!--section:footer-->
|
|
15
|
+
|
|
16
|
+
This is the footer.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
In your template:
|
|
20
|
+
|
|
21
|
+
```nunjucks
|
|
22
|
+
{{ content | section('intro') }}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Output:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
This is the introduction section.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Multiple Names per Section
|
|
32
|
+
|
|
33
|
+
```markdown
|
|
34
|
+
<!--section:summary,abstract-->
|
|
35
|
+
|
|
36
|
+
This content appears in both 'summary' and 'abstract' sections.
|
|
37
|
+
|
|
38
|
+
<!--section:conclusion-->
|
|
39
|
+
|
|
40
|
+
Final thoughts.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Both of these work:
|
|
44
|
+
|
|
45
|
+
```nunjucks
|
|
46
|
+
{{ content | section('summary') }}
|
|
47
|
+
{{ content | section('abstract') }}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Real-World Example
|
|
51
|
+
|
|
52
|
+
```markdown
|
|
53
|
+
# Research Paper
|
|
54
|
+
|
|
55
|
+
<!--section:abstract,summary-->
|
|
56
|
+
|
|
57
|
+
A brief overview of the research findings.
|
|
58
|
+
|
|
59
|
+
<!--section:introduction-->
|
|
60
|
+
|
|
61
|
+
Background and context for the research.
|
|
62
|
+
|
|
63
|
+
<!--section:methodology-->
|
|
64
|
+
|
|
65
|
+
How the research was conducted.
|
|
66
|
+
|
|
67
|
+
<!--section:results-->
|
|
68
|
+
|
|
69
|
+
Key findings from the study.
|
|
70
|
+
|
|
71
|
+
<!--section:conclusion,summary-->
|
|
72
|
+
|
|
73
|
+
Summary and implications of the research.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Usage:
|
|
77
|
+
|
|
78
|
+
```nunjucks
|
|
79
|
+
<!-- Get full summary (abstract + conclusion) -->
|
|
80
|
+
<div class="summary">
|
|
81
|
+
{{ content | section('summary') }}
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<!-- Get just introduction -->
|
|
85
|
+
<div class="intro">
|
|
86
|
+
{{ content | section('introduction') }}
|
|
87
|
+
</div>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Notes
|
|
91
|
+
|
|
92
|
+
- Section names are **case-insensitive**: `intro`, `INTRO`, and `Intro` are all the same
|
|
93
|
+
- Multiple names can be comma-separated: `<!--section:name1,name2,name3-->`
|
|
94
|
+
- Whitespace around names is trimmed
|
|
95
|
+
- Content extends from the section marker to the next `<!--section*>` or EOF
|
|
96
|
+
- If a section name appears multiple times, all matching sections are concatenated
|
package/package.json
CHANGED
package/src/eleventy.config.js
CHANGED
|
@@ -36,7 +36,7 @@ export default function (eleventyConfig) {
|
|
|
36
36
|
mdAutoRawTags: true,
|
|
37
37
|
autoLinkFavicons: true,
|
|
38
38
|
siteData: true,
|
|
39
|
-
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "fetch"],
|
|
39
|
+
filters: ["attr_set", "attr_includes", "merge", "remove_tag", "if", "attr_concat", "fetch", "section"],
|
|
40
40
|
});
|
|
41
41
|
if (pluginTOC) {
|
|
42
42
|
eleventyConfig.addPlugin(pluginTOC, {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract a named section from content marked with HTML comments
|
|
3
|
+
*
|
|
4
|
+
* @param {string} content - The content to process
|
|
5
|
+
* @param {string} sectionName - The section name(s) to extract
|
|
6
|
+
* @returns {string} The extracted section content
|
|
7
|
+
*/
|
|
8
|
+
export function section(content, sectionName) {
|
|
9
|
+
if (!content || typeof content !== "string") {
|
|
10
|
+
return content;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (typeof sectionName !== "string" || !sectionName) {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Normalize section name for comparison (trim whitespace)
|
|
18
|
+
const targetName = sectionName.trim().toLowerCase();
|
|
19
|
+
|
|
20
|
+
// Regex to match section markers with content up to the next section or end of string
|
|
21
|
+
// Captures: (1) section names, (2) content until next section marker or end
|
|
22
|
+
const sectionRegex = /<!--section:([^>]+)-->([\s\S]*?)(?=<!--section|$)/g;
|
|
23
|
+
|
|
24
|
+
let results = [];
|
|
25
|
+
let match;
|
|
26
|
+
|
|
27
|
+
// Find all sections
|
|
28
|
+
while ((match = sectionRegex.exec(content)) !== null) {
|
|
29
|
+
const namesStr = match[1];
|
|
30
|
+
const sectionContent = match[2];
|
|
31
|
+
const names = namesStr.split(",").map((n) => n.trim().toLowerCase());
|
|
32
|
+
|
|
33
|
+
// Check if any of the names match the target
|
|
34
|
+
if (names.includes(targetName)) {
|
|
35
|
+
results.push(sectionContent);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Join all matching sections
|
|
40
|
+
return results.join("");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* section filter - Extract a named section from content
|
|
45
|
+
*
|
|
46
|
+
* Usage in templates:
|
|
47
|
+
* {{ content | section('intro') }}
|
|
48
|
+
* {{ content | section('footer') }}
|
|
49
|
+
*
|
|
50
|
+
* Content format:
|
|
51
|
+
* <!--section:intro-->
|
|
52
|
+
* This is the intro content
|
|
53
|
+
* <!--section:main-->
|
|
54
|
+
* This is the main content
|
|
55
|
+
* <!--section:footer,sidebar-->
|
|
56
|
+
* This appears in both footer and sidebar sections
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} eleventyConfig - The Eleventy configuration object
|
|
59
|
+
*/
|
|
60
|
+
export function sectionFilter(eleventyConfig) {
|
|
61
|
+
eleventyConfig.addFilter("section", section);
|
|
62
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { section } from "./section.js";
|
|
4
|
+
|
|
5
|
+
describe("section", () => {
|
|
6
|
+
it("should extract a single named section", () => {
|
|
7
|
+
const content = `Before
|
|
8
|
+
<!--section:intro-->
|
|
9
|
+
This is the intro
|
|
10
|
+
<!--section:main-->
|
|
11
|
+
This is the main`;
|
|
12
|
+
|
|
13
|
+
const result = section(content, "intro");
|
|
14
|
+
assert.strictEqual(result, "\nThis is the intro\n");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("should extract section up to the next section marker", () => {
|
|
18
|
+
const content = `<!--section:first-->
|
|
19
|
+
First content
|
|
20
|
+
<!--section:second-->
|
|
21
|
+
Second content
|
|
22
|
+
<!--section:third-->
|
|
23
|
+
Third content`;
|
|
24
|
+
|
|
25
|
+
const result = section(content, "second");
|
|
26
|
+
assert.strictEqual(result, "\nSecond content\n");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should extract section up to EOF when no next marker", () => {
|
|
30
|
+
const content = `<!--section:intro-->
|
|
31
|
+
Intro content
|
|
32
|
+
<!--section:main-->
|
|
33
|
+
Main content that goes to the end`;
|
|
34
|
+
|
|
35
|
+
const result = section(content, "main");
|
|
36
|
+
assert.strictEqual(result, "\nMain content that goes to the end");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should handle section with multiple names", () => {
|
|
40
|
+
const content = `<!--section:header,nav-->
|
|
41
|
+
Shared content
|
|
42
|
+
<!--section:main-->
|
|
43
|
+
Main content`;
|
|
44
|
+
|
|
45
|
+
const resultHeader = section(content, "header");
|
|
46
|
+
const resultNav = section(content, "nav");
|
|
47
|
+
|
|
48
|
+
assert.strictEqual(resultHeader, "\nShared content\n");
|
|
49
|
+
assert.strictEqual(resultNav, "\nShared content\n");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should handle section with multiple names (spaces around commas)", () => {
|
|
53
|
+
const content = `<!--section:header, nav , top-->
|
|
54
|
+
Shared content
|
|
55
|
+
<!--section:main-->
|
|
56
|
+
Main content`;
|
|
57
|
+
|
|
58
|
+
const resultHeader = section(content, "header");
|
|
59
|
+
const resultNav = section(content, "nav");
|
|
60
|
+
const resultTop = section(content, "top");
|
|
61
|
+
|
|
62
|
+
assert.strictEqual(resultHeader, "\nShared content\n");
|
|
63
|
+
assert.strictEqual(resultNav, "\nShared content\n");
|
|
64
|
+
assert.strictEqual(resultTop, "\nShared content\n");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should return empty string for non-existent section", () => {
|
|
68
|
+
const content = `<!--section:intro-->
|
|
69
|
+
Content here
|
|
70
|
+
<!--section:main-->
|
|
71
|
+
More content`;
|
|
72
|
+
|
|
73
|
+
const result = section(content, "footer");
|
|
74
|
+
assert.strictEqual(result, "");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should handle empty or null input", () => {
|
|
78
|
+
assert.strictEqual(section("", "test"), "");
|
|
79
|
+
assert.strictEqual(section(null, "test"), null);
|
|
80
|
+
assert.strictEqual(section(undefined, "test"), undefined);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should handle missing section name", () => {
|
|
84
|
+
const content = `<!--section:intro-->Content`;
|
|
85
|
+
|
|
86
|
+
assert.strictEqual(section(content, ""), "");
|
|
87
|
+
assert.strictEqual(section(content, null), "");
|
|
88
|
+
assert.strictEqual(section(content, undefined), "");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should be case-insensitive for section names", () => {
|
|
92
|
+
const content = `<!--section:INTRO-->
|
|
93
|
+
Content here
|
|
94
|
+
<!--section:Main-->
|
|
95
|
+
More content`;
|
|
96
|
+
|
|
97
|
+
const result1 = section(content, "intro");
|
|
98
|
+
const result2 = section(content, "INTRO");
|
|
99
|
+
const result3 = section(content, "main");
|
|
100
|
+
const result4 = section(content, "MAIN");
|
|
101
|
+
|
|
102
|
+
assert.strictEqual(result1, "\nContent here\n");
|
|
103
|
+
assert.strictEqual(result2, "\nContent here\n");
|
|
104
|
+
assert.strictEqual(result3, "\nMore content");
|
|
105
|
+
assert.strictEqual(result4, "\nMore content");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should handle multiple sections with the same name", () => {
|
|
109
|
+
const content = `<!--section:note-->
|
|
110
|
+
First note
|
|
111
|
+
<!--section:main-->
|
|
112
|
+
Main content
|
|
113
|
+
<!--section:note-->
|
|
114
|
+
Second note
|
|
115
|
+
<!--section:footer-->
|
|
116
|
+
Footer`;
|
|
117
|
+
|
|
118
|
+
const result = section(content, "note");
|
|
119
|
+
assert.strictEqual(result, "\nFirst note\n\nSecond note\n");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should handle sections with no content", () => {
|
|
123
|
+
const content = `<!--section:empty--><!--section:main-->
|
|
124
|
+
Main content`;
|
|
125
|
+
|
|
126
|
+
const result = section(content, "empty");
|
|
127
|
+
assert.strictEqual(result, "");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("should handle content before first section", () => {
|
|
131
|
+
const content = `Some preamble
|
|
132
|
+
<!--section:intro-->
|
|
133
|
+
Intro content`;
|
|
134
|
+
|
|
135
|
+
const result = section(content, "intro");
|
|
136
|
+
assert.strictEqual(result, "\nIntro content");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should handle complex real-world example", () => {
|
|
140
|
+
const content = `# Document Title
|
|
141
|
+
|
|
142
|
+
<!--section:summary,abstract-->
|
|
143
|
+
This is a summary that can be used as an abstract.
|
|
144
|
+
<!--section:introduction-->
|
|
145
|
+
This is the introduction.
|
|
146
|
+
<!--section:methods-->
|
|
147
|
+
These are the methods.
|
|
148
|
+
<!--section:conclusion,summary-->
|
|
149
|
+
This is the conclusion and also part of summary.`;
|
|
150
|
+
|
|
151
|
+
const summary = section(content, "summary");
|
|
152
|
+
const introduction = section(content, "introduction");
|
|
153
|
+
const methods = section(content, "methods");
|
|
154
|
+
const conclusion = section(content, "conclusion");
|
|
155
|
+
|
|
156
|
+
assert.strictEqual(
|
|
157
|
+
summary,
|
|
158
|
+
"\nThis is a summary that can be used as an abstract.\n\nThis is the conclusion and also part of summary.",
|
|
159
|
+
);
|
|
160
|
+
assert.strictEqual(introduction, "\nThis is the introduction.\n");
|
|
161
|
+
assert.strictEqual(methods, "\nThese are the methods.\n");
|
|
162
|
+
assert.strictEqual(conclusion, "\nThis is the conclusion and also part of summary.");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("should handle section markers with extra whitespace", () => {
|
|
166
|
+
const content = `<!--section: intro -->
|
|
167
|
+
Content
|
|
168
|
+
<!--section: main -->
|
|
169
|
+
More`;
|
|
170
|
+
|
|
171
|
+
const result = section(content, "intro");
|
|
172
|
+
assert.strictEqual(result, "\nContent\n");
|
|
173
|
+
});
|
|
174
|
+
});
|
package/src/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { mergeFilter, merge } from "./filters/merge.js";
|
|
|
13
13
|
import { removeTagFilter, removeTag } from "./filters/remove_tag.js";
|
|
14
14
|
import { ifFilter, iff } from "./filters/if.js";
|
|
15
15
|
import { attrConcatFilter, attrConcat } from "./filters/attr_concat.js";
|
|
16
|
+
import { sectionFilter, section as sectionFn } from "./filters/section.js";
|
|
16
17
|
import { siteData } from "./siteData.js";
|
|
17
18
|
|
|
18
19
|
// Conditionally import fetchFilter only if @11ty/eleventy-fetch is available
|
|
@@ -36,7 +37,7 @@ try {
|
|
|
36
37
|
* @param {boolean} options.mdAutoRawTags - Enable mdAutoRawTags preprocessor (default: false)
|
|
37
38
|
* @param {boolean} options.mdAutoNl2br - Enable mdAutoNl2br for \n to <br> conversion (default: false)
|
|
38
39
|
* @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: [])
|
|
40
|
+
* @param {Array<string>} options.filters - Array of filter names to enable: 'attr_set', 'attr_includes', 'merge', 'remove_tag', 'if', 'attr_concat', 'section', 'fetch' (default: [])
|
|
40
41
|
* @param {boolean} options.siteData - Enable site.year and site.prod global data (default: false)
|
|
41
42
|
*/
|
|
42
43
|
export default function eleventyBricksPlugin(eleventyConfig, options = {}) {
|
|
@@ -54,6 +55,7 @@ export default function eleventyBricksPlugin(eleventyConfig, options = {}) {
|
|
|
54
55
|
remove_tag: removeTagFilter,
|
|
55
56
|
if: ifFilter,
|
|
56
57
|
attr_concat: attrConcatFilter,
|
|
58
|
+
section: sectionFilter,
|
|
57
59
|
...(fetchFilter && { fetch: fetchFilter }),
|
|
58
60
|
};
|
|
59
61
|
|
|
@@ -86,6 +88,7 @@ export {
|
|
|
86
88
|
removeTagFilter,
|
|
87
89
|
ifFilter,
|
|
88
90
|
attrConcatFilter,
|
|
91
|
+
sectionFilter,
|
|
89
92
|
fetchFilter,
|
|
90
93
|
siteData,
|
|
91
94
|
};
|
|
@@ -104,4 +107,5 @@ export {
|
|
|
104
107
|
iff,
|
|
105
108
|
attrConcat,
|
|
106
109
|
attrSet,
|
|
110
|
+
sectionFn as section,
|
|
107
111
|
};
|