yamlover 0.3.22 → 0.3.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -1
- package/dist/client/assets/{decoded-CJRPjXa1.js → decoded-D6QOaoKb.js} +1 -1
- package/dist/client/assets/{djvu-DTScSRBE.js → djvu-E4zw82nI.js} +1 -1
- package/dist/client/assets/{docx-CZ_-bbiw.js → docx-BCPZI9sD.js} +1 -1
- package/dist/client/assets/{heic-GGCTCDdl.js → heic-BMjqVVlg.js} +1 -1
- package/dist/client/assets/{imagemap-99Y1w9r3.js → imagemap-Dn9snPoS.js} +1 -1
- package/dist/client/assets/{index-1sCxQdj3.css → index-BpjZr9s_.css} +1 -1
- package/dist/client/assets/index-CteLUngZ.js +638 -0
- package/dist/client/assets/{map-B1r-13cZ.js → map-BWtVwabj.js} +1 -1
- package/dist/client/assets/{openable-Bh72damS.js → openable-DClR-5sz.js} +1 -1
- package/dist/client/assets/{paged-DMHOhYfR.js → paged-BrajMFZP.js} +1 -1
- package/dist/client/assets/{pdf-DNh_WoxB.js → pdf-DLY4bQIN.js} +1 -1
- package/dist/client/assets/{psd-BODwPXZY.js → psd-DpmZVKKr.js} +1 -1
- package/dist/client/assets/{spreadsheet-jmhwwLqI.js → spreadsheet-CxTCFdEW.js} +1 -1
- package/dist/client/assets/{tiff-B7WRQzVg.js → tiff-BB8pmY6L.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server.js +228 -163
- package/package.json +1 -1
- package/dist/client/assets/index-Dwsn6NQE.js +0 -632
package/dist/server.js
CHANGED
|
@@ -66856,64 +66856,17 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
66856
66856
|
(data) => enqueue(async () => {
|
|
66857
66857
|
const d = data;
|
|
66858
66858
|
const edits = Array.isArray(d.edits) ? d.edits : [d];
|
|
66859
|
-
const touched = applyEdits2(dataRoot, s2, edits);
|
|
66860
|
-
|
|
66859
|
+
const { touched, created, appended } = applyEdits2(dataRoot, s2, edits);
|
|
66860
|
+
if (created.length) broadcast(await doReindex());
|
|
66861
|
+
else for (const f2 of touched) broadcast(await doReindexFile(f2));
|
|
66861
66862
|
scheduleHasher();
|
|
66863
|
+
if (created.length) return { ok: true, path: created[created.length - 1] };
|
|
66864
|
+
if (appended.length) return { ok: true, path: lastBodyChildPath(s2, appended[appended.length - 1]) };
|
|
66862
66865
|
return { ok: true };
|
|
66863
66866
|
})
|
|
66864
66867
|
).then((body) => sendJson(res, 200, body)).catch((e3) => sendJson(res, 400, { error: String(e3.message || e3) }));
|
|
66865
66868
|
return;
|
|
66866
66869
|
}
|
|
66867
|
-
if (req.method === "POST" && url.pathname === "/api/create") {
|
|
66868
|
-
readBody(req).then(
|
|
66869
|
-
(data) => enqueue(async () => {
|
|
66870
|
-
const b = data;
|
|
66871
|
-
const reg = CREATABLE[String(b.schema ?? "")];
|
|
66872
|
-
if (!reg) throw new Error(`unknown schema: ${b.schema}`);
|
|
66873
|
-
const concrete = String(b.concrete ?? "");
|
|
66874
|
-
const parentSegs = strToSegs(b.parent ?? ":");
|
|
66875
|
-
const row2 = s2.node(storePath(parentSegs));
|
|
66876
|
-
if (!row2) throw new Error(`no such node: ${b.parent}`);
|
|
66877
|
-
const title = String(b.title ?? "").trim() || defaultTitle(String(b.schema));
|
|
66878
|
-
const body = reg.body(title);
|
|
66879
|
-
const objSrc = objectFileSource(reg.tag, body);
|
|
66880
|
-
if (reg.childOf.includes(row2.format ?? "")) {
|
|
66881
|
-
const { docSegs, bodyFile, dirBacked } = chapterSource(dataRoot, s2, parentSegs);
|
|
66882
|
-
const within = parentSegs.slice(docSegs.length);
|
|
66883
|
-
if (concrete === "yamlover") {
|
|
66884
|
-
const src = fs10.readFileSync(bodyFile, "utf8");
|
|
66885
|
-
fs10.writeFileSync(bodyFile, appendBody(src, within, (indent) => inlineChildLines(body, indent)));
|
|
66886
|
-
broadcast(await doReindexFile(bodyFile));
|
|
66887
|
-
scheduleHasher();
|
|
66888
|
-
return { path: lastBodyChildPath(s2, parentSegs) };
|
|
66889
|
-
}
|
|
66890
|
-
if (concrete === "file/yamlover" || concrete === "dir/yamlover") {
|
|
66891
|
-
const writeDirSegs = dirBacked ? docSegs : docSegs.slice(0, -1);
|
|
66892
|
-
const writeDir = path10.resolve(dataRoot, ...writeDirSegs.map(String));
|
|
66893
|
-
const final = writeObject(dataRoot, writeDir, sanitizeName(title), concrete, objSrc);
|
|
66894
|
-
const targetSegs = [...writeDirSegs, final];
|
|
66895
|
-
const pointer = dirBacked ? `*/${final}` : `*/${segsToStr(targetSegs)}`;
|
|
66896
|
-
const src = fs10.readFileSync(bodyFile, "utf8");
|
|
66897
|
-
fs10.writeFileSync(bodyFile, appendBody(src, within, (indent) => [`${" ".repeat(indent)}- ${pointer}`]));
|
|
66898
|
-
broadcast(await doReindex());
|
|
66899
|
-
scheduleHasher();
|
|
66900
|
-
return { path: segsToStr(targetSegs) };
|
|
66901
|
-
}
|
|
66902
|
-
throw new Error(`invalid concrete for a child: ${concrete}`);
|
|
66903
|
-
}
|
|
66904
|
-
const abs = path10.resolve(dataRoot, ...parentSegs.map(String));
|
|
66905
|
-
if (parentSegs.every((g) => typeof g === "string") && fs10.existsSync(abs) && fs10.statSync(abs).isDirectory()) {
|
|
66906
|
-
if (concrete !== "file/yamlover" && concrete !== "dir/yamlover") throw new Error(`invalid concrete for a directory member: ${concrete}`);
|
|
66907
|
-
const final = writeObject(dataRoot, abs, objectBaseName(title), concrete, objSrc);
|
|
66908
|
-
broadcast(await doReindex());
|
|
66909
|
-
scheduleHasher();
|
|
66910
|
-
return { path: segsToStr([...parentSegs, final]) };
|
|
66911
|
-
}
|
|
66912
|
-
throw new Error("this schema can be created only inside a directory or a compatible parent");
|
|
66913
|
-
})
|
|
66914
|
-
).then((body) => sendJson(res, 201, body)).catch((e3) => sendJson(res, 400, { error: String(e3.message || e3) }));
|
|
66915
|
-
return;
|
|
66916
|
-
}
|
|
66917
66870
|
if (req.method === "POST" && url.pathname === "/api/mv") {
|
|
66918
66871
|
readBody(req).then(
|
|
66919
66872
|
(data) => enqueue(async () => {
|
|
@@ -67694,13 +67647,13 @@ function handlePaste(dataRoot, s2, input) {
|
|
|
67694
67647
|
const bytes = Buffer.from(input.contentBase64 || "", "base64");
|
|
67695
67648
|
if (bytes.length === 0) throw new Error("empty paste (no file bytes)");
|
|
67696
67649
|
const name = sanitizeName(input.filename ?? "");
|
|
67697
|
-
if (row.format === "x-yamlover-chapter") return pasteIntoChapter(dataRoot, s2, segs, name, bytes);
|
|
67650
|
+
if (row.format === "x-yamlover-chapter" && !input.inline) return pasteIntoChapter(dataRoot, s2, segs, name, bytes);
|
|
67698
67651
|
const dirSegs = nearestDirSegs(dataRoot, segs);
|
|
67699
67652
|
if (!dirSegs) throw new Error("no enclosing directory to paste into");
|
|
67700
67653
|
const dir = path10.resolve(dataRoot, ...dirSegs.map(String));
|
|
67701
67654
|
const final = uniqueName(dir, name);
|
|
67702
67655
|
writeInside(dataRoot, dir, final, bytes);
|
|
67703
|
-
return { path: segsToStr([...dirSegs, final]), dir: segsToStr(dirSegs), open: dirSegs.length !== segs.length };
|
|
67656
|
+
return { path: segsToStr([...dirSegs, final]), dir: segsToStr(dirSegs), open: !input.inline && dirSegs.length !== segs.length };
|
|
67704
67657
|
}
|
|
67705
67658
|
function nearestDirSegs(dataRoot, segs) {
|
|
67706
67659
|
for (let i2 = segs.length; i2 >= 0; i2--) {
|
|
@@ -67850,32 +67803,11 @@ function titleFromText(text) {
|
|
|
67850
67803
|
const t3 = first.replace(/^#{1,6}\s+/, "").trim();
|
|
67851
67804
|
return (t3.length > 80 ? t3.slice(0, 79).trimEnd() + "\u2026" : t3) || "Pasted text";
|
|
67852
67805
|
}
|
|
67853
|
-
var CREATABLE = {
|
|
67854
|
-
"::yamlover:$defs:chapter": {
|
|
67855
|
-
tag: "*::yamlover:$defs:chapter",
|
|
67856
|
-
childOf: ["x-yamlover-chapter", "x-yamlover-task"],
|
|
67857
|
-
// a chapter with one empty prose chunk (a positional body item), so it is immediately editable
|
|
67858
|
-
body: (title) => [`title: ${JSON.stringify(title)}`, `- ""`]
|
|
67859
|
-
}
|
|
67860
|
-
};
|
|
67861
67806
|
function lastBodyChildPath(s2, parentSegs) {
|
|
67862
67807
|
const positional = s2.entries(storePath(parentSegs)).filter((e3) => e3.kind === "contain" && e3.label == null);
|
|
67863
67808
|
const last = positional[positional.length - 1];
|
|
67864
67809
|
return last ? segsToStr(storePathToSegs(last.to)) : segsToStr([...parentSegs, 0]);
|
|
67865
67810
|
}
|
|
67866
|
-
function defaultTitle(schema) {
|
|
67867
|
-
const segs = strToSegs(schema);
|
|
67868
|
-
return "New " + String(segs[segs.length - 1] ?? "object");
|
|
67869
|
-
}
|
|
67870
|
-
function objectFileSource(tag, body) {
|
|
67871
|
-
return `!!<${tag}>
|
|
67872
|
-
${body.join("\n")}
|
|
67873
|
-
`;
|
|
67874
|
-
}
|
|
67875
|
-
function inlineChildLines(body, indent) {
|
|
67876
|
-
const pad = " ".repeat(indent);
|
|
67877
|
-
return body.map((line, i2) => i2 === 0 ? `${pad}- ${line}` : `${pad} ${line}`);
|
|
67878
|
-
}
|
|
67879
67811
|
function objectBaseName(title) {
|
|
67880
67812
|
const base = title.replace(/[^\p{L}\p{N} ._-]+/gu, " ").replace(/\s+/g, " ").trim().slice(0, 60).trim().replace(/^\.+/, "");
|
|
67881
67813
|
return base || "new";
|
|
@@ -67952,13 +67884,20 @@ var isContentLine2 = (line) => {
|
|
|
67952
67884
|
const t3 = line.trim();
|
|
67953
67885
|
return t3.length > 0 && !t3.startsWith("#");
|
|
67954
67886
|
};
|
|
67955
|
-
function
|
|
67956
|
-
const pad = " ".repeat(indent);
|
|
67887
|
+
function escapeScalarSrc(text) {
|
|
67957
67888
|
const first = text.split("\n").find((l2) => l2.trim().length > 0);
|
|
67958
|
-
if (!first || /^\s/.test(first)) return
|
|
67889
|
+
if (!first || /^\s/.test(first)) return JSON.stringify(text);
|
|
67959
67890
|
const body = text.endsWith("\n") ? text.slice(0, -1) : text;
|
|
67960
67891
|
const head = text.endsWith("\n") ? "|" : "|-";
|
|
67961
|
-
return [
|
|
67892
|
+
return [head, ...body.split("\n").map((l2) => l2.trim().length ? " " + l2 : "")].join("\n");
|
|
67893
|
+
}
|
|
67894
|
+
function renderEntry(valueSrc, indent, marker, tag, deeper = false) {
|
|
67895
|
+
const pad = " ".repeat(indent + (deeper ? 2 : 0));
|
|
67896
|
+
const [first, ...rest] = valueSrc.split("\n");
|
|
67897
|
+
return [`${" ".repeat(indent)}${marker}${tag ? tag + " " : ""}${first}`, ...rest.map((l2) => l2.trim().length ? pad + l2 : "")];
|
|
67898
|
+
}
|
|
67899
|
+
function textChunkLines(text, indent) {
|
|
67900
|
+
return renderEntry(escapeScalarSrc(text), indent, "- ");
|
|
67962
67901
|
}
|
|
67963
67902
|
function chapterEntries(lines, r2) {
|
|
67964
67903
|
const starts = [];
|
|
@@ -67983,16 +67922,36 @@ function chapterEntries(lines, r2) {
|
|
|
67983
67922
|
inline: s2.inline
|
|
67984
67923
|
}));
|
|
67985
67924
|
}
|
|
67986
|
-
function
|
|
67987
|
-
|
|
67925
|
+
function findEntry(lines, r2, seg) {
|
|
67926
|
+
const entries = chapterEntries(lines, r2);
|
|
67927
|
+
return typeof seg === "number" ? entries[seg] : entries.find((e3) => e3.key === seg);
|
|
67928
|
+
}
|
|
67929
|
+
function entryHead(lines, e3) {
|
|
67930
|
+
let t3 = lines[e3.start].trim().replace(/^-\s*/, "").replace(/^!!<[^>]*>\s*/, "");
|
|
67931
|
+
if (e3.key) t3 = t3.slice(t3.indexOf(":") + 1).trim();
|
|
67932
|
+
return t3;
|
|
67933
|
+
}
|
|
67934
|
+
function isContainerEntry(lines, e3, childIndent) {
|
|
67935
|
+
const head = entryHead(lines, e3);
|
|
67936
|
+
if (/^[|>][+-]?\d*$/.test(head.trim())) return itemHasFields(lines, e3, childIndent);
|
|
67937
|
+
if (/^[^\s"'*|>#-][^:]*:(\s|$)/.test(head)) return true;
|
|
67938
|
+
for (let i2 = e3.start + 1; i2 < e3.end; i2++) {
|
|
67939
|
+
if (!isContentLine2(lines[i2])) continue;
|
|
67940
|
+
const ind = indentOf2(lines[i2]);
|
|
67941
|
+
if (ind < childIndent) break;
|
|
67942
|
+
if (ind === childIndent) return true;
|
|
67943
|
+
}
|
|
67944
|
+
return false;
|
|
67988
67945
|
}
|
|
67989
|
-
function reachChapter(lines,
|
|
67946
|
+
function reachChapter(lines, within) {
|
|
67990
67947
|
let r2 = { lo: 0, hi: lines.length, indent: firstContentIndent2(lines), marker: -1 };
|
|
67991
|
-
for (const seg of
|
|
67992
|
-
const
|
|
67993
|
-
|
|
67994
|
-
if (!
|
|
67995
|
-
|
|
67948
|
+
for (const seg of within) {
|
|
67949
|
+
const entry = findEntry(lines, r2, seg);
|
|
67950
|
+
if (!entry) throw new Error(`no entry at ${typeof seg === "number" ? `[${seg}]` : seg}`);
|
|
67951
|
+
if (!isContainerEntry(lines, entry, r2.indent + 2)) {
|
|
67952
|
+
throw new Error(`cannot descend into a scalar element at ${typeof seg === "number" ? `[${seg}]` : seg}`);
|
|
67953
|
+
}
|
|
67954
|
+
r2 = { lo: entry.start + 1, hi: entry.end, indent: r2.indent + 2, marker: entry.start };
|
|
67996
67955
|
}
|
|
67997
67956
|
return r2;
|
|
67998
67957
|
}
|
|
@@ -68009,60 +67968,106 @@ function appendBody(text, chapterPath, renderItems) {
|
|
|
68009
67968
|
lines.splice(bodyAppendPoint(lines, r2), 0, ...renderItems(r2.indent));
|
|
68010
67969
|
return lines.join("\n");
|
|
68011
67970
|
}
|
|
68012
|
-
|
|
68013
|
-
|
|
68014
|
-
|
|
68015
|
-
|
|
67971
|
+
var opensEntry = (t3) => t3 === "-" || t3.startsWith("- ") || /^[^\s"'*|>#-][^:]*:(\s|$)/.test(t3);
|
|
67972
|
+
var isBlockHeader = (head) => /^[|>][+-]?\d*$/.test(head.trim());
|
|
67973
|
+
function groupEntries(lines, at) {
|
|
67974
|
+
const starts = lines.map((l2, i2) => i2).filter((i2) => isContentLine2(lines[i2]) && indentOf2(lines[i2]) === at);
|
|
67975
|
+
const keyed = [];
|
|
67976
|
+
const ordinal = [];
|
|
67977
|
+
starts.forEach((s2, k) => {
|
|
67978
|
+
const group = lines.slice(s2, k + 1 < starts.length ? starts[k + 1] : lines.length).map((l2) => l2.slice(at));
|
|
67979
|
+
(lines[s2].trim() === "-" || lines[s2].trim().startsWith("- ") ? ordinal : keyed).push(group);
|
|
67980
|
+
});
|
|
67981
|
+
return { keyed, ordinal };
|
|
67982
|
+
}
|
|
67983
|
+
function payloadFacets(src) {
|
|
67984
|
+
const lines = src.split("\n");
|
|
67985
|
+
const first = lines.find(isContentLine2);
|
|
67986
|
+
if (first === void 0) return { keyed: [], ordinal: [] };
|
|
67987
|
+
if (!opensEntry(first.trim())) return { scalar: src, keyed: [], ordinal: [] };
|
|
67988
|
+
return { scalar: void 0, ...groupEntries(lines, 0) };
|
|
67989
|
+
}
|
|
67990
|
+
function entryFacets(lines, e3, indent) {
|
|
67991
|
+
const marked = lines[e3.start].trim().replace(/^-\s*/, "");
|
|
67992
|
+
const tag = marked.match(/^(!!<[^>]*>)/)?.[1];
|
|
67993
|
+
const head = entryHead(lines, e3);
|
|
67994
|
+
const childIndent = indent + 2;
|
|
67995
|
+
const value = (from, to2, at) => [head, ...lines.slice(from, to2).map((l2) => l2.trim().length ? " " + l2.slice(at) : "")].join("\n").replace(/\n+$/, "");
|
|
67996
|
+
if (!isContainerEntry(lines, e3, childIndent)) {
|
|
67997
|
+
return { tag, scalar: value(e3.start + 1, e3.end, childIndent), keyed: [], ordinal: [] };
|
|
67998
|
+
}
|
|
67999
|
+
const blockValue = isBlockHeader(head);
|
|
68000
|
+
let firstChild = e3.end;
|
|
68001
|
+
for (let i2 = e3.start + 1; i2 < e3.end; i2++) {
|
|
68002
|
+
if (isContentLine2(lines[i2]) && indentOf2(lines[i2]) === childIndent) {
|
|
68003
|
+
firstChild = i2;
|
|
68004
|
+
break;
|
|
68005
|
+
}
|
|
68006
|
+
}
|
|
68007
|
+
const scalar2 = blockValue ? value(e3.start + 1, firstChild, childIndent + 2) : void 0;
|
|
68008
|
+
const groups = groupEntries(lines.slice(firstChild, e3.end), childIndent);
|
|
68009
|
+
if (!blockValue && head) groups.keyed.unshift([head]);
|
|
68010
|
+
return { tag, scalar: scalar2, ...groups };
|
|
68016
68011
|
}
|
|
68017
|
-
function
|
|
68018
|
-
const
|
|
68019
|
-
|
|
68020
|
-
|
|
68021
|
-
|
|
68012
|
+
function renderNode(f2, indent, marker, tag) {
|
|
68013
|
+
const pad = " ".repeat(indent);
|
|
68014
|
+
const childPad = " ".repeat(indent + 2);
|
|
68015
|
+
const groups = [...f2.keyed, ...f2.ordinal];
|
|
68016
|
+
const child = (g) => g.map((l2) => l2.trim().length ? childPad + l2 : "");
|
|
68017
|
+
if (f2.scalar !== void 0) {
|
|
68018
|
+
return [...renderEntry(f2.scalar, indent, marker, tag, groups.length > 0), ...groups.flatMap(child)];
|
|
68019
|
+
}
|
|
68020
|
+
if (!groups.length) return [`${pad}${marker.trimEnd()}${tag ? " " + tag : ""}`];
|
|
68021
|
+
if (marker.startsWith("-") && !tag) {
|
|
68022
|
+
const [g0, ...rest] = groups;
|
|
68023
|
+
return [`${pad}${marker}${g0[0]}`, ...child(g0.slice(1)), ...rest.flatMap(child)];
|
|
68024
|
+
}
|
|
68025
|
+
return [`${pad}${marker.trimEnd()}${tag ? " " + tag : ""}`, ...groups.flatMap(child)];
|
|
68026
|
+
}
|
|
68027
|
+
function metaTag(meta, existing, preserve) {
|
|
68028
|
+
if (meta === null) return void 0;
|
|
68029
|
+
if (meta !== void 0) return `!!<${meta}>`;
|
|
68030
|
+
return preserve ? existing : void 0;
|
|
68031
|
+
}
|
|
68032
|
+
function assignAt(lines, r2, seg, op, valueSrc, meta) {
|
|
68033
|
+
const marker = (s2) => typeof s2 === "string" ? `${s2}: ` : "- ";
|
|
68034
|
+
if (op === "insert") {
|
|
68035
|
+
if (typeof seg === "string") throw new Error("`insert` needs a positional target (a path ending `[i]`, or the node itself)");
|
|
68036
|
+
const entry2 = seg === void 0 ? void 0 : findEntry(lines, r2, seg);
|
|
68037
|
+
const at = entry2 ? entry2.start : bodyAppendPoint(lines, r2);
|
|
68038
|
+
lines.splice(at, 0, ...renderNode(payloadFacets(valueSrc), r2.indent, "- ", metaTag(meta, void 0, false)));
|
|
68022
68039
|
return;
|
|
68023
68040
|
}
|
|
68024
|
-
|
|
68025
|
-
|
|
68026
|
-
|
|
68041
|
+
if (seg === void 0) throw new Error(`\`${op}\` needs a key or index target`);
|
|
68042
|
+
const entry = findEntry(lines, r2, seg);
|
|
68043
|
+
if (op === "remove") {
|
|
68044
|
+
if (!entry) throw new Error(`no entry at ${typeof seg === "number" ? `[${seg}]` : seg}`);
|
|
68045
|
+
lines.splice(entry.start, entry.end - entry.start);
|
|
68027
68046
|
return;
|
|
68028
68047
|
}
|
|
68029
|
-
|
|
68030
|
-
if (entry)
|
|
68031
|
-
|
|
68032
|
-
|
|
68033
|
-
|
|
68034
|
-
|
|
68035
|
-
|
|
68036
|
-
|
|
68037
|
-
const
|
|
68038
|
-
const
|
|
68039
|
-
const
|
|
68040
|
-
|
|
68041
|
-
|
|
68042
|
-
|
|
68043
|
-
|
|
68044
|
-
|
|
68045
|
-
|
|
68046
|
-
|
|
68047
|
-
|
|
68048
|
-
|
|
68049
|
-
|
|
68050
|
-
|
|
68051
|
-
lines.splice(start, end - start);
|
|
68052
|
-
}
|
|
68053
|
-
function taggedChunkLines(text, indent, tag) {
|
|
68054
|
-
const pad = " ".repeat(indent);
|
|
68055
|
-
const first = text.split("\n").find((l2) => l2.trim().length > 0);
|
|
68056
|
-
if (!first || /^\s/.test(first)) return [`${pad}- ${tag} ${JSON.stringify(text)}`];
|
|
68057
|
-
const body = text.endsWith("\n") ? text.slice(0, -1) : text;
|
|
68058
|
-
const head = text.endsWith("\n") ? "|" : "|-";
|
|
68059
|
-
return [`${pad}- ${tag} ${head}`, ...body.split("\n").map((l2) => l2.trim().length ? `${pad} ${l2}` : "")];
|
|
68060
|
-
}
|
|
68061
|
-
function assertProseBodyItem(lines, r2, rank) {
|
|
68062
|
-
const head = bodyItemHead(lines, r2, rank);
|
|
68063
|
-
if (head.startsWith("*")) throw new Error("cannot edit a file/pointer chunk as text");
|
|
68064
|
-
const tag = head.match(/^!!<([^>]*)>/)?.[1];
|
|
68065
|
-
if (tag && !/text\/(markdown|marklower|x-latex)/.test(tag)) throw new Error("cannot edit a non-text chunk as text");
|
|
68048
|
+
if (op !== "emplace" && op !== "replace") throw new Error(`unknown edit op: ${op}`);
|
|
68049
|
+
if (!entry) {
|
|
68050
|
+
if (op === "replace") throw new Error(`no entry at ${typeof seg === "number" ? `[${seg}]` : seg}`);
|
|
68051
|
+
const rendered = renderNode(payloadFacets(valueSrc), r2.indent, marker(seg), metaTag(meta, void 0, false));
|
|
68052
|
+
const at = typeof seg === "string" ? r2.marker >= 0 ? r2.marker + 1 : trimBack2(lines, r2.lo - 1, r2.hi) : bodyAppendPoint(lines, r2);
|
|
68053
|
+
lines.splice(at, 0, ...rendered);
|
|
68054
|
+
return;
|
|
68055
|
+
}
|
|
68056
|
+
const had = entryFacets(lines, entry, r2.indent);
|
|
68057
|
+
const payload = payloadFacets(valueSrc);
|
|
68058
|
+
const inlineKey = entry.inline ? entry.key : null;
|
|
68059
|
+
const next = op === "replace" ? payload : {
|
|
68060
|
+
scalar: payload.scalar ?? had.scalar,
|
|
68061
|
+
keyed: payload.keyed.length ? payload.keyed : had.keyed,
|
|
68062
|
+
ordinal: payload.ordinal.length ? payload.ordinal : had.ordinal
|
|
68063
|
+
};
|
|
68064
|
+
const tag = metaTag(meta, had.tag, op === "emplace");
|
|
68065
|
+
if (inlineKey) {
|
|
68066
|
+
const pad = " ".repeat(indentOf2(lines[entry.start]));
|
|
68067
|
+
lines[entry.start] = `${pad}- ${tag ? tag + " " : ""}${inlineKey}: ${next.scalar ?? '""'}`;
|
|
68068
|
+
return;
|
|
68069
|
+
}
|
|
68070
|
+
lines.splice(entry.start, entry.end - entry.start, ...renderNode(next, r2.indent, marker(seg), tag));
|
|
68066
68071
|
}
|
|
68067
68072
|
function reachChapterItem(lines, indices) {
|
|
68068
68073
|
const parent = reachChapter(lines, indices.slice(0, -1));
|
|
@@ -68125,49 +68130,109 @@ function splitChunkWithin(within) {
|
|
|
68125
68130
|
while (i2 < within.length && typeof within[i2] === "number") i2++;
|
|
68126
68131
|
return { indices: within.slice(0, i2).map(Number), keys: within.slice(i2).map(String) };
|
|
68127
68132
|
}
|
|
68128
|
-
function
|
|
68129
|
-
const
|
|
68130
|
-
|
|
68131
|
-
|
|
68132
|
-
if (
|
|
68133
|
-
|
|
68134
|
-
return lines.join("\n");
|
|
68133
|
+
function setRootTag(lines, meta) {
|
|
68134
|
+
const at = lines.findIndex(isContentLine2);
|
|
68135
|
+
const existing = at >= 0 && lines[at].trim().startsWith("!!<") ? at : -1;
|
|
68136
|
+
if (meta === null) {
|
|
68137
|
+
if (existing >= 0) lines.splice(existing, 1);
|
|
68138
|
+
return;
|
|
68135
68139
|
}
|
|
68136
|
-
if (
|
|
68137
|
-
|
|
68138
|
-
|
|
68139
|
-
|
|
68140
|
-
const
|
|
68141
|
-
if (
|
|
68142
|
-
|
|
68143
|
-
|
|
68144
|
-
|
|
68145
|
-
|
|
68146
|
-
|
|
68147
|
-
|
|
68148
|
-
|
|
68149
|
-
|
|
68140
|
+
if (existing >= 0) lines[existing] = `!!<${meta}>`;
|
|
68141
|
+
else lines.splice(Math.max(at, 0), 0, `!!<${meta}>`);
|
|
68142
|
+
}
|
|
68143
|
+
function editChapterSource(src, within, op, valueSrc, meta) {
|
|
68144
|
+
const lines = src.split("\n");
|
|
68145
|
+
if (within.length === 0) {
|
|
68146
|
+
if (op === "insert") {
|
|
68147
|
+
assignAt(lines, reachChapter(lines, []), void 0, op, valueSrc, meta);
|
|
68148
|
+
return lines.join("\n");
|
|
68149
|
+
}
|
|
68150
|
+
if (op === "emplace" && meta !== void 0 && !valueSrc) {
|
|
68151
|
+
setRootTag(lines, meta);
|
|
68152
|
+
return lines.join("\n");
|
|
68153
|
+
}
|
|
68154
|
+
throw new Error(`\`${op}\` at a document root needs a key or index target`);
|
|
68150
68155
|
}
|
|
68156
|
+
assignAt(lines, reachChapter(lines, within.slice(0, -1)), within[within.length - 1], op, valueSrc, meta);
|
|
68151
68157
|
return lines.join("\n");
|
|
68152
68158
|
}
|
|
68159
|
+
var isPointerValue = (src) => /^\*\S*$/.test(src.trim()) && !src.includes("\n");
|
|
68160
|
+
function isPlainDir(dataRoot, s2, segs) {
|
|
68161
|
+
if (!segs.every((g) => typeof g === "string")) return false;
|
|
68162
|
+
const abs = path10.resolve(dataRoot, ...segs.map(String));
|
|
68163
|
+
if (!fs10.existsSync(abs) || !fs10.statSync(abs).isDirectory()) return false;
|
|
68164
|
+
try {
|
|
68165
|
+
chapterSource(dataRoot, s2, segs);
|
|
68166
|
+
return false;
|
|
68167
|
+
} catch {
|
|
68168
|
+
return true;
|
|
68169
|
+
}
|
|
68170
|
+
}
|
|
68171
|
+
function bornAsDocument(dataRoot, e3, tag) {
|
|
68172
|
+
const writeDirSegs = e3.dirBacked ? e3.docSegs : e3.docSegs.slice(0, -1);
|
|
68173
|
+
const writeDir = path10.resolve(dataRoot, ...writeDirSegs.map(String));
|
|
68174
|
+
const src = [...tag ? [tag] : [], e3.valueSrc, ""].join("\n");
|
|
68175
|
+
const final = writeObject(dataRoot, writeDir, sanitizeName(e3.name || "object"), e3.concrete, src);
|
|
68176
|
+
const targetSegs = [...writeDirSegs, final];
|
|
68177
|
+
return { pointer: e3.dirBacked ? `*/${final}` : `*/${segsToStr(targetSegs)}`, path: segsToStr(targetSegs) };
|
|
68178
|
+
}
|
|
68153
68179
|
function applyEdits2(dataRoot, s2, edits) {
|
|
68154
68180
|
const byFile = /* @__PURE__ */ new Map();
|
|
68181
|
+
const appended = [];
|
|
68182
|
+
const created = [];
|
|
68155
68183
|
for (const e3 of edits) {
|
|
68156
68184
|
const editSegs = strToSegs(e3.path ?? "");
|
|
68157
|
-
const
|
|
68158
|
-
|
|
68185
|
+
const op = String(e3.op ?? "");
|
|
68186
|
+
if (op === "insert" && (e3.concrete === "file/yamlover" || e3.concrete === "dir/yamlover") && isPlainDir(dataRoot, s2, editSegs)) {
|
|
68187
|
+
const dir = path10.resolve(dataRoot, ...editSegs.map(String));
|
|
68188
|
+
const src = [...metaTag(e3.meta, void 0, false) ? [metaTag(e3.meta, void 0, false)] : [], String(e3.yamlover ?? ""), ""].join("\n");
|
|
68189
|
+
if (e3.yamlover) parseYamlover(String(e3.yamlover), "<edit>");
|
|
68190
|
+
const final = writeObject(dataRoot, dir, objectBaseName(String(e3.name || "new")), String(e3.concrete), src);
|
|
68191
|
+
created.push(segsToStr([...editSegs, final]));
|
|
68192
|
+
continue;
|
|
68193
|
+
}
|
|
68194
|
+
const { docSegs, bodyFile, dirBacked } = chapterSource(dataRoot, s2, editSegs);
|
|
68195
|
+
if (op === "insert" && !e3.concrete?.includes("/")) {
|
|
68196
|
+
const last = editSegs[editSegs.length - 1];
|
|
68197
|
+
if (typeof last !== "number") appended.push(editSegs);
|
|
68198
|
+
else if (!s2.node(storePath(editSegs))) appended.push(editSegs.slice(0, -1));
|
|
68199
|
+
}
|
|
68200
|
+
const concrete = e3.concrete ? String(e3.concrete) : void 0;
|
|
68201
|
+
if (concrete && concrete !== "yamlover" && op !== "insert" && !(op === "emplace" && !s2.node(storePath(editSegs)))) {
|
|
68202
|
+
throw new Error("`concrete` is only for content being created \u2014 converting an existing node is a move, not an edit");
|
|
68203
|
+
}
|
|
68159
68204
|
const list = byFile.get(bodyFile) ?? [];
|
|
68160
|
-
list.push({
|
|
68205
|
+
list.push({
|
|
68206
|
+
within: editSegs.slice(docSegs.length),
|
|
68207
|
+
op,
|
|
68208
|
+
valueSrc: String(e3.yamlover ?? ""),
|
|
68209
|
+
meta: e3.meta === void 0 ? void 0 : e3.meta === null ? null : String(e3.meta),
|
|
68210
|
+
concrete,
|
|
68211
|
+
name: e3.name ? String(e3.name) : void 0,
|
|
68212
|
+
docSegs,
|
|
68213
|
+
dirBacked
|
|
68214
|
+
});
|
|
68161
68215
|
byFile.set(bodyFile, list);
|
|
68162
68216
|
}
|
|
68163
68217
|
const touched = [];
|
|
68164
68218
|
for (const [bodyFile, ops] of byFile) {
|
|
68165
68219
|
let src = fs10.readFileSync(bodyFile, "utf8");
|
|
68166
|
-
for (const o2 of ops)
|
|
68220
|
+
for (const o2 of ops) {
|
|
68221
|
+
let { valueSrc, meta } = o2;
|
|
68222
|
+
const tag = metaTag(meta, void 0, false);
|
|
68223
|
+
if (valueSrc && !isPointerValue(valueSrc)) parseYamlover(valueSrc, "<edit>");
|
|
68224
|
+
if (o2.concrete === "file/yamlover" || o2.concrete === "dir/yamlover") {
|
|
68225
|
+
const born = bornAsDocument(dataRoot, o2, tag);
|
|
68226
|
+
created.push(born.path);
|
|
68227
|
+
valueSrc = born.pointer;
|
|
68228
|
+
meta = void 0;
|
|
68229
|
+
}
|
|
68230
|
+
src = editChapterSource(src, o2.within, o2.op, valueSrc, meta);
|
|
68231
|
+
}
|
|
68167
68232
|
fs10.writeFileSync(bodyFile, src);
|
|
68168
68233
|
touched.push(bodyFile);
|
|
68169
68234
|
}
|
|
68170
|
-
return touched;
|
|
68235
|
+
return { touched, created, appended };
|
|
68171
68236
|
}
|
|
68172
68237
|
function firstContentIndent2(lines) {
|
|
68173
68238
|
for (const l2 of lines) if (isContentLine2(l2)) return indentOf2(l2);
|
|
@@ -68211,7 +68276,7 @@ function descriptionOf(s2, p2) {
|
|
|
68211
68276
|
function scalarKeyOf(s2, p2, key) {
|
|
68212
68277
|
const kp = (p2 === ":" ? "" : p2) + ":" + key;
|
|
68213
68278
|
const t3 = s2.node(kp);
|
|
68214
|
-
if (t3 && t3.type === "scalar" &&
|
|
68279
|
+
if (t3 && t3.type === "scalar" && t3.value != null) return String(t3.value);
|
|
68215
68280
|
return null;
|
|
68216
68281
|
}
|
|
68217
68282
|
var PATH_TOKEN = /\[\d+\]|[^:\[\]]+/g;
|