From 3ab6c4caa2e53b2dd9e7bac31e0fd36abad2612b Mon Sep 17 00:00:00 2001 From: Sven Date: Sun, 15 Mar 2026 23:36:55 +0100 Subject: [PATCH] fix(patches): silence false-positive warnings for beta.41 native features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four patch scripts were warning when they couldn't find their target snippets in @indiekit/endpoint-posts beta.41, because beta.41 already ships those features natively: - patch-endpoint-posts-ai-cleanup: beta.41 form.js has native AI field cleanup — detect via "ai-text-level" presence and skip silently - patch-endpoint-posts-search-tags: beta.41 posts.js/posts.njk have native filter/sort/search — detect via buildFilterQuery / posts-filter-row - patch-endpoint-posts-uid-lookup: beta.41 utils.js uses direct MongoDB queries (getPostProperties) — skip silently - patch-preset-eleventy-ai-frontmatter: add v5 block matching the new upstream structure (mpUrl + URL pathname normalization) Co-Authored-By: Claude Sonnet 4.6 --- scripts/patch-endpoint-posts-ai-cleanup.mjs | 4 + scripts/patch-endpoint-posts-search-tags.mjs | 9 + scripts/patch-endpoint-posts-uid-lookup.mjs | 4 + .../patch-preset-eleventy-ai-frontmatter.mjs | 157 +++++++++++++++++- 4 files changed, 173 insertions(+), 1 deletion(-) diff --git a/scripts/patch-endpoint-posts-ai-cleanup.mjs b/scripts/patch-endpoint-posts-ai-cleanup.mjs index fa786612..4583fb47 100644 --- a/scripts/patch-endpoint-posts-ai-cleanup.mjs +++ b/scripts/patch-endpoint-posts-ai-cleanup.mjs @@ -69,6 +69,10 @@ for (const filePath of candidates) { } if (!source.includes(oldSnippet)) { + // Beta.41+ has native AI field cleanup — skip silently + if (source.includes('"ai-text-level"') && source.includes('"ai-code-level"')) { + continue; + } console.warn( `[postinstall] Skipping endpoint-posts AI cleanup patch for ${filePath}: upstream format changed`, ); diff --git a/scripts/patch-endpoint-posts-search-tags.mjs b/scripts/patch-endpoint-posts-search-tags.mjs index 47e81f1f..77561165 100644 --- a/scripts/patch-endpoint-posts-search-tags.mjs +++ b/scripts/patch-endpoint-posts-search-tags.mjs @@ -232,6 +232,11 @@ for (const filePath of controllerCandidates) { [oldRender, newRender], ]) { if (!source.includes(oldSnip)) { + // Beta.41+ has native filter/search/sort built in — skip silently + if (source.includes("buildFilterQuery") || source.includes("filters.postType")) { + changed = false; + break; + } console.warn( `[postinstall] posts search-tags: snippet not found in ${filePath}, skipping`, ); @@ -259,6 +264,10 @@ for (const filePath of viewCandidates) { if (source.includes(viewMarker)) continue; if (!source.includes(oldView)) { + // Beta.41+ has native filter/sort UI built in — skip silently + if (source.includes("posts-filter-row") || source.includes("posts.filter.type")) { + continue; + } console.warn( `[postinstall] posts search-tags: view not found in ${filePath}, skipping`, ); diff --git a/scripts/patch-endpoint-posts-uid-lookup.mjs b/scripts/patch-endpoint-posts-uid-lookup.mjs index 07c71e9d..55d6c5fe 100644 --- a/scripts/patch-endpoint-posts-uid-lookup.mjs +++ b/scripts/patch-endpoint-posts-uid-lookup.mjs @@ -90,6 +90,10 @@ for (const spec of patchSpecs) { if (source.includes(spec.marker)) continue; if (!source.includes(spec.oldSnippet)) { + // Beta.41+ uses direct MongoDB queries — uid lookup is native, skip silently + if (source.includes("getPostProperties") || source.includes("getPosts")) { + continue; + } console.log(`[postinstall] ${spec.name}: snippet not found in ${filePath}`); continue; } diff --git a/scripts/patch-preset-eleventy-ai-frontmatter.mjs b/scripts/patch-preset-eleventy-ai-frontmatter.mjs index f9369a95..c228be20 100644 --- a/scripts/patch-preset-eleventy-ai-frontmatter.mjs +++ b/scripts/patch-preset-eleventy-ai-frontmatter.mjs @@ -365,6 +365,159 @@ const v4Block = [ "};", ].join("\n"); +// v5: upstream added mpUrl storage + URL normalization (pathname extraction). +// Matches the new block structure added after v4. +const v5UpstreamBlock = [ + " // Store the Micropub URL for frontend edit links before deleting it", + " if (properties.url) {", + " properties.mpUrl = properties.url;", + " }", + "", + " // Convert Indiekit URL to Eleventy permalink so pages generate", + " // at the canonical URL (e.g., /notes/2026/02/22/slug/) instead of", + " // the file-path-based URL (e.g., /content/notes/2026-02-22-slug/).", + " if (properties.url) {", + " let url = properties.url;", + " if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {", + " try {", + " url = new URL(url).pathname;", + " } catch {", + " // If URL parsing fails, use as-is", + " }", + " }", + " properties.permalink = url.endsWith(\"/\") ? url : `${url}/`;", + " }", + " delete properties.url;", + "", + " const frontMatter = YAML.stringify(properties, { lineWidth: 0 });", + " return `---\\n${frontMatter}---\\n`;", + "};", +].join("\n"); + +const v5PatchedBlock = [ + " // Store the Micropub URL for frontend edit links before deleting it", + " if (properties.url) {", + " properties.mpUrl = properties.url;", + " }", + "", + " // Convert Indiekit URL to Eleventy permalink so pages generate", + " // at the canonical URL (e.g., /notes/2026/02/22/slug/) instead of", + " // the file-path-based URL (e.g., /content/notes/2026-02-22-slug/).", + " if (properties.url) {", + " let url = properties.url;", + " if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {", + " try {", + " url = new URL(url).pathname;", + " } catch {", + " // If URL parsing fails, use as-is", + " }", + " }", + " properties.permalink = url.endsWith(\"/\") ? url : `${url}/`;", + " }", + " delete properties.url;", + "", + " // Normalize and sanitize AI disclosure metadata for articles and notes only.", + " const aiSource =", + " properties.ai && typeof properties.ai === \"object\" && !Array.isArray(properties.ai)", + " ? properties.ai", + " : {};", + "", + " const normaliseString = (value) => {", + " if (value === undefined || value === null) {", + " return undefined;", + " }", + "", + " const text = String(value).trim();", + " return text === \"\" ? undefined : text;", + " };", + "", + " const normaliseLevel = (value, allowedValues, fallback = \"0\") => {", + " const candidate = normaliseString(value);", + "", + " if (!candidate) {", + " return fallback;", + " }", + "", + " return allowedValues.includes(candidate) ? candidate : fallback;", + " };", + "", + " const aiTextLevelRaw =", + " aiSource.textLevel ??", + " aiSource.aiTextLevel ??", + " properties.aiTextLevel ??", + " properties[\"ai-text-level\"] ??", + " \"0\";", + "", + " const aiCodeLevelRaw =", + " aiSource.codeLevel ??", + " aiSource.aiCodeLevel ??", + " properties.aiCodeLevel ??", + " properties[\"ai-code-level\"] ??", + " \"0\";", + "", + " const aiTextLevel = normaliseLevel(aiTextLevelRaw, [\"0\", \"1\", \"2\", \"3\"]);", + " // Legacy value \"3\" is folded into \"2\" for code-level taxonomy compatibility.", + " const aiCodeLevel = normaliseLevel(", + " aiCodeLevelRaw === \"3\" ? \"2\" : aiCodeLevelRaw,", + " [\"0\", \"1\", \"2\"],", + " );", + "", + " const aiTools = normaliseString(", + " aiSource.aiTools ?? aiSource.tools ?? properties.aiTools ?? properties[\"ai-tools\"],", + " );", + "", + " const aiDescription = normaliseString(", + " aiSource.aiDescription ??", + " aiSource.description ??", + " properties.aiDescription ??", + " properties[\"ai-description\"],", + " );", + "", + " delete properties.ai;", + " delete properties.aiTextLevel;", + " delete properties.aiCodeLevel;", + " delete properties.aiTools;", + " delete properties.aiDescription;", + " delete properties[\"ai-text-level\"];", + " delete properties[\"ai-code-level\"];", + " delete properties[\"ai-tools\"];", + " delete properties[\"ai-description\"];", + "", + " // Indiekit removes post-type before calling postTemplate; fall back to permalink-based detection.", + " const postType = String(", + " properties.postType ?? properties[\"post-type\"] ?? properties.type ?? \"\",", + " ).toLowerCase();", + " const permalink = String(properties.permalink ?? \"\");", + " const supportsAiDisclosure =", + " postType === \"article\" || postType === \"note\" ||", + " /\\/articles(?:\\/|$)/.test(permalink) || /\\/notes(?:\\/|$)/.test(permalink);", + "", + " const frontMatter = YAML.stringify(properties, { lineWidth: 0 });", + "", + " if (!supportsAiDisclosure) {", + " return `---\\n${frontMatter}---\\n`;", + " }", + "", + " let aiFrontMatter = `ai:\\n textLevel: \\\"${aiTextLevel}\\\"\\n codeLevel: \\\"${aiCodeLevel}\\\"\\n # aiTools: \\\"Claude, ChatGPT, Copilot\\\"\\n # aiDescription: \\\"Optional disclosure about how AI was used\\\"\\n`;", + "", + " if (aiTools) {", + " aiFrontMatter = aiFrontMatter.replace(", + " ' # aiTools: \\\"Claude, ChatGPT, Copilot\\\"\\n',", + " ` aiTools: ${JSON.stringify(aiTools)}\\n`,", + " );", + " }", + "", + " if (aiDescription) {", + " aiFrontMatter = aiFrontMatter.replace(", + " ' # aiDescription: \\\"Optional disclosure about how AI was used\\\"\\n',", + " ` aiDescription: ${JSON.stringify(aiDescription)}\\n`,", + " );", + " }", + "", + " return `---\\n${frontMatter}${aiFrontMatter}---\\n`;", + "};", +].join("\n"); + async function exists(filePath) { try { await access(filePath); @@ -392,7 +545,9 @@ for (const filePath of candidates) { let updated = source; - if (source.includes(v3Block)) { + if (source.includes(v5UpstreamBlock)) { + updated = source.replace(v5UpstreamBlock, v5PatchedBlock); + } else if (source.includes(v3Block)) { updated = source.replace(v3Block, v4Block); } else if (source.includes(v2PatchedBlock)) { updated = source.replace(v2PatchedBlock, v4Block);