import test from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; const pluginPath = path.resolve("/home/venus/Documents/Notes/.obsidian/plugins/blog-publisher/main.js"); // Pure helper function to be tested and exported/used by plugin export function insertOrUpdateFrontmatterProperty(content, key, value) { if (typeof content !== "string") return ""; const fmRegex = /^---\r?\n([\s\S]*?)\r?\n---/; const match = content.match(fmRegex); if (match) { let fmBlock = match[1]; const keyRegex = new RegExp(`^${key}:.*$`, "m"); if (value === null || value === undefined) { // Remove property if value is null fmBlock = fmBlock.replace(new RegExp(`^${key}:.*\\r?\\n?`, "m"), ""); } else if (keyRegex.test(fmBlock)) { // Replace existing property fmBlock = fmBlock.replace(keyRegex, `${key}: "${value}"`); } else { // Append property to frontmatter fmBlock = `${fmBlock}\n${key}: "${value}"`; } return content.replace(fmRegex, `---\n${fmBlock.trim()}\n---`); } else if (value) { return `---\n${key}: "${value}"\n---\n\n${content}`; } return content; } export function computePublicUrl(serverUrl, postPath) { const base = (serverUrl || "").replace(/\/+$/, ""); const p = (postPath || "").startsWith("/") ? postPath : `/${postPath || ""}`; return `${base}${p}`; } test("Obsidian Plugin: computePublicUrl normalizes slashes correctly", () => { assert.equal( computePublicUrl("https://riverrooks.dev", "/posts/test-note/"), "https://riverrooks.dev/posts/test-note/" ); assert.equal( computePublicUrl("https://riverrooks.dev/", "/posts/test-note/"), "https://riverrooks.dev/posts/test-note/" ); assert.equal( computePublicUrl("https://riverrooks.dev///", "posts/test-note/"), "https://riverrooks.dev/posts/test-note/" ); assert.equal( computePublicUrl("http://localhost:8080", "/posts/test-note/"), "http://localhost:8080/posts/test-note/" ); }); test("Obsidian Plugin: insertOrUpdateFrontmatterProperty adds public-url when missing", () => { const original = `--- title: "Sample Note" date: 2026-09-23 publish: true --- # Content here`; const updated = insertOrUpdateFrontmatterProperty( original, "public-url", "https://riverrooks.dev/posts/sample-note/" ); assert.match( updated, /public-url:\s*"https:\/\/riverrooks\.dev\/posts\/sample-note\/"/, "Must insert public-url into frontmatter" ); assert.match(updated, /title:\s*"Sample Note"/, "Preserves title"); assert.match(updated, /publish:\s*true/, "Preserves publish flag"); assert.match(updated, /# Content here/, "Preserves body content"); }); test("Obsidian Plugin: insertOrUpdateFrontmatterProperty updates existing public-url", () => { const original = `--- title: "Updated Note" date: 2026-09-23 public-url: "https://old.domain/posts/sample-note/" --- Body`; const updated = insertOrUpdateFrontmatterProperty( original, "public-url", "https://riverrooks.dev/posts/updated-note/" ); assert.match( updated, /public-url:\s*"https:\/\/riverrooks\.dev\/posts\/updated-note\/"/, "Must update public-url to new URL" ); assert.doesNotMatch( updated, /old\.domain/, "Old URL must be replaced" ); }); test("Obsidian Plugin: insertOrUpdateFrontmatterProperty removes public-url on unpublish", () => { const original = `--- title: "Unpublished Note" date: 2026-09-23 public-url: "https://riverrooks.dev/posts/sample-note/" --- Body`; const updated = insertOrUpdateFrontmatterProperty(original, "public-url", null); assert.doesNotMatch(updated, /public-url:/, "Must remove public-url when value is null"); assert.match(updated, /title:\s*"Unpublished Note"/, "Preserves other frontmatter"); }); test("Obsidian Plugin: Adversarial edge cases for frontmatter property insertion", () => { // 1. Empty content assert.equal(insertOrUpdateFrontmatterProperty("", "public-url", "https://url"), "---\npublic-url: \"https://url\"\n---\n\n"); // 2. Non-string inputs assert.equal(insertOrUpdateFrontmatterProperty(null, "public-url", "https://url"), ""); assert.equal(insertOrUpdateFrontmatterProperty(undefined, "public-url", "https://url"), ""); // 3. Note without frontmatter const plain = "# Just a header\nSome text."; const result = insertOrUpdateFrontmatterProperty(plain, "public-url", "https://url"); assert.match(result, /^---\npublic-url:\s*"https:\/\/url"\n---/); }); test("Obsidian Plugin: main.js in vault includes public-url insertion and recursion guard", () => { assert.ok(fs.existsSync(pluginPath), `Plugin main.js must exist at ${pluginPath}`); const pluginContent = fs.readFileSync(pluginPath, "utf-8"); // 1. Must handle public-url assert.match(pluginContent, /public-url/i, "main.js must reference 'public-url'"); // 2. Must guard against infinite loops during frontmatter updates assert.match( pluginContent, /isUpdatingFrontmatter/i, "main.js must maintain a guard to prevent metadataCache recursion loops" ); // 3. Must use processFrontMatter or frontmatter updater assert.match( pluginContent, /processFrontMatter|updateFrontmatter/i, "main.js must implement frontmatter updating logic" ); });