yamlover 0.3.13 → 0.3.14

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/dist/server.js CHANGED
@@ -62535,7 +62535,7 @@ function pathOf(chain) {
62535
62535
 
62536
62536
  // ../engine/ts/src/store.ts
62537
62537
  import { DatabaseSync } from "node:sqlite";
62538
- var SCHEMA_VERSION = 4;
62538
+ var SCHEMA_VERSION = 5;
62539
62539
  var SCHEMA = `
62540
62540
  CREATE TABLE IF NOT EXISTS node (
62541
62541
  path TEXT PRIMARY KEY,
@@ -62568,6 +62568,18 @@ CREATE TABLE IF NOT EXISTS dangling (
62568
62568
  reason TEXT NOT NULL -- why it did not resolve
62569
62569
  );
62570
62570
  `;
62571
+ function encodeScalarValue(v) {
62572
+ if (typeof v === "number" && !Number.isFinite(v)) return JSON.stringify({ "@nonfinite": String(v) });
62573
+ return JSON.stringify(v);
62574
+ }
62575
+ function decodeScalarValue(s2) {
62576
+ const v = JSON.parse(s2);
62577
+ if (v && typeof v === "object" && !Array.isArray(v) && "@nonfinite" in v) {
62578
+ const n2 = v["@nonfinite"];
62579
+ return n2 === "Infinity" ? Infinity : n2 === "-Infinity" ? -Infinity : NaN;
62580
+ }
62581
+ return v;
62582
+ }
62571
62583
  var Store = class {
62572
62584
  db;
62573
62585
  /** True while the DB holds no usable index (a new file, or a schema-version mismatch dropped
@@ -62612,7 +62624,7 @@ var Store = class {
62612
62624
  const meta = node.meta ? JSON.stringify(node.meta) : null;
62613
62625
  const owned = node.entries?.filter((e3) => e3.edge !== "back") ?? [];
62614
62626
  const isArray = node.array || node.kind === "mapping" && owned.length > 0 && owned.every((e3) => e3.key === null);
62615
- const value = node.kind === "scalar" ? JSON.stringify(node.value) : null;
62627
+ const value = node.kind === "scalar" ? encodeScalarValue(node.value) : null;
62616
62628
  const format = node.kind === "blob" ? node.format : formatFromMeta(node);
62617
62629
  const hash = node.kind === "blob" ? node.contentHash : null;
62618
62630
  const size = node.kind === "blob" ? node.size : null;
@@ -62679,7 +62691,7 @@ var Store = class {
62679
62691
  const meta = node.meta ? JSON.stringify(node.meta) : null;
62680
62692
  const owned = node.entries?.filter((e3) => e3.edge !== "back") ?? [];
62681
62693
  const isArray = node.array || node.kind === "mapping" && owned.length > 0 && owned.every((e3) => e3.key === null);
62682
- const value = node.kind === "scalar" ? JSON.stringify(node.value) : null;
62694
+ const value = node.kind === "scalar" ? encodeScalarValue(node.value) : null;
62683
62695
  const format = node.kind === "blob" ? node.format : formatFromMeta(node);
62684
62696
  const hash = node.kind === "blob" ? node.contentHash : null;
62685
62697
  const size = node.kind === "blob" ? node.size : null;
@@ -62720,7 +62732,7 @@ var Store = class {
62720
62732
  walkNodes(doc.root, annStorePath, (p2, node, parent, label, pos) => {
62721
62733
  const meta = node.meta ? JSON.stringify(node.meta) : null;
62722
62734
  const isArray = node.array || node.kind === "mapping" && (node.entries?.every((e3) => e3.key === null) ?? false);
62723
- const value = node.kind === "scalar" ? JSON.stringify(node.value) : null;
62735
+ const value = node.kind === "scalar" ? encodeScalarValue(node.value) : null;
62724
62736
  const format = p2 === annStorePath ? "x-yamlover-annotation" : node.kind === "blob" ? node.format : formatFromMeta(node);
62725
62737
  const hash = node.kind === "blob" ? node.contentHash : null;
62726
62738
  const size = node.kind === "blob" ? node.size : null;
@@ -62919,7 +62931,7 @@ function rowToNode(r2) {
62919
62931
  path: r2.path,
62920
62932
  type: r2.type,
62921
62933
  format: r2.format ?? null,
62922
- value: r2.value != null ? JSON.parse(r2.value) : null,
62934
+ value: r2.value != null ? decodeScalarValue(r2.value) : null,
62923
62935
  content_hash: r2.content_hash ?? null,
62924
62936
  size: r2.size ?? null,
62925
62937
  is_array: !!r2.is_array,
@@ -62981,7 +62993,11 @@ async function e() {
62981
62993
 
62982
62994
  // ../parser/ts/src/pointer.ts
62983
62995
  var LINK_RE = /^(?:[A-Za-z][A-Za-z0-9+.-]*:)?\/\//;
62984
- function parsePointer(raw) {
62996
+ function parsePointer(raw, yaml = false) {
62997
+ if (yaml) {
62998
+ const p2 = parsePointer(raw);
62999
+ return p2.base.scope === "current" ? { ...p2, base: { scope: "document" } } : p2;
63000
+ }
62985
63001
  if (looksColon(raw)) return parseColon(raw);
62986
63002
  const lm = LINK_RE.exec(raw);
62987
63003
  if (lm) {
@@ -63268,13 +63284,13 @@ function unescape(s2) {
63268
63284
  }
63269
63285
  return out;
63270
63286
  }
63271
- function makeAnchor(body, fail) {
63287
+ function makeAnchor(body, fail, yaml = false) {
63272
63288
  let ordinal = false;
63273
63289
  if (body.endsWith("[]") && !body.endsWith("\\[]")) {
63274
63290
  ordinal = true;
63275
63291
  body = body.slice(0, -2);
63276
63292
  }
63277
- const path11 = parsePointer(body);
63293
+ const path11 = parsePointer(body, yaml);
63278
63294
  if (!ordinal) {
63279
63295
  const last = path11.steps[path11.steps.length - 1];
63280
63296
  if (last === void 0) fail('an anchor path needs a key segment (or a trailing "[]" for ordinal membership)');
@@ -63287,8 +63303,117 @@ function escapeSegment(name) {
63287
63303
  return name.replace(/[\\/:[\]*&#~?!()<>=|]/g, (c3) => "\\" + c3);
63288
63304
  }
63289
63305
 
63306
+ // ../parser/ts/src/comments.ts
63307
+ function attachComments(doc, raws, src, uri) {
63308
+ if (raws.length === 0) return;
63309
+ raws.sort((a2, b) => a2.start - b.start);
63310
+ const entries = [];
63311
+ const parentOf2 = /* @__PURE__ */ new Map();
63312
+ const collect = (n2) => {
63313
+ for (const e3 of n2.entries ?? []) {
63314
+ if (e3.meta?.span) {
63315
+ entries.push(e3);
63316
+ parentOf2.set(e3, n2);
63317
+ }
63318
+ if (!isPointer(e3.value)) collect(e3.value);
63319
+ }
63320
+ };
63321
+ collect(doc.root);
63322
+ const firstStart = entries.length ? Math.min(...entries.map((e3) => e3.meta.span.start)) : src.length;
63323
+ const lineOf = lineIndexer(src);
63324
+ const blankBetween = (a2, b) => b > a2 && /\r?\n[ \t]*\r?\n/.test(src.slice(a2, b));
63325
+ const make = (r2, placement) => ({
63326
+ text: r2.text,
63327
+ span: { uri, start: r2.start, end: r2.end },
63328
+ placement,
63329
+ style: r2.style,
63330
+ ...precededByBlank(src, r2.start) ? { blankBefore: true } : {}
63331
+ });
63332
+ const push = (host, c3) => {
63333
+ host.comments = [...host.comments ?? [], c3];
63334
+ };
63335
+ const used = /* @__PURE__ */ new Set();
63336
+ const pre = raws.filter((r2) => r2.ownLine && r2.start < firstStart);
63337
+ if (pre.length > 0) {
63338
+ let m = 0;
63339
+ while (m + 1 < pre.length && !blankBetween(pre[m].end, pre[m + 1].start)) m++;
63340
+ const after = m + 1 < pre.length ? pre[m + 1].start : firstStart;
63341
+ if (blankBetween(pre[m].end, after)) {
63342
+ doc.head = pre.slice(0, m + 1).map((r2) => make(r2, "leading"));
63343
+ for (let i2 = 0; i2 <= m; i2++) used.add(pre[i2]);
63344
+ }
63345
+ }
63346
+ for (const r2 of raws) {
63347
+ if (used.has(r2)) continue;
63348
+ if (!r2.ownLine) {
63349
+ const rl = lineOf(r2.start);
63350
+ let best;
63351
+ for (const e3 of entries) {
63352
+ const s2 = e3.meta.span;
63353
+ if (s2.end > r2.start || lineOf(s2.end) !== rl) continue;
63354
+ const b = best ? best.meta.span : void 0;
63355
+ if (!b || s2.end > b.end || s2.end === b.end && s2.start > b.start) best = e3;
63356
+ }
63357
+ if (best) {
63358
+ push(best.meta, make(r2, "trailing"));
63359
+ used.add(r2);
63360
+ continue;
63361
+ }
63362
+ const next = nextEntryAfter(entries, r2.start);
63363
+ if (next && lineOf(next.meta.span.start) === rl) {
63364
+ push(next.meta, make(r2, "leading"));
63365
+ used.add(r2);
63366
+ continue;
63367
+ }
63368
+ const host = next ? parentOf2.get(next) : doc.root;
63369
+ host.meta = host.meta ?? {};
63370
+ push(host.meta, make(r2, "trailing"));
63371
+ used.add(r2);
63372
+ continue;
63373
+ }
63374
+ const target = nextEntryAfter(entries, r2.start);
63375
+ if (target) {
63376
+ push(target.meta, make(r2, "leading"));
63377
+ used.add(r2);
63378
+ continue;
63379
+ }
63380
+ doc.root.meta = doc.root.meta ?? {};
63381
+ push(doc.root.meta, make(r2, r2.ownLine ? "leading" : "trailing"));
63382
+ used.add(r2);
63383
+ }
63384
+ }
63385
+ function nextEntryAfter(entries, off) {
63386
+ let best;
63387
+ for (const e3 of entries) {
63388
+ const st = e3.meta.span.start;
63389
+ if (st > off && (!best || st < best.meta.span.start)) best = e3;
63390
+ }
63391
+ return best;
63392
+ }
63393
+ function lineIndexer(src) {
63394
+ const starts = [0];
63395
+ for (let i2 = 0; i2 < src.length; i2++) if (src[i2] === "\n") starts.push(i2 + 1);
63396
+ return (off) => {
63397
+ let lo = 0;
63398
+ let hi = starts.length - 1;
63399
+ while (lo < hi) {
63400
+ const mid = lo + hi + 1 >> 1;
63401
+ if (starts[mid] <= off) lo = mid;
63402
+ else hi = mid - 1;
63403
+ }
63404
+ return lo;
63405
+ };
63406
+ }
63407
+ function precededByBlank(src, off) {
63408
+ const ls = src.lastIndexOf("\n", off - 1);
63409
+ if (ls < 0) return false;
63410
+ const ps = src.lastIndexOf("\n", ls - 1);
63411
+ return /^[ \t\r]*$/.test(src.slice(ps + 1, ls));
63412
+ }
63413
+
63290
63414
  // ../parser/ts/src/yamlover.ts
63291
- function parseYamlover(src, uri = "<yamlover>") {
63415
+ function parseYamlover(src, uri = "<yamlover>", opts = {}) {
63416
+ const yaml = opts.yaml === true;
63292
63417
  const raw = [];
63293
63418
  const lineStarts = [];
63294
63419
  const sep2 = /\r\n|\r|\n/g;
@@ -63300,7 +63425,8 @@ function parseYamlover(src, uri = "<yamlover>") {
63300
63425
  }
63301
63426
  raw.push(src.slice(at));
63302
63427
  lineStarts.push(at);
63303
- const p2 = new Block(lex(raw), raw, uri, lineStarts);
63428
+ const lexed = lex(raw, lineStarts, uri);
63429
+ const p2 = new Block(lexed.lines, raw, uri, lineStarts, yaml);
63304
63430
  for (let k = 0; k < p2.lines.length; k++) {
63305
63431
  const l2 = p2.lines[k];
63306
63432
  if (l2.indent === 0 && (l2.text === "---" || l2.text.startsWith("--- ") || l2.text === "...")) {
@@ -63321,21 +63447,46 @@ function parseYamlover(src, uri = "<yamlover>") {
63321
63447
  }
63322
63448
  if (p2.i < p2.lines.length) p2.fail("unexpected content");
63323
63449
  if (rootSchema !== void 0) root.meta = { ...root.meta, schema: rootSchema };
63324
- return { root, source: { concrete: "yamlover", uri } };
63450
+ root.meta = { ...root.meta, span: { uri, start: 0, end: src.length } };
63451
+ const doc = { root, source: { concrete: yaml ? "yaml" : "yamlover", uri } };
63452
+ const comments = lexed.comments.filter((c3) => !p2.blockLines.has(c3.n)).map(({ n: _n, ...r2 }) => r2);
63453
+ attachComments(doc, comments, src, uri);
63454
+ return doc;
63325
63455
  }
63326
- function lex(raw) {
63456
+ function lex(raw, lineStarts, uri) {
63327
63457
  const out = [];
63458
+ const comments = [];
63459
+ let prevBlank = false;
63328
63460
  for (let n2 = 0; n2 < raw.length; n2++) {
63329
63461
  const line = raw[n2];
63330
63462
  let indent = 0;
63331
63463
  while (indent < line.length && line[indent] === " ") indent++;
63332
- const content = stripComment(line.slice(indent)).replace(/\s+$/, "");
63333
- if (content === "") continue;
63334
- out.push({ indent, text: content, n: n2 });
63464
+ const body = line.slice(indent);
63465
+ const at = commentStart(body);
63466
+ const content = (at >= 0 ? body.slice(0, at) : body).replace(/\s+$/, "");
63467
+ if (at >= 0) {
63468
+ const base = lineStarts[n2] ?? 0;
63469
+ comments.push({
63470
+ start: base + indent + at,
63471
+ end: base + line.replace(/\s+$/, "").length,
63472
+ // through the last non-blank char
63473
+ text: body.slice(at + 1).replace(/\s+$/, ""),
63474
+ // body after `#`, trailing ws trimmed
63475
+ ownLine: content === "",
63476
+ style: "line",
63477
+ n: n2
63478
+ });
63479
+ }
63480
+ if (content === "") {
63481
+ prevBlank = at < 0;
63482
+ continue;
63483
+ }
63484
+ out.push({ indent, text: content, n: n2, ...prevBlank ? { blankBefore: true } : {} });
63485
+ prevBlank = false;
63335
63486
  }
63336
- return out;
63487
+ return { lines: out, comments };
63337
63488
  }
63338
- function stripComment(s2) {
63489
+ function commentStart(s2) {
63339
63490
  let inS = false;
63340
63491
  let inD = false;
63341
63492
  for (let i2 = 0; i2 < s2.length; i2++) {
@@ -63347,10 +63498,10 @@ function stripComment(s2) {
63347
63498
  if (c3 === "'" && !inD) inS = !inS;
63348
63499
  else if (c3 === '"' && !inS) inD = !inD;
63349
63500
  else if (c3 === "#" && !inS && !inD && (i2 === 0 || s2[i2 - 1] === " " || s2[i2 - 1] === " ")) {
63350
- return s2.slice(0, i2);
63501
+ return i2;
63351
63502
  }
63352
63503
  }
63353
- return s2;
63504
+ return -1;
63354
63505
  }
63355
63506
  var Block = class {
63356
63507
  lines;
@@ -63360,12 +63511,17 @@ var Block = class {
63360
63511
  // source path/id, surfaced in parse-error messages
63361
63512
  lineStarts;
63362
63513
  // absolute offset of each raw line's first character
63514
+ blockLines = /* @__PURE__ */ new Set();
63515
+ // raw lines consumed by a block scalar (their `#` is content)
63516
+ yaml;
63517
+ // YAML concrete: bare `&`/`*` resolve at the document root
63363
63518
  i = 0;
63364
- constructor(lines, raw, uri = "<yamlover>", lineStarts = []) {
63519
+ constructor(lines, raw, uri = "<yamlover>", lineStarts = [], yaml = false) {
63365
63520
  this.lines = lines;
63366
63521
  this.raw = raw;
63367
63522
  this.uri = uri;
63368
63523
  this.lineStarts = lineStarts;
63524
+ this.yaml = yaml;
63369
63525
  }
63370
63526
  /** Absolute span of `len` chars starting at column `col` of raw line `lineN`. Valid
63371
63527
  * because every Line.text is a prefix-aligned slice of its raw line (lex strips only
@@ -63415,7 +63571,7 @@ var Block = class {
63415
63571
  body = text.slice(1, j);
63416
63572
  tokenLen = j;
63417
63573
  }
63418
- const anchor = makeAnchor(body, (m) => this.fail(m));
63574
+ const anchor = makeAnchor(body, (m) => this.fail(m), this.yaml);
63419
63575
  anchor.path.span = this.spanAt(lineN, col, tokenLen);
63420
63576
  const a2 = adv(text, tokenLen, col);
63421
63577
  return { anchor, rest: a2.rest, col: a2.col };
@@ -63489,6 +63645,9 @@ var Block = class {
63489
63645
  for (; ; ) {
63490
63646
  const l2 = this.peek();
63491
63647
  if (!l2 || l2.indent !== indent) break;
63648
+ const startLineN = l2.n;
63649
+ const startCol = l2.indent;
63650
+ const startBlank = l2.blankBefore === true;
63492
63651
  let value;
63493
63652
  let entry;
63494
63653
  if (l2.text.startsWith("&")) {
@@ -63570,6 +63729,10 @@ var Block = class {
63570
63729
  value = this.valueAfter(kv.rest, indent, l2.n, l2.indent + kv.restCol);
63571
63730
  entry = { key: unquoteKey(key), edge: back ? "back" : isPointer(value) ? "ref" : "contain", value };
63572
63731
  }
63732
+ const endLine = this.lines[this.i - 1];
63733
+ const start = (this.lineStarts[startLineN] ?? 0) + startCol;
63734
+ const end = endLine ? (this.lineStarts[endLine.n] ?? 0) + endLine.indent + endLine.text.length : start;
63735
+ entry.meta = { ...entry.meta, span: { uri: this.uri, start, end }, ...startBlank ? { blankBefore: true } : {} };
63573
63736
  entries.push(entry);
63574
63737
  }
63575
63738
  const owned = entries.filter((e3) => e3.edge !== "back");
@@ -63662,6 +63825,7 @@ var Block = class {
63662
63825
  if (ind >= r2.length) {
63663
63826
  lines.push("");
63664
63827
  lastN = n2;
63828
+ this.blockLines.add(n2);
63665
63829
  continue;
63666
63830
  }
63667
63831
  if (ind <= parentIndent) break;
@@ -63669,6 +63833,7 @@ var Block = class {
63669
63833
  if (blockIndent < 0) blockIndent = ind;
63670
63834
  lines.push(r2.slice(blockIndent));
63671
63835
  lastN = n2;
63836
+ this.blockLines.add(n2);
63672
63837
  }
63673
63838
  while (this.peek() && this.peek().n <= lastN) this.i++;
63674
63839
  let last = -1;
@@ -63685,10 +63850,10 @@ var Block = class {
63685
63850
  ({ rest: text, col } = adv(text, 0, col));
63686
63851
  const c3 = text[0];
63687
63852
  if (c3 === "{" || c3 === "[") {
63688
- return new Flow(text, this.uri, (this.lineStarts[lineN] ?? 0) + col).parse();
63853
+ return new Flow(text, this.uri, (this.lineStarts[lineN] ?? 0) + col, this.yaml).parse();
63689
63854
  }
63690
63855
  if (c3 === "*") {
63691
- const p2 = parsePointer(unquoteIfQuoted(text.slice(1)));
63856
+ const p2 = parsePointer(unquoteIfQuoted(text.slice(1)), this.yaml);
63692
63857
  p2.span = this.spanAt(lineN, col, text.length);
63693
63858
  return p2;
63694
63859
  }
@@ -63715,10 +63880,12 @@ var Flow = class {
63715
63880
  uri;
63716
63881
  base;
63717
63882
  // absolute offset of s[0] in the source (span tracking)
63718
- constructor(s2, uri = "<flow>", base = 0) {
63883
+ yaml;
63884
+ constructor(s2, uri = "<flow>", base = 0, yaml = false) {
63719
63885
  this.s = s2;
63720
63886
  this.uri = uri;
63721
63887
  this.base = base;
63888
+ this.yaml = yaml;
63722
63889
  }
63723
63890
  fail(msg) {
63724
63891
  throw new SyntaxError(`yamlover (flow): ${msg} at offset ${this.i}`);
@@ -63761,7 +63928,7 @@ var Flow = class {
63761
63928
  }
63762
63929
  txt = this.s.slice(st, this.i).trim();
63763
63930
  }
63764
- const p2 = parsePointer(txt);
63931
+ const p2 = parsePointer(txt, this.yaml);
63765
63932
  p2.span = { uri: this.uri, start: this.base + start, end: this.base + this.i };
63766
63933
  return p2;
63767
63934
  }
@@ -63779,7 +63946,7 @@ var Flow = class {
63779
63946
  }
63780
63947
  body = this.s.slice(st, this.i);
63781
63948
  }
63782
- const anchor = makeAnchor(body, (m) => this.fail(m));
63949
+ const anchor = makeAnchor(body, (m) => this.fail(m), this.yaml);
63783
63950
  anchor.path.span = { uri: this.uri, start: this.base + start, end: this.base + this.i };
63784
63951
  this.ws();
63785
63952
  const v = this.value();
@@ -64011,6 +64178,8 @@ function plainScalar(text) {
64011
64178
  if (t3 === "" || t3 === "~" || t3 === "null" || t3 === "Null" || t3 === "NULL") return { kind: "scalar", value: null, raw: text };
64012
64179
  if (t3 === "true" || t3 === "True" || t3 === "TRUE") return { kind: "scalar", value: true, raw: text };
64013
64180
  if (t3 === "false" || t3 === "False" || t3 === "FALSE") return { kind: "scalar", value: false, raw: text };
64181
+ if (/^[-+]?\.(?:inf|Inf|INF)$/.test(t3)) return { kind: "scalar", value: t3[0] === "-" ? -Infinity : Infinity, raw: text };
64182
+ if (/^\.(?:nan|NaN|NAN)$/.test(t3)) return { kind: "scalar", value: NaN, raw: text };
64014
64183
  if (/^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(t3)) return { kind: "scalar", value: Number(t3), raw: text };
64015
64184
  if (/^[-+]?0x[0-9a-fA-F]+$/.test(t3)) return { kind: "scalar", value: Number(t3), raw: text };
64016
64185
  return { kind: "scalar", value: t3, raw: text };
@@ -64040,12 +64209,17 @@ function parseJson5p(src, uri = "<json5p>") {
64040
64209
  p2.ws();
64041
64210
  if (p2.i < src.length) p2.fail("trailing characters");
64042
64211
  if (isPointer(root)) return p2.fail("a top-level pointer is not allowed");
64043
- return { root, source: { concrete: "json5p", uri } };
64212
+ root.meta = { ...root.meta, span: { uri, start: 0, end: src.length } };
64213
+ const doc = { root, source: { concrete: "json5p", uri } };
64214
+ attachComments(doc, p2.comments, src, uri);
64215
+ return doc;
64044
64216
  }
64045
64217
  var Parser = class {
64046
64218
  src;
64047
64219
  uri;
64048
64220
  i = 0;
64221
+ comments = [];
64222
+ // captured in ws(); placed onto the tree after the parse
64049
64223
  constructor(src, uri) {
64050
64224
  this.src = src;
64051
64225
  this.uri = uri;
@@ -64068,20 +64242,29 @@ var Parser = class {
64068
64242
  continue;
64069
64243
  }
64070
64244
  if (c3 === "/" && this.src[this.i + 1] === "/") {
64245
+ const start = this.i;
64071
64246
  this.i += 2;
64072
64247
  while (this.i < this.src.length && this.src[this.i] !== "\n" && this.src[this.i] !== "\r") this.i++;
64248
+ this.comments.push({ start, end: this.i, text: this.src.slice(start + 2, this.i).replace(/\s+$/, ""), ownLine: this.atLineStart(start), style: "line" });
64073
64249
  continue;
64074
64250
  }
64075
64251
  if (c3 === "/" && this.src[this.i + 1] === "*") {
64252
+ const start = this.i;
64076
64253
  this.i += 2;
64077
64254
  while (this.i < this.src.length && !(this.src[this.i] === "*" && this.src[this.i + 1] === "/")) this.i++;
64078
64255
  if (this.i >= this.src.length) this.fail("unterminated block comment");
64079
64256
  this.i += 2;
64257
+ this.comments.push({ start, end: this.i, text: this.src.slice(start + 2, this.i - 2).trim(), ownLine: this.atLineStart(start), style: "block" });
64080
64258
  continue;
64081
64259
  }
64082
64260
  return;
64083
64261
  }
64084
64262
  }
64263
+ /** True when only whitespace precedes `off` on its line (so a comment there is own-line). */
64264
+ atLineStart(off) {
64265
+ const ls = this.src.lastIndexOf("\n", off - 1);
64266
+ return /^[ \t\r]*$/.test(this.src.slice(ls + 1, off));
64267
+ }
64085
64268
  value() {
64086
64269
  const c3 = this.peek();
64087
64270
  if (c3 === void 0) this.fail("unexpected end of input");
@@ -64103,13 +64286,14 @@ var Parser = class {
64103
64286
  break;
64104
64287
  }
64105
64288
  if (c3 === void 0) this.fail("unterminated object");
64289
+ const entryStart = this.i;
64106
64290
  let back = false;
64107
64291
  if (this.peek() === "~") {
64108
64292
  back = true;
64109
64293
  this.i++;
64110
64294
  }
64111
64295
  if (back && this.peek() === "*") {
64112
- entries.push({ key: null, edge: "back", value: this.pointer() });
64296
+ entries.push(withSpan({ key: null, edge: "back", value: this.pointer() }, this.uri, entryStart, this.i));
64113
64297
  } else {
64114
64298
  const key = this.key();
64115
64299
  this.ws();
@@ -64117,7 +64301,7 @@ var Parser = class {
64117
64301
  this.i++;
64118
64302
  this.ws();
64119
64303
  const v = this.value();
64120
- entries.push(makeEntry(key, back, v));
64304
+ entries.push(withSpan(makeEntry(key, back, v), this.uri, entryStart, this.i));
64121
64305
  }
64122
64306
  this.ws();
64123
64307
  const n2 = this.peek();
@@ -64144,12 +64328,13 @@ var Parser = class {
64144
64328
  break;
64145
64329
  }
64146
64330
  if (c3 === void 0) this.fail("unterminated array");
64331
+ const entryStart = this.i;
64147
64332
  if (c3 === "~") {
64148
64333
  this.i++;
64149
64334
  if (this.peek() !== "*") this.fail('expected a pointer after "~" (keyless back member)');
64150
- entries.push({ key: null, edge: "back", value: this.pointer() });
64335
+ entries.push(withSpan({ key: null, edge: "back", value: this.pointer() }, this.uri, entryStart, this.i));
64151
64336
  } else {
64152
- entries.push(makeEntry(null, false, this.value()));
64337
+ entries.push(withSpan(makeEntry(null, false, this.value()), this.uri, entryStart, this.i));
64153
64338
  }
64154
64339
  this.ws();
64155
64340
  const n2 = this.peek();
@@ -64286,6 +64471,10 @@ function makeEntry(key, back, v) {
64286
64471
  const edge = back ? "back" : isPointer(v) ? "ref" : "contain";
64287
64472
  return { key, edge, value: v };
64288
64473
  }
64474
+ function withSpan(e3, uri, start, end) {
64475
+ e3.meta = { ...e3.meta, span: { uri, start, end } };
64476
+ return e3;
64477
+ }
64289
64478
  function scalar(value, raw) {
64290
64479
  return { kind: "scalar", value, raw };
64291
64480
  }
@@ -64734,14 +64923,15 @@ function textScalar(abs, format, ctx) {
64734
64923
  return { kind: "scalar", value: text, raw: text, meta: { schema: inlineFormat(format) } };
64735
64924
  }
64736
64925
  function parsedScalar(abs, ext, ctx) {
64737
- return parsedDoc(abs, ext === ".json" || ext === ".json5" || ext === ".json5p" ? "json5p" : "yamlover", ctx);
64926
+ const lang = ext === ".json" || ext === ".json5" || ext === ".json5p" ? "json5p" : ext === ".yaml" || ext === ".yml" ? "yaml" : "yamlover";
64927
+ return parsedDoc(abs, lang, ctx);
64738
64928
  }
64739
64929
  function parsedDoc(abs, lang, ctx) {
64740
64930
  const text = readTracked(ctx, abs).toString("utf8");
64741
64931
  try {
64742
- const doc = lang === "json5p" ? parseJson5p(text, abs) : parseYamlover(text, abs);
64932
+ const doc = lang === "json5p" ? parseJson5p(text, abs) : parseYamlover(text, abs, { yaml: lang === "yaml" });
64743
64933
  const root = doc.root;
64744
- root.meta = { ...root.meta, documentRoot: true };
64934
+ root.meta = { ...root.meta, documentRoot: true, ...doc.head?.length ? { head: doc.head } : {} };
64745
64935
  return root;
64746
64936
  } catch {
64747
64937
  return { kind: "scalar", value: text, raw: text };
@@ -64826,12 +65016,13 @@ function applyBody(dir, node, ctx) {
64826
65016
  if (!fs2.existsSync(file)) return node;
64827
65017
  const bodyDoc = parseYamlover(readTracked(ctx, file).toString("utf8"), file);
64828
65018
  const body = bodyDoc.root;
64829
- if (body.kind !== "mapping" && body.kind !== "scalar" || !body.entries) return node;
64830
- const meta = { ...node.meta, ...body.meta, documentRoot: true };
64831
- if (body.kind === "mapping" && (body.array || body.entries.length > 0 && body.entries.every((e3) => e3.key === null))) {
65019
+ if (body.kind !== "mapping" && body.kind !== "scalar") return node;
65020
+ const bodyEntries = body.entries ?? [];
65021
+ const meta = { ...node.meta, ...body.meta, documentRoot: true, ...bodyDoc.head?.length ? { head: bodyDoc.head } : {} };
65022
+ if (body.kind === "mapping" && (body.array || bodyEntries.length > 0 && bodyEntries.every((e3) => e3.key === null))) {
64832
65023
  const byKey = new Map(node.entries.map((e3) => [e3.key, e3]));
64833
65024
  const ordered = [];
64834
- for (const e3 of body.entries) {
65025
+ for (const e3 of bodyEntries) {
64835
65026
  const targetKey = isPointer(e3.value) ? pointerLeafKey(e3.value) : null;
64836
65027
  const hit = targetKey != null ? byKey.get(targetKey) : null;
64837
65028
  if (hit) {
@@ -64844,7 +65035,7 @@ function applyBody(dir, node, ctx) {
64844
65035
  }
64845
65036
  const merged = new Map(node.entries.map((e3) => [e3.key, e3]));
64846
65037
  const order = node.entries.map((e3) => e3.key);
64847
- for (const e3 of body.entries) {
65038
+ for (const e3 of bodyEntries) {
64848
65039
  const existing = merged.get(e3.key);
64849
65040
  if (!existing) {
64850
65041
  order.push(e3.key);
@@ -64940,9 +65131,9 @@ var EXT_FORMAT = {
64940
65131
  var TEXT_FORMATS = /* @__PURE__ */ new Set(["text/markdown", "text/asciidoc", "text/x-plantuml", "text/csv", "text/tab-separated-values"]);
64941
65132
  var DOC_FORMATS = {
64942
65133
  "yamlover": "yamlover",
64943
- "yaml": "yamlover",
65134
+ "yaml": "yaml",
64944
65135
  "yamlover/meta": "yamlover",
64945
- "yaml/meta": "yamlover",
65136
+ "yaml/meta": "yaml",
64946
65137
  "json": "json5p",
64947
65138
  "json5": "json5p",
64948
65139
  "json5p": "json5p",
@@ -64954,6 +65145,11 @@ var DOC_FORMATS = {
64954
65145
  // ../engine/ts/src/rewrite.ts
64955
65146
  import * as path3 from "node:path";
64956
65147
 
65148
+ // ../parser/ts/src/serialize-common.ts
65149
+ function anchorBody(a2) {
65150
+ return renderPointer(a2.path) + (a2.ordinal ? "[]" : "");
65151
+ }
65152
+
64957
65153
  // ../parser/ts/src/serialize-yamlover.ts
64958
65154
  function pointerToken(raw) {
64959
65155
  if (raw !== raw.trim()) return `*'${raw.replace(/'/g, "''")}'`;
@@ -65967,6 +66163,36 @@ function removeAnnotation(text, within, predicate) {
65967
66163
  return text;
65968
66164
  }
65969
66165
 
66166
+ // src/concrete.ts
66167
+ var JSON_FAMILY = /* @__PURE__ */ new Set(["json", "json5", "json5p"]);
66168
+ var YAML_FAMILY = /* @__PURE__ */ new Set(["yaml", "yamlover"]);
66169
+ function isDirConcrete(c3) {
66170
+ return c3 === "dir" || c3 === "dir/yamlover";
66171
+ }
66172
+ function baseLanguage(c3) {
66173
+ if (!c3) return null;
66174
+ const bare = c3.startsWith("file/") ? c3.slice("file/".length) : c3;
66175
+ return JSON_FAMILY.has(bare) || YAML_FAMILY.has(bare) ? bare : null;
66176
+ }
66177
+ function interiorOf(c3) {
66178
+ return baseLanguage(c3) ?? "yaml";
66179
+ }
66180
+ var EXT_FILE_CONCRETE = {
66181
+ ".yamlover": "file/yamlover",
66182
+ ".yaml": "file/yaml",
66183
+ ".yml": "file/yaml",
66184
+ ".json": "file/json",
66185
+ ".json5": "file/json5",
66186
+ ".json5p": "file/json5p"
66187
+ };
66188
+ function dataFileConcrete(filePath) {
66189
+ const slash = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
66190
+ const base = filePath.slice(slash + 1);
66191
+ const dot = base.lastIndexOf(".");
66192
+ const ext = dot > 0 ? base.slice(dot).toLowerCase() : "";
66193
+ return EXT_FILE_CONCRETE[ext] ?? null;
66194
+ }
66195
+
65970
66196
  // src/server/extract/types.ts
65971
66197
  var byFormat = (...fmts) => (format) => format !== null && fmts.includes(format);
65972
66198
 
@@ -66226,6 +66452,9 @@ var TaskRegistry = class {
66226
66452
  var LINK_KEY = "$yamloverLink";
66227
66453
  var BINARY_KEY = "$yamloverBinary";
66228
66454
  var MIXED_KEY = "$yamloverMixed";
66455
+ var REF_KEY = "$yamloverRef";
66456
+ var NUM_KEY = "$yamloverNum";
66457
+ var wireScalar = (v) => typeof v === "number" && !Number.isFinite(v) ? { [NUM_KEY]: String(v) } : v;
66229
66458
  function createHandlers(dataRoot, opts = {}) {
66230
66459
  const rootName = path10.basename(path10.resolve(dataRoot)) || "/";
66231
66460
  const dbPath = path10.join(dataRoot, ".yamlover", "index.db");
@@ -66692,8 +66921,8 @@ function createHandlers(dataRoot, opts = {}) {
66692
66921
  }
66693
66922
  const row = s2.node(p2);
66694
66923
  if (!row) return notFound(res, url);
66695
- const viewDepth = depth ?? 1;
66696
66924
  const kind = displayKind(s2, p2, row);
66925
+ const viewDepth = depth === void 0 ? defaultDepth(s2, dataRoot, segs, row, kind) : depth;
66697
66926
  if (url.pathname === "/api/json") {
66698
66927
  const wantBytes = row.type === "blob" && url.searchParams.get("binary") === "1";
66699
66928
  sendJson(res, 200, {
@@ -66702,13 +66931,14 @@ function createHandlers(dataRoot, opts = {}) {
66702
66931
  format: row.format ?? null,
66703
66932
  ...facetsOf(s2, p2, row),
66704
66933
  // valueType / hasKeyed / hasOrdinal — the renderer dispatch facets (TYPES.md §9)
66705
- concrete: concreteOf(dataRoot, segs, row),
66706
- // dir | yamlover | null (stat-derived; engine tracks no per-node concrete yet)
66934
+ concrete: concreteOf(s2, dataRoot, segs, row),
66935
+ // the full per-node concrete taxonomy (stat + document language)
66707
66936
  documentPath: documentPath(s2, segs),
66708
66937
  // nearest enclosing document root (for `/…` links)
66709
66938
  title: titleOf(s2, p2),
66710
66939
  description: null,
66711
66940
  value: wantBytes ? binaryContent(dataRoot, segs, row) : projectValue(dataRoot, s2, segs, viewDepth, true),
66941
+ comments: cachedDoc && !wantBytes ? collectComments(cachedDoc, segs, viewDepth) : {},
66712
66942
  relations: buildRelations(dataRoot, s2, segs)
66713
66943
  });
66714
66944
  } else if (url.pathname === "/api/schema") {
@@ -66734,30 +66964,23 @@ function createHandlers(dataRoot, opts = {}) {
66734
66964
  function tocType(s2, p2, row) {
66735
66965
  return typeName(s2, p2, row);
66736
66966
  }
66737
- var JSON_EXT = { ".json": "json", ".json5": "json5", ".json5p": "json5p" };
66738
- function concreteOf(dataRoot, segs, row) {
66739
- const last = segs[segs.length - 1];
66740
- if (typeof last === "string") {
66741
- const json = JSON_EXT[path10.extname(last).toLowerCase()];
66742
- if (json) {
66743
- const abs2 = path10.resolve(dataRoot, ...segs.map(String));
66744
- try {
66745
- if (fs10.statSync(abs2).isFile()) return json;
66746
- } catch {
66747
- }
66967
+ function concreteOf(s2, dataRoot, segs, row) {
66968
+ if (segs.every((g) => typeof g === "string")) {
66969
+ const abs = path10.resolve(dataRoot, ...segs.map(String));
66970
+ let st;
66971
+ try {
66972
+ st = fs10.statSync(abs);
66973
+ } catch {
66748
66974
  }
66975
+ if (st?.isDirectory()) return fs10.existsSync(path10.join(abs, ".yamlover")) ? "dir/yamlover" : "dir";
66976
+ if (st?.isFile()) return dataFileConcrete(abs) ?? (row.type === "blob" ? "file/binary" : "file/yaml");
66749
66977
  }
66750
- if (row.type !== "mapping") return null;
66751
- if (segs.some((g) => typeof g === "number")) return null;
66752
- const abs = path10.resolve(dataRoot, ...segs.map(String));
66753
- let st;
66978
+ const docAbs = path10.resolve(dataRoot, ...documentRootSegs(s2, segs).map(String));
66754
66979
  try {
66755
- st = fs10.statSync(abs);
66980
+ if (fs10.statSync(docAbs).isFile()) return interiorOf(dataFileConcrete(docAbs) ?? "file/yaml");
66756
66981
  } catch {
66757
- return null;
66758
66982
  }
66759
- if (!st.isDirectory()) return null;
66760
- return fs10.existsSync(path10.join(abs, ".yamlover")) ? "yamlover" : "dir";
66983
+ return "yamlover";
66761
66984
  }
66762
66985
  var relKey = (label, other) => `${label ?? ""}\0${other}`;
66763
66986
  var isHidden = (s2, to2) => !!s2.node(to2)?.meta?.hidden;
@@ -66795,12 +67018,17 @@ function projectValue(dataRoot, s2, segs, depth, top) {
66795
67018
  if (k === "binary" && !top) return linkMarker(dataRoot, s2, segs);
66796
67019
  if (k === "binary") return { size: row.size, format: row.format };
66797
67020
  const kids = downstreamEntries(s2, p2);
66798
- const project = (c3) => c3.kind === "contain" ? projectValue(dataRoot, s2, [...segs, c3.label ?? c3.pos ?? 0], depth - 1, false) : linkMarker(dataRoot, s2, storePathToSegs(c3.to));
67021
+ const currentDoc = documentRootSegs(s2, segs);
67022
+ const project = (c3) => {
67023
+ if (c3.kind === "contain") return projectValue(dataRoot, s2, [...segs, c3.label ?? c3.pos ?? 0], depth - 1, false);
67024
+ const targetSegs = storePathToSegs(c3.to);
67025
+ return depth === Infinity ? refMarker(refPointerText(s2, targetSegs, currentDoc), segsToStr(targetSegs)) : linkMarker(dataRoot, s2, targetSegs);
67026
+ };
66799
67027
  if (k === "array") return kids.map(project);
66800
67028
  if (k === "omni" || k === "mix") {
66801
67029
  const entries = kids.map((c3) => ({ key: c3.label, value: project(c3) }));
66802
67030
  const marker = { kind: k, entries };
66803
- if (k === "omni") marker.value = row.value;
67031
+ if (k === "omni") marker.value = wireScalar(row.value);
66804
67032
  return { [MIXED_KEY]: marker };
66805
67033
  }
66806
67034
  if (k === "object") {
@@ -66808,7 +67036,77 @@ function projectValue(dataRoot, s2, segs, depth, top) {
66808
67036
  for (const c3 of kids) out[c3.label ?? String(c3.pos)] = project(c3);
66809
67037
  return out;
66810
67038
  }
66811
- return row.value;
67039
+ return wireScalar(row.value);
67040
+ }
67041
+ function irNodeAt(doc, segs) {
67042
+ let node = doc.root;
67043
+ for (const seg of segs) {
67044
+ const entries = node.entries ?? [];
67045
+ let val;
67046
+ if (typeof seg === "number") {
67047
+ const e3 = entries[seg];
67048
+ if (!e3 || e3.key !== null || e3.edge !== "contain") return void 0;
67049
+ val = e3.value;
67050
+ } else {
67051
+ val = entries.find((en) => en.key === seg && en.edge === "contain")?.value;
67052
+ }
67053
+ if (!val || isPointer(val)) return void 0;
67054
+ node = val;
67055
+ }
67056
+ return node;
67057
+ }
67058
+ function tagOf(n2) {
67059
+ if (n2.meta?.set) return "!!set";
67060
+ const owned = (n2.entries ?? []).filter((e3) => e3.edge !== "back");
67061
+ if (n2.kind === "mapping" && owned.some((e3) => e3.key != null) && owned.some((e3) => e3.key === null)) return "!!mix";
67062
+ if (n2.kind === "scalar" && owned.length > 0) return "!!var";
67063
+ return void 0;
67064
+ }
67065
+ function nodeDeco(bucket, node) {
67066
+ const anchors = (node.meta?.anchors ?? []).map(anchorBody);
67067
+ if (anchors.length > 0) bucket.anchors = anchors;
67068
+ const tag = tagOf(node);
67069
+ if (tag) bucket.tag = tag;
67070
+ const vt = (node.meta?.comments ?? []).filter((c3) => c3.placement === "trailing").map((c3) => c3.text);
67071
+ if (vt.length > 0) bucket.valueTrailing = vt;
67072
+ }
67073
+ function collectComments(doc, segs, depth) {
67074
+ const out = {};
67075
+ const root = irNodeAt(doc, segs);
67076
+ if (!root) return out;
67077
+ {
67078
+ const self2 = {};
67079
+ nodeDeco(self2, root);
67080
+ if (self2.anchors || self2.tag || self2.valueTrailing) out[""] = self2;
67081
+ }
67082
+ const head = (root.meta?.head ?? []).map((c3) => c3.text);
67083
+ if (head.length > 0) out.$head = head;
67084
+ const tail = (root.meta?.comments ?? []).filter((c3) => c3.placement === "leading").map((c3) => c3.text);
67085
+ if (tail.length > 0) out.$tail = tail;
67086
+ const placed = (cs, p2) => (cs ?? []).filter((c3) => c3.placement === p2).map((c3) => c3.text);
67087
+ const walk = (node, rel, d, top) => {
67088
+ if (!top && d <= 0) return;
67089
+ let i2 = 0;
67090
+ for (const e3 of node.entries ?? []) {
67091
+ if (e3.edge === "back") continue;
67092
+ if (e3.edge === "contain" && !isPointer(e3.value) && e3.value.meta?.hidden) continue;
67093
+ const cont = e3.key != null ? `/${e3.key}` : `[${i2}]`;
67094
+ i2++;
67095
+ const bucket = {};
67096
+ const lead = placed(e3.meta?.comments, "leading");
67097
+ const trail = placed(e3.meta?.comments, "trailing");
67098
+ if (lead.length > 0) bucket.leading = lead;
67099
+ if (trail.length > 0) bucket.trailing = trail;
67100
+ const leadComment = e3.meta?.comments?.find((c3) => c3.placement === "leading");
67101
+ if (e3.meta?.blankBefore || leadComment?.blankBefore) bucket.blankBefore = true;
67102
+ if (isPointer(e3.value)) bucket.pointer = renderPointer(e3.value);
67103
+ else nodeDeco(bucket, e3.value);
67104
+ if (Object.keys(bucket).length > 0) out[rel + cont] = bucket;
67105
+ if (e3.edge === "contain" && !isPointer(e3.value)) walk(e3.value, rel + cont, d - 1, false);
67106
+ }
67107
+ };
67108
+ walk(root, "", depth, true);
67109
+ return out;
66812
67110
  }
66813
67111
  function projectSchema(dataRoot, s2, segs, depth, top) {
66814
67112
  const p2 = storePath(segs);
@@ -66843,15 +67141,14 @@ function linkMarker(dataRoot, s2, segs) {
66843
67141
  const k = displayKind(s2, p2, row);
66844
67142
  const info = { kind: k, type: tocType(s2, p2, row), ...facetsOf(s2, p2, row), path: segsToStr(segs) };
66845
67143
  if (row.format) info.format = row.format;
66846
- const concrete = concreteOf(dataRoot, segs, row);
66847
- if (concrete) info.concrete = concrete;
67144
+ info.concrete = concreteOf(s2, dataRoot, segs, row);
66848
67145
  const title = titleOf(s2, p2);
66849
67146
  if (title) info.title = title;
66850
67147
  if (k === "binary") info.size = row.size;
66851
- else if (k === "scalar") info.value = row.value;
67148
+ else if (k === "scalar") info.value = wireScalar(row.value);
66852
67149
  else if (k === "omni" || k === "mix") {
66853
67150
  info.count = ownedEntries(s2, p2).length;
66854
- if (k === "omni") info.value = row.value;
67151
+ if (k === "omni") info.value = wireScalar(row.value);
66855
67152
  } else info.count = s2.children(p2).filter((c3) => !isHidden(s2, c3.to)).length;
66856
67153
  if (row.format === TAG_FORMAT) {
66857
67154
  const c3 = s2.node(p2 + ":color")?.value;
@@ -66864,6 +67161,14 @@ function scopedPath(s2, src, currentDoc) {
66864
67161
  if (segsEqual(documentRootSegs(s2, src), currentDoc)) return segsToStr(src.slice(currentDoc.length));
66865
67162
  return "::" + segsToStr(src).slice(1);
66866
67163
  }
67164
+ function refPointerText(s2, src, currentDoc) {
67165
+ const seg = (x2) => typeof x2 === "number" ? `[${x2}]` : `: ${x2}`;
67166
+ if (segsEqual(documentRootSegs(s2, src), currentDoc)) {
67167
+ const tail = src.slice(currentDoc.length);
67168
+ return "*" + (tail.length > 0 ? tail.map(seg).join("") : ":");
67169
+ }
67170
+ return "*:" + src.map(seg).join("");
67171
+ }
66867
67172
  function buildRelations(dataRoot, s2, segs) {
66868
67173
  const p2 = storePath(segs);
66869
67174
  const out = {};
@@ -66872,7 +67177,7 @@ function buildRelations(dataRoot, s2, segs) {
66872
67177
  for (let i2 = 2; k in out; i2++) k = `${label} (${i2})`;
66873
67178
  out[k] = marker;
66874
67179
  };
66875
- if (segs.length > 0) put("..", linkMarker(dataRoot, s2, segs.slice(0, -1)));
67180
+ if (segs.length > 0) put("..", refMarker("..", segsToStr(segs.slice(0, -1))));
66876
67181
  const currentDoc = documentRootSegs(s2, segs);
66877
67182
  const { out: outEdges, in: inEdges } = s2.relationships(p2);
66878
67183
  const upstream = /* @__PURE__ */ new Map();
@@ -66883,7 +67188,8 @@ function buildRelations(dataRoot, s2, segs) {
66883
67188
  for (const e3 of outEdges) if (e3.kind === "back") addUp(e3.to, e3.label);
66884
67189
  for (const src of upstream.values()) {
66885
67190
  const segs2 = storePathToSegs(src);
66886
- put(scopedPath(s2, segs2, currentDoc), linkMarker(dataRoot, s2, segs2));
67191
+ const key = scopedPath(s2, segs2, currentDoc);
67192
+ put(key, s2.node(src)?.format === TAG_FORMAT ? linkMarker(dataRoot, s2, segs2) : refMarker(key, segsToStr(segs2)));
66887
67193
  }
66888
67194
  return out;
66889
67195
  }
@@ -66901,7 +67207,7 @@ function buildTree(dataRoot, s2, segs, label, depth) {
66901
67207
  type: tocType(s2, p2, row),
66902
67208
  format: row.format ?? null,
66903
67209
  ...facetsOf(s2, p2, row),
66904
- concrete: concreteOf(dataRoot, segs, row),
67210
+ concrete: concreteOf(s2, dataRoot, segs, row),
66905
67211
  hasChildren: visibleHasChildren(s2, p2),
66906
67212
  children: []
66907
67213
  };
@@ -67533,9 +67839,17 @@ function formatFromExt(file) {
67533
67839
  return EXT_CT[path10.extname(file).toLowerCase()] ?? null;
67534
67840
  }
67535
67841
  function parseDepth(raw) {
67536
- if (raw == null || raw === "") return null;
67842
+ if (raw == null || raw === "") return void 0;
67843
+ if (raw === ".inf" || raw === "inf") return Infinity;
67537
67844
  const n2 = Number(raw);
67538
- return Number.isInteger(n2) && n2 >= 0 ? n2 : null;
67845
+ return Number.isInteger(n2) && n2 >= 0 ? n2 : void 0;
67846
+ }
67847
+ function defaultDepth(s2, dataRoot, segs, row, kind) {
67848
+ if (kind === "binary") return 1;
67849
+ return isDirConcrete(concreteOf(s2, dataRoot, segs, row)) ? 1 : Infinity;
67850
+ }
67851
+ function refMarker(text, path11) {
67852
+ return { [REF_KEY]: { text, path: path11 } };
67539
67853
  }
67540
67854
  function clampThumbDim(raw, def) {
67541
67855
  const n2 = raw == null ? NaN : Math.round(Number(raw));