From a303ec2ba13d685123f08beec2ce11aaec79bdd1 Mon Sep 17 00:00:00 2001 From: mwdelaney Date: Tue, 21 Oct 2025 17:22:00 -0400 Subject: [PATCH 1/3] Custom globbing, debuging, easier-to-understand output config --- README.md | 6 +- src/collections.js | 29 +++++- src/config.js | 3 +- src/debug.js | 214 +++++++++++++++++++++++++++++++++++++++++++++ src/filters.js | 83 +++++++++++++++--- src/plugin.js | 11 ++- 6 files changed, 327 insertions(+), 19 deletions(-) create mode 100644 src/debug.js diff --git a/README.md b/README.md index 3b8de5d..6c10822 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ A configurable [Eleventy](https://www.11ty.dev/) plugin that enables a powerful - 🧩 **Dynamic Component Rendering** - Render components based on content data - 🎨 **Template Language Agnostic** - Works with Nunjucks, Liquid, WebC, Vento, and more - 🏗️ **Flexible Configuration** - Customizable directories and options -- 🚀 **Production Ready** - Excludes development components from production builds +- 🚀 **Output Control** - Choose whether components are written to their own output files - 🔧 **Developer Friendly** - Comprehensive error handling and debugging ## Installation @@ -478,7 +478,7 @@ const defaultOptions = { componentsDir: "src/components/*.*", collectionName: "components", enableRenderPlugin: true, - excludeFromProduction: true + output: true }; ``` @@ -1024,7 +1024,7 @@ If no template language is specified, the filter will use the calling template's | `componentsDir` | `string` | `"src/components/*.*"` | Glob pattern for component files | | `collectionName` | `string` | `"components"` | Name of components collection | | `enableRenderPlugin` | `boolean` | `true` | Enable Eleventy Render Plugin | -| `excludeFromProduction` | `boolean` | `true` | Exclude components from production | +| `output` | `boolean` | `true` | Whether components are written to their own output files/endpoints | ### Filters diff --git a/src/collections.js b/src/collections.js index 2033d71..a79320b 100644 --- a/src/collections.js +++ b/src/collections.js @@ -1,3 +1,8 @@ +import { glob } from "fs/promises"; +import matter from "gray-matter"; +import { readFileSync } from "fs"; +import path from "path"; + /** * Add components collection to Eleventy * @param {Object} eleventyConfig - Eleventy configuration object @@ -7,8 +12,28 @@ export function addCollections(eleventyConfig, options) { /** * Components Collection * This collection includes all components from the configured components directory. + * Uses manual globbing to allow components outside the Eleventy input directory. */ - eleventyConfig.addCollection(options.collectionName, function(collectionApi) { - return collectionApi.getFilteredByGlob(options.componentsDir); + eleventyConfig.addCollection(options.collectionName, async function() { + // Manually glob files from the components directory using Node's fs.glob (Node 20+) + const componentFiles = await Array.fromAsync(glob(options.componentsDir)); + + // Process each component file to extract frontmatter and content + const components = componentFiles.map(filePath => { + const fileContent = readFileSync(filePath, 'utf-8'); + const { data, content } = matter(fileContent); + + return { + data: data, + rawInput: content, + inputPath: filePath, + page: { + inputPath: filePath, + fileSlug: path.basename(filePath, path.extname(filePath)) + } + }; + }); + + return components; }); } diff --git a/src/config.js b/src/config.js index 7e3e335..e7772c4 100644 --- a/src/config.js +++ b/src/config.js @@ -5,5 +5,6 @@ export const defaultOptions = { componentsDir: "src/components/*.*", collectionName: "components", enableRenderPlugin: true, - excludeFromProduction: true + output: true, + debug: process.env.DEBUG === "Eleventy:*" || process.env.DEBUG === "true" }; diff --git a/src/debug.js b/src/debug.js new file mode 100644 index 0000000..25c9da6 --- /dev/null +++ b/src/debug.js @@ -0,0 +1,214 @@ +import EleventyPluginDebug from "@11ty/eleventy-plugin-debug"; + +const PLUGIN_NAME = "eleventy-plugin-reusable-components"; +let DEBUG_ENABLED = false; + +/** + * Enable or disable debug output + * @param {boolean} enabled - Whether debug is enabled + */ +export function setDebugEnabled(enabled) { + DEBUG_ENABLED = enabled; +} + +/** + * Debug logging utilities for the plugin + * Uses Eleventy's standard debug format + */ + +/** + * Log a debug message with the plugin prefix + * @param {string} message - The message to log + * @param {number} indent - Indentation level (0-2) + */ +export function debug(message, indent = 0) { + if (!DEBUG_ENABLED) return; + + const prefix = "[11ty]"; + const pluginPrefix = `[${PLUGIN_NAME}]`; + const indentation = " ".repeat(indent); + console.log(`${prefix} ${pluginPrefix} ${indentation}${message}`); +} + +/** + * Log plugin initialization with options + * @param {Object} options - Plugin options + */ +export function debugInit(options) { + debug("Plugin initialized with options:"); + debug(`componentsDir: "${options.componentsDir}"`, 1); + debug(`collectionName: "${options.collectionName}"`, 1); + debug(`enableRenderPlugin: ${options.enableRenderPlugin}`, 1); + debug(`excludeFromProduction: ${options.excludeFromProduction}`, 1); + debug(`ELEVENTY_ENV: "${process.env.ELEVENTY_ENV || 'development'}"`, 1); +} + +/** + * Log production mode detection + * @param {string} componentsDir - The components directory pattern + */ +export function debugProductionMode(componentsDir) { + debug("Production mode detected"); + debug(`Ignoring components directory: ${componentsDir}`, 1); +} + +/** + * Log discovered components + * @param {Array} components - Array of component objects + * @param {Function} slugifyFilter - Eleventy's slugify filter + */ +export function debugComponents(components, slugifyFilter) { + debug(`Found ${components.length} component${components.length !== 1 ? 's' : ''}:`); + + if (components.length === 0) { + debug("⚠ No components found", 1); + return; + } + + components.forEach(component => { + if (component.data && component.data.title) { + const title = component.data.title; + const slug = slugifyFilter(title); + const path = component.inputPath || component.page?.inputPath || 'unknown path'; + debug(`✓ ${title} (${slug}) → ${path}`, 1); + } + }); +} + +/** + * Log renderComponent filter call + * @param {Array} items - Array of items to render + * @param {string} lang - Template language + */ +export function debugRenderStart(items, lang) { + debug("renderComponent called:"); + debug(`Items: ${items.length}`, 1); + debug(`Template language: ${lang || 'auto-detect'}`, 1); + debug("", 1); // Empty line for readability +} + +/** + * Log warning when no items provided + */ +export function debugNoItems() { + debug("⚠ Warning: No items provided"); + debug("Returning empty string", 1); +} + +/** + * Log warning when items are filtered out + * @param {number} filteredCount - Number of items filtered out + * @param {number} validCount - Number of valid items remaining + */ +export function debugFilteredItems(filteredCount, validCount) { + debug(`⚠ Warning: ${filteredCount} item${filteredCount !== 1 ? 's' : ''} without 'type' property ${filteredCount !== 1 ? 'were' : 'was'} filtered out`); + debug(`Valid items: ${validCount}`, 1); +} + +/** + * Log component match success + * @param {number} itemIndex - Index of the item (1-based) + * @param {string} type - Component type + * @param {string} componentPath - Path to component file + * @param {Object} mergedData - Merged data object + */ +export function debugMatchSuccess(itemIndex, type, componentPath, mergedData) { + debug(`Item ${itemIndex}:`, 1); + debug(`Type: ${type}`, 2); + debug(`Match: ✓ ${type}`, 2); + debug(`Component: ${componentPath}`, 2); + debug(`Merged data keys: ${Object.keys(mergedData).join(', ')}`, 2); +} + +/** + * Log component match success (simplified for multiple items) + * @param {number} itemIndex - Index of the item (1-based) + * @param {string} type - Component type + */ +export function debugMatchSuccessSimple(itemIndex, type) { + debug(`Item ${itemIndex}:`, 1); + debug(`Type: ${type}`, 2); + debug(`Match: ✓ ${type}`, 2); +} + +/** + * Log component match failure + * @param {number} itemIndex - Index of the item (1-based) + * @param {string} type - Component type that wasn't found + * @param {Array} availableComponents - Array of available component slugs + */ +export function debugMatchFailure(itemIndex, type, availableComponents) { + debug(`Item ${itemIndex}:`, 1); + debug(`Type: ${type}`, 2); + debug(`Match: ✗ No matching component found`, 2); + if (availableComponents.length > 0) { + debug(`Available: ${availableComponents.join(', ')}`, 2); + } +} + +/** + * Log warning when collections are missing + */ +export function debugNoCollections() { + if (!DEBUG_ENABLED) return; + debug("⚠ Warning: Collections not available or components collection is empty"); + debug("Returning empty string", 1); +} + +/** + * Debug wrapper for renderComponent filter + * Handles all debug logging for the filter lifecycle + */ +export function debugRenderComponent(context) { + if (!DEBUG_ENABLED) return; + + const { + phase, + items, + validItems, + filteredCount, + lang, + itemIndex, + itemType, + matched, + componentPath, + mergedData, + availableComponents, + components, + slugifyFilter + } = context; + + switch (phase) { + case 'no-items': + debugNoItems(); + break; + + case 'filtered-items': + debugFilteredItems(filteredCount, validItems.length); + break; + + case 'no-collections': + debugNoCollections(); + break; + + case 'components-list': + debugComponents(components, slugifyFilter); + break; + + case 'render-start': + debugRenderStart(validItems, lang); + break; + + case 'match': + if (validItems.length === 1) { + debugMatchSuccess(itemIndex, itemType, componentPath, mergedData); + } else { + debugMatchSuccessSimple(itemIndex, itemType); + } + break; + + case 'no-match': + debugMatchFailure(itemIndex, itemType, availableComponents); + break; + } +} diff --git a/src/filters.js b/src/filters.js index 26cd2de..ad74ecd 100644 --- a/src/filters.js +++ b/src/filters.js @@ -1,3 +1,5 @@ +import { debugRenderComponent } from "./debug.js"; + /** * Add filters for the component system * @param {Object} eleventyConfig - Eleventy configuration object @@ -83,54 +85,113 @@ export function addFilters(eleventyConfig) { // Render components filter - returns matched component templates eleventyConfig.addFilter("renderComponent", async function (items, lang) { + // Early return if no items provided if (!items) { + debugRenderComponent({ phase: 'no-items' }); return ""; } - // Normalize input to always be an array + // Normalize input to always be an array for consistent processing const itemsArray = Array.isArray(items) ? items : [items]; - // Filter out any items without a type + // Filter out any items that don't have a required 'type' property const validItems = itemsArray.filter(item => item && item.type); + // Early return if no valid items after filtering if (validItems.length === 0) { + debugRenderComponent({ phase: 'no-items' }); return ""; } + // Log warning if some items were filtered out due to missing 'type' + if (validItems.length < itemsArray.length) { + debugRenderComponent({ + phase: 'filtered-items', + filteredCount: itemsArray.length - validItems.length, + validItems + }); + } + + // Get the components collection from Eleventy's context const collections = this.ctx.collections || this.collections; if (!collections || !collections.components) { + debugRenderComponent({ phase: 'no-collections' }); return ""; } + // Get required filters from Eleventy const slugifyFilter = eleventyConfig.getFilter("slugify"); const renderFilter = eleventyConfig.getFilter("renderContent"); + + // Determine template language: use provided lang, or auto-detect from current page + const templateLang = lang || (this.page && this.page.templateSyntax); + + // Log discovered components once on first render (avoids spam in logs) + if (!this._componentsDebugLogged) { + debugRenderComponent({ + phase: 'components-list', + components: collections.components, + slugifyFilter + }); + this._componentsDebugLogged = true; + } + + debugRenderComponent({ phase: 'render-start', validItems, lang: templateLang }); + + // Pre-build list of available component slugs for error reporting + const availableComponents = collections.components + .filter(c => c.data && c.data.title) + .map(c => slugifyFilter(c.data.title)); + const renderedComponents = []; - // Process each item - for (const item of validItems) { - // Find the matching component in the collections + // Process each valid item + for (let i = 0; i < validItems.length; i++) { + const item = validItems[i]; + let matched = false; + + // Search through all components for a matching type for (const component of collections.components) { if (component.data && component.data.title) { + // Slugify both the component title and item type for comparison const componentSlug = slugifyFilter(component.data.title); const itemSlug = slugifyFilter(item.type); + // Check if this component matches the item's type if (componentSlug === itemSlug) { - // Merge component defaults with item data (item data takes precedence) + // Merge component's default data with item data (item overrides defaults) const mergedData = { ...component.data, ...item }; - // If a language was passed to the filter as lang, use it, otherwise get the calling template's templateSyntax - const templateLang = lang || (this.page && this.page.templateSyntax); + debugRenderComponent({ + phase: 'match', + validItems, + itemIndex: i + 1, + itemType: item.type, + componentPath: component.inputPath || component.page?.inputPath || 'unknown path', + mergedData + }); - // Render the component's rawInput with merged data using the determined template language + // Render the component template with merged data const rendered = await renderFilter.call(this, component.rawInput, templateLang, mergedData); renderedComponents.push(rendered); - break; // Move to next item after finding a match + matched = true; + break; // Stop searching once we find a match } } } + + // Log if no matching component was found for this item + if (!matched) { + debugRenderComponent({ + phase: 'no-match', + itemIndex: i + 1, + itemType: item.type, + availableComponents + }); + } } - // Join all rendered components with newlines + // Join all rendered components with newlines and return return renderedComponents.join("\n"); }); } diff --git a/src/plugin.js b/src/plugin.js index 9697087..534ad4d 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -2,6 +2,7 @@ import { EleventyRenderPlugin } from "@11ty/eleventy"; import { defaultOptions } from "./config.js"; import { addCollections } from "./collections.js"; import { addFilters } from "./filters.js"; +import { setDebugEnabled, debugInit, debugProductionMode } from "./debug.js"; /** * Universal Components for Eleventy Plugin @@ -13,6 +14,7 @@ import { addFilters } from "./filters.js"; * @param {string} [options.collectionName="components"] - Name of the components collection * @param {boolean} [options.enableRenderPlugin=true] - Whether to enable the Eleventy Render Plugin * @param {boolean} [options.excludeFromProduction=true] - Whether to exclude components from production builds + * @param {boolean} [options.debug=false] - Whether to enable debug output * * Collections: * - `components` (or custom name): A collection of components sourced from the components directory. @@ -25,6 +27,10 @@ export function reusableComponents(eleventyConfig, userOptions = {}) { // Merge user options with defaults const options = { ...defaultOptions, ...userOptions }; + // Configure debug output + setDebugEnabled(options.debug); + debugInit(options); + /** * Add the Eleventy Render Plugin. * Check if the plugin is already enabled before enabling it. @@ -34,10 +40,11 @@ export function reusableComponents(eleventyConfig, userOptions = {}) { } /** - * Exclude components from production builds + * Exclude components from builds */ - if (options.excludeFromProduction && process.env.ELEVENTY_ENV === "production") { + if (options.output == false) { eleventyConfig.ignores.add(options.componentsDir); + debugProductionMode(options.componentsDir); } // Add collections From 01074d57f533240e189aeb7b863b1f3ec6b4a81f Mon Sep 17 00:00:00 2001 From: mwdelaney Date: Wed, 22 Oct 2025 14:58:33 -0400 Subject: [PATCH 2/3] Fix linting errors --- src/collections.js | 2 +- src/debug.js | 34 +++++++++++++++------------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/collections.js b/src/collections.js index a79320b..fa5ca0b 100644 --- a/src/collections.js +++ b/src/collections.js @@ -20,7 +20,7 @@ export function addCollections(eleventyConfig, options) { // Process each component file to extract frontmatter and content const components = componentFiles.map(filePath => { - const fileContent = readFileSync(filePath, 'utf-8'); + const fileContent = readFileSync(filePath, "utf-8"); const { data, content } = matter(fileContent); return { diff --git a/src/debug.js b/src/debug.js index 25c9da6..016d4b3 100644 --- a/src/debug.js +++ b/src/debug.js @@ -1,5 +1,3 @@ -import EleventyPluginDebug from "@11ty/eleventy-plugin-debug"; - const PLUGIN_NAME = "eleventy-plugin-reusable-components"; let DEBUG_ENABLED = false; @@ -39,8 +37,8 @@ export function debugInit(options) { debug(`componentsDir: "${options.componentsDir}"`, 1); debug(`collectionName: "${options.collectionName}"`, 1); debug(`enableRenderPlugin: ${options.enableRenderPlugin}`, 1); - debug(`excludeFromProduction: ${options.excludeFromProduction}`, 1); - debug(`ELEVENTY_ENV: "${process.env.ELEVENTY_ENV || 'development'}"`, 1); + debug(`output: ${options.output}`, 1); + debug(`ELEVENTY_ENV: "${process.env.ELEVENTY_ENV || "development"}"`, 1); } /** @@ -58,7 +56,7 @@ export function debugProductionMode(componentsDir) { * @param {Function} slugifyFilter - Eleventy's slugify filter */ export function debugComponents(components, slugifyFilter) { - debug(`Found ${components.length} component${components.length !== 1 ? 's' : ''}:`); + debug(`Found ${components.length} component${components.length !== 1 ? "s" : ""}:`); if (components.length === 0) { debug("⚠ No components found", 1); @@ -69,7 +67,7 @@ export function debugComponents(components, slugifyFilter) { if (component.data && component.data.title) { const title = component.data.title; const slug = slugifyFilter(title); - const path = component.inputPath || component.page?.inputPath || 'unknown path'; + const path = component.inputPath || component.page?.inputPath || "unknown path"; debug(`✓ ${title} (${slug}) → ${path}`, 1); } }); @@ -83,7 +81,7 @@ export function debugComponents(components, slugifyFilter) { export function debugRenderStart(items, lang) { debug("renderComponent called:"); debug(`Items: ${items.length}`, 1); - debug(`Template language: ${lang || 'auto-detect'}`, 1); + debug(`Template language: ${lang || "auto-detect"}`, 1); debug("", 1); // Empty line for readability } @@ -101,7 +99,7 @@ export function debugNoItems() { * @param {number} validCount - Number of valid items remaining */ export function debugFilteredItems(filteredCount, validCount) { - debug(`⚠ Warning: ${filteredCount} item${filteredCount !== 1 ? 's' : ''} without 'type' property ${filteredCount !== 1 ? 'were' : 'was'} filtered out`); + debug(`⚠ Warning: ${filteredCount} item${filteredCount !== 1 ? "s" : ""} without 'type' property ${filteredCount !== 1 ? "were" : "was"} filtered out`); debug(`Valid items: ${validCount}`, 1); } @@ -117,7 +115,7 @@ export function debugMatchSuccess(itemIndex, type, componentPath, mergedData) { debug(`Type: ${type}`, 2); debug(`Match: ✓ ${type}`, 2); debug(`Component: ${componentPath}`, 2); - debug(`Merged data keys: ${Object.keys(mergedData).join(', ')}`, 2); + debug(`Merged data keys: ${Object.keys(mergedData).join(", ")}`, 2); } /** @@ -142,7 +140,7 @@ export function debugMatchFailure(itemIndex, type, availableComponents) { debug(`Type: ${type}`, 2); debug(`Match: ✗ No matching component found`, 2); if (availableComponents.length > 0) { - debug(`Available: ${availableComponents.join(', ')}`, 2); + debug(`Available: ${availableComponents.join(", ")}`, 2); } } @@ -164,13 +162,11 @@ export function debugRenderComponent(context) { const { phase, - items, validItems, filteredCount, lang, itemIndex, itemType, - matched, componentPath, mergedData, availableComponents, @@ -179,27 +175,27 @@ export function debugRenderComponent(context) { } = context; switch (phase) { - case 'no-items': + case "no-items": debugNoItems(); break; - case 'filtered-items': + case "filtered-items": debugFilteredItems(filteredCount, validItems.length); break; - case 'no-collections': + case "no-collections": debugNoCollections(); break; - case 'components-list': + case "components-list": debugComponents(components, slugifyFilter); break; - case 'render-start': + case "render-start": debugRenderStart(validItems, lang); break; - case 'match': + case "match": if (validItems.length === 1) { debugMatchSuccess(itemIndex, itemType, componentPath, mergedData); } else { @@ -207,7 +203,7 @@ export function debugRenderComponent(context) { } break; - case 'no-match': + case "no-match": debugMatchFailure(itemIndex, itemType, availableComponents); break; } From 2a70aad106e4844761d47bbc65dcfc04b151fe78 Mon Sep 17 00:00:00 2001 From: mwdelaney Date: Wed, 22 Oct 2025 15:02:33 -0400 Subject: [PATCH 3/3] Fix linting errors --- src/debug.js | 64 +++++++++++++++++++++++++------------------------- src/filters.js | 18 +++++++------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/debug.js b/src/debug.js index 016d4b3..f3a5541 100644 --- a/src/debug.js +++ b/src/debug.js @@ -138,7 +138,7 @@ export function debugMatchSuccessSimple(itemIndex, type) { export function debugMatchFailure(itemIndex, type, availableComponents) { debug(`Item ${itemIndex}:`, 1); debug(`Type: ${type}`, 2); - debug(`Match: ✗ No matching component found`, 2); + debug("Match: ✗ No matching component found", 2); if (availableComponents.length > 0) { debug(`Available: ${availableComponents.join(", ")}`, 2); } @@ -175,36 +175,36 @@ export function debugRenderComponent(context) { } = context; switch (phase) { - case "no-items": - debugNoItems(); - break; - - case "filtered-items": - debugFilteredItems(filteredCount, validItems.length); - break; - - case "no-collections": - debugNoCollections(); - break; - - case "components-list": - debugComponents(components, slugifyFilter); - break; - - case "render-start": - debugRenderStart(validItems, lang); - break; - - case "match": - if (validItems.length === 1) { - debugMatchSuccess(itemIndex, itemType, componentPath, mergedData); - } else { - debugMatchSuccessSimple(itemIndex, itemType); - } - break; - - case "no-match": - debugMatchFailure(itemIndex, itemType, availableComponents); - break; + case "no-items": + debugNoItems(); + break; + + case "filtered-items": + debugFilteredItems(filteredCount, validItems.length); + break; + + case "no-collections": + debugNoCollections(); + break; + + case "components-list": + debugComponents(components, slugifyFilter); + break; + + case "render-start": + debugRenderStart(validItems, lang); + break; + + case "match": + if (validItems.length === 1) { + debugMatchSuccess(itemIndex, itemType, componentPath, mergedData); + } else { + debugMatchSuccessSimple(itemIndex, itemType); + } + break; + + case "no-match": + debugMatchFailure(itemIndex, itemType, availableComponents); + break; } } diff --git a/src/filters.js b/src/filters.js index ad74ecd..e0e409f 100644 --- a/src/filters.js +++ b/src/filters.js @@ -87,7 +87,7 @@ export function addFilters(eleventyConfig) { eleventyConfig.addFilter("renderComponent", async function (items, lang) { // Early return if no items provided if (!items) { - debugRenderComponent({ phase: 'no-items' }); + debugRenderComponent({ phase: "no-items" }); return ""; } @@ -99,14 +99,14 @@ export function addFilters(eleventyConfig) { // Early return if no valid items after filtering if (validItems.length === 0) { - debugRenderComponent({ phase: 'no-items' }); + debugRenderComponent({ phase: "no-items" }); return ""; } // Log warning if some items were filtered out due to missing 'type' if (validItems.length < itemsArray.length) { debugRenderComponent({ - phase: 'filtered-items', + phase: "filtered-items", filteredCount: itemsArray.length - validItems.length, validItems }); @@ -115,7 +115,7 @@ export function addFilters(eleventyConfig) { // Get the components collection from Eleventy's context const collections = this.ctx.collections || this.collections; if (!collections || !collections.components) { - debugRenderComponent({ phase: 'no-collections' }); + debugRenderComponent({ phase: "no-collections" }); return ""; } @@ -129,14 +129,14 @@ export function addFilters(eleventyConfig) { // Log discovered components once on first render (avoids spam in logs) if (!this._componentsDebugLogged) { debugRenderComponent({ - phase: 'components-list', + phase: "components-list", components: collections.components, slugifyFilter }); this._componentsDebugLogged = true; } - debugRenderComponent({ phase: 'render-start', validItems, lang: templateLang }); + debugRenderComponent({ phase: "render-start", validItems, lang: templateLang }); // Pre-build list of available component slugs for error reporting const availableComponents = collections.components @@ -163,11 +163,11 @@ export function addFilters(eleventyConfig) { const mergedData = { ...component.data, ...item }; debugRenderComponent({ - phase: 'match', + phase: "match", validItems, itemIndex: i + 1, itemType: item.type, - componentPath: component.inputPath || component.page?.inputPath || 'unknown path', + componentPath: component.inputPath || component.page?.inputPath || "unknown path", mergedData }); @@ -183,7 +183,7 @@ export function addFilters(eleventyConfig) { // Log if no matching component was found for this item if (!matched) { debugRenderComponent({ - phase: 'no-match', + phase: "no-match", itemIndex: i + 1, itemType: item.type, availableComponents