Linting Eleventy data #3147
-
I'm looking at options for how to lint data on an Eleventy page to ensure that anything required by the template is present and valid. Some data is in front matter, some in directory data files, and some in global data files, so I really need the data after the data cascade to be complete. I have a solution, shown below, but I'm wondering if there's a better way (ideally a way that could be a plugin that's passed the data configuration to validate). Options that didn't work:
The one solution that is working is using computed data. File: module.exports = {
invalid: (data) => {
// Check `data` for validity, which has data after the cascade...
// Log errors to an `errors` array...
console.error(`[11ty] Invalid data for ${page.inputPath}: ${errors.join(', ')}`);
return errors.length > 0;
}
}; Then during a build this outputs errors like:
One by-product of this approach is the All of this raises two questions:
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 14 replies
-
I've actually given this a go over at https://github.com/uncenter/eleventy-frontmatter-with-zod using Zod for validation. It is possible with current Eleventy I think but that version showcases a potential change to Eleventy that allows for access to data from front matter specifically (which opens it up to stricter comparisons, not allowing extra keys...). |
Beta Was this translation helpful? Give feedback.
-
+1 to the https://github.com/pdehaan/11ty-schema-ajv I should really add a README.md to that repo, but basically you can define collection specific schemas in ./schemas/blog.js (or whatever), like this: // ./schemas/blog.js
module.exports = {
"$id": "blogs",
"type": "object",
"properties": {
"title": { type: "string" },
"orderId": { type: "number" },
},
"required": ["title", "orderId"],
}; Then I have ./schemas/index.js which creates my Ajv instance and exports a validator which throws an Error if the required fields aren't found in data cascade: // ./schemas/index.js
const Ajv = require("ajv");
const ajv = new Ajv({ allErrors: true });
ajv.addSchema(require("./blogs"));
function validateSchema(data, id, dataVar) {
const validate = ajv.getSchema(id);
if (!validate(data)) {
throw new Error(ajv.errorsText(validate.errors, { dataVar }));
}
}
module.exports = {
validate: validateSchema,
}; Finally, my eleventy.config.js imports the const { validate } = require("./schemas/index");
/**
* @param {import("@11ty/eleventy/src/UserConfig")} eleventyConfig
* @returns {ReturnType<import("@11ty/eleventy/src/defaultConfig")>}
*/
module.exports = function (eleventyConfig) {
addCollectionValidate("blogs");
function addCollectionValidate(name) {
eleventyConfig.addCollection(name, function (collectionApi) {
const pages = [...collectionApi.getFilteredByTag(name)];
for (const p of pages) {
try {
validate(p.data, name, p.inputPath);
} catch (err) {
console.error(err.message);
process.exitCode = 1;
}
}
return pages;
});
}
return {
dir: {
input: "src",
output: "www",
}
};
}; And my console output looks like this: npm run build
> [email protected] build
> eleventy
./src/blogs/four.njk must have required property 'orderId'
./src/blogs/one.njk must have required property 'title', ./src/blogs/one.njk must have required property 'orderId'
./src/blogs/three.njk must have required property 'orderId'
./src/blogs/two.njk must have required property 'orderId'
./src/blogs/four.njk must have required property 'orderId'
./src/blogs/one.njk must have required property 'title', ./src/blogs/one.njk must have required property 'orderId'
./src/blogs/three.njk must have required property 'orderId'
./src/blogs/two.njk must have required property 'orderId'
[11ty] Writing www/index.html from ./src/index.njk
[11ty] Writing www/blogs/two/index.html from ./src/blogs/two.njk
[11ty] Writing www/blogs/four/index.html from ./src/blogs/four.njk
[11ty] Writing www/blogs/five/index.html from ./src/blogs/five.njk
[11ty] Writing www/blogs/three/index.html from ./src/blogs/three.njk
[11ty] Writing www/blogs/one/index.html from ./src/blogs/one.njk
[11ty] Wrote 6 files in 0.04 seconds (v2.0.1) I image we could/should probably fail louder on schema validation errors versus just logging a message and still building. Another option would be specifying a template's or collection's schema name in front-matter or directory data files, then just using |
Beta Was this translation helpful? Give feedback.
-
One note with the collection approach is that adding the collection adds that tag in
|
Beta Was this translation helpful? Give feedback.
Yeah I've made it into a plugin, I'll try to add support for other validator libraries!