feat: added headers to links in local pages
This commit is contained in:
@@ -57,20 +57,32 @@ export function normalizeObsidianMarkdown(content) {
|
|||||||
|
|
||||||
// 2. Convert wikilinks with label: [[target-slug|Custom Label]] -> [Custom Label](/posts/target-slug/)
|
// 2. Convert wikilinks with label: [[target-slug|Custom Label]] -> [Custom Label](/posts/target-slug/)
|
||||||
normalized = normalized.replace(/\[\[([^|\]]+)\|([^\]]+)\]\]/g, (match, target, label) => {
|
normalized = normalized.replace(/\[\[([^|\]]+)\|([^\]]+)\]\]/g, (match, target, label) => {
|
||||||
const slug = slugify(target);
|
return `[${label.trim()}](${wikilinkUrl(target)})`;
|
||||||
return `[${label.trim()}](/posts/${slug}/)`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Convert simple wikilinks: [[target-slug]] -> [target-slug](/posts/target-slug/)
|
// 3. Convert simple wikilinks: [[target-slug]] -> [target-slug](/posts/target-slug/)
|
||||||
normalized = normalized.replace(/\[\[([^\]]+)\]\]/g, (match, target) => {
|
normalized = normalized.replace(/\[\[([^\]]+)\]\]/g, (match, target) => {
|
||||||
const trimmed = target.trim();
|
const trimmed = target.trim();
|
||||||
const slug = slugify(trimmed);
|
return `[${trimmed}](${wikilinkUrl(trimmed)})`;
|
||||||
return `[${trimmed}](/posts/${slug}/)`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wikilinkUrl(target) {
|
||||||
|
const trimmed = target.trim();
|
||||||
|
const fragmentIndex = trimmed.indexOf("#");
|
||||||
|
|
||||||
|
if (fragmentIndex === -1) {
|
||||||
|
return `/posts/${slugify(trimmed)}/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const noteSlug = slugify(trimmed.slice(0, fragmentIndex));
|
||||||
|
const headerSlug = slugify(trimmed.slice(fragmentIndex + 1));
|
||||||
|
const fragment = headerSlug ? `#${headerSlug}` : "";
|
||||||
|
return `/posts/${noteSlug}/${fragment}`;
|
||||||
|
}
|
||||||
|
|
||||||
function slugify(text) {
|
function slugify(text) {
|
||||||
return text
|
return text
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
|
|||||||
@@ -3,10 +3,27 @@ import assert from "node:assert/strict";
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import { createServer, triggerEleventyBuild } from "../server.js";
|
import { createServer, normalizeObsidianMarkdown, triggerEleventyBuild } from "../server.js";
|
||||||
|
|
||||||
const TEST_SECRET = "super-secret-test-token";
|
const TEST_SECRET = "super-secret-test-token";
|
||||||
|
|
||||||
|
test("Obsidian normalization: preserves linked note header fragments", () => {
|
||||||
|
const normalized = normalizeObsidianMarkdown(
|
||||||
|
"See [[a note#header one]] and [[another note#Second Header|the other section]]."
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.match(
|
||||||
|
normalized,
|
||||||
|
/\[a note#header one\]\(\/posts\/a-note\/#header-one\)/,
|
||||||
|
"A wikilink header must become a URL fragment on the linked note"
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
normalized,
|
||||||
|
/\[the other section\]\(\/posts\/another-note\/#second-header\)/,
|
||||||
|
"Aliased wikilinks must retain their linked-note header fragment"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("Ingestion API: rejects requests without proper Bearer token", async () => {
|
test("Ingestion API: rejects requests without proper Bearer token", async () => {
|
||||||
const tmpDir = fs.mkdtempSync(path.join(process.cwd(), "test-tmp-site-"));
|
const tmpDir = fs.mkdtempSync(path.join(process.cwd(), "test-tmp-site-"));
|
||||||
const tmpPosts = fs.mkdtempSync(path.join(process.cwd(), "test-tmp-posts-"));
|
const tmpPosts = fs.mkdtempSync(path.join(process.cwd(), "test-tmp-posts-"));
|
||||||
|
|||||||
Reference in New Issue
Block a user