61 lines
1.6 KiB
TypeScript
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,
|
|
},
|
|
};
|
|
}
|