eleventy-plugin-vento 1.0.4

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/.editorconfig ADDED
@@ -0,0 +1,16 @@
1
+ # EditorConfig is awesome: https://EditorConfig.org
2
+
3
+ # top-most EditorConfig file
4
+ root = true
5
+
6
+ [*]
7
+ charset = utf-8
8
+ end_of_line = lf
9
+ insert_final_newline = true
10
+ indent_style = tab
11
+ indent_size = 2
12
+ trim_trailing_whitespace = true
13
+ max_line_length = 100
14
+
15
+ [*.{yaml,yml,md}]
16
+ indent_style = space
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": ["github>noelforte/renovate-config", "group:allNonMajor"],
3
+ "customManagers": [
4
+ {
5
+ "customType": "regex",
6
+ "fileMatch": ["(^|\\/)\\.mise\\.toml$"],
7
+ "matchStrings": [
8
+ "#renovate: datasource=(?<datasource>\\S+)(\\s|\\sversioning=(?<versioning>\\S+)\\s)(?<depName>\\S+)\\s?=\\s?\"(?<currentValue>[^\\\"]+)\""
9
+ ],
10
+ "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,48 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [renovate/**]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ ci:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ # ========== SETUP ========== #
13
+ - name: Check out repository
14
+ uses: actions/checkout@v4.1.6
15
+
16
+ # Setup node
17
+ - name: Setup tools
18
+ uses: jdx/mise-action@v2
19
+
20
+ # Setup pnpm
21
+ - name: Setup pnpm
22
+ uses: pnpm/action-setup@v4.0.0
23
+
24
+ # Get metadata
25
+ - name: Get pnpm store directory
26
+ id: get-pnpm-store
27
+ shell: bash
28
+ run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
29
+
30
+ # Setup the cache
31
+ - uses: actions/cache@v4
32
+ name: Restore cache
33
+ id: cache-deps
34
+ with:
35
+ path: ${{ steps.get-pnpm-store.outputs.path }}
36
+ key:
37
+ deps_os-${{ runner.os }}_arch-${{ runner.arch }}_${{
38
+ hashFiles('./pnpm-lock.yaml') }}
39
+
40
+ # Install dependencies
41
+ - name: Install dependencies
42
+ run: pnpm install --frozen-lockfile --prefer-offline
43
+ shell: bash
44
+
45
+ # ========== CHECK ========== #
46
+ - name: Run checks
47
+ run: pnpm test
48
+ shell: bash
package/.mise.toml ADDED
@@ -0,0 +1,3 @@
1
+ [tools]
2
+ #renovate: datasource=node-version versioning=node
3
+ node = "20.14.0"
@@ -0,0 +1,3 @@
1
+ {
2
+ "cSpell.words": ["Vento"]
3
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Noel Forte
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/VentoPlugin.js ADDED
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @file Adds Vento support to Eleventy.
3
+ *
4
+ * @typedef VentoPluginOptions
5
+ * @prop {Object<string,(...any) => any} [filters={}] An object containing methods that
6
+ * will be loaded as filters into Vento.
7
+ * @prop {import('ventojs').Options} [ventoOptions] Vento engine configuration object
8
+ * that will be merged with default options.
9
+ * @prop {string|boolean} [addHelpers=true] Whether
10
+ * [Javascript Functions](https://www.11ty.dev/docs/languages/javascript/#javascript-template-functions)
11
+ * should be merged into data provided to templates. If a string, functions will be namespaced under
12
+ * a property with this name.
13
+ */
14
+
15
+ import path from 'node:path';
16
+ import VentoJs from 'ventojs';
17
+
18
+ /**
19
+ * @param {import('@11ty/eleventy/src/UserConfig.js').default} eleventyConfig
20
+ * @param {VentoPluginOptions} options
21
+ */
22
+ export function VentoPlugin(eleventyConfig, options = {}) {
23
+ if (!('addExtension' in eleventyConfig)) {
24
+ console.log(
25
+ `[eleventy-plugin-vento] WARN Eleventy plugin compatibility: Custom templates are required for this plugin, please use Eleventy v1.0 or newer.`
26
+ );
27
+ }
28
+
29
+ // Pull some bits from eleventyConfig and merge user-options with defaults
30
+ const { dir, javascriptFunctions } = eleventyConfig;
31
+ options = {
32
+ addHelpers: true,
33
+ filters: {},
34
+ ventoOptions: {
35
+ includes: path.join(dir.input, dir.includes),
36
+ autoescape: false,
37
+ },
38
+ ...options,
39
+ };
40
+
41
+ // Init vento
42
+ const env = VentoJs(options.ventoOptions);
43
+
44
+ // Load user-defined filters into vento
45
+ for (const filter in options.filters) env.filters[filter] = options.filters[filter];
46
+
47
+ eleventyConfig.on('eleventy.before', () => {
48
+ env.cache.clear();
49
+ });
50
+
51
+ // Add vto as a template format and create a custom template for it
52
+ eleventyConfig.addTemplateFormats('vto');
53
+ eleventyConfig.addExtension('vto', {
54
+ outputFileExtension: 'html',
55
+ async compile(inputContent, inputPath) {
56
+ return async (data) => {
57
+ if (options.addHelpers) {
58
+ // Extract a possible namespace from the addHelpers option
59
+ const namespace = options.addHelpers;
60
+
61
+ // Rebind functions to page data so this.page, this.eleventy, etc works as intended
62
+ const helpers = Object.assign(
63
+ ...Object.entries(javascriptFunctions).map(([name, fn]) => ({ [name]: fn.bind(data) }))
64
+ );
65
+
66
+ // Merge helpers into page data
67
+ if (typeof namespace === 'string') data = { ...data, [namespace]: helpers };
68
+ else data = { ...data, ...helpers };
69
+ }
70
+
71
+ return await env.runString(inputContent, data, inputPath).then((result) => result.content);
72
+ };
73
+ },
74
+ });
75
+ }
@@ -0,0 +1,67 @@
1
+ import js from '@eslint/js';
2
+
3
+ // Configs
4
+ import gitignore from 'eslint-config-flat-gitignore';
5
+ import eslintConfigPrettier from 'eslint-config-prettier';
6
+
7
+ // Plugins
8
+ import globals from 'globals';
9
+
10
+ export default [
11
+ // Set ignores from gitignore
12
+ gitignore(),
13
+
14
+ // Import configuration presets
15
+ js.configs.recommended,
16
+ eslintConfigPrettier,
17
+
18
+ // Configure ignores
19
+ {
20
+ ignores: ['**/.cache', '**/_site', '**/node_modules', '**/functions'],
21
+ },
22
+
23
+ // Configure defaults
24
+ {
25
+ languageOptions: {
26
+ ecmaVersion: 'latest',
27
+ },
28
+ rules: {
29
+ 'no-unused-vars': [
30
+ 'error',
31
+ {
32
+ argsIgnorePattern: '^_',
33
+ },
34
+ ],
35
+ 'no-else-return': [
36
+ 'error',
37
+ {
38
+ allowElseIf: false,
39
+ },
40
+ ],
41
+ 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
42
+ 'prefer-object-spread': 'error',
43
+ 'prefer-const': ['error', { destructuring: 'all' }],
44
+ 'prefer-arrow-callback': ['error', { allowNamedFunctions: true }],
45
+ 'prefer-destructuring': [
46
+ 'error',
47
+ {
48
+ VariableDeclarator: { array: false, object: true },
49
+ AssignmentExpression: { array: false, object: false },
50
+ },
51
+ ],
52
+ 'object-shorthand': ['error', 'always'],
53
+ 'arrow-body-style': ['error', 'as-needed'],
54
+ eqeqeq: ['error', 'smart'],
55
+ },
56
+ },
57
+
58
+ // Match all node-files
59
+ {
60
+ files: ['**/*.js'],
61
+ languageOptions: {
62
+ globals: {
63
+ ...globals.node,
64
+ },
65
+ },
66
+ },
67
+ ];
package/jsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "NodeNext",
4
+ "moduleResolution": "NodeNext"
5
+ }
6
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "eleventy-plugin-vento",
3
+ "version": "1.0.4",
4
+ "description": "Adds support for the Vento templating language to Eleventy",
5
+ "type": "module",
6
+ "packageManager": "pnpm@9.1.4",
7
+ "scripts": {
8
+ "test": "rm -rf test/output; cd test/input; eleventy",
9
+ "test-serve": "rm -rf test/output; cd test/input; eleventy --serve"
10
+ },
11
+ "main": "./VentoPlugin.js",
12
+ "repository": "git@github.com:noelforte/eleventy-plugin-vento.git",
13
+ "bugs": {
14
+ "url": "https://github.com/noelforte/eleventy-plugin-vento/issues"
15
+ },
16
+ "keywords": [
17
+ "eleventy",
18
+ "eleventy-plugin",
19
+ "ventojs",
20
+ "templating"
21
+ ],
22
+ "author": {
23
+ "name": "Noel Forte",
24
+ "email": "noel@forte.is",
25
+ "url": "https://forte.is/"
26
+ },
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "ventojs": "0.12.6"
30
+ },
31
+ "devDependencies": {
32
+ "eslint": "9.4.0",
33
+ "eslint-config-flat-gitignore": "0.1.5",
34
+ "eslint-config-prettier": "9.1.0",
35
+ "globals": "15.3.0",
36
+ "@11ty/eleventy": "3.0.0-alpha.10"
37
+ },
38
+ "prettier": {
39
+ "bracketSameLine": true,
40
+ "singleQuote": true,
41
+ "semi": true,
42
+ "trailingComma": "es5"
43
+ }
44
+ }
package/readme.md ADDED
@@ -0,0 +1,132 @@
1
+ # eleventy-plugin-vento 🌬️🎈🐀
2
+
3
+ An [Eleventy](https://11ty.dev/) plugin that adds support for [Vento](https://vento.js.org/) templates.
4
+
5
+ [Installing](#installing)<br>
6
+ [Usage](#usage)<br>
7
+ [Plugin Options](#plugin-options)<br>
8
+ [Vento Filters](#vento-filters)<br>
9
+ [JavaScript Helpers](#javascript-helpers)<br>
10
+
11
+ ## Installing
12
+
13
+ ```sh
14
+ npm install eleventy-plugin-vento
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ This plugin is ESM only and cannot be required from CommonJS. As such, it's best used with Eleventy v3.0.0.
20
+
21
+ If you're using CommonJS and loading it asynchronously (ie `await import`), you will need at minimum Eleventy v1.0.0 which added support for [Custom Templates](https://www.11ty.dev/docs/languages/custom/).
22
+
23
+ In your Eleventy config:
24
+
25
+ ```js
26
+ import { VentoPlugin } from 'eleventy-plugin-vento';
27
+
28
+ export default function (eleventyConfig) {
29
+ eleventyConfig.addPlugin(VentoPlugin);
30
+ }
31
+ ```
32
+
33
+ ## Plugin Options
34
+
35
+ This plugin ships with default options out of the box, but you can [pass an options object](https://www.11ty.dev/docs/plugins/#plugin-configuration-options) to your `addPlugin` call to configure things further. The below example shows the configurable options as well as their defaults.
36
+
37
+ ```js
38
+ import { VentoPlugin } from 'eleventy-plugin-vento';
39
+
40
+ export default function (eleventyConfig) {
41
+
42
+ eleventyConfig.addPlugin(VentoPlugin, {
43
+ // A set of filters to load into Vento
44
+ filters: {},
45
+
46
+ // Define whether Javascript Functions should be added
47
+ // to page data. See below for usage notes on this.
48
+ addHelpers: true
49
+
50
+ // A Vento configuration object
51
+ ventoOptions: {
52
+ includes: '...', // defaults to the Eleventy 'includes' directory
53
+ autoescape: false,
54
+ },
55
+ });
56
+
57
+ }
58
+ ```
59
+
60
+ View the [full list of options](https://vento.js.org/configuration/#options/) to pass as a Vento Configuration object.
61
+
62
+ ## Vento Filters
63
+
64
+ Set the `filters` property to an object with methods, these will be loaded as filters into Vento when Eleventy is run. Note that this feature exists **separately** from the concept of filters in Eleventy ([which are optionally accessible as data in Vento templates]()).
65
+
66
+ Here's an example of defining an `italicize` filter like the example in the Vento documentation:
67
+
68
+ ```js
69
+ {
70
+ filters: {
71
+ italicize(text) {
72
+ return `<em>${text}</em>`
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ And now we can use our filter in a template:
79
+
80
+ ```hbs
81
+ <p>The title of my page is: "{{ title |> italicize }}"</p>
82
+ ```
83
+
84
+ See https://vento.js.org/configuration/#filters for more information about filters and how they work.
85
+
86
+ ## JavaScript Helpers
87
+
88
+ Vento can [run arbitrary JavaScript](https://vento.js.org/syntax/javascript/) in templates through its `{{> ...}}` operator, which evaluates at the time the template is run. However, you may want to use Eleventy Shortcodes and Filters in your templates as well.
89
+
90
+ By setting `addHelpers` in the plugin options (defaults to `true`), all JavaScript functions (which includes any Universal Filters and Shortcodes) are exposed as functions in page data. This feature functions very similarly to WebC's ["helper functions"](https://www.11ty.dev/docs/languages/javascript/#javascript-template-functions) feature.
91
+
92
+ As an example:
93
+
94
+ ```js
95
+ export default function (eleventyConfig) {
96
+ // via Universal Filter...
97
+ eleventyConfig.addFilter('italicize', (content) => `<em>${content}</em>`);
98
+
99
+ // ...or via Universal Shortcode
100
+ eleventyConfig.addShortcode('greeting', (name) => `My name is ${name}`);
101
+
102
+ // ...or via JavaScript Template Function
103
+ eleventyConfig.addJavaScriptFunction('possumPosse', () => 'Release the possums!!!');
104
+ }
105
+ ```
106
+
107
+ ```hbs
108
+ <p>This is something {{ italicize('really') }} important.</p>
109
+ <p>{{ possumPosse() }}</p>
110
+
111
+ <!-- renders as: -->
112
+
113
+ <p>This is something <em>really</em> important.</p>
114
+ <p>Release the possums!!!</p>
115
+
116
+ ```
117
+
118
+ Alternatively, if you'd rather keep functions namespaced in your page data, pass a string to `addHelpers`. Your functions will be namespaced under this property name in page data.
119
+
120
+ ```js
121
+ addPlugin(VentoPlugin, { addHelpers: 'functions' });
122
+ ```
123
+
124
+ ```hbs
125
+ <!-- With the above, this: -->
126
+ <p>This is something {{ italicize('really') }} important.</p>
127
+ <p>{{ possumPosse() }}</p>
128
+
129
+ <!-- should be written as: -->
130
+ <p>This is something {{ functions.italicize('really') }} important.</p>
131
+ <p>{{ functions.possumPosse() }}</p>
132
+ ```
@@ -0,0 +1,20 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{ title }}</title>
7
+ </head>
8
+ <body>
9
+ <header>
10
+ <h1>Page title: {{ title }}</h1>
11
+ </header>
12
+ <main>
13
+ <section>This is an alternative layout.</section>
14
+ <section>{{ content }}</section>
15
+ </main>
16
+ <footer>
17
+ <p>I am a footer, outside the layout</p>
18
+ </footer>
19
+ </body>
20
+ </html>
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{ title }}</title>
7
+ </head>
8
+ <body>
9
+ <header>
10
+ <h1>Page title: {{ title }}</h1>
11
+ </header>
12
+ <main>{{ content }}</main>
13
+ <footer>
14
+ <p>I am a footer, outside the layout</p>
15
+ </footer>
16
+ </body>
17
+ </html>
@@ -0,0 +1,3 @@
1
+ <section class="include">
2
+ <p>This content is included.</p>
3
+ </section>
@@ -0,0 +1,21 @@
1
+ import { VentoPlugin } from '../../VentoPlugin.js';
2
+
3
+ export const config = {
4
+ dir: {
5
+ input: '.',
6
+ output: '../output',
7
+ },
8
+ };
9
+
10
+ /** @param {import('@11ty/eleventy/src/UserConfig.js').default} eleventyConfig */
11
+ export default async function (eleventyConfig) {
12
+ eleventyConfig.addPlugin(VentoPlugin, {
13
+ filters: {
14
+ italicize(content) {
15
+ return `<em>${content}</em>`;
16
+ },
17
+ },
18
+ });
19
+
20
+ eleventyConfig.addShortcode('possumPosse', () => 'Release the possums!!!');
21
+ }
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: Page with filters
3
+ ---
4
+
5
+ <h1>{{ title }}</h1>
6
+
7
+ This is a page with a filter.
8
+
9
+ Built with {{ eleventy.generator |> italicize }}
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: Simple Page
3
+ ---
4
+
5
+ <h1>{{ title }}</h1>
6
+
7
+ This is a standalone page.
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: Page with includes
3
+ ---
4
+
5
+ <h1>{{ title }}</h1>
6
+
7
+ {{ include 'partial.vto' }}
@@ -0,0 +1,11 @@
1
+ ---
2
+ title: Page with layout
3
+ layout: page-layout.vto
4
+ ---
5
+
6
+ <p>This is a page that uses a layout.</p>
7
+
8
+ <p>This is another paragraph.</p>
9
+ <p>This is another paragraph.</p>
10
+ <p>This is another paragraph.</p>
11
+
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: Page with shortcodes
3
+ layout: page-layout.vto
4
+ ---
5
+
6
+ {{ possumPosse() }}