fix(patches): silence false-positive warnings for beta.41 native features
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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`,
|
||||
);
|
||||
|
||||
@@ -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`,
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user