yamlover 0.3.50 → 0.3.52
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 +4 -4
- package/dist/client/assets/{decoded-5u9KK4Nb.js → decoded-DIrynyA3.js} +1 -1
- package/dist/client/assets/{djvu-CvRKxWcX.js → djvu-nd21Uprr.js} +1 -1
- package/dist/client/assets/{docx-CFqmrRMY.js → docx-Vop1BSUJ.js} +1 -1
- package/dist/client/assets/{heic-P0RPecFK.js → heic-CsSwcPBN.js} +1 -1
- package/dist/client/assets/{imagemap-BCrt0kPn.js → imagemap-zS65hQz-.js} +1 -1
- package/dist/client/assets/index-CJnH1FIn.css +1 -0
- package/dist/client/assets/index-DosWj0lR.js +759 -0
- package/dist/client/assets/{map-ClMfiQr8.js → map-CWLpLgs5.js} +1 -1
- package/dist/client/assets/{openable-9ABNW3A9.js → openable-DE9jbyAc.js} +1 -1
- package/dist/client/assets/{paged-UVifI3SC.js → paged-B9vOXGFT.js} +1 -1
- package/dist/client/assets/{pdf-BGgu5LFZ.js → pdf-BlhT_YB6.js} +1 -1
- package/dist/client/assets/{psd-D15IXPVu.js → psd-DqFDBsP9.js} +1 -1
- package/dist/client/assets/{spreadsheet-CeOcWWb2.js → spreadsheet-C1PFD0U5.js} +1 -1
- package/dist/client/assets/{tiff-pZPBtPPg.js → tiff-BhJNM15B.js} +1 -1
- package/dist/client/assets/{xyflow-uN1JIC1A.js → xyflow-CAiiOrwd.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server.js +392 -65
- package/package.json +1 -1
- package/dist/client/assets/index-_gAtxDG4.css +0 -1
- package/dist/client/assets/index-l1SxxFJR.js +0 -754
package/dist/server.js
CHANGED
|
@@ -67887,6 +67887,27 @@ function deadLinkDiagnostics(doc, store, dataRoot) {
|
|
|
67887
67887
|
}
|
|
67888
67888
|
return out;
|
|
67889
67889
|
}
|
|
67890
|
+
function doubledFragmentDiagnostics(doc) {
|
|
67891
|
+
const out = [];
|
|
67892
|
+
const walk = (node, segs) => {
|
|
67893
|
+
const entries = node.entries ?? [];
|
|
67894
|
+
entries.forEach((e3, i2) => {
|
|
67895
|
+
const key = typeof e3.key === "string" ? e3.key : null;
|
|
67896
|
+
if (key === "fragments" && segs[segs.length - 1] === "fragments" && segs[segs.length - 2] === "yo") {
|
|
67897
|
+
out.push({
|
|
67898
|
+
code: "annotations/doubled-fragments",
|
|
67899
|
+
severity: "warning",
|
|
67900
|
+
message: `a \`fragments:\` mapping nested inside \`yo: fragments:\` \u2014 left by a pre-fix annotate over the flat spelling`,
|
|
67901
|
+
path: ":" + [...segs, key].join(":"),
|
|
67902
|
+
hint: "move its child fragments up one level, into the enclosing fragments mapping"
|
|
67903
|
+
});
|
|
67904
|
+
}
|
|
67905
|
+
if (e3.value !== null && typeof e3.value === "object") walk(e3.value, [...segs, key ?? String(i2)]);
|
|
67906
|
+
});
|
|
67907
|
+
};
|
|
67908
|
+
walk(doc.root, []);
|
|
67909
|
+
return out;
|
|
67910
|
+
}
|
|
67890
67911
|
function deadLinkTargets(doc, store) {
|
|
67891
67912
|
const out = /* @__PURE__ */ new Set();
|
|
67892
67913
|
for (const l2 of scanTextLinks(doc)) {
|
|
@@ -67935,6 +67956,18 @@ function findKeyLine(lines, lo, hi, indent, key) {
|
|
|
67935
67956
|
}
|
|
67936
67957
|
return -1;
|
|
67937
67958
|
}
|
|
67959
|
+
function flatRun(line, keys, k) {
|
|
67960
|
+
let rest = line.trim();
|
|
67961
|
+
let n2 = 0;
|
|
67962
|
+
while (k + n2 < keys.length && rest !== "") {
|
|
67963
|
+
const key = keys[k + n2];
|
|
67964
|
+
const tok = [key, keyToken(key)].find((t3) => rest === `${t3}:` || rest.startsWith(`${t3}: `));
|
|
67965
|
+
if (tok === void 0) break;
|
|
67966
|
+
rest = rest === `${tok}:` ? "" : rest.slice(tok.length + 2);
|
|
67967
|
+
n2++;
|
|
67968
|
+
}
|
|
67969
|
+
return Math.max(1, n2);
|
|
67970
|
+
}
|
|
67938
67971
|
function trimBack(lines, floor, end) {
|
|
67939
67972
|
let e3 = end;
|
|
67940
67973
|
while (e3 > floor + 1 && !isContentLine(lines[e3 - 1])) e3--;
|
|
@@ -67971,7 +68004,8 @@ function bodyUnder(lines, L2, hi, indent) {
|
|
|
67971
68004
|
}
|
|
67972
68005
|
function reachBodyAt(lines, start, within) {
|
|
67973
68006
|
let { lo, hi, indent } = start;
|
|
67974
|
-
for (
|
|
68007
|
+
for (let k = 0; k < within.length; ) {
|
|
68008
|
+
const key = within[k];
|
|
67975
68009
|
const L2 = findKeyLine(lines, lo, hi, indent, key);
|
|
67976
68010
|
if (L2 < 0) {
|
|
67977
68011
|
const at = trimBack(lines, lo - 1, hi);
|
|
@@ -67979,18 +68013,23 @@ function reachBodyAt(lines, start, within) {
|
|
|
67979
68013
|
lo = at + 1;
|
|
67980
68014
|
hi = at + 1;
|
|
67981
68015
|
indent += 2;
|
|
68016
|
+
k++;
|
|
67982
68017
|
continue;
|
|
67983
68018
|
}
|
|
68019
|
+
const consumed = flatRun(lines[L2], within, k);
|
|
67984
68020
|
({ lo, hi, indent } = bodyUnder(lines, L2, hi, indent));
|
|
68021
|
+
k += consumed;
|
|
67985
68022
|
}
|
|
67986
68023
|
return { lo, hi, indent };
|
|
67987
68024
|
}
|
|
67988
68025
|
function findBody(lines, within) {
|
|
67989
68026
|
let region = { lo: 0, hi: lines.length, indent: firstContentIndent(lines) };
|
|
67990
|
-
for (
|
|
67991
|
-
const L2 = findKeyLine(lines, region.lo, region.hi, region.indent,
|
|
68027
|
+
for (let k = 0; k < within.length; ) {
|
|
68028
|
+
const L2 = findKeyLine(lines, region.lo, region.hi, region.indent, within[k]);
|
|
67992
68029
|
if (L2 < 0) return null;
|
|
68030
|
+
const consumed = flatRun(lines[L2], within, k);
|
|
67993
68031
|
region = bodyUnder(lines, L2, region.hi, region.indent);
|
|
68032
|
+
k += consumed;
|
|
67994
68033
|
}
|
|
67995
68034
|
return region;
|
|
67996
68035
|
}
|
|
@@ -68016,31 +68055,40 @@ function seqItemLines(lines, region, key) {
|
|
|
68016
68055
|
}
|
|
68017
68056
|
return { keyLine, items, end: trimBack(lines, end, region.hi) };
|
|
68018
68057
|
}
|
|
68019
|
-
function upsertMapEntry(text, within,
|
|
68058
|
+
function upsertMapEntry(text, within, mapPath, entryKey, render) {
|
|
68020
68059
|
const lines = text.replace(/\n$/, "").split("\n");
|
|
68021
|
-
upsertMapEntryAt(lines, reachBody(lines, within
|
|
68060
|
+
upsertMapEntryAt(lines, reachBody(lines, [...within, ...mapPath]), entryKey, render);
|
|
68022
68061
|
return lines.join("\n") + "\n";
|
|
68023
68062
|
}
|
|
68024
|
-
function upsertMapEntryAt(lines,
|
|
68025
|
-
|
|
68026
|
-
if (mapLine < 0) {
|
|
68027
|
-
const at = trimBack(lines, region.lo - 1, region.hi);
|
|
68028
|
-
lines.splice(at, 0, `${" ".repeat(region.indent)}${keyToken(mapKey)}:`);
|
|
68029
|
-
mapLine = at;
|
|
68030
|
-
}
|
|
68031
|
-
const mapIndent = region.indent + 2;
|
|
68032
|
-
const mapBody = { lo: mapLine + 1, hi: blockEnd(lines, mapLine + 1, lines.length, region.indent + 1), indent: mapIndent };
|
|
68033
|
-
const existing = findKeyLine(lines, mapBody.lo, mapBody.hi, mapIndent, entryKey);
|
|
68063
|
+
function upsertMapEntryAt(lines, body, entryKey, render) {
|
|
68064
|
+
const existing = findKeyLine(lines, body.lo, body.hi, body.indent, entryKey);
|
|
68034
68065
|
if (existing >= 0) {
|
|
68035
|
-
const end = blockEnd(lines, existing + 1,
|
|
68036
|
-
lines.splice(existing, end - existing, ...render(
|
|
68066
|
+
const end = blockEnd(lines, existing + 1, body.hi, body.indent + 1);
|
|
68067
|
+
lines.splice(existing, end - existing, ...render(body.indent));
|
|
68037
68068
|
} else {
|
|
68038
|
-
const at = trimBack(lines,
|
|
68039
|
-
lines.splice(at, 0, ...render(
|
|
68069
|
+
const at = trimBack(lines, body.lo - 1, body.hi);
|
|
68070
|
+
lines.splice(at, 0, ...render(body.indent));
|
|
68040
68071
|
}
|
|
68041
68072
|
}
|
|
68073
|
+
function replaceSeqEntryAt(lines, region, key, render) {
|
|
68074
|
+
const keyLine = findKeyLine(lines, region.lo, region.hi, region.indent, key);
|
|
68075
|
+
if (keyLine < 0) {
|
|
68076
|
+
const at = trimBack(lines, region.lo - 1, region.hi);
|
|
68077
|
+
lines.splice(at, 0, ...render(region.indent));
|
|
68078
|
+
return;
|
|
68079
|
+
}
|
|
68080
|
+
let end = keyLine + 1;
|
|
68081
|
+
for (let i2 = keyLine + 1; i2 < region.hi; i2++) {
|
|
68082
|
+
if (!isContentLine(lines[i2])) continue;
|
|
68083
|
+
const ind = indentOf(lines[i2]);
|
|
68084
|
+
if (ind < region.indent) break;
|
|
68085
|
+
if (ind === region.indent && seqMarkLen(lines[i2].trim()) === null) break;
|
|
68086
|
+
end = i2 + 1;
|
|
68087
|
+
}
|
|
68088
|
+
lines.splice(keyLine, trimBack(lines, keyLine, end) - keyLine, ...render(region.indent));
|
|
68089
|
+
}
|
|
68042
68090
|
function upsertFragment(text, within, slug, render) {
|
|
68043
|
-
return upsertMapEntry(text,
|
|
68091
|
+
return upsertMapEntry(text, within, [YO_KEY, FRAGMENTS_SUBKEY], slug, render);
|
|
68044
68092
|
}
|
|
68045
68093
|
function pruneEmptyKeyAt(lines, region, key) {
|
|
68046
68094
|
const L2 = findKeyLine(lines, region.lo, region.hi, region.indent, key);
|
|
@@ -68103,7 +68151,7 @@ function pruneEmptyYo(text, within) {
|
|
|
68103
68151
|
return pruneEmptyKeyAt(lines, region, YO_KEY) ? lines.join("\n") + "\n" : text;
|
|
68104
68152
|
}
|
|
68105
68153
|
function upsertThumbnail(text, within, resKey, render) {
|
|
68106
|
-
return upsertMapEntry(text, within, THUMBNAILS_KEY, resKey, render);
|
|
68154
|
+
return upsertMapEntry(text, within, [THUMBNAILS_KEY], resKey, render);
|
|
68107
68155
|
}
|
|
68108
68156
|
function annotationsRemainAt(lines, region) {
|
|
68109
68157
|
const seq = seqItemLines(lines, region, ANNOTATIONS_KEY);
|
|
@@ -68144,31 +68192,126 @@ function pruneEmptyAnnotations(text, within, pruneHosts) {
|
|
|
68144
68192
|
const droppedHosts = pruneHosts && pruneEmptyKeys(lines, within);
|
|
68145
68193
|
return droppedHusk || droppedHosts ? lines.join("\n") + "\n" : text;
|
|
68146
68194
|
}
|
|
68147
|
-
function
|
|
68195
|
+
function findMapping(lines, region, mapPath) {
|
|
68196
|
+
let r2 = region;
|
|
68197
|
+
let line = -1;
|
|
68198
|
+
for (let k = 0; k < mapPath.length; ) {
|
|
68199
|
+
const L2 = findKeyLine(lines, r2.lo, r2.hi, r2.indent, mapPath[k]);
|
|
68200
|
+
if (L2 < 0) return null;
|
|
68201
|
+
const consumed = flatRun(lines[L2], mapPath, k);
|
|
68202
|
+
line = L2;
|
|
68203
|
+
r2 = bodyUnder(lines, L2, r2.hi, r2.indent);
|
|
68204
|
+
k += consumed;
|
|
68205
|
+
}
|
|
68206
|
+
return line < 0 ? null : { line, body: r2 };
|
|
68207
|
+
}
|
|
68208
|
+
function removeMapEntry(text, within, mapPath, entryKey) {
|
|
68148
68209
|
const lines = text.replace(/\n$/, "").split("\n");
|
|
68149
|
-
|
|
68150
|
-
|
|
68151
|
-
|
|
68152
|
-
|
|
68153
|
-
|
|
68154
|
-
const
|
|
68155
|
-
|
|
68156
|
-
const entry = findKeyLine(lines,
|
|
68210
|
+
const region = findBody(lines, within);
|
|
68211
|
+
if (!region) return text;
|
|
68212
|
+
return removeMapEntryAt(lines, region, mapPath, entryKey) ? lines.join("\n") + "\n" : text;
|
|
68213
|
+
}
|
|
68214
|
+
function removeMapEntryAt(lines, region, mapPath, entryKey) {
|
|
68215
|
+
const map = findMapping(lines, region, mapPath);
|
|
68216
|
+
if (!map) return false;
|
|
68217
|
+
const entry = findKeyLine(lines, map.body.lo, map.body.hi, map.body.indent, entryKey);
|
|
68157
68218
|
if (entry < 0) return false;
|
|
68158
|
-
const end = blockEnd(lines, entry + 1,
|
|
68219
|
+
const end = blockEnd(lines, entry + 1, map.body.hi, map.body.indent + 1);
|
|
68159
68220
|
lines.splice(entry, end - entry);
|
|
68160
|
-
const
|
|
68221
|
+
const mapIndent = indentOf(lines[map.line]);
|
|
68222
|
+
const newHi = blockEnd(lines, map.line + 1, lines.length, mapIndent + 1);
|
|
68161
68223
|
let hasChild = false;
|
|
68162
|
-
for (let i2 =
|
|
68163
|
-
if (isContentLine(lines[i2]) && indentOf(lines[i2]) ===
|
|
68224
|
+
for (let i2 = map.line + 1; i2 < newHi; i2++) {
|
|
68225
|
+
if (isContentLine(lines[i2]) && indentOf(lines[i2]) === map.body.indent) {
|
|
68164
68226
|
hasChild = true;
|
|
68165
68227
|
break;
|
|
68166
68228
|
}
|
|
68167
68229
|
}
|
|
68168
|
-
if (!hasChild) lines.splice(
|
|
68230
|
+
if (!hasChild) lines.splice(map.line, newHi - map.line);
|
|
68169
68231
|
return true;
|
|
68170
68232
|
}
|
|
68171
68233
|
|
|
68234
|
+
// src/board-model.ts
|
|
68235
|
+
var supersetOf = (tags, wanted) => wanted.every((t3) => tags.has(t3));
|
|
68236
|
+
function compartmentAt(structure, at) {
|
|
68237
|
+
if (!at) return null;
|
|
68238
|
+
return structure[at.lane]?.[at.comp] ?? null;
|
|
68239
|
+
}
|
|
68240
|
+
function reconcile(structure, chapters) {
|
|
68241
|
+
let changed = false;
|
|
68242
|
+
const out = structure.map(
|
|
68243
|
+
(lane) => lane.map((comp) => {
|
|
68244
|
+
if (comp.tags.length === 0) {
|
|
68245
|
+
const kept2 = comp.items.filter((it) => !chapters.has(it.path));
|
|
68246
|
+
if (kept2.length === comp.items.length) return comp;
|
|
68247
|
+
changed = true;
|
|
68248
|
+
return { tags: comp.tags, items: kept2 };
|
|
68249
|
+
}
|
|
68250
|
+
const kept = [];
|
|
68251
|
+
const seen = /* @__PURE__ */ new Set();
|
|
68252
|
+
let compChanged = false;
|
|
68253
|
+
for (const item of comp.items) {
|
|
68254
|
+
if (seen.has(item.path)) {
|
|
68255
|
+
compChanged = true;
|
|
68256
|
+
continue;
|
|
68257
|
+
}
|
|
68258
|
+
const tags = chapters.get(item.path);
|
|
68259
|
+
if (tags && !supersetOf(tags, comp.tags)) {
|
|
68260
|
+
compChanged = true;
|
|
68261
|
+
continue;
|
|
68262
|
+
}
|
|
68263
|
+
kept.push(item);
|
|
68264
|
+
seen.add(item.path);
|
|
68265
|
+
}
|
|
68266
|
+
for (const [p2, tags] of chapters) {
|
|
68267
|
+
if (seen.has(p2) || !supersetOf(tags, comp.tags)) continue;
|
|
68268
|
+
kept.push({ path: p2 });
|
|
68269
|
+
seen.add(p2);
|
|
68270
|
+
compChanged = true;
|
|
68271
|
+
}
|
|
68272
|
+
if (!compChanged) return comp;
|
|
68273
|
+
changed = true;
|
|
68274
|
+
return { tags: comp.tags, items: kept };
|
|
68275
|
+
})
|
|
68276
|
+
);
|
|
68277
|
+
return changed ? { structure: out, changed } : { structure, changed };
|
|
68278
|
+
}
|
|
68279
|
+
function moveDeltas(chapterTags, from, to2) {
|
|
68280
|
+
const toTags = new Set(to2?.tags ?? []);
|
|
68281
|
+
const untag = (from?.tags ?? []).filter((t3) => chapterTags.has(t3) && !toTags.has(t3));
|
|
68282
|
+
const tag = (to2?.tags ?? []).filter((t3) => !chapterTags.has(t3));
|
|
68283
|
+
return { untag, tag };
|
|
68284
|
+
}
|
|
68285
|
+
function applyMove(structure, task, from, to2) {
|
|
68286
|
+
let moved = { path: task };
|
|
68287
|
+
const out = structure.map(
|
|
68288
|
+
(lane, li) => lane.map((comp, ci) => {
|
|
68289
|
+
let items = comp.items;
|
|
68290
|
+
if (from && from.lane === li && from.comp === ci) {
|
|
68291
|
+
const i2 = items.findIndex((it) => it.path === task);
|
|
68292
|
+
if (i2 >= 0) {
|
|
68293
|
+
moved = items[i2];
|
|
68294
|
+
items = [...items.slice(0, i2), ...items.slice(i2 + 1)];
|
|
68295
|
+
}
|
|
68296
|
+
}
|
|
68297
|
+
return items === comp.items ? comp : { tags: comp.tags, items };
|
|
68298
|
+
})
|
|
68299
|
+
);
|
|
68300
|
+
if (to2) {
|
|
68301
|
+
const dest = out[to2.lane]?.[to2.comp];
|
|
68302
|
+
if (dest && !dest.items.some((it) => it.path === task)) {
|
|
68303
|
+
out[to2.lane] = out[to2.lane].map((c3, ci) => ci === to2.comp ? { tags: c3.tags, items: [...c3.items, moved] } : c3);
|
|
68304
|
+
}
|
|
68305
|
+
}
|
|
68306
|
+
return out;
|
|
68307
|
+
}
|
|
68308
|
+
function seedFromWorkflow(statePaths) {
|
|
68309
|
+
return statePaths.map((p2) => [{ tags: [p2], items: [] }]);
|
|
68310
|
+
}
|
|
68311
|
+
function seedFromOldLanes(lanes) {
|
|
68312
|
+
return lanes.map((laneTags) => laneTags.length === 0 ? [{ tags: [], items: [] }] : laneTags.map((t3) => ({ tags: [t3], items: [] })));
|
|
68313
|
+
}
|
|
68314
|
+
|
|
68172
68315
|
// src/concrete.ts
|
|
68173
68316
|
var OVERLAY_DIR = ".yo";
|
|
68174
68317
|
var BODY_FILE2 = "body.yo";
|
|
@@ -69355,7 +69498,7 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
69355
69498
|
}
|
|
69356
69499
|
};
|
|
69357
69500
|
let reconcilePending = null;
|
|
69358
|
-
const
|
|
69501
|
+
const reconcile2 = () => {
|
|
69359
69502
|
if (reconcilePending) return reconcilePending;
|
|
69360
69503
|
const p2 = enqueue(async () => {
|
|
69361
69504
|
reconcilePending = null;
|
|
@@ -69400,7 +69543,7 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
69400
69543
|
return;
|
|
69401
69544
|
}
|
|
69402
69545
|
log(`watch: ${external.length} change(s) \u2014 ${external.slice(0, 5).join(", ")}${external.length > 5 ? ", \u2026" : ""}`);
|
|
69403
|
-
|
|
69546
|
+
reconcile2().catch(() => {
|
|
69404
69547
|
});
|
|
69405
69548
|
}, { ignore: ignore2 }) : null;
|
|
69406
69549
|
const handler = (req, res, url) => {
|
|
@@ -69424,14 +69567,14 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
69424
69567
|
return;
|
|
69425
69568
|
}
|
|
69426
69569
|
if (req.method === "POST" && url.pathname === "/api/reindex") {
|
|
69427
|
-
|
|
69570
|
+
reconcile2().then((diff2) => sendJson(res, 200, diff2)).catch((e3) => sendJson(res, 500, { error: String(e3.message || e3) }));
|
|
69428
69571
|
return;
|
|
69429
69572
|
}
|
|
69430
69573
|
if (url.pathname === "/api/doctor") {
|
|
69431
69574
|
try {
|
|
69432
69575
|
const v = validateTree(scanTree(dataRoot, ignore2));
|
|
69433
69576
|
const doc = cachedDoc ?? walkTree(dataRoot, walkOpts).doc;
|
|
69434
|
-
sendJson(res, 200, { allowed: v.allowed, diagnostics: [...v.diagnostics, ...deadLinkDiagnostics(doc, s2, dataRoot)] });
|
|
69577
|
+
sendJson(res, 200, { allowed: v.allowed, diagnostics: [...v.diagnostics, ...deadLinkDiagnostics(doc, s2, dataRoot), ...doubledFragmentDiagnostics(doc)] });
|
|
69435
69578
|
} catch (e3) {
|
|
69436
69579
|
sendJson(res, 500, { error: String(e3.message || e3) });
|
|
69437
69580
|
}
|
|
@@ -69585,14 +69728,48 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
69585
69728
|
readBody(req).then(
|
|
69586
69729
|
(data) => enqueue(async () => {
|
|
69587
69730
|
const b = data;
|
|
69588
|
-
const
|
|
69589
|
-
const
|
|
69590
|
-
|
|
69591
|
-
const
|
|
69592
|
-
|
|
69593
|
-
|
|
69594
|
-
|
|
69595
|
-
|
|
69731
|
+
const boardSegs = strToSegs(b?.path || ":");
|
|
69732
|
+
const boardStore = storePath(boardSegs);
|
|
69733
|
+
if (!s2.node(boardStore)) throw new Error(`no board at ${b?.path || ":"}`);
|
|
69734
|
+
const op = String(b?.op ?? "");
|
|
69735
|
+
const read2 = readBoardStructure(s2, boardStore);
|
|
69736
|
+
const structure = read2 ?? seedBoardStructure(s2, boardStore);
|
|
69737
|
+
const writeStructure = async (st) => {
|
|
69738
|
+
const { bodyFile } = hostFor(dataRoot, s2, boardSegs);
|
|
69739
|
+
mkdirInside(dataRoot, path11.dirname(bodyFile), { recursive: true });
|
|
69740
|
+
const src = fs10.existsSync(bodyFile) ? fs10.readFileSync(bodyFile, "utf8") : "";
|
|
69741
|
+
writeBody(dataRoot, s2, bodyFile, writeBoardStructure(src, st));
|
|
69742
|
+
broadcast(await doReindexFile(bodyFile));
|
|
69743
|
+
};
|
|
69744
|
+
if (op === "structure") {
|
|
69745
|
+
const st = sanitizeBoardStructure(b.structure);
|
|
69746
|
+
const rec = reconcile(st, memberTagSets(s2, boardMembers(dataRoot, s2, boardStore)));
|
|
69747
|
+
await writeStructure(rec.structure);
|
|
69748
|
+
scheduleHasher();
|
|
69749
|
+
return { seeded: false, ...resolveBoard(dataRoot, s2, boardMembers(dataRoot, s2, boardStore), rec.structure) };
|
|
69750
|
+
}
|
|
69751
|
+
if (op === "move") {
|
|
69752
|
+
const task = String(b.task ?? "");
|
|
69753
|
+
const taskStore = storePath(strToSegs(task));
|
|
69754
|
+
if (!task || !s2.node(taskStore)) throw new Error("move needs a `task` naming an existing node");
|
|
69755
|
+
const from = boardCoord(b.from);
|
|
69756
|
+
const to2 = boardCoord(b.to);
|
|
69757
|
+
const deltas = moveDeltas(memberTagSets(s2, [task]).get(task), compartmentAt(structure, from), compartmentAt(structure, to2));
|
|
69758
|
+
for (const t3 of deltas.untag) broadcast(await doReindexFile(unembedAnnotation(dataRoot, s2, task, t3)));
|
|
69759
|
+
for (const t3 of deltas.tag) broadcast(await doReindexFile(embedAnnotation(dataRoot, s2, settings.sidecars, { target: task, tag: t3 })));
|
|
69760
|
+
const moved = applyMove(structure, task, from, to2);
|
|
69761
|
+
const rec = reconcile(moved, memberTagSets(s2, boardMembers(dataRoot, s2, boardStore)));
|
|
69762
|
+
await writeStructure(rec.structure);
|
|
69763
|
+
scheduleHasher();
|
|
69764
|
+
return { seeded: false, ...resolveBoard(dataRoot, s2, boardMembers(dataRoot, s2, boardStore), rec.structure) };
|
|
69765
|
+
}
|
|
69766
|
+
if (op === "reconcile") {
|
|
69767
|
+
const rec = reconcile(structure, memberTagSets(s2, boardMembers(dataRoot, s2, boardStore)));
|
|
69768
|
+
if (read2 !== null && rec.changed) await writeStructure(rec.structure);
|
|
69769
|
+
scheduleHasher();
|
|
69770
|
+
return { seeded: read2 === null, ...resolveBoard(dataRoot, s2, boardMembers(dataRoot, s2, boardStore), rec.structure) };
|
|
69771
|
+
}
|
|
69772
|
+
throw new Error(`unknown board op: ${op || "(none)"}`);
|
|
69596
69773
|
})
|
|
69597
69774
|
).then((body) => sendJson(res, 201, body)).catch((e3) => sendJson(res, 400, { error: String(e3.message || e3) }));
|
|
69598
69775
|
return;
|
|
@@ -69660,7 +69837,7 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
69660
69837
|
}
|
|
69661
69838
|
if (url.pathname === "/api/content" || url.pathname.startsWith("/api/content/")) {
|
|
69662
69839
|
(async () => {
|
|
69663
|
-
if (!cachedDoc) await
|
|
69840
|
+
if (!cachedDoc) await reconcile2();
|
|
69664
69841
|
const doc = cachedDoc;
|
|
69665
69842
|
if (!doc) throw new Error("the merged document is unavailable (index rebuild failed)");
|
|
69666
69843
|
const rest = url.pathname === "/api/content" ? "" : url.pathname.slice("/api/content/".length);
|
|
@@ -69809,6 +69986,15 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
69809
69986
|
sendJson(res, 200, taggedMaterials(dataRoot, s2, p2));
|
|
69810
69987
|
return;
|
|
69811
69988
|
}
|
|
69989
|
+
if (url.pathname === "/api/board") {
|
|
69990
|
+
const row2 = s2.node(p2);
|
|
69991
|
+
if (!row2) return notFound(res, url);
|
|
69992
|
+
const read2 = readBoardStructure(s2, p2);
|
|
69993
|
+
const members = boardMembers(dataRoot, s2, p2);
|
|
69994
|
+
const { structure } = reconcile(read2 ?? seedBoardStructure(s2, p2), memberTagSets(s2, members));
|
|
69995
|
+
sendJson(res, 200, { seeded: read2 === null, ...resolveBoard(dataRoot, s2, members, structure) });
|
|
69996
|
+
return;
|
|
69997
|
+
}
|
|
69812
69998
|
if (url.pathname === "/api/tree") {
|
|
69813
69999
|
const row2 = s2.node(p2);
|
|
69814
70000
|
if (!row2) return notFound(res, url);
|
|
@@ -69841,15 +70027,18 @@ function createHandlers(dataRoot, opts = {}) {
|
|
|
69841
70027
|
}
|
|
69842
70028
|
return sendJson(res, 415, { error: `no thumbnail for format: ${fmt ?? "unknown"}` });
|
|
69843
70029
|
}
|
|
69844
|
-
const serve = (file) => {
|
|
70030
|
+
const serve = (file, mime2 = "image/jpeg") => {
|
|
69845
70031
|
res.statusCode = 200;
|
|
69846
|
-
res.setHeader("Content-Type",
|
|
70032
|
+
res.setHeader("Content-Type", mime2);
|
|
69847
70033
|
res.setHeader("Content-Length", String(fs10.statSync(file).size));
|
|
69848
70034
|
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
69849
70035
|
const stream = fs10.createReadStream(file);
|
|
69850
70036
|
stream.on("error", () => res.destroy());
|
|
69851
70037
|
stream.pipe(res);
|
|
69852
70038
|
};
|
|
70039
|
+
if (segs.some((g) => String(g) === OVERLAY_DIR)) {
|
|
70040
|
+
return serve(sourceAbs, sourceAbs.endsWith(".png") ? "image/png" : "image/jpeg");
|
|
70041
|
+
}
|
|
69853
70042
|
const ready2 = existingThumb(dataRoot, s2, settings.sidecars, segs, sourceRow, w, h);
|
|
69854
70043
|
if (ready2) return serve(ready2);
|
|
69855
70044
|
if (readOnly) return sendJson(res, 415, { error: `thumbnail not pre-generated (read-only)` });
|
|
@@ -70272,21 +70461,131 @@ function pointerRaw(clientPath) {
|
|
|
70272
70461
|
}
|
|
70273
70462
|
return "::" + out;
|
|
70274
70463
|
}
|
|
70275
|
-
|
|
70276
|
-
|
|
70277
|
-
|
|
70464
|
+
var LANES_SUBKEY = "lanes";
|
|
70465
|
+
var BOARD_CONFIG_KEYS = /* @__PURE__ */ new Set(["workflow", "lanes", "yamlover", "ontos", YO_KEY2]);
|
|
70466
|
+
var TAGISH_FORMATS = /* @__PURE__ */ new Set([ONTO_FORMAT, "x-yamlover-workflow", "x-yamlover-board"]);
|
|
70467
|
+
function writeBoardStructure(src, structure) {
|
|
70278
70468
|
let lines = src.replace(/\n+$/, "").split("\n");
|
|
70279
70469
|
if (src.trim() === "") lines = ["!!<*yamlover:$defs:board>"];
|
|
70280
|
-
const
|
|
70281
|
-
|
|
70282
|
-
|
|
70283
|
-
|
|
70284
|
-
|
|
70285
|
-
|
|
70286
|
-
|
|
70287
|
-
|
|
70470
|
+
const render = (indent) => {
|
|
70471
|
+
const pad = " ".repeat(indent);
|
|
70472
|
+
if (structure.length === 0) return [`${pad}lanes: []`];
|
|
70473
|
+
const out = [`${pad}lanes:`];
|
|
70474
|
+
const cpad = " ".repeat(indent + 2);
|
|
70475
|
+
const bpad = " ".repeat(indent + 4);
|
|
70476
|
+
for (const lane of structure) {
|
|
70477
|
+
const comps = lane.length ? lane : [{ tags: [], items: [] }];
|
|
70478
|
+
comps.forEach((comp, ci) => {
|
|
70479
|
+
out.push(ci === 0 ? `${pad}- -` : `${cpad}-`);
|
|
70480
|
+
for (const t3 of comp.tags) out.push(`${bpad}&${pointerRaw(t3)}:-`);
|
|
70481
|
+
for (const it of comp.items)
|
|
70482
|
+
out.push(it.key !== void 0 ? `${bpad}${keyToken(it.key)}: *${pointerRaw(it.path)}` : `${bpad}- *${pointerRaw(it.path)}`);
|
|
70483
|
+
});
|
|
70484
|
+
}
|
|
70485
|
+
return out;
|
|
70486
|
+
};
|
|
70487
|
+
replaceSeqEntryAt(lines, reachBody(lines, [YO_KEY2]), LANES_SUBKEY, render);
|
|
70288
70488
|
return lines.join("\n") + "\n";
|
|
70289
70489
|
}
|
|
70490
|
+
function membershipPathsOf(s2, store) {
|
|
70491
|
+
return s2.relationships(store).out.filter((e3) => e3.kind === "back" && e3.label == null).map((e3) => segsToStr(storePathToSegs(e3.to)));
|
|
70492
|
+
}
|
|
70493
|
+
function readBoardStructure(s2, boardStore) {
|
|
70494
|
+
const lanesStore = childPath(childPath(boardStore, YO_KEY2), LANES_SUBKEY);
|
|
70495
|
+
if (!s2.node(lanesStore)) return null;
|
|
70496
|
+
return s2.children(lanesStore).map(
|
|
70497
|
+
(lane) => s2.children(lane.to).map((comp) => ({
|
|
70498
|
+
tags: membershipPathsOf(s2, comp.to),
|
|
70499
|
+
items: s2.entries(comp.to).filter((e3) => e3.kind === "ref").map((e3) => ({ path: segsToStr(storePathToSegs(e3.to)), ...e3.label != null ? { key: e3.label } : {} }))
|
|
70500
|
+
}))
|
|
70501
|
+
);
|
|
70502
|
+
}
|
|
70503
|
+
function seedBoardStructure(s2, boardStore) {
|
|
70504
|
+
const oldLanes = childPath(boardStore, LANES_SUBKEY);
|
|
70505
|
+
if (s2.node(oldLanes)) {
|
|
70506
|
+
return seedFromOldLanes(
|
|
70507
|
+
s2.children(oldLanes).map(
|
|
70508
|
+
(lane) => s2.entries(lane.to).filter((e3) => e3.kind === "ref" && e3.label == null).map((e3) => segsToStr(storePathToSegs(e3.to)))
|
|
70509
|
+
)
|
|
70510
|
+
);
|
|
70511
|
+
}
|
|
70512
|
+
const wf = s2.relationships(boardStore).out.find((e3) => e3.kind === "ref" && e3.label === "workflow");
|
|
70513
|
+
if (wf) {
|
|
70514
|
+
const children2 = s2.children(wf.to).filter((c3) => c3.label && c3.label !== "initial" && c3.label !== "color");
|
|
70515
|
+
const ontos = children2.filter((c3) => s2.node(c3.to)?.format === ONTO_FORMAT);
|
|
70516
|
+
return seedFromWorkflow((ontos.length ? ontos : children2).map((c3) => segsToStr(storePathToSegs(c3.to))));
|
|
70517
|
+
}
|
|
70518
|
+
return [];
|
|
70519
|
+
}
|
|
70520
|
+
function boardMembers(dataRoot, s2, boardStore) {
|
|
70521
|
+
const out = [];
|
|
70522
|
+
for (const c3 of s2.children(boardStore)) {
|
|
70523
|
+
if (!c3.label || BOARD_CONFIG_KEYS.has(c3.label) || isHidden(s2, c3.to)) continue;
|
|
70524
|
+
const n2 = s2.node(c3.to);
|
|
70525
|
+
if (!n2 || n2.format && TAGISH_FORMATS.has(n2.format)) continue;
|
|
70526
|
+
const segs = storePathToSegs(c3.to);
|
|
70527
|
+
if (n2.type === "scalar" && s2.children(c3.to).length === 0 && !fs10.existsSync(path11.resolve(dataRoot, ...segs.map(String)))) continue;
|
|
70528
|
+
out.push(segsToStr(segs));
|
|
70529
|
+
}
|
|
70530
|
+
return out;
|
|
70531
|
+
}
|
|
70532
|
+
function memberTagSets(s2, members) {
|
|
70533
|
+
return new Map(members.map((p2) => [p2, new Set(membershipPathsOf(s2, storePath(strToSegs(p2))))]));
|
|
70534
|
+
}
|
|
70535
|
+
function boardCardStub(dataRoot, s2, p2) {
|
|
70536
|
+
const segs = strToSegs(p2);
|
|
70537
|
+
const store = storePath(segs);
|
|
70538
|
+
const row = s2.node(store);
|
|
70539
|
+
const field = (k) => {
|
|
70540
|
+
const v = s2.node(childPath(store, k))?.value;
|
|
70541
|
+
return v == null ? null : String(v);
|
|
70542
|
+
};
|
|
70543
|
+
return {
|
|
70544
|
+
path: p2,
|
|
70545
|
+
title: (row ? displayNameOf(s2, store) : null) ?? String(segs[segs.length - 1] ?? p2),
|
|
70546
|
+
type: row ? tocType(s2, store, row) : null,
|
|
70547
|
+
format: row?.format ?? null,
|
|
70548
|
+
concrete: row ? concreteOf(s2, dataRoot, segs, row) : null,
|
|
70549
|
+
priority: field("priority"),
|
|
70550
|
+
assignee: field("assignee"),
|
|
70551
|
+
due: field("due"),
|
|
70552
|
+
// resolved refs, not bare paths — the card FACE shows its tags (names + colors)
|
|
70553
|
+
tags: membershipPathsOf(s2, store).map((t3) => projectTag(s2, storePath(strToSegs(t3)))).filter(Boolean)
|
|
70554
|
+
};
|
|
70555
|
+
}
|
|
70556
|
+
function resolveBoard(dataRoot, s2, members, structure) {
|
|
70557
|
+
const inComp = /* @__PURE__ */ new Set();
|
|
70558
|
+
const lanes = structure.map(
|
|
70559
|
+
(lane) => lane.map((comp) => ({
|
|
70560
|
+
tags: comp.tags.map((t3) => projectTag(s2, storePath(strToSegs(t3)))).filter(Boolean),
|
|
70561
|
+
items: comp.items.map((it) => {
|
|
70562
|
+
inComp.add(it.path);
|
|
70563
|
+
return { ...boardCardStub(dataRoot, s2, it.path), ...it.key !== void 0 ? { key: it.key } : {} };
|
|
70564
|
+
})
|
|
70565
|
+
}))
|
|
70566
|
+
);
|
|
70567
|
+
const backlog = members.filter((p2) => !inComp.has(p2)).map((p2) => boardCardStub(dataRoot, s2, p2));
|
|
70568
|
+
return { lanes, backlog };
|
|
70569
|
+
}
|
|
70570
|
+
function sanitizeBoardStructure(raw) {
|
|
70571
|
+
if (!Array.isArray(raw)) throw new Error("board structure must be an array of lanes");
|
|
70572
|
+
return raw.map(
|
|
70573
|
+
(lane) => (Array.isArray(lane) ? lane : []).map((comp) => {
|
|
70574
|
+
const c3 = comp;
|
|
70575
|
+
return {
|
|
70576
|
+
tags: Array.isArray(c3?.tags) ? c3.tags.map(String) : [],
|
|
70577
|
+
items: Array.isArray(c3?.items) ? c3.items.map((it) => {
|
|
70578
|
+
const o2 = it;
|
|
70579
|
+
return { path: String(o2?.path ?? ""), ...o2?.key != null ? { key: String(o2.key) } : {} };
|
|
70580
|
+
}).filter((it) => it.path !== "") : []
|
|
70581
|
+
};
|
|
70582
|
+
})
|
|
70583
|
+
);
|
|
70584
|
+
}
|
|
70585
|
+
function boardCoord(v) {
|
|
70586
|
+
const o2 = v;
|
|
70587
|
+
return o2 != null && typeof o2.lane === "number" && typeof o2.comp === "number" ? { lane: o2.lane, comp: o2.comp } : null;
|
|
70588
|
+
}
|
|
70290
70589
|
function overlaidDir(bodyFile) {
|
|
70291
70590
|
if (bodyFile.endsWith(path11.join(OVERLAY_DIR, BODY_FILE2))) return path11.dirname(path11.dirname(bodyFile));
|
|
70292
70591
|
return path11.basename(bodyFile) === INDEX_FILE2 ? path11.dirname(bodyFile) : null;
|
|
@@ -70436,15 +70735,34 @@ function embedAnnotation(dataRoot, s2, mode, a2) {
|
|
|
70436
70735
|
writeBody(dataRoot, s2, bodyFile2, lines.join("\n") + "\n");
|
|
70437
70736
|
return bodyFile2;
|
|
70438
70737
|
}
|
|
70738
|
+
const own = ownDocFile(dataRoot, segs);
|
|
70739
|
+
if (own) {
|
|
70740
|
+
writeBody(dataRoot, s2, own, appendBookmark(fs10.readFileSync(own, "utf8"), [], tokens));
|
|
70741
|
+
return own;
|
|
70742
|
+
}
|
|
70439
70743
|
const { bodyFile, within } = hostFor(dataRoot, s2, segs);
|
|
70440
70744
|
mkdirInside(dataRoot, path11.dirname(bodyFile), { recursive: true });
|
|
70441
70745
|
const src = fs10.existsSync(bodyFile) ? fs10.readFileSync(bodyFile, "utf8") : "";
|
|
70442
70746
|
writeBody(dataRoot, s2, bodyFile, appendBookmark(src, within, tokens));
|
|
70443
70747
|
return bodyFile;
|
|
70444
70748
|
}
|
|
70749
|
+
function ownDocFile(dataRoot, segs) {
|
|
70750
|
+
if (segs.length === 0 || segs.some((s2) => typeof s2 === "number")) return null;
|
|
70751
|
+
const abs = path11.resolve(dataRoot, ...segs.map(String));
|
|
70752
|
+
if (!/\.(yo|yamlover)$/i.test(abs)) return null;
|
|
70753
|
+
try {
|
|
70754
|
+
return fs10.statSync(abs).isFile() ? abs : null;
|
|
70755
|
+
} catch {
|
|
70756
|
+
return null;
|
|
70757
|
+
}
|
|
70758
|
+
}
|
|
70445
70759
|
function embedFragment(dataRoot, s2, mode, f2) {
|
|
70446
70760
|
const segs = strToSegs(f2.target || ":");
|
|
70447
|
-
const
|
|
70761
|
+
const chosen = typeof f2.slug === "string" ? f2.slug.trim() : "";
|
|
70762
|
+
if (chosen !== "" && s2.node(storePath([...segs, YO_KEY2, FRAGS_SUBKEY, chosen]))) {
|
|
70763
|
+
throw new Error(`a fragment \`${chosen}\` already exists on this node`);
|
|
70764
|
+
}
|
|
70765
|
+
const slug = chosen !== "" ? chosen : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
70448
70766
|
if (isChunkTarget(s2, segs)) {
|
|
70449
70767
|
const { docSegs, bodyFile: bodyFile2 } = chapterSource(dataRoot, s2, segs);
|
|
70450
70768
|
const { indices, keys } = splitChunkWithin(segs.slice(docSegs.length));
|
|
@@ -70457,7 +70775,7 @@ function embedFragment(dataRoot, s2, mode, f2) {
|
|
|
70457
70775
|
/*ensureOmni*/
|
|
70458
70776
|
true
|
|
70459
70777
|
);
|
|
70460
|
-
upsertMapEntryAt(lines, reachBodyAt(lines, region, [YO_KEY2
|
|
70778
|
+
upsertMapEntryAt(lines, reachBodyAt(lines, region, [YO_KEY2, FRAGS_SUBKEY]), slug, (indent) => fragmentBlockLines(slug, f2.selector, null, indent));
|
|
70461
70779
|
writeBody(dataRoot, s2, bodyFile2, lines.join("\n") + "\n");
|
|
70462
70780
|
return { slug, fragmentPath: segsToStr([...segs, YO_KEY2, FRAGS_SUBKEY, slug]) };
|
|
70463
70781
|
}
|
|
@@ -70542,7 +70860,7 @@ function unembedAnnotation(dataRoot, s2, target, tag, sel) {
|
|
|
70542
70860
|
), keys);
|
|
70543
70861
|
removeBookmarkAt(lines, fragRegion, pred);
|
|
70544
70862
|
if (isFragmentSegs(keys) && !bookmarksRemainAt(lines, fragRegion())) {
|
|
70545
|
-
removeMapEntryAt(lines,
|
|
70863
|
+
removeMapEntryAt(lines, chunkFieldRegion(lines, indices, false), keys.slice(0, -1), keys[keys.length - 1]);
|
|
70546
70864
|
pruneEmptyKeyAt(lines, chunkFieldRegion(lines, indices, false), YO_KEY2);
|
|
70547
70865
|
collapseChunkOmni(lines, indices);
|
|
70548
70866
|
} else if (keys.length === 0 && !bookmarksRemainAt(lines, fragRegion())) {
|
|
@@ -70551,12 +70869,21 @@ function unembedAnnotation(dataRoot, s2, target, tag, sel) {
|
|
|
70551
70869
|
writeBody(dataRoot, s2, bodyFile2, lines.join("\n") + "\n");
|
|
70552
70870
|
return bodyFile2;
|
|
70553
70871
|
}
|
|
70872
|
+
const own = ownDocFile(dataRoot, segs);
|
|
70873
|
+
if (own) {
|
|
70874
|
+
const before = fs10.readFileSync(own, "utf8");
|
|
70875
|
+
const after = removeBookmark(before, [], pred);
|
|
70876
|
+
if (after !== before) {
|
|
70877
|
+
writeBody(dataRoot, s2, own, after);
|
|
70878
|
+
return own;
|
|
70879
|
+
}
|
|
70880
|
+
}
|
|
70554
70881
|
const { bodyFile, within } = hostFor(dataRoot, s2, segs);
|
|
70555
70882
|
if (!fs10.existsSync(bodyFile)) return bodyFile;
|
|
70556
70883
|
let src = removeBookmark(fs10.readFileSync(bodyFile, "utf8"), within, pred);
|
|
70557
70884
|
const overlay2 = overlaidDir(bodyFile) !== null;
|
|
70558
70885
|
if (isFragmentSegs(within) && !bookmarksRemain(src, within)) {
|
|
70559
|
-
src = removeMapEntry(src, within.slice(0, -
|
|
70886
|
+
src = removeMapEntry(src, within.slice(0, -3), [YO_KEY2, FRAGS_SUBKEY], within[within.length - 1]);
|
|
70560
70887
|
src = pruneEmptyYo(src, within.slice(0, -3));
|
|
70561
70888
|
src = pruneEmptyAnnotations(src, within.slice(0, -3), overlay2);
|
|
70562
70889
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yamlover",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.52",
|
|
4
4
|
"description": "A local-first, editable knowledge graph for humans and LLMs: npx yamlover <root> serves a browser UI over a plain-text directory, with an editor, live queries, pointers, and an LLM-agent API.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|