Files
xboct-flow/src/frontmatter/frontmatterFields.ts
T

61 lines
1.6 KiB
TypeScript

import {
extractFrontmatterBlock,
findFieldLineRange,
findFieldRange,
type TextRange,
} from "./frontmatterBlock";
export { findFieldLineRange, findFieldRange };
export type { TextRange };
export type ReplaceFrontmatterFieldResult =
| { ok: true; content: string; range: TextRange }
| { ok: false; reason: "no-frontmatter" | "no-field" };
/**
* Replace a scalar frontmatter field value on its line.
* Does not re-serialize YAML; only rewrites the value after `:`.
*/
export function replaceFrontmatterField(
content: string,
key: string,
value: string,
): ReplaceFrontmatterFieldResult {
const block = extractFrontmatterBlock(content);
if (!block || block.closeLine < 0) {
return { ok: false, reason: "no-frontmatter" };
}
const lineRange = findFieldLineRange(content, key);
if (!lineRange) {
return { ok: false, reason: "no-field" };
}
const lines = content.split(/\r?\n/);
const line = lines[lineRange.startLine] ?? "";
const colonIndex = line.indexOf(":");
if (colonIndex < 0) {
return { ok: false, reason: "no-field" };
}
const prefix = line.slice(0, colonIndex + 1);
const spacing = line.slice(colonIndex + 1).match(/^\s*/)?.[0] ?? " ";
const newLine = `${prefix}${spacing || " "}${value}`;
lines[lineRange.startLine] = newLine;
const eol = content.includes("\r\n") ? "\r\n" : "\n";
const next = lines.join(eol);
const valueRange = findFieldRange(next, key);
return {
ok: true,
content: next,
range: valueRange ?? {
startLine: lineRange.startLine,
startCol: 0,
endLine: lineRange.startLine,
endCol: newLine.length,
},
};
}