eleventy-plugin-vento 4.0.1 → 4.1.1-beta.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/CHANGELOG.md CHANGED
@@ -1,10 +1,49 @@
1
1
  # eleventy-plugin-vento
2
2
 
3
+ ## 4.1.1-beta.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 335f21e: Select type updates (shouldn't affect compilation, however should improve DX)
8
+
9
+ Changes are:
10
+
11
+ - split types into separate files
12
+ - namespace `ventojs` type imports
13
+ - make `PluginOptions` optional by default
14
+ - make Eleventy types more readable
15
+ - declare a special (`EleventyVentoEnvironment`) for this plugin to replace Vento's own `Environment`
16
+
17
+ - 9eaa059: Update `debug` to v4.4.0
18
+ - f387b5e: Update `ventojs` to v1.12.13
19
+ - 070109a: Refactored files and functions internally that shouldn't have any impact on usage or performance:
20
+
21
+ - Split `debug` functions into separate exports, renamed `runCompatiblityCheck -> compatibilityCheck` (dd4c379b)
22
+ - Utilities are now split into separate files (e06a83ab)
23
+ - Main file renamed from `index.ts` to `plugin.ts` (1b122d2a)
24
+
25
+ ## 4.1.0
26
+
27
+ ### Minor Changes
28
+
29
+ - eb33d79: Expose Vento's `FilterThis` on Eleventy-declared filters. (fixes #72)
30
+
31
+ > [!IMPORTANT]
32
+ > Using this feature incurs the same performance regression that [`eleventyComputed` template strings](https://www.11ty.dev/docs/data-computed/#using-a-template-string) do. Caching can assist with this, see [README](https://github.com/noelforte/eleventy-plugin-vento/blob/main/readme.md) for more information.
33
+
34
+ Vento binds its own `this` object when executing filter functions. The `this` object contains 2 keys, `this.env` and `this.data`, for getting access to both the Vento environment and the template data respectively.
35
+
36
+ In addition to Vento's object, `this.page` and `this.eleventy` are also cloned to the top level from `this.data` to maintain feature-parity with Eleventy.
37
+
38
+ With this change, you can now create filters that leverage the Vento environment. See [README](https://github.com/noelforte/eleventy-plugin-vento/blob/main/readme.md) for more info.
39
+
40
+ - eb33d79: Update vento to 1.12.12
41
+
3
42
  ## 4.0.1
4
43
 
5
44
  ### Patch Changes
6
45
 
7
- - - hotfix - include `types` field in package.json to declare bundled types
46
+ - hotfix - include `types` field in package.json to declare bundled types
8
47
 
9
48
  ## 4.0.0
10
49
 
@@ -1,13 +1,13 @@
1
1
  import { UserConfig } from '@11ty/eleventy';
2
- import { Options } from 'ventojs';
2
+ import { LiteralUnion } from 'type-fest';
3
+ import * as ventojs from 'ventojs';
3
4
  import { Plugin } from 'ventojs/src/environment.js';
4
5
 
5
- type AutotrimConfig = boolean | ('@11ty' | '@vento' | (string & Record<never, never>))[];
6
- interface VentoPluginOptions {
6
+ interface PluginOptions {
7
7
  /**
8
8
  * An array of Vento plugins
9
9
  */
10
- plugins: Plugin[];
10
+ plugins?: Plugin[];
11
11
  /**
12
12
  * Enables Vento's autotrim plugin.
13
13
  * ```js
@@ -20,13 +20,13 @@ interface VentoPluginOptions {
20
20
  * autotrim: true
21
21
  * ```
22
22
  */
23
- autotrim: AutotrimConfig;
23
+ autotrim?: LiteralUnion<'@11ty' | '@vento', string>[] | boolean;
24
24
  /** Enable use of Eleventy filters */
25
- filters: boolean;
25
+ filters?: boolean;
26
26
  /** Enable use of Eleventy shortcodes */
27
- shortcodes: boolean;
27
+ shortcodes?: boolean;
28
28
  /** Enable use of Eleventy paired shortcodes */
29
- pairedShortcodes: boolean;
29
+ pairedShortcodes?: boolean;
30
30
  /**
31
31
  * A Vento configuration object.
32
32
  *
@@ -34,13 +34,9 @@ interface VentoPluginOptions {
34
34
  * Eleventy's own `dir.includes` location.**
35
35
  * @see {@link https://vento.js.org/configuration/}
36
36
  */
37
- ventoOptions: Options;
37
+ ventoOptions?: ventojs.Options;
38
38
  }
39
39
 
40
- /**
41
- * @file Main plugin declaration
42
- */
43
-
44
- declare function VentoPlugin(eleventyConfig: UserConfig, userOptions: Partial<VentoPluginOptions>): void;
40
+ declare function VentoPlugin(eleventyConfig: UserConfig, userOptions: PluginOptions): void;
45
41
 
46
42
  export { VentoPlugin };
package/dist/plugin.js ADDED
@@ -0,0 +1,243 @@
1
+ // src/plugin.ts
2
+ import path from "node:path";
3
+ import autotrimPlugin, { defaultTags as autotrimDefaultTags } from "ventojs/plugins/auto_trim.js";
4
+
5
+ // src/engine.ts
6
+ import createVentoEnv from "ventojs";
7
+
8
+ // src/utils/create-vento-tag.ts
9
+ function createVentoTag(tagInfo) {
10
+ const IS_PAIRED = tagInfo.group === "pairedShortcodes";
11
+ let INT = 0;
12
+ const tag = (env, code, output, tokens) => {
13
+ if (!code.startsWith(tagInfo.name)) return;
14
+ const { dataVarname } = env.options;
15
+ const thisArg = `{
16
+ page: ${dataVarname}.page,
17
+ eleventy: ${dataVarname}.eleventy
18
+ }`;
19
+ const fn = `__env.utils.eleventyFunctions.${tagInfo.group}.${tagInfo.name}`;
20
+ const args = [code.replace(tagInfo.name, "").trim()];
21
+ const compiled = [];
22
+ if (IS_PAIRED) {
23
+ const nestedVarname = `__arg${INT++}`;
24
+ args.unshift(env.compileFilters(tokens, nestedVarname, env.options.autoescape));
25
+ compiled.push(
26
+ "{",
27
+ `let ${nestedVarname} = "";`,
28
+ ...env.compileTokens(tokens, nestedVarname, [`/${tagInfo.name}`])
29
+ );
30
+ if (tokens.length > 0 && (tokens[0][0] !== "tag" || tokens[0][1] !== `/${tagInfo.name}`)) {
31
+ throw new Error(`Vento: Missing closing tag for ${tagInfo.name} tag: ${code}`);
32
+ }
33
+ tokens.shift();
34
+ }
35
+ args.unshift(thisArg);
36
+ compiled.push(
37
+ "{",
38
+ `const __result = await ${fn}.call(${args.filter(Boolean).join(", ")});`,
39
+ `${output} += ${env.compileFilters(tokens, "__result", env.options.autoescape)}`,
40
+ "}"
41
+ );
42
+ if (IS_PAIRED) {
43
+ compiled.push("}");
44
+ }
45
+ return compiled.join("\n");
46
+ };
47
+ return Object.defineProperty(tag, "name", {
48
+ value: tagInfo.name + IS_PAIRED ? `PairedTag` : `Tag`
49
+ });
50
+ }
51
+
52
+ // src/utils/debuggers.ts
53
+ import createDebugger from "debug";
54
+ var debugBaseNamespace = "Eleventy:Vento";
55
+ var debugMain = createDebugger(debugBaseNamespace);
56
+ var debugCache = createDebugger(`${debugBaseNamespace}:Cache`);
57
+ var debugRender = createDebugger(`${debugBaseNamespace}:Render`);
58
+
59
+ // src/engine.ts
60
+ function createVentoEngine(options) {
61
+ const env = createVentoEnv(options);
62
+ env.utils.eleventyFunctions = { shortcodes: {}, pairedShortcodes: {} };
63
+ function loadPlugins(plugins) {
64
+ for (const plugin of plugins) {
65
+ env.use(plugin);
66
+ }
67
+ }
68
+ function loadFilters(filters) {
69
+ for (const [name, fn] of Object.entries(filters)) {
70
+ env.filters[name] = async function(...args) {
71
+ const { page, eleventy } = this.data;
72
+ const filterResult = await fn.apply({ ...this, page, eleventy }, args);
73
+ return filterResult;
74
+ };
75
+ }
76
+ }
77
+ function loadShortcodes(shortcodes) {
78
+ for (const [name, fn] of Object.entries(shortcodes)) {
79
+ env.utils.eleventyFunctions.shortcodes[name] = fn;
80
+ const shortcodeTag = createVentoTag({ name, group: "shortcodes" });
81
+ env.tags.push(shortcodeTag);
82
+ }
83
+ }
84
+ function loadPairedShortcodes(pairedShortcodes) {
85
+ for (const [name, fn] of Object.entries(pairedShortcodes)) {
86
+ env.utils.eleventyFunctions.pairedShortcodes[name] = fn;
87
+ const shortcodeTag = createVentoTag({ name, group: "pairedShortcodes" });
88
+ env.tags.push(shortcodeTag);
89
+ }
90
+ }
91
+ function getTemplateFunction(source, file, useVentoCache = true) {
92
+ let template = env.cache.get(file);
93
+ if ((template == null ? void 0 : template.source) === source) {
94
+ debugCache("Cache HIT for `%s`, used precompiled template", file);
95
+ } else {
96
+ template = env.compile(source, file);
97
+ debugCache(
98
+ `Cache MISS for \`%s\`, compiled new template:
99
+ Use Vento cache: %o
100
+
101
+ ${template}`,
102
+ file,
103
+ useVentoCache
104
+ );
105
+ if (useVentoCache) {
106
+ env.cache.set(file, template);
107
+ }
108
+ }
109
+ return template;
110
+ }
111
+ return {
112
+ cache: env.cache,
113
+ loadPlugins,
114
+ loadFilters,
115
+ loadShortcodes,
116
+ loadPairedShortcodes,
117
+ getTemplateFunction
118
+ };
119
+ }
120
+ async function renderVentoTemplate(template, data, from) {
121
+ debugRender("Rendering `%s`", from);
122
+ const { content } = await template(data);
123
+ return content;
124
+ }
125
+
126
+ // src/utils/compat-check.ts
127
+ var REQUIRED_API_METHODS = [
128
+ ["getShortcodes", "v3.0.0-alpha.15"],
129
+ ["getPairedShortcodes", "v3.0.0-alpha.15"],
130
+ ["getFilters", "v3.0.0-alpha.15"],
131
+ ["addExtension", "v1.0.0"]
132
+ ];
133
+ function compatibilityCheck(config) {
134
+ debugMain("Run compatibility check");
135
+ for (const [method, version] of REQUIRED_API_METHODS) {
136
+ if (!(method in config)) {
137
+ console.error(
138
+ "[eleventy-plugin-vento] Plugin compatibility error:",
139
+ `\`${method}\``,
140
+ "not found. Please use Eleventy",
141
+ version,
142
+ "or later."
143
+ );
144
+ }
145
+ }
146
+ }
147
+
148
+ // src/plugin.ts
149
+ function VentoPlugin(eleventyConfig, userOptions) {
150
+ debugMain("Initializing eleventy-plugin-vento");
151
+ compatibilityCheck(eleventyConfig);
152
+ const options = {
153
+ // Define defaults
154
+ autotrim: false,
155
+ plugins: [],
156
+ filters: true,
157
+ shortcodes: true,
158
+ pairedShortcodes: true,
159
+ ventoOptions: {
160
+ includes: eleventyConfig.directories.includes
161
+ },
162
+ // Merge in user-provided options
163
+ ...userOptions
164
+ };
165
+ debugMain("Merged default and user config: %O", options);
166
+ const filters = eleventyConfig.getFilters();
167
+ debugMain("Reading filters from Eleventy: %o", filters);
168
+ const shortcodes = eleventyConfig.getShortcodes();
169
+ debugMain("Reading shortcodes from Eleventy: %o", shortcodes);
170
+ const pairedShortcodes = eleventyConfig.getPairedShortcodes();
171
+ debugMain("Reading paired shortcodes from Eleventy: %o", pairedShortcodes);
172
+ if (options.autotrim) {
173
+ const defaults = ["@vento", "@11ty"];
174
+ const tagSet = new Set(options.autotrim === true ? defaults : options.autotrim);
175
+ if (tagSet.has("@vento")) {
176
+ tagSet.delete("@vento");
177
+ for (const name of autotrimDefaultTags) {
178
+ tagSet.add(name);
179
+ }
180
+ }
181
+ if (tagSet.has("@11ty")) {
182
+ tagSet.delete("@11ty");
183
+ for (const name in pairedShortcodes) {
184
+ tagSet.add(name);
185
+ }
186
+ }
187
+ debugMain("Enabled autotrim for tags: %o", tagSet);
188
+ options.plugins.push(autotrimPlugin({ tags: [...tagSet] }));
189
+ }
190
+ debugMain("Initializing Vento environment");
191
+ const engine = createVentoEngine(options.ventoOptions);
192
+ debugMain("Loading plugins: %o", options.plugins);
193
+ engine.loadPlugins(options.plugins);
194
+ if (options.filters) {
195
+ debugMain("Loading filters: %o", filters);
196
+ engine.loadFilters(filters);
197
+ }
198
+ if (options.shortcodes) {
199
+ debugMain("Loading shortcodes: %o", shortcodes);
200
+ engine.loadShortcodes(shortcodes);
201
+ }
202
+ if (options.pairedShortcodes) {
203
+ debugMain("Loading paired shortcodes: %o", pairedShortcodes);
204
+ engine.loadPairedShortcodes(pairedShortcodes);
205
+ }
206
+ debugMain("Registering Vento cache handler on eleventy.beforeWatch event");
207
+ eleventyConfig.on("eleventy.beforeWatch", async (updatedFiles) => {
208
+ for (let file of updatedFiles) {
209
+ file = path.normalize(file);
210
+ debugCache("Delete cache entry for %s", file);
211
+ engine.cache.delete(file);
212
+ }
213
+ });
214
+ debugMain("Registering .vto as a template format");
215
+ eleventyConfig.addTemplateFormats("vto");
216
+ debugMain("Registering .vto extension with eleventy");
217
+ eleventyConfig.addExtension("vto", {
218
+ outputFileExtension: "html",
219
+ read: true,
220
+ compile(inputContent, inputPath) {
221
+ inputPath = path.normalize(inputPath);
222
+ debugMain("Getting template function for `%s`", inputPath);
223
+ const template = engine.getTemplateFunction(inputContent, inputPath, false);
224
+ return async (data) => await renderVentoTemplate(template, data, inputPath);
225
+ },
226
+ compileOptions: {
227
+ // Custom permalink compilation
228
+ permalink(permalinkContent, inputPath) {
229
+ if (typeof permalinkContent !== "string" || !/\{\{\s+.+\s+\}\}/.test(permalinkContent)) {
230
+ return permalinkContent;
231
+ }
232
+ inputPath = "Permalink::" + path.normalize(inputPath);
233
+ debugMain("Getting template function for `%s`", inputPath);
234
+ const template = engine.getTemplateFunction(permalinkContent, inputPath);
235
+ return async (data) => await renderVentoTemplate(template, data, inputPath);
236
+ }
237
+ }
238
+ });
239
+ debugMain("eleventy-plugin-vento initialized");
240
+ }
241
+ export {
242
+ VentoPlugin
243
+ };
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "eleventy-plugin-vento",
3
- "version": "4.0.1",
3
+ "version": "4.1.1-beta.0",
4
4
  "description": "Adds support for the Vento templating language to Eleventy.",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": ">=18"
8
8
  },
9
- "types": "./dist/index.d.ts",
9
+ "types": "./dist/plugin.d.ts",
10
10
  "exports": {
11
11
  ".": {
12
- "import": "./dist/index.js",
13
- "types": "./dist/index.d.ts"
12
+ "import": "./dist/plugin.js",
13
+ "types": "./dist/plugin.d.ts"
14
14
  }
15
15
  },
16
16
  "files": [
@@ -36,25 +36,27 @@
36
36
  },
37
37
  "license": "MIT",
38
38
  "dependencies": {
39
- "debug": "4.3.7",
40
- "ventojs": "1.12.11"
39
+ "debug": "4.4.0",
40
+ "ventojs": "1.12.13"
41
41
  },
42
42
  "devDependencies": {
43
43
  "11ty.ts": "0.0.5",
44
44
  "@11ty/eleventy": "3.0.0",
45
- "@changesets/cli": "2.27.9",
46
- "@eslint/js": "9.14.0",
45
+ "@changesets/cli": "2.27.10",
46
+ "@eslint/js": "9.16.0",
47
47
  "@types/debug": "4.1.12",
48
48
  "@types/eslint-config-prettier": "6.11.3",
49
49
  "@types/eslint__js": "8.42.3",
50
- "@types/node": "22.8.4",
51
- "eslint": "9.14.0",
50
+ "@types/node": "22.10.1",
51
+ "eslint": "9.16.0",
52
52
  "eslint-config-prettier": "9.1.0",
53
- "eslint-plugin-unicorn": "56.0.0",
53
+ "eslint-plugin-unicorn": "56.0.1",
54
+ "globals": "15.13.0",
54
55
  "tsup": "8.3.5",
55
- "typescript": "5.6.3",
56
- "typescript-eslint": "8.12.2",
57
- "vitest": "2.1.4"
56
+ "type-fest": "4.30.0",
57
+ "typescript": "5.7.2",
58
+ "typescript-eslint": "8.18.0",
59
+ "vitest": "2.1.8"
58
60
  },
59
61
  "prettier": {
60
62
  "bracketSameLine": true,
@@ -64,13 +66,13 @@
64
66
  },
65
67
  "scripts": {
66
68
  "test": "vitest --run",
67
- "check": "pnpm --color run '/ts-check|lint/'",
68
- "lint": "eslint '.'",
69
- "ts-check": "tsc --noEmit",
69
+ "check": "pnpm --color run '/^check:/'",
70
+ "check:lint": "eslint '.'",
71
+ "check:types": "tsc --noEmit",
70
72
  "build": "tsup",
73
+ "dev": "tsup --watch ./src",
71
74
  "ci:version": "changeset version && pnpm install --no-frozen-lockfile",
72
75
  "ci:publish": "changeset publish",
73
- "ci:generate-changesets": "node ./scripts/generate-changesets.js",
74
76
  "format": "pnpm dlx prettier --config ./package.json --write ."
75
77
  }
76
78
  }
package/readme.md CHANGED
@@ -62,9 +62,6 @@ export default function (eleventyConfig) {
62
62
  // to trim the default tags (see section on Auto-trimming)
63
63
  autotrim: false,
64
64
 
65
- // Enable/disable ignore tag syntax (see section on ignoring tags)
66
- ignoreTag: false,
67
-
68
65
  // A Vento configuration object
69
66
  ventoOptions: {
70
67
  includes: eleventyConfig.directories.includes,
@@ -90,6 +87,24 @@ Filters that are added via Eleventy's `.addFilter()` or `.addAsyncFilter()` meth
90
87
 
91
88
  If you'd prefer to set filters yourself (via a plugin or other method) or prevent Eleventy from loading filters into Vento, set `filters: false` in the plugin options.
92
89
 
90
+ ### Filters and `this`
91
+
92
+ Eleventy provides filters with scoped data via the `this.page` and `this.eleventy` objects (see [Filters#Scoped data in Filters](https://www.11ty.dev/docs/filters/#scoped-data-in-filters) in Eleventy's docs for more details). Likewise, Vento provides filters with `this.env` and `this.data` representing the Vento environment and the current template data. This plugin merges both objects together to make `this.page` (and `eleventy`/`env`/`data`) available on all filters processed by Vento.
93
+
94
+ This feature enables re-use of the Vento environment this plugin provides, within Eleventy filters. As an example use case, you could create a filter that compiles dynamic data and cache it with Vento's own cache to improve performance:
95
+
96
+ ```js
97
+ import 'hash' from 'node:crypto'; // since Node v20.12.0
98
+
99
+ const sha1Hash(str) => hash('sha1', str, 'hex');
100
+
101
+ eleventyConfig.addFilter('vento', function (content) {
102
+ const file = `dynamicString:${sha1Hash(content)}`;
103
+ const res = this.env.runString(content, this.data, file);
104
+ return res.content;
105
+ });
106
+ ```
107
+
93
108
  ### Relevant documentation
94
109
 
95
110
  Vento: See [Filters](https://vento.js.org/configuration/#filters) and [Pipes](https://vento.js.org/syntax/pipes/)
@@ -144,7 +159,8 @@ Eleventy: See [Shortcodes](https://www.11ty.dev/docs/shortcodes/) and the sub-se
144
159
 
145
160
  ## Vento Plugins
146
161
 
147
- _Note: The `auto_trim` plugin that ships with Vento has a specific implementation in the scope of this plugin. See [Auto-Trimming Tags](#auto-trimming-tags) for more details._
162
+ > [!NOTE]
163
+ > The `auto_trim` plugin that ships with Vento has a specific implementation in the scope of this plugin. See [Auto-Trimming Tags](#auto-trimming-tags) for more details.\_
148
164
 
149
165
  If you'd like to extend the Vento library with any plugins, include them in an array passed to the `plugins` option.
150
166
 
@@ -202,7 +218,7 @@ Vento: See [Auto Trim Plugin](https://vento.js.org/plugins/auto-trim/).
202
218
 
203
219
  Like Eleventy, this plugin uses the [`debug`](https://www.npmjs.com/package/debug) package to handle verbose logging. The following `DEBUG` namespaces are implemented:
204
220
 
205
- - `Eleventy:Vento:Setup` - Logs initial setup of the plugin, loading features, pre-page compile setup steps (like changing `page` and `eleventy` objects)
221
+ - `Eleventy:Vento` - Logs initial setup of the plugin, loading features, pre-page compile setup steps (like changing `page` and `eleventy` objects)
206
222
  - `Eleventy:Vento:Cache` - Logs updates to Vento's own internal cache, which is used in tandem with Eleventy's cache.
207
223
  - `Eleventy:Vento:Render` - Logs when templates are rendered
208
224
 
@@ -215,7 +231,7 @@ $ DEBUG='Eleventy:*' npx @11ty/eleventy
215
231
  Alternatively, use a finer grained namespace to see only the output generated by `eleventy-plugin-vento`.
216
232
 
217
233
  ```sh
218
- $ DEBUG='Eleventy:Vento:*' npx @11ty/eleventy
234
+ $ DEBUG='Eleventy:Vento*' npx @11ty/eleventy
219
235
  ```
220
236
 
221
237
  ```sh
package/dist/index.js DELETED
@@ -1,244 +0,0 @@
1
- // src/index.ts
2
- import path from "node:path";
3
- import autotrimPlugin, { defaultTags as autotrimDefaultTags } from "ventojs/plugins/auto_trim.js";
4
-
5
- // src/create-vento-interface.ts
6
- import { default as ventojs } from "ventojs";
7
-
8
- // src/create-vento-tag.ts
9
- function createVentoTag(spec) {
10
- const IS_PAIRED = spec.group === "pairedShortcodes";
11
- const tag = (env, code, output, tokens) => {
12
- if (!code.startsWith(spec.name)) return;
13
- const fn = `__env.utils._11tyFns.${spec.group}.${spec.name}`;
14
- const ctx = "__env.utils._11tyCtx";
15
- const args = [code.replace(spec.name, "").trim()];
16
- const varname = output.startsWith("__shortcode_content") ? `${output}_precomp` : "__shortcode_content";
17
- const compiled = [];
18
- if (IS_PAIRED) {
19
- args.unshift(env.compileFilters(tokens, varname, env.options.autoescape));
20
- compiled.push(
21
- "{",
22
- `let ${varname} = "";`,
23
- ...env.compileTokens(tokens, varname, [`/${spec.name}`])
24
- );
25
- if (tokens.length > 0 && (tokens[0][0] !== "tag" || tokens[0][1] !== `/${spec.name}`)) {
26
- throw new Error(`Vento: Missing closing tag for ${spec.name} tag: ${code}`);
27
- }
28
- tokens.shift();
29
- }
30
- args.unshift(ctx);
31
- compiled.push(
32
- "{",
33
- `const __shortcode_result = await ${fn}.call(${args.filter(Boolean).join(", ")});`,
34
- `${output} += ${env.compileFilters(tokens, "__shortcode_result", env.options.autoescape)}`,
35
- "}"
36
- );
37
- if (IS_PAIRED) {
38
- compiled.push("}");
39
- }
40
- const compiledTag = compiled.join("\n");
41
- return compiledTag;
42
- };
43
- return Object.defineProperty(tag, "name", {
44
- value: spec.name + IS_PAIRED ? `PairedTag` : `Tag`
45
- });
46
- }
47
-
48
- // src/utils.ts
49
- import createDebugger from "debug";
50
- var debugBaseNamespace = "Eleventy:Vento";
51
- var DEBUG = {
52
- setup: createDebugger(`${debugBaseNamespace}:Setup`),
53
- cache: createDebugger(`${debugBaseNamespace}:Cache`),
54
- render: createDebugger(`${debugBaseNamespace}:Render`)
55
- };
56
- var REQUIRED_API_METHODS = [
57
- ["getShortcodes", "v3.0.0-alpha.15"],
58
- ["getPairedShortcodes", "v3.0.0-alpha.15"],
59
- ["getFilters", "v3.0.0-alpha.15"],
60
- ["addExtension", "v1.0.0"]
61
- ];
62
- var CONTEXT_DATA_KEYS = ["page", "eleventy"];
63
- function runCompatibilityCheck(config) {
64
- DEBUG.setup("Run compatibility check");
65
- for (const [method, version] of REQUIRED_API_METHODS) {
66
- if (!(method in config)) {
67
- console.error(
68
- "[eleventy-plugin-vento] Plugin compatibility error:",
69
- `\`${method}\``,
70
- "not found. Please use Eleventy",
71
- version,
72
- "or later."
73
- );
74
- }
75
- }
76
- }
77
-
78
- // src/create-vento-interface.ts
79
- function createVentoInterface(options) {
80
- const env = ventojs(options);
81
- env.utils._11tyFns = { shortcodes: {}, pairedShortcodes: {} };
82
- env.utils._11tyCtx = {};
83
- function setContext(newContext) {
84
- if (env.utils._11tyCtx?.page?.inputPath === newContext?.page?.inputPath) {
85
- return;
86
- }
87
- for (const K of CONTEXT_DATA_KEYS) {
88
- env.utils._11tyCtx[K] = newContext[K];
89
- }
90
- DEBUG.setup("Reload context, new context is: %o", env.utils._11tyCtx);
91
- }
92
- function loadPlugins(plugins) {
93
- for (const plugin of plugins) {
94
- env.use(plugin);
95
- }
96
- }
97
- function loadFilters(filters) {
98
- for (const [name, fn] of Object.entries(filters)) {
99
- env.filters[name] = fn.bind(env.utils._11tyCtx);
100
- }
101
- }
102
- function loadShortcodes(shortcodes) {
103
- for (const [name, fn] of Object.entries(shortcodes)) {
104
- env.utils._11tyFns.shortcodes[name] = fn;
105
- env.tags.push(createVentoTag({ name, group: "shortcodes" }));
106
- }
107
- }
108
- function loadPairedShortcodes(pairedShortcodes) {
109
- for (const [name, fn] of Object.entries(pairedShortcodes)) {
110
- env.utils._11tyFns.pairedShortcodes[name] = fn;
111
- env.tags.push(createVentoTag({ name, group: "pairedShortcodes" }));
112
- }
113
- }
114
- function getTemplateFunction(source, file, useVentoCache = true) {
115
- let template = env.cache.get(file);
116
- if (template?.source === source) {
117
- DEBUG.cache("Cache HIT for `%s`, used precompiled template", file);
118
- } else {
119
- template = env.compile(source, file);
120
- DEBUG.cache(
121
- `Cache MISS for \`%s\`, compiled new template:
122
- Use Vento cache: %o
123
-
124
- ${template}`,
125
- file,
126
- useVentoCache
127
- );
128
- if (useVentoCache) {
129
- env.cache.set(file, template);
130
- }
131
- }
132
- return template;
133
- }
134
- async function render(template, data, from) {
135
- setContext(data);
136
- DEBUG.render("Rendering `%s`", from);
137
- const { content } = await template(data);
138
- return content;
139
- }
140
- return {
141
- cache: env.cache,
142
- loadPlugins,
143
- loadFilters,
144
- loadShortcodes,
145
- loadPairedShortcodes,
146
- getTemplateFunction,
147
- render
148
- };
149
- }
150
-
151
- // src/index.ts
152
- function VentoPlugin(eleventyConfig, userOptions) {
153
- DEBUG.setup("Initializing eleventy-plugin-vento");
154
- runCompatibilityCheck(eleventyConfig);
155
- const options = {
156
- // Define defaults
157
- autotrim: false,
158
- plugins: [],
159
- filters: true,
160
- shortcodes: true,
161
- pairedShortcodes: true,
162
- ventoOptions: {
163
- includes: eleventyConfig.directories.includes
164
- },
165
- // Merge in user-provided options
166
- ...userOptions
167
- };
168
- DEBUG.setup("Merged default and user config: %O", options);
169
- const filters = eleventyConfig.getFilters();
170
- DEBUG.setup("Reading filters from Eleventy: %o", filters);
171
- const shortcodes = eleventyConfig.getShortcodes();
172
- DEBUG.setup("Reading shortcodes from Eleventy: %o", shortcodes);
173
- const pairedShortcodes = eleventyConfig.getPairedShortcodes();
174
- DEBUG.setup("Reading paired shortcodes from Eleventy: %o", pairedShortcodes);
175
- if (options.autotrim) {
176
- const defaults = ["@vento", "@11ty"];
177
- const tagSet = new Set(options.autotrim === true ? defaults : options.autotrim);
178
- if (tagSet.has("@vento")) {
179
- tagSet.delete("@vento");
180
- for (const name of autotrimDefaultTags) {
181
- tagSet.add(name);
182
- }
183
- }
184
- if (tagSet.has("@11ty")) {
185
- tagSet.delete("@11ty");
186
- for (const name in pairedShortcodes) {
187
- tagSet.add(name);
188
- }
189
- }
190
- DEBUG.setup("Enabled autotrim for tags: %o", tagSet);
191
- options.plugins.push(autotrimPlugin({ tags: [...tagSet] }));
192
- }
193
- DEBUG.setup("Initializing Vento environment");
194
- const engine = createVentoInterface(options.ventoOptions);
195
- DEBUG.setup("Loading plugins: %o", options.plugins);
196
- engine.loadPlugins(options.plugins);
197
- if (options.filters) {
198
- DEBUG.setup("Loading filters: %o", filters);
199
- engine.loadFilters(filters);
200
- }
201
- if (options.shortcodes) {
202
- DEBUG.setup("Loading shortcodes: %o", shortcodes);
203
- engine.loadShortcodes(shortcodes);
204
- }
205
- if (options.pairedShortcodes) {
206
- DEBUG.setup("Loading paired shortcodes: %o", pairedShortcodes);
207
- engine.loadPairedShortcodes(pairedShortcodes);
208
- }
209
- DEBUG.setup("Registering Vento cache handler on eleventy.beforeWatch event");
210
- eleventyConfig.on("eleventy.beforeWatch", async (updatedFiles) => {
211
- for (let file of updatedFiles) {
212
- file = path.normalize(file);
213
- DEBUG.cache("Delete cache entry for %s", file);
214
- engine.cache.delete(file);
215
- }
216
- });
217
- DEBUG.setup("Registering .vto as a template format");
218
- eleventyConfig.addTemplateFormats("vto");
219
- DEBUG.setup("Registering .vto extension with eleventy");
220
- eleventyConfig.addExtension("vto", {
221
- outputFileExtension: "html",
222
- read: true,
223
- compile(inputContent, inputPath) {
224
- inputPath = path.normalize(inputPath);
225
- const template = engine.getTemplateFunction(inputContent, inputPath, false);
226
- return async (data) => await engine.render(template, data, inputPath);
227
- },
228
- compileOptions: {
229
- // Custom permalink compilation
230
- permalink(permalinkContent, inputPath) {
231
- if (typeof permalinkContent === "string" && /\{\{\s+.+\s+\}\}/.test(permalinkContent)) {
232
- inputPath = "Permalink::" + path.normalize(inputPath);
233
- const template = engine.getTemplateFunction(permalinkContent, inputPath);
234
- return async (data) => await engine.render(template, data, inputPath);
235
- }
236
- return permalinkContent;
237
- }
238
- }
239
- });
240
- DEBUG.setup("eleventy-plugin-vento initialized");
241
- }
242
- export {
243
- VentoPlugin
244
- };