Skip to content

Commit

Permalink
feat: update using collectionApi.getAll() to allow config defined col…
Browse files Browse the repository at this point in the history
…lections
  • Loading branch information
uncenter committed Jan 5, 2024
1 parent c1f5e4f commit e6de4a1
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 9 deletions.
45 changes: 39 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import { log } from './utils';

export { z as zod } from 'zod';

const DUMMY_COLLECTION_NAME = '__eleventy-plugin-validate';

export function plugin(eleventyConfig: any, opts: Options) {
if (opts === null || typeof opts !== 'object')
throw new Error(`options: expected an object but received ${typeof opts}`);
const options = mergeOptions(opts);
validateOptions(options);

eleventyConfig.addCollection(
'__eleventy-plugin-validate',
DUMMY_COLLECTION_NAME,
async (collectionApi: any) => {
const issues: {
data: {
Expand All @@ -22,17 +24,42 @@ export function plugin(eleventyConfig: any, opts: Options) {
};
issue: ZodIssue;
}[] = [];

// Get a list of every collection item.
const all = collectionApi.getAll() as any[];
if (all.length === 0) return [];

// Loop through the user provided schemas.
for (const schema of options.schemas) {
const items = schema.collections
? collectionApi.getFilteredByTags(...schema.collections)
: collectionApi.getAll();
const items: any[] = [];

// Loop through all entries.
for (const entry of all) {
// Loop through each of the collections this entry is a part of.
for (const [name, values] of Object.entries(entry.data.collections)) {
// If collections was left blank / unpecified by the user, or the name of this collection is in the user's list of collections...
if (!schema.collections || schema.collections.includes(name)) {
// Loop through each of the collection items.
for (const value of values as any[]) {
// And if we don't already have the same item in our items list (compare input paths), add it.
if (!items.some((item) => item.inputPath === value.inputPath)) {
items.push(value);
}
}
}
}
}

// Now, loop through the items that we have narrowed down to be applicable here.
for (const item of items) {
const { data: fm } = item.template._frontMatter;
// Use a hack to get *just* the front matter data, nothing else (allos for usage of .strict() on Zod schemas).
const fm = item.template._frontMatter.data;
// Safely parse the front matter with the user's schema.
const result = schema.schema.safeParse(fm);

if (!result.success) {
issues.push(
// Add the issues to a list, maing sure to add context to each about the item/data it came with.
...result.error.issues.map((i) => {
return {
data: {
Expand All @@ -47,7 +74,9 @@ export function plugin(eleventyConfig: any, opts: Options) {
}
}

// Now that we have gone through all of the user defined schemas and gathered any issues, loop through them.
for (const { data, issue } of issues) {
// Lots of formatting...
let message = '';
let path = issue.path.join('.');
path = path ? path + ': ' : '';
Expand All @@ -72,9 +101,13 @@ export function plugin(eleventyConfig: any, opts: Options) {
}
log.error(`[${data.path}] ${message}`);
}
if (issues.length > 0)

// Throw an error if there was at least one issue.
if (issues.length > 0) {
throw new Error(`Invalid frontmatter data provided`);
}

// Return dummy array so Eleventy doesn't complain
return [];
},
);
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/eleventy.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const { zod, plugin } = require('../../dist/index.cjs');

module.exports = (eleventyConfig) => {
eleventyConfig.addCollection('posts', (collectionsApi) => {
return collectionsApi.getFilteredByGlob('./posts/*.md');
});

eleventyConfig.addPlugin(plugin, {
schemas: [
{
Expand Down
3 changes: 0 additions & 3 deletions test/fixtures/posts/posts.11tydata.js

This file was deleted.

0 comments on commit e6de4a1

Please sign in to comment.