eleventy-plugin-vento 3.3.0 → 4.0.0-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,5 +1,29 @@
1
1
  # eleventy-plugin-vento
2
2
 
3
+ ## 4.0.0-beta.0
4
+
5
+ ### Major Changes
6
+
7
+ - fc80b5f: Removed ignore tag `{{! ... }}` syntax. As mentioned in the 3.3.0 release notes, the now preferred way to "pass through" tags is with string literals.
8
+
9
+ You should update code with `{{! ... }}` to be `{{ '{{ }}' }}` like so:
10
+
11
+ ```diff
12
+ - {{! if condition }}
13
+ + {{ '{{ if condition }}' }}
14
+ do something
15
+ - {{! /if }}
16
+ - {{ '{{ /if }}' }}
17
+ ```
18
+
19
+ While more verbose, this change ensures that there isn't any ambiguity between a tag that needs ignoring and JS negation expressions.
20
+
21
+ ### Minor Changes
22
+
23
+ - 2b5f337: Rewrite project in Typescript and add a build/packaging step for releases and testing.
24
+
25
+ These changes also include `.d.ts` generation as part of the build step. If you're using `11ty.ts`'s `defineConfig` function, it will pick the types from this plugin up automatically. (resolves #22)
26
+
3
27
  ## 3.3.0
4
28
 
5
29
  ### Minor Changes
@@ -0,0 +1,46 @@
1
+ import { UserConfig } from '@11ty/eleventy';
2
+ import { Options } from 'ventojs';
3
+ import { Plugin } from 'ventojs/src/environment.js';
4
+
5
+ type AutotrimConfig = boolean | ('@11ty' | '@vento' | (string & Record<never, never>))[];
6
+ interface VentoPluginOptions {
7
+ /**
8
+ * An array of Vento plugins
9
+ */
10
+ plugins: Plugin[];
11
+ /**
12
+ * Enables Vento's autotrim plugin.
13
+ * ```js
14
+ * // Set to an array of tags
15
+ * autotrim: ['tag1', 'tag2']
16
+ *
17
+ * // Use Vento's defaults and Eleventy paired shortcodes
18
+ * // If set to `true`, uses both
19
+ * autotrim: ['@vento', '@11ty']
20
+ * autotrim: true
21
+ * ```
22
+ */
23
+ autotrim: AutotrimConfig;
24
+ /** Enable use of Eleventy filters */
25
+ filters: boolean;
26
+ /** Enable use of Eleventy shortcodes */
27
+ shortcodes: boolean;
28
+ /** Enable use of Eleventy paired shortcodes */
29
+ pairedShortcodes: boolean;
30
+ /**
31
+ * A Vento configuration object.
32
+ *
33
+ * **Note that `ventoOptions.includes` defaults to
34
+ * Eleventy's own `dir.includes` location.**
35
+ * @see {@link https://vento.js.org/configuration/}
36
+ */
37
+ ventoOptions: Options;
38
+ }
39
+
40
+ /**
41
+ * @file Main plugin declaration
42
+ */
43
+
44
+ declare function VentoPlugin(eleventyConfig: UserConfig, userOptions: Partial<VentoPluginOptions>): void;
45
+
46
+ export { VentoPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,244 @@
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/engine.ts
6
+ import { default as ventojs } from "ventojs";
7
+
8
+ // src/modules/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/modules/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/engine.ts
79
+ function createVentoEngine(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 = createVentoEngine(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
+ };
package/package.json CHANGED
@@ -1,16 +1,23 @@
1
1
  {
2
2
  "name": "eleventy-plugin-vento",
3
- "version": "3.3.0",
3
+ "version": "4.0.0-beta.0",
4
4
  "description": "Adds support for the Vento templating language to Eleventy.",
5
5
  "type": "module",
6
6
  "engines": {
7
- "node": ">=16"
7
+ "node": ">=18"
8
8
  },
9
9
  "exports": {
10
10
  ".": {
11
- "import": "./src/index.js"
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
12
13
  }
13
14
  },
15
+ "files": [
16
+ "dist/*",
17
+ "LICENSE",
18
+ "CHANGELOG.md",
19
+ "readme.md"
20
+ ],
14
21
  "repository": "git@github.com:noelforte/eleventy-plugin-vento.git",
15
22
  "bugs": {
16
23
  "url": "https://github.com/noelforte/eleventy-plugin-vento/issues"
@@ -27,23 +34,25 @@
27
34
  "url": "https://forte.is/"
28
35
  },
29
36
  "license": "MIT",
30
- "files": [
31
- "src/*",
32
- "CHANGELOG.md"
33
- ],
34
37
  "dependencies": {
35
38
  "debug": "4.3.7",
36
39
  "ventojs": "1.12.10"
37
40
  },
38
41
  "devDependencies": {
42
+ "11ty.ts": "0.0.5",
39
43
  "@11ty/eleventy": "3.0.0",
40
44
  "@changesets/cli": "2.27.9",
41
45
  "@eslint/js": "9.13.0",
46
+ "@types/debug": "4.1.12",
47
+ "@types/eslint-config-prettier": "6.11.3",
48
+ "@types/eslint__js": "8.42.3",
49
+ "@types/node": "22.8.4",
42
50
  "eslint": "9.13.0",
43
- "eslint-config-flat-gitignore": "0.3.0",
44
51
  "eslint-config-prettier": "9.1.0",
45
52
  "eslint-plugin-unicorn": "56.0.0",
46
- "globals": "15.11.0",
53
+ "tsup": "8.3.5",
54
+ "typescript": "5.6.3",
55
+ "typescript-eslint": "8.12.2",
47
56
  "vitest": "2.1.4"
48
57
  },
49
58
  "prettier": {
@@ -53,8 +62,11 @@
53
62
  "trailingComma": "es5"
54
63
  },
55
64
  "scripts": {
56
- "test": "vitest",
57
- "lint": "eslint '**/*.js'",
65
+ "test": "vitest --run",
66
+ "check": "pnpm --color run '/ts-check|lint/'",
67
+ "lint": "eslint '.'",
68
+ "ts-check": "tsc --noEmit",
69
+ "build": "tsup",
58
70
  "ci:version": "changeset version && pnpm install --no-frozen-lockfile",
59
71
  "ci:publish": "changeset publish",
60
72
  "ci:generate-changesets": "node ./scripts/generate-changesets.js",
package/readme.md CHANGED
@@ -16,7 +16,6 @@ An [Eleventy](https://11ty.dev/) plugin that adds support for [Vento](https://ve
16
16
  [Shortcodes (Single & Paired)](#shortcodes-single--paired)<br>
17
17
  [Vento Plugins](#vento-plugins)<br>
18
18
  [Auto-Trimming Tags](#auto-trimming-tags)<br>
19
- [Ignoring Tags](#ignoring-tags)<br>
20
19
  [Debugging](#debugging)<br>
21
20
 
22
21
  ## Installing
@@ -199,77 +198,6 @@ eleventyConfig.addPlugin(VentoPlugin, {
199
198
 
200
199
  Vento: See [Auto Trim Plugin](https://vento.js.org/plugins/auto-trim/).
201
200
 
202
- ## Ignoring Tags
203
-
204
- > [!WARNING]
205
- > This feature is now deprecated as of version 3.3.0. I added it primarily for my own use case, however it can cause more issues than it solves (conflict with `!` negation syntax in JS, ambiguity between ignoring a tag and negating an expression in a template). See the 3.3.0 release notes for more information.
206
-
207
- Exclusive to this plugin is the ability to skip processing a vento tag entirely and instead preserve the tag in the markup. This could be useful if you're doing some hybrid rendering and would like to defer certain tags from being processed until load time, so they can be rendered on the server.
208
-
209
- This feature is enabled through use of the `enableIgnoreTag` plugin option.
210
-
211
- ```js
212
- eleventyConfig.addPlugin(VentoPlugin, {
213
- enableIgnoreTag: true,
214
- });
215
- ```
216
-
217
- To skip over a tag, add a `!` directly after the opening tag.
218
-
219
- ```nunjucks
220
- <!-- This: -->
221
- {{! doSomeServerSideStuff() }}
222
-
223
- <!-- Renders as: -->
224
- {{ doSomeServerSideStuff() }}
225
- ```
226
-
227
- Works with JS expressions too:
228
-
229
- ```nunjucks
230
- {{!> 2 + 2 }}
231
-
232
- <!-- Renders as: -->
233
- {{> 2 + 2 }}
234
- ```
235
-
236
- The Vento language offers similar functionality via the [`echo` tag](https://vento.js.org/syntax/print/#echo) which works great for blocks, but can be verbose for 1-off tags.
237
-
238
- Consider the following:
239
-
240
- ```nunjucks
241
- {{ echo }}
242
- <!-- Will be preserved in output -->
243
- {{ if someCondition }}
244
- <p>{{ getServerData }}</p>
245
- {{ /echo }}
246
-
247
- <!-- Can't render this without exiting and re-entering echo -->
248
- <p>Page built on: {{ localBuildTime }}</p>
249
-
250
- {{ echo }}
251
- {{ /if }}
252
- {{ /echo }}
253
- ```
254
-
255
- Rather than having to do multiple `{{ /echo }} ... {{ echo }}` statements, the previous can be rewritten as such:
256
-
257
- ```nunjucks
258
- <!-- This: -->
259
- {{! if someCondition }}
260
- <p>{{! getServerData }}</p>
261
-
262
- <p>Page built on: {{ localBuildTime }}</p>
263
- {{! /if }}
264
-
265
- <!-- Renders as: -->
266
- {{ if someCondition }}
267
- <p>{{ getServerData }}</p>
268
-
269
- <p>Page built on: 09-19-2024</p>
270
- {{ /if }}
271
- ```
272
-
273
201
  ## Debugging
274
202
 
275
203
  Like Eleventy, this plugin uses the [`debug`](https://www.npmjs.com/package/debug) package to handle verbose logging. The following `DEBUG` namespaces are implemented:
package/src/engine.js DELETED
@@ -1,126 +0,0 @@
1
- /**
2
- * @file Function that handles creating the Vento environment. Exposes
3
- * a simple API for Eleventy to interface with.
4
- *
5
- * @typedef {{eleventy?: Record<string, unknown>, page?: Record<string, unknown>}} EleventyContext
6
- * @typedef {EleventyContext & Record<string, unknown>} EleventyData
7
- * @typedef {(...args: unknown[]) => unknown} EleventyFunction
8
- * @typedef {Record<string, EleventyFunction>} EleventyFunctionSet
9
- * @typedef {import('ventojs/src/environment.js').Environment} VentoEnvironment
10
- * @typedef {VentoEnvironment & {
11
- * utils: {
12
- * _11tyFns: { shortcodes: EleventyFunctionSet, pairedShortcodes: EleventyFunctionSet }
13
- * _11tyCtx: EleventyContext
14
- * }
15
- * }} EleventyVentoEnvironment
16
- */
17
-
18
- // External library
19
- import ventojs from 'ventojs';
20
-
21
- // Internal modules
22
- import { createVentoTag } from './modules/create-vento-tag.js';
23
- import { CONTEXT_DATA_KEYS, DEBUG } from './modules/utils.js';
24
-
25
- /** @param {import('ventojs').Options} options */
26
- export function createVentoEngine(options) {
27
- /** @type {EleventyVentoEnvironment} */
28
- const env = ventojs(options);
29
- env.utils._11tyFns = { shortcodes: {}, pairedShortcodes: {} };
30
- env.utils._11tyCtx = {};
31
-
32
- /** @param {EleventyData} newContext */
33
- function setContext(newContext) {
34
- if (env.utils._11tyCtx?.page?.inputPath === newContext?.page?.inputPath) {
35
- return;
36
- }
37
-
38
- for (const K of CONTEXT_DATA_KEYS) {
39
- env.utils._11tyCtx[K] = newContext[K];
40
- }
41
-
42
- DEBUG.setup('Reload context, new context is: %o', env.utils._11tyCtx);
43
- }
44
-
45
- /** @param {import('ventojs/src/environment.js').Plugin[]} plugins */
46
- function loadPlugins(plugins) {
47
- for (const plugin of plugins) {
48
- env.use(plugin);
49
- }
50
- }
51
-
52
- /** @param {Record<string, EleventyFunction>} filters */
53
- function loadFilters(filters) {
54
- for (const [name, fn] of Object.entries(filters)) {
55
- env.filters[name] = fn.bind(env.utils._11tyCtx);
56
- }
57
- }
58
-
59
- /** @param {Record<string, EleventyFunction>} shortcodes */
60
- function loadShortcodes(shortcodes) {
61
- for (const [name, fn] of Object.entries(shortcodes)) {
62
- env.utils._11tyFns.shortcodes[name] = fn;
63
- env.tags.push(createVentoTag({ name, group: 'shortcodes' }));
64
- }
65
- }
66
-
67
- /** @param {Record<string, EleventyFunction>} pairedShortcodes */
68
- function loadPairedShortcodes(pairedShortcodes) {
69
- for (const [name, fn] of Object.entries(pairedShortcodes)) {
70
- env.utils._11tyFns.pairedShortcodes[name] = fn;
71
- env.tags.push(createVentoTag({ name, group: 'pairedShortcodes' }));
72
- }
73
- }
74
-
75
- /**
76
- * @param {string} source
77
- * @param {string} file
78
- * @param {boolean} [useVentoCache=true]
79
- */
80
- function getTemplateFunction(source, file, useVentoCache = true) {
81
- // Attempt to retrieve template function from cache
82
- let template = env.cache.get(file);
83
-
84
- if (template?.source === source) {
85
- DEBUG.cache('Cache HIT for `%s`, used precompiled template', file);
86
- } else {
87
- template = env.compile(source, file);
88
-
89
- DEBUG.cache(
90
- `Cache MISS for \`%s\`, compiled new template:\nUse Vento cache: %o\n\n${template}`,
91
- file,
92
- useVentoCache
93
- );
94
- if (useVentoCache) {
95
- env.cache.set(file, template);
96
- }
97
- }
98
-
99
- return template;
100
- }
101
-
102
- /**
103
- * @param {import('ventojs/src/environment.js').Template} template
104
- * @param {EleventyData} data
105
- * @param {string} from
106
- */
107
- async function render(template, data, from) {
108
- // Load new context
109
- setContext(data);
110
-
111
- // Render template
112
- DEBUG.render('Rendering `%s`', from);
113
- const { content } = await template(data);
114
- return content;
115
- }
116
-
117
- return {
118
- cache: env.cache,
119
- loadPlugins,
120
- loadFilters,
121
- loadShortcodes,
122
- loadPairedShortcodes,
123
- getTemplateFunction,
124
- render,
125
- };
126
- }
package/src/index.js DELETED
@@ -1,185 +0,0 @@
1
- /**
2
- * @file Main plugin declaration
3
- *
4
- * @typedef VentoPluginOptions
5
- * @prop {import('ventojs/src/environment.js').Plugin[]} plugins
6
- * Array of vento plugins to use when compiling templates
7
- * @prop {boolean|string[]} autotrim
8
- * Enable Vento's [`autoTrim`](https://vento.js.org/plugins/auto-trim/)
9
- * plugin to remove whitespace from tags in output
10
- * @prop {boolean} [shortcodes=true]
11
- * Create vento tags for Eleventy [Shortcodes](https://www.11ty.dev/docs/shortcodes/)
12
- * @prop {boolean} [pairedShortcodes=true]
13
- * Create vento tags for Eleventy [Paired Shortcodes](https://www.11ty.dev/docs/shortcodes/#paired-shortcodes)
14
- * @prop {boolean} [filters=true]
15
- * Create vento filters for Eleventy [Filters](https://www.11ty.dev/docs/filters/)
16
- * @prop {boolean} [ignoreTag=false]
17
- * Enables/disables tag ignore (`{{! ... }}`) syntax in templates
18
- * @prop {import('ventojs').Options} ventoOptions
19
- * Options to pass on to the `ventojs` engine.
20
- * (See [Vento Docs](https://vento.js.org/configuration/#options))
21
- */
22
-
23
- // Built-ins
24
- import path from 'node:path';
25
-
26
- // External modules
27
- import autotrimPlugin, { defaultTags as autotrimDefaultTags } from 'ventojs/plugins/auto_trim.js';
28
-
29
- // Local modules
30
- import { createVentoEngine } from './engine.js';
31
- import { ignoreTagPlugin } from './modules/ignore-tag.js';
32
- import { DEBUG, runCompatibilityCheck } from './modules/utils.js';
33
-
34
- /**
35
- * @param {import('@11ty/eleventy').UserConfig} eleventyConfig
36
- * @param {Partial<VentoPluginOptions>} userOptions
37
- */
38
- export function VentoPlugin(eleventyConfig, userOptions) {
39
- DEBUG.setup('Initializing eleventy-plugin-vento');
40
- runCompatibilityCheck(eleventyConfig);
41
-
42
- /** @type {VentoPluginOptions} */
43
- const options = {
44
- // Define defaults
45
- autotrim: false,
46
- plugins: [],
47
- filters: true,
48
- shortcodes: true,
49
- pairedShortcodes: true,
50
- ignoreTag: false,
51
- ventoOptions: {
52
- includes: eleventyConfig.directories.includes,
53
- },
54
-
55
- // Merge in user-provided options
56
- ...userOptions,
57
- };
58
-
59
- DEBUG.setup('Merged default and user config: %O', options);
60
-
61
- if (options.ignoreTag) {
62
- console.error(
63
- '[eleventy-plugin-vento] DEPRECATION NOTICE:',
64
- 'Plugin was called with `ignoreTag` option, which has been deprecated.',
65
- 'For more information, see: https://github.com/noelforte/eleventy-plugin-vento/blob/main/readme.md#ignoring-tags'
66
- );
67
- }
68
-
69
- // Get list of filters, shortcodes and paired shortcodes
70
- const filters = eleventyConfig.getFilters();
71
- DEBUG.setup('Reading filters from Eleventy: %o', filters);
72
-
73
- const shortcodes = eleventyConfig.getShortcodes();
74
- DEBUG.setup('Reading shortcodes from Eleventy: %o', shortcodes);
75
-
76
- const pairedShortcodes = eleventyConfig.getPairedShortcodes();
77
- DEBUG.setup('Reading paired shortcodes from Eleventy: %o', pairedShortcodes);
78
-
79
- // Add autotrim plugin if enabled
80
- if (options.autotrim) {
81
- const defaults = ['@vento', '@11ty'];
82
-
83
- /** @type {Set<string>} */
84
- const tagSet = new Set(options.autotrim === true ? defaults : options.autotrim);
85
-
86
- if (tagSet.has('@vento')) {
87
- tagSet.delete('@vento');
88
- for (const name of autotrimDefaultTags) {
89
- tagSet.add(name);
90
- }
91
- }
92
-
93
- if (tagSet.has('@11ty')) {
94
- tagSet.delete('@11ty');
95
- for (const name in pairedShortcodes) {
96
- tagSet.add(name);
97
- }
98
- }
99
-
100
- DEBUG.setup('Enabled autotrim for tags: %o', tagSet);
101
-
102
- options.plugins.push(autotrimPlugin({ tags: [...tagSet] }));
103
- }
104
-
105
- // Add ignore tag plugin if enabled
106
- if (options.ignoreTag) {
107
- DEBUG.setup('Enabling `{{! ... }}` tag syntax');
108
- options.plugins.push(ignoreTagPlugin);
109
- }
110
-
111
- // Create the vento engine instance
112
- DEBUG.setup('Initializing Vento environment');
113
- const engine = createVentoEngine(options.ventoOptions);
114
-
115
- // Load plugins
116
- DEBUG.setup('Loading plugins: %o', options.plugins);
117
- engine.loadPlugins(options.plugins);
118
-
119
- // Add filters, single and paired shortcodes if enabled
120
- if (options.filters) {
121
- DEBUG.setup('Loading filters: %o', filters);
122
- engine.loadFilters(filters);
123
- }
124
- if (options.shortcodes) {
125
- DEBUG.setup('Loading shortcodes: %o', shortcodes);
126
- engine.loadShortcodes(shortcodes);
127
- }
128
- if (options.pairedShortcodes) {
129
- DEBUG.setup('Loading paired shortcodes: %o', pairedShortcodes);
130
- engine.loadPairedShortcodes(pairedShortcodes);
131
- }
132
-
133
- // Handle emptying the cache when files are updated
134
- DEBUG.setup('Registering Vento cache handler on eleventy.beforeWatch event');
135
- eleventyConfig.on('eleventy.beforeWatch', async (updatedFiles) => {
136
- for (let file of updatedFiles) {
137
- file = path.normalize(file);
138
- DEBUG.cache('Delete cache entry for %s', file);
139
- engine.cache.delete(file);
140
- }
141
- });
142
-
143
- // Add vto as a template format
144
- DEBUG.setup('Registering .vto as a template format');
145
- eleventyConfig.addTemplateFormats('vto');
146
-
147
- // Add extension handling
148
- DEBUG.setup('Registering .vto extension with eleventy');
149
- eleventyConfig.addExtension('vto', {
150
- outputFileExtension: 'html',
151
- read: true,
152
-
153
- compile(inputContent, inputPath) {
154
- // Normalize input path
155
- inputPath = path.normalize(inputPath);
156
-
157
- // Retrieve the template function
158
- const template = engine.getTemplateFunction(inputContent, inputPath, false);
159
-
160
- // Return a render function
161
- return async (data) => await engine.render(template, data, inputPath);
162
- },
163
-
164
- compileOptions: {
165
- // Custom permalink compilation
166
- permalink(permalinkContent, inputPath) {
167
- // Short circuit if input isn't a string and doesn't look like a vento template
168
- if (typeof permalinkContent === 'string' && /\{\{\s+.+\s+\}\}/.test(permalinkContent)) {
169
- // Normalize input path
170
- inputPath = 'Permalink::' + path.normalize(inputPath);
171
-
172
- // Retrieve the template function
173
- const template = engine.getTemplateFunction(permalinkContent, inputPath);
174
-
175
- // Return a render function
176
- return async (data) => await engine.render(template, data, inputPath);
177
- }
178
-
179
- return permalinkContent;
180
- },
181
- },
182
- });
183
-
184
- DEBUG.setup('eleventy-plugin-vento initialized');
185
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * @file Helper function that creates vento tags from eleventy functions
3
- *
4
- * @param {{name: string, group: 'shortcodes' | 'pairedShortcodes' }} options
5
- */
6
-
7
- export function createVentoTag(options) {
8
- const IS_PAIRED = options.group === 'pairedShortcodes';
9
-
10
- /** @type {import("ventojs/src/environment.js").Tag} */
11
- const tag = (env, code, output, tokens) => {
12
- if (!code.startsWith(options.name)) return;
13
-
14
- // Declare helper variables for repeated strings in template
15
- const fn = `__env.utils._11tyFns.${options.group}.${options.name}`;
16
- const ctx = '__env.utils._11tyCtx';
17
- const args = [code.replace(options.name, '').trim()];
18
-
19
- const varname = output.startsWith('__shortcode_content')
20
- ? `${output}_precomp`
21
- : '__shortcode_content';
22
-
23
- // Create an array to hold compiled template code
24
- const compiled = [];
25
-
26
- if (IS_PAIRED) {
27
- args.unshift(env.compileFilters(tokens, varname, env.options.autoescape));
28
- compiled.push(
29
- '{',
30
- `let ${varname} = "";`,
31
- ...env.compileTokens(tokens, varname, [`/${options.name}`])
32
- );
33
- if (tokens.length > 0 && (tokens[0][0] !== 'tag' || tokens[0][1] !== `/${options.name}`)) {
34
- throw new Error(`Vento: Missing closing tag for ${options.name} tag: ${code}`);
35
- }
36
- tokens.shift();
37
- }
38
-
39
- args.unshift(ctx);
40
-
41
- compiled.push(
42
- '{',
43
- `const __shortcode_result = await ${fn}.call(${args.filter(Boolean).join(', ')});`,
44
- `${output} += ${env.compileFilters(tokens, '__shortcode_result', env.options.autoescape)}`,
45
- '}'
46
- );
47
-
48
- if (IS_PAIRED) {
49
- compiled.push('}');
50
- }
51
-
52
- const compiledTag = compiled.join('\n');
53
-
54
- return compiledTag;
55
- };
56
-
57
- return Object.defineProperty(tag, 'name', {
58
- value: options.name + IS_PAIRED ? `PairedTag` : `Tag`,
59
- });
60
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * @file Definition for tag that preserves vento syntax in output
3
- */
4
-
5
- /** @type {import('ventojs/src/environment.js').Tag} */
6
- function ignoreTag(_env, code, output, _tokens) {
7
- if (!code.startsWith('!')) return;
8
- const compiled = `{{${code.replace(/!(>?)\s+/, '$1 ')}}}`;
9
- return `${output} += "${compiled}";`;
10
- }
11
-
12
- /** @type {import('ventojs/src/environment.js').Plugin} */
13
- export function ignoreTagPlugin(env) {
14
- env.tags.push(ignoreTag);
15
- }
@@ -1,34 +0,0 @@
1
- // Set up debugger global
2
- import createDebugger from 'debug';
3
- const debugBaseNamespace = 'Eleventy:Vento';
4
- export const DEBUG = {
5
- setup: createDebugger(`${debugBaseNamespace}:Setup`),
6
- cache: createDebugger(`${debugBaseNamespace}:Cache`),
7
- render: createDebugger(`${debugBaseNamespace}:Render`),
8
- };
9
-
10
- // Project-wide constants
11
- export const REQUIRED_API_METHODS = [
12
- ['getShortcodes', 'v3.0.0-alpha.15'],
13
- ['getPairedShortcodes', 'v3.0.0-alpha.15'],
14
- ['getFilters', 'v3.0.0-alpha.15'],
15
- ['addExtension', 'v1.0.0'],
16
- ];
17
-
18
- export const CONTEXT_DATA_KEYS = ['page', 'eleventy'];
19
-
20
- // Helper functions
21
- export function runCompatibilityCheck(config) {
22
- DEBUG.setup('Run compatibility check');
23
- for (const [method, version] of REQUIRED_API_METHODS) {
24
- if (!config?.[method]) {
25
- console.error(
26
- '[eleventy-plugin-vento] Plugin compatibility error:',
27
- `\`${method}\``,
28
- 'not found. Please use Eleventy',
29
- version,
30
- 'or later.'
31
- );
32
- }
33
- }
34
- }