@ai-matrx/content-ir 0.11.7 → 0.13.0

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/index.cjs CHANGED
@@ -1266,18 +1266,18 @@ var KindStreamParser = class {
1266
1266
  completeTypedObject(path, objectValue, at) {
1267
1267
  const pathKey = this.pathKey(path);
1268
1268
  if (this.rawObjectPaths.has(pathKey)) return;
1269
- const declaredKind = readObjectKind(objectValue);
1269
+ const declaredKind2 = readObjectKind(objectValue);
1270
1270
  const committedKind = this.objectKinds.get(pathKey);
1271
1271
  if (committedKind && this.pendingSchemaPaths.get(committedKind)?.has(pathKey)) {
1272
1272
  this.closedPendingPaths.add(pathKey);
1273
1273
  return;
1274
1274
  }
1275
- if (!declaredKind && committedKind && this.speculativeKinds.has(pathKey)) {
1275
+ if (!declaredKind2 && committedKind && this.speculativeKinds.has(pathKey)) {
1276
1276
  this.speculativeKinds.delete(pathKey);
1277
1277
  this.finalizeSpeculatedObject(path, objectValue, committedKind, at);
1278
1278
  return;
1279
1279
  }
1280
- if (path.length === 0 && !declaredKind && !committedKind && this.rootSurfaceKind) {
1280
+ if (path.length === 0 && !declaredKind2 && !committedKind && this.rootSurfaceKind) {
1281
1281
  const surfaceKind = this.rootSurfaceKind;
1282
1282
  this.rootSurfaceKind = null;
1283
1283
  this.objectKinds.set(pathKey, surfaceKind);
@@ -1293,7 +1293,7 @@ var KindStreamParser = class {
1293
1293
  this.finalizeSpeculatedObject(path, objectValue, surfaceKind, at);
1294
1294
  return;
1295
1295
  }
1296
- if (!declaredKind) {
1296
+ if (!declaredKind2) {
1297
1297
  this.emitRawObject(
1298
1298
  path,
1299
1299
  objectValue,
@@ -3209,8 +3209,8 @@ function refToObjectField(resolved, path, ctx) {
3209
3209
  function isAnyValueSchema(node) {
3210
3210
  return node.type === void 0 && node.enum === void 0 && node.const === void 0 && node.properties === void 0 && node.items === void 0 && node.additionalProperties === void 0 && node.anyOf === void 0 && node.oneOf === void 0 && node.allOf === void 0 && node.$ref === void 0;
3211
3211
  }
3212
- function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
3213
- if (ctx.blockSchemas.some((draft) => draft.slug === declaredKind)) return;
3212
+ function registerDeclaredKindDraft(declaredKind2, objectNode, path, ctx) {
3213
+ if (ctx.blockSchemas.some((draft) => draft.slug === declaredKind2)) return;
3214
3214
  if (!isRecord4(objectNode.properties)) return;
3215
3215
  const memberRequired = new Set(
3216
3216
  Array.isArray(objectNode.required) ? objectNode.required.filter((k) => typeof k === "string") : []
@@ -3228,8 +3228,8 @@ function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
3228
3228
  );
3229
3229
  }
3230
3230
  ctx.blockSchemas.push({
3231
- slug: declaredKind,
3232
- label: formatBlockLabel(declaredKind),
3231
+ slug: declaredKind2,
3232
+ label: formatBlockLabel(declaredKind2),
3233
3233
  fields
3234
3234
  });
3235
3235
  }
@@ -4973,6 +4973,1656 @@ function asKindInstance(item, kind) {
4973
4973
  return { [KIND_KEY]: resolved, ...item };
4974
4974
  }
4975
4975
 
4976
+ // source/offsets.ts
4977
+ function isHigh(code) {
4978
+ return code >= 55296 && code <= 56319;
4979
+ }
4980
+ function isLow(code) {
4981
+ return code >= 56320 && code <= 57343;
4982
+ }
4983
+ function splitsSurrogatePair(text, offset) {
4984
+ if (offset <= 0 || offset >= text.length) return false;
4985
+ return isHigh(text.charCodeAt(offset - 1)) && isLow(text.charCodeAt(offset));
4986
+ }
4987
+ function buildCodePointIndex(text) {
4988
+ const pairStarts = [];
4989
+ for (let i = 0; i < text.length - 1; i++) {
4990
+ if (isHigh(text.charCodeAt(i)) && isLow(text.charCodeAt(i + 1))) {
4991
+ pairStarts.push(i);
4992
+ i++;
4993
+ }
4994
+ }
4995
+ const countBelow = (limit) => {
4996
+ let lo = 0;
4997
+ let hi = pairStarts.length;
4998
+ while (lo < hi) {
4999
+ const mid = lo + hi >>> 1;
5000
+ if (pairStarts[mid] < limit) lo = mid + 1;
5001
+ else hi = mid;
5002
+ }
5003
+ return lo;
5004
+ };
5005
+ const toCodePoint = (utf16) => {
5006
+ return utf16 - countBelow(utf16 - 1);
5007
+ };
5008
+ const toUtf16 = (codePoint) => {
5009
+ let lo = 0;
5010
+ let hi = pairStarts.length;
5011
+ while (lo < hi) {
5012
+ const mid = lo + hi >>> 1;
5013
+ const start = pairStarts[mid];
5014
+ if (start - mid < codePoint) lo = mid + 1;
5015
+ else hi = mid;
5016
+ }
5017
+ return codePoint + lo;
5018
+ };
5019
+ return {
5020
+ toCodePoint,
5021
+ toUtf16,
5022
+ lengthCp: text.length - pairStarts.length
5023
+ };
5024
+ }
5025
+ function toCodePointOffset(text, utf16) {
5026
+ return buildCodePointIndex(text).toCodePoint(utf16);
5027
+ }
5028
+ function toUtf16Offset(text, codePoint) {
5029
+ return buildCodePointIndex(text).toUtf16(codePoint);
5030
+ }
5031
+
5032
+ // source/constants.ts
5033
+ var XML_TAG_BLOCK_NAMES = [
5034
+ "thinking",
5035
+ "think",
5036
+ "reasoning",
5037
+ "info",
5038
+ "task",
5039
+ "database",
5040
+ "private",
5041
+ "plan",
5042
+ "event",
5043
+ "tool",
5044
+ "questionnaire",
5045
+ "flashcards",
5046
+ "cooking_recipe",
5047
+ "timeline",
5048
+ "progress_tracker",
5049
+ "troubleshooting",
5050
+ "resources",
5051
+ "research"
5052
+ ];
5053
+ var THINKING_FAMILY = ["thinking", "think", "reasoning"];
5054
+ var ATTRIBUTE_XML_NAMES = [
5055
+ "decision",
5056
+ "artifact",
5057
+ "editor_error",
5058
+ "editor_code_snippet",
5059
+ "audiocite"
5060
+ ];
5061
+ var KNOWN_XML_TAG_NAMES = /* @__PURE__ */ new Set([
5062
+ ...XML_TAG_BLOCK_NAMES,
5063
+ ...ATTRIBUTE_XML_NAMES
5064
+ ]);
5065
+ var ALLOWED_RAW_HTML_TAGS = /* @__PURE__ */ new Set([
5066
+ "img",
5067
+ "a",
5068
+ "br",
5069
+ "hr",
5070
+ "span",
5071
+ "p",
5072
+ "strong",
5073
+ "b",
5074
+ "em",
5075
+ "i",
5076
+ "u",
5077
+ "s",
5078
+ "del",
5079
+ "ins",
5080
+ "sup",
5081
+ "sub",
5082
+ "mark",
5083
+ "kbd",
5084
+ "abbr",
5085
+ "small",
5086
+ "code",
5087
+ "pre",
5088
+ "ul",
5089
+ "ol",
5090
+ "li",
5091
+ "blockquote",
5092
+ "h1",
5093
+ "h2",
5094
+ "h3",
5095
+ "h4",
5096
+ "h5",
5097
+ "h6",
5098
+ "table",
5099
+ "thead",
5100
+ "tbody",
5101
+ "tfoot",
5102
+ "tr",
5103
+ "th",
5104
+ "td",
5105
+ "caption",
5106
+ "colgroup",
5107
+ "col",
5108
+ "figure",
5109
+ "figcaption"
5110
+ ]);
5111
+ var HTML_BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
5112
+ "p",
5113
+ "hr",
5114
+ "ul",
5115
+ "ol",
5116
+ "li",
5117
+ "blockquote",
5118
+ "h1",
5119
+ "h2",
5120
+ "h3",
5121
+ "h4",
5122
+ "h5",
5123
+ "h6",
5124
+ "table",
5125
+ "thead",
5126
+ "tbody",
5127
+ "tfoot",
5128
+ "tr",
5129
+ "th",
5130
+ "td",
5131
+ "caption",
5132
+ "colgroup",
5133
+ "col",
5134
+ "figure",
5135
+ "figcaption"
5136
+ ]);
5137
+ var SPECIAL_CODE_LANGUAGES = /* @__PURE__ */ new Set([
5138
+ "transcript",
5139
+ "tasks",
5140
+ "structured_info",
5141
+ "questionnaire",
5142
+ "flashcards",
5143
+ "cooking_recipe",
5144
+ "mermaid",
5145
+ "svg",
5146
+ "chart",
5147
+ "map",
5148
+ "stats",
5149
+ "diff",
5150
+ "html",
5151
+ "react",
5152
+ "matrx"
5153
+ ]);
5154
+ var CODE_LANGUAGE_ALIASES = {
5155
+ mmd: "mermaid",
5156
+ jsx: "react",
5157
+ tsx: "react"
5158
+ };
5159
+ var TYPED_JSON_ROOT_KEYS = {
5160
+ quiz_title: "quiz",
5161
+ presentation: "presentation",
5162
+ decision_tree: "decision_tree",
5163
+ comparison: "comparison_table",
5164
+ diagram: "diagram",
5165
+ math_problem: "math_problem",
5166
+ item_presentation: "item_presentation",
5167
+ name: "schema_proposal"
5168
+ };
5169
+ var TREE_GLYPHS = /[├└│┌┐┘┬┴┤┼─]/;
5170
+ var PINNED_ANCHOR_RE = /^<!--@a:([A-Za-z0-9_-]+)-->$/;
5171
+ var STRICT_VARIABLE_RE = /^\{\{([a-zA-Z_][a-zA-Z0-9_.]*)\}\}$/;
5172
+ var CITE_RE = /^<matrxcite\s+n="(\d+)"\s*\/>/;
5173
+ function normalizeFenceLanguage(language) {
5174
+ const lower = language.toLowerCase();
5175
+ return CODE_LANGUAGE_ALIASES[lower] ?? lower;
5176
+ }
5177
+
5178
+ // source/fence-nesting.ts
5179
+ var NESTING_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
5180
+ "markdown",
5181
+ "md",
5182
+ "mdx"
5183
+ ]);
5184
+ function fenceNestsInnerFences(language) {
5185
+ return !!language && NESTING_FENCE_LANGUAGES.has(language.toLowerCase());
5186
+ }
5187
+ function classifyInnerFenceLine(trimmed, openTicks, nests, nestedDepth) {
5188
+ let ticks = 0;
5189
+ while (ticks < trimmed.length && trimmed[ticks] === "`") ticks++;
5190
+ if (ticks < 3) return "content";
5191
+ const info = trimmed.slice(ticks).trim();
5192
+ if (info === "") {
5193
+ if (ticks < openTicks) return "content";
5194
+ if (nests && nestedDepth > 0) return "close-nested";
5195
+ return "close-outer";
5196
+ }
5197
+ if (nests && ticks >= openTicks && !info.includes("`")) return "open-nested";
5198
+ return "content";
5199
+ }
5200
+
5201
+ // source/math.ts
5202
+ var TEX_SIGNAL = /\\[A-Za-z]+|[\\^_{}=<>+]/;
5203
+ var LONE_VARIABLE = /^[A-Za-z](?:'|[0-9])?$/;
5204
+ function isSingleDollarMath(content, after) {
5205
+ if (!content || content.length > 400) return false;
5206
+ if (/^\s/.test(content) || /\s$/.test(content)) return false;
5207
+ if (after !== void 0 && /[0-9]/.test(after)) return false;
5208
+ if (LONE_VARIABLE.test(content)) return true;
5209
+ if (/^[0-9]/.test(content)) return /\\[A-Za-z]+|[\\^_{}]/.test(content);
5210
+ return TEX_SIGNAL.test(content);
5211
+ }
5212
+ function singleDollarMathEnd(text, open, limit = text.length) {
5213
+ const bound = Math.min(limit, open + 403);
5214
+ let close = -1;
5215
+ for (let k = open + 1; k < bound; k += 1) {
5216
+ const c = text[k];
5217
+ if (c === "\n") break;
5218
+ if (c === "\\") {
5219
+ k += 1;
5220
+ continue;
5221
+ }
5222
+ if (c === "$") {
5223
+ close = k;
5224
+ break;
5225
+ }
5226
+ }
5227
+ if (close === -1 || text[close + 1] === "$") return -1;
5228
+ const content = text.slice(open + 1, close);
5229
+ return isSingleDollarMath(content, text[close + 1]) ? close + 1 : -1;
5230
+ }
5231
+
5232
+ // source/math-pairs.ts
5233
+ var MAX_MATH_SPAN = 600;
5234
+ var STRUCTURAL_MARKDOWN = /\]\(|https?:\/\/|\*\*|(?:^|\n)[ \t]{0,3}#{1,6}[ \t]|(?:^|\n)[ \t]*[-*+][ \t]+|(?:^|\n)[ \t]*\d+[.)][ \t]/;
5235
+ var LATEX_COMMAND = /\\[a-zA-Z]/;
5236
+ var PROSE_WORD = /[A-Za-z]{3,}/g;
5237
+ var PROSE_WORD_LIMIT = 6;
5238
+ function looksLikeDisplayMath(inner) {
5239
+ const s = inner.trim();
5240
+ if (!s) return false;
5241
+ if (STRUCTURAL_MARKDOWN.test(s)) return false;
5242
+ if (s.length > MAX_MATH_SPAN) return false;
5243
+ if (LATEX_COMMAND.test(s)) {
5244
+ return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT * 3;
5245
+ }
5246
+ if (/\n[ \t]*\n/.test(s)) return false;
5247
+ return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT;
5248
+ }
5249
+ function codeRanges(text) {
5250
+ const ranges = [];
5251
+ for (const re of [/```[\s\S]*?(?:```|$)/g, /~~~[\s\S]*?(?:~~~|$)/g, /`[^`\n]*`/g]) {
5252
+ let m;
5253
+ while ((m = re.exec(text)) !== null) {
5254
+ ranges.push([m.index, m.index + m[0].length]);
5255
+ if (m[0].length === 0) re.lastIndex++;
5256
+ }
5257
+ }
5258
+ return ranges.sort((a, b) => a[0] - b[0]);
5259
+ }
5260
+ function pairDisplayMath(text) {
5261
+ const pairs = /* @__PURE__ */ new Map();
5262
+ if (!text.includes("$$")) return pairs;
5263
+ const ranges = codeRanges(text);
5264
+ const tokens = [];
5265
+ let r = 0;
5266
+ let maxEnd = -1;
5267
+ for (let i = text.indexOf("$$"); i !== -1 && i < text.length - 1; i = text.indexOf("$$", i)) {
5268
+ while (r < ranges.length && ranges[r][0] <= i) {
5269
+ maxEnd = Math.max(maxEnd, ranges[r][1]);
5270
+ r++;
5271
+ }
5272
+ if (maxEnd <= i) tokens.push(i);
5273
+ i += 2;
5274
+ }
5275
+ let j = 0;
5276
+ while (j < tokens.length) {
5277
+ const open = tokens[j];
5278
+ const close = tokens[j + 1];
5279
+ if (close === void 0) break;
5280
+ if (looksLikeDisplayMath(text.slice(open + 2, close))) {
5281
+ pairs.set(open, close);
5282
+ j += 2;
5283
+ continue;
5284
+ }
5285
+ j += 1;
5286
+ }
5287
+ return pairs;
5288
+ }
5289
+
5290
+ // source/xml-tag.ts
5291
+ var XML_NAME_START = /[A-Za-z_]/;
5292
+ var XML_NAME_CHARACTER = /[\w.:-]/;
5293
+ var WHITESPACE = /\s/;
5294
+ function readXmlTag(content, start, find = (needle, from) => content.indexOf(needle, from)) {
5295
+ let cursor = start + 1;
5296
+ const isClosing = content[cursor] === "/";
5297
+ if (isClosing) cursor++;
5298
+ if (!XML_NAME_START.test(content[cursor] ?? "")) return null;
5299
+ const nameStart = cursor;
5300
+ while (XML_NAME_CHARACTER.test(content[cursor] ?? "")) cursor++;
5301
+ const tagName = content.slice(nameStart, cursor);
5302
+ const attributes = [];
5303
+ if (isClosing) {
5304
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5305
+ if (content[cursor] !== ">") return null;
5306
+ return {
5307
+ tagName,
5308
+ raw: content.slice(start, cursor + 1),
5309
+ isClosing,
5310
+ isSelfClosing: false,
5311
+ attributes
5312
+ };
5313
+ }
5314
+ while (cursor < content.length) {
5315
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5316
+ if (content[cursor] === ">")
5317
+ return {
5318
+ tagName,
5319
+ raw: content.slice(start, cursor + 1),
5320
+ isClosing,
5321
+ isSelfClosing: false,
5322
+ attributes
5323
+ };
5324
+ if (content[cursor] === "/") {
5325
+ cursor++;
5326
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5327
+ if (content[cursor] !== ">") return null;
5328
+ return {
5329
+ tagName,
5330
+ raw: content.slice(start, cursor + 1),
5331
+ isClosing,
5332
+ isSelfClosing: true,
5333
+ attributes
5334
+ };
5335
+ }
5336
+ if (!XML_NAME_START.test(content[cursor] ?? "")) return null;
5337
+ const attributeStart = cursor;
5338
+ while (XML_NAME_CHARACTER.test(content[cursor] ?? "")) cursor++;
5339
+ const name = content.slice(attributeStart, cursor);
5340
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5341
+ if (content[cursor] !== "=") return null;
5342
+ cursor++;
5343
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5344
+ const quote = content[cursor];
5345
+ if (quote !== '"' && quote !== "'") return null;
5346
+ const valueStart = ++cursor;
5347
+ const valueEnd = find(quote, valueStart);
5348
+ if (valueEnd === -1) return null;
5349
+ cursor = valueEnd;
5350
+ attributes.push({ name, value: content.slice(valueStart, cursor) });
5351
+ cursor++;
5352
+ }
5353
+ return null;
5354
+ }
5355
+ function isEscapedBacktick(line, offset) {
5356
+ let slashes = 0;
5357
+ for (let i = offset - 1; line[i] === "\\"; i--) slashes++;
5358
+ return slashes % 2 === 1;
5359
+ }
5360
+ var XmlContainerTracker = class {
5361
+ constructor(rootTag) {
5362
+ this.rootTag = rootTag;
5363
+ }
5364
+ rootTag;
5365
+ depth = 0;
5366
+ inComment = false;
5367
+ inCdata = false;
5368
+ inlineTicks = 0;
5369
+ fenceMarker = null;
5370
+ consumeLine(line, startOffset = 0) {
5371
+ const fence = /^[ \t]*(`{3,}|~{3,})(.*)$/.exec(line);
5372
+ if (!this.inComment && !this.inCdata && this.inlineTicks === 0 && fence) {
5373
+ const marker = fence[1];
5374
+ const char = marker[0];
5375
+ const suffix = fence[2];
5376
+ if (marker.length >= 3) {
5377
+ if (!this.fenceMarker) {
5378
+ this.fenceMarker = { char, ticks: marker.length };
5379
+ return null;
5380
+ }
5381
+ if (char === this.fenceMarker.char && marker.length >= this.fenceMarker.ticks && suffix.trim() === "") {
5382
+ this.fenceMarker = null;
5383
+ }
5384
+ return null;
5385
+ }
5386
+ }
5387
+ if (this.fenceMarker) return null;
5388
+ for (let i = startOffset; i < line.length; i++) {
5389
+ if (this.inlineTicks > 0) {
5390
+ if (line[i] === "`") {
5391
+ let end = i;
5392
+ while (line[end] === "`") end++;
5393
+ if (end - i === this.inlineTicks) this.inlineTicks = 0;
5394
+ i = end - 1;
5395
+ }
5396
+ continue;
5397
+ }
5398
+ if (this.inComment) {
5399
+ const end = line.indexOf("-->", i);
5400
+ if (end === -1) return null;
5401
+ this.inComment = false;
5402
+ i = end + 2;
5403
+ continue;
5404
+ }
5405
+ if (this.inCdata) {
5406
+ const end = line.indexOf("]]>", i);
5407
+ if (end === -1) return null;
5408
+ this.inCdata = false;
5409
+ i = end + 2;
5410
+ continue;
5411
+ }
5412
+ if (line.startsWith("<!--", i)) {
5413
+ this.inComment = true;
5414
+ i += 3;
5415
+ continue;
5416
+ }
5417
+ if (line.startsWith("<![CDATA[", i)) {
5418
+ this.inCdata = true;
5419
+ i += 8;
5420
+ continue;
5421
+ }
5422
+ if (line[i] === "`" && !isEscapedBacktick(line, i)) {
5423
+ let end = i;
5424
+ while (line[end] === "`") end++;
5425
+ this.inlineTicks = end - i;
5426
+ i = end - 1;
5427
+ continue;
5428
+ }
5429
+ if (line[i] !== "<") continue;
5430
+ const tag = readXmlTag(line, i);
5431
+ if (!tag) continue;
5432
+ const tagEnd = i + tag.raw.length;
5433
+ if (tag.tagName === this.rootTag) {
5434
+ if (tag.isClosing) this.depth--;
5435
+ else if (!tag.isSelfClosing) this.depth++;
5436
+ if (this.depth === 0) return tagEnd;
5437
+ }
5438
+ i = tagEnd - 1;
5439
+ }
5440
+ return null;
5441
+ }
5442
+ };
5443
+
5444
+ // source/tokenize.ts
5445
+ var NOT_WHITESPACE = /\S/;
5446
+ function countStructuralBraces(source) {
5447
+ let opens = 0;
5448
+ let closes = 0;
5449
+ let inString = false;
5450
+ let escaped = false;
5451
+ for (let i = 0; i < source.length; i++) {
5452
+ const char = source[i];
5453
+ if (inString) {
5454
+ if (escaped) escaped = false;
5455
+ else if (char === "\\") escaped = true;
5456
+ else if (char === '"') inString = false;
5457
+ continue;
5458
+ }
5459
+ if (char === '"') inString = true;
5460
+ else if (char === "{") opens++;
5461
+ else if (char === "}") closes++;
5462
+ }
5463
+ return { opens, closes };
5464
+ }
5465
+ function firstJsonKey(content) {
5466
+ const match = /^\{\s*"([^"]+)"/.exec(content.trimStart());
5467
+ return match ? match[1] : null;
5468
+ }
5469
+ function jsonMeta(content) {
5470
+ const meta = {};
5471
+ const key = firstJsonKey(content);
5472
+ if (key) meta.firstKey = key;
5473
+ try {
5474
+ const parsed = JSON.parse(content.trim());
5475
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
5476
+ const kind = parsed.__kind;
5477
+ if (typeof kind === "string" && kind.trim()) meta.kind = kind;
5478
+ }
5479
+ } catch {
5480
+ const head = /^\{\s*"__kind"\s*:\s*"([^"]*)"/.exec(content.trimStart());
5481
+ if (head) meta.kind = head[1];
5482
+ }
5483
+ if (typeof meta.kind === "string" && meta.kind.startsWith("directive_v")) {
5484
+ meta.directive = true;
5485
+ }
5486
+ if (key === "matrx_version") meta.directive = true;
5487
+ if (key && TYPED_JSON_ROOT_KEYS[key]) meta.typed = TYPED_JSON_ROOT_KEYS[key];
5488
+ return meta;
5489
+ }
5490
+ function isRecognizedJsonHead(content) {
5491
+ const key = firstJsonKey(content);
5492
+ if (!key) return false;
5493
+ return key === "__kind" || key === "matrx_version" || key in TYPED_JSON_ROOT_KEYS;
5494
+ }
5495
+ function matchingJsonObjectEnd(source, start, limit) {
5496
+ if (source[start] !== "{") return null;
5497
+ const stack = ["{"];
5498
+ let inString = false;
5499
+ let escaped = false;
5500
+ for (let index = start + 1; index < limit; index++) {
5501
+ const char = source[index];
5502
+ if (inString) {
5503
+ if (escaped) escaped = false;
5504
+ else if (char === "\\") escaped = true;
5505
+ else if (char === '"') inString = false;
5506
+ continue;
5507
+ }
5508
+ if (char === '"') {
5509
+ inString = true;
5510
+ continue;
5511
+ }
5512
+ if (char === "{" || char === "[") {
5513
+ stack.push(char);
5514
+ continue;
5515
+ }
5516
+ if (char !== "}" && char !== "]") continue;
5517
+ const opening = stack.pop();
5518
+ if (char === "}" && opening !== "{" || char === "]" && opening !== "[") return null;
5519
+ if (stack.length === 0) return index + 1;
5520
+ }
5521
+ return null;
5522
+ }
5523
+ function declaredKind(candidate) {
5524
+ try {
5525
+ const parsed = JSON.parse(candidate);
5526
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
5527
+ const kind = parsed.__kind;
5528
+ return typeof kind === "string" && kind.trim() ? kind : null;
5529
+ } catch {
5530
+ return null;
5531
+ }
5532
+ }
5533
+ function isUnclosedGenericXmlOpening(source) {
5534
+ const text = source.trimStart();
5535
+ const prefix = /^<([A-Za-z_][\w.:-]*)(?=\s|\/|$)/.exec(text);
5536
+ if (!prefix || KNOWN_XML_TAG_NAMES.has(prefix[1]) || ALLOWED_RAW_HTML_TAGS.has(prefix[1].toLowerCase()))
5537
+ return false;
5538
+ let quote = null;
5539
+ for (let i = prefix[0].length; i < text.length; i++) {
5540
+ if (quote) {
5541
+ if (text[i] === quote) quote = null;
5542
+ } else if (text[i] === "'" || text[i] === '"') quote = text[i];
5543
+ else if (text[i] === ">") return false;
5544
+ }
5545
+ return true;
5546
+ }
5547
+ function jsonStringState(line, from, upTo, state) {
5548
+ let { inString, escaped } = state;
5549
+ for (let idx = from; idx < upTo; idx++) {
5550
+ const ch = line[idx];
5551
+ if (escaped) {
5552
+ escaped = false;
5553
+ continue;
5554
+ }
5555
+ if (ch === "\\" && inString) {
5556
+ escaped = true;
5557
+ continue;
5558
+ }
5559
+ if (ch === '"') inString = !inString;
5560
+ }
5561
+ return { inString, escaped };
5562
+ }
5563
+ function backtickRunLength(str2, pos) {
5564
+ let n = 0;
5565
+ while (pos + n < str2.length && str2[pos + n] === "`") n++;
5566
+ return n;
5567
+ }
5568
+ function isSplitterTreeLine(line) {
5569
+ return TREE_GLYPHS.test(line) || /^[\s│|]*[├└+|][\s─\-]+/.test(line);
5570
+ }
5571
+ var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
5572
+ var Tokenizer = class {
5573
+ constructor(text) {
5574
+ this.text = text;
5575
+ this.n = text.length;
5576
+ this.mathPairs = pairDisplayMath(text);
5577
+ let start = 0;
5578
+ for (let i = 0; i < text.length; i++) {
5579
+ if (text.charCodeAt(i) === 10) {
5580
+ this.lineStarts.push(start);
5581
+ this.contentEnds.push(i > start && text.charCodeAt(i - 1) === 13 ? i - 1 : i);
5582
+ this.lineEnds.push(i + 1);
5583
+ start = i + 1;
5584
+ }
5585
+ }
5586
+ if (start < text.length || text.length === 0) {
5587
+ this.lineStarts.push(start);
5588
+ this.contentEnds.push(text.length);
5589
+ this.lineEnds.push(text.length);
5590
+ }
5591
+ }
5592
+ text;
5593
+ n;
5594
+ lineStarts = [];
5595
+ contentEnds = [];
5596
+ lineEnds = [];
5597
+ blocks = [];
5598
+ blockCache = /* @__PURE__ */ new Map();
5599
+ /** Lazily built: for line i, first line j >= i where brace net from i drops to <= 0. */
5600
+ braceStop = null;
5601
+ braceNet = null;
5602
+ /** Every occurrence offset of each needle searched so far (overlapping, like indexOf). */
5603
+ occurrences = /* @__PURE__ */ new Map();
5604
+ /** `$$` opener → closer for the pairs the core renders as math. */
5605
+ mathPairs;
5606
+ finder = (needle, from) => this.next(needle, from);
5607
+ /**
5608
+ * `text.indexOf(needle, from)` in O(log k): the first query for a needle
5609
+ * indexes all of its occurrences once, so repeated searches for a closer
5610
+ * that never comes stay linear over the whole text.
5611
+ */
5612
+ next(needle, from) {
5613
+ let list = this.occurrences.get(needle);
5614
+ if (!list) {
5615
+ list = [];
5616
+ for (let at = this.text.indexOf(needle); at !== -1; at = this.text.indexOf(needle, at + 1)) {
5617
+ list.push(at);
5618
+ }
5619
+ this.occurrences.set(needle, list);
5620
+ }
5621
+ let lo = 0;
5622
+ let hi = list.length;
5623
+ while (lo < hi) {
5624
+ const mid = lo + hi >>> 1;
5625
+ if (list[mid] < from) lo = mid + 1;
5626
+ else hi = mid;
5627
+ }
5628
+ return lo < list.length ? list[lo] : -1;
5629
+ }
5630
+ get lineCount() {
5631
+ return this.lineStarts.length;
5632
+ }
5633
+ lineOf(pos) {
5634
+ let lo = 0;
5635
+ let hi = this.lineStarts.length - 1;
5636
+ while (lo < hi) {
5637
+ const mid = lo + hi + 1 >>> 1;
5638
+ if (this.lineStarts[mid] <= pos) lo = mid;
5639
+ else hi = mid - 1;
5640
+ }
5641
+ return lo;
5642
+ }
5643
+ isBlank(from, to) {
5644
+ return !NOT_WHITESPACE.test(this.text.slice(from, to));
5645
+ }
5646
+ lineIsBlank(li) {
5647
+ return this.isBlank(this.lineStarts[li], this.contentEnds[li]);
5648
+ }
5649
+ lineText(li) {
5650
+ return this.text.slice(this.lineStarts[li], this.contentEnds[li]);
5651
+ }
5652
+ run() {
5653
+ let pos = 0;
5654
+ while (pos < this.n) {
5655
+ const li = this.lineOf(pos);
5656
+ const ce = this.contentEnds[li];
5657
+ if (this.isBlank(pos, ce)) {
5658
+ pos = this.gap(pos, li);
5659
+ continue;
5660
+ }
5661
+ const island = this.detectBlock(pos, li, true);
5662
+ if (island) {
5663
+ this.push({ kind: "island", start: island.start, end: island.end, island, inlines: [] });
5664
+ pos = island.end;
5665
+ continue;
5666
+ }
5667
+ pos = this.paragraph(pos, li);
5668
+ }
5669
+ return this.blocks;
5670
+ }
5671
+ push(block) {
5672
+ if (block.end <= block.start) return;
5673
+ if (block.kind === "prose" && this.isBlank(block.start, block.end)) {
5674
+ block = { kind: "gap", start: block.start, end: block.end, island: null, inlines: [] };
5675
+ }
5676
+ const last = this.blocks[this.blocks.length - 1];
5677
+ if (block.kind === "gap" && last && last.kind === "gap" && last.end === block.start) {
5678
+ last.end = block.end;
5679
+ return;
5680
+ }
5681
+ this.blocks.push(block);
5682
+ }
5683
+ gap(pos, li) {
5684
+ let end = this.lineEnds[li];
5685
+ let k = li + 1;
5686
+ while (k < this.lineCount && this.lineIsBlank(k)) {
5687
+ end = this.lineEnds[k];
5688
+ k++;
5689
+ }
5690
+ this.push({ kind: "gap", start: pos, end, island: null, inlines: [] });
5691
+ return end;
5692
+ }
5693
+ // ── block detection ────────────────────────────────────────────────────
5694
+ detectBlock(p, li, atParaStart) {
5695
+ const cacheKey = atParaStart ? -1 - p : p;
5696
+ if (this.blockCache.has(cacheKey)) return this.blockCache.get(cacheKey) ?? null;
5697
+ const found = this.detectBlockUncached(p, li, atParaStart);
5698
+ this.blockCache.set(cacheKey, found);
5699
+ return found;
5700
+ }
5701
+ detectBlockUncached(p, li, atParaStart) {
5702
+ const ce = this.contentEnds[li];
5703
+ const seg = this.text.slice(p, ce);
5704
+ const t = seg.trimStart();
5705
+ const indent = seg.length - t.length;
5706
+ const tp = p + indent;
5707
+ if (p === 0) {
5708
+ const fm = this.frontMatter(li, t);
5709
+ if (fm) return fm;
5710
+ }
5711
+ if (t.startsWith("```")) return this.backtickFence(p, li, t);
5712
+ if (indent <= 3 && t.startsWith("~~~")) {
5713
+ const tilde = this.tildeFence(p, li, t);
5714
+ if (tilde) return tilde;
5715
+ }
5716
+ if (t.startsWith("$$")) {
5717
+ const math = this.mathBlock(p, tp);
5718
+ if (math) return math;
5719
+ }
5720
+ if (t.startsWith("<")) {
5721
+ const attr = this.attributeXml(p, tp, t);
5722
+ if (attr) return attr;
5723
+ const region = this.xmlRegion(p, tp, t);
5724
+ if (region) return region;
5725
+ const container = this.genericXml(p, li, seg, indent);
5726
+ if (container) return container;
5727
+ if (t.startsWith("<!--")) {
5728
+ const comment = this.blockComment(p, tp, li);
5729
+ if (comment) return comment;
5730
+ }
5731
+ const html = this.htmlBlock(p, li, t, tp, atParaStart);
5732
+ if (html) return html;
5733
+ }
5734
+ if (t.startsWith("{")) {
5735
+ const json = this.bareJson(p, li, tp);
5736
+ if (json) return json;
5737
+ }
5738
+ if (TREE_GLYPHS.test(t)) {
5739
+ const tree = this.tree(p, li);
5740
+ if (tree) return tree;
5741
+ }
5742
+ return null;
5743
+ }
5744
+ island(type, start, end, complete, meta = {}) {
5745
+ return { type, start, end, complete, meta };
5746
+ }
5747
+ frontMatter(li, t) {
5748
+ if (this.lineText(li) !== "---" || t !== "---") return null;
5749
+ let sawContent = false;
5750
+ for (let k = li + 1; k < this.lineCount; k++) {
5751
+ const line = this.lineText(k);
5752
+ if (line === "---" || line === "...") {
5753
+ return sawContent ? this.island("front_matter", 0, this.contentEnds[k], true) : null;
5754
+ }
5755
+ if (!NOT_WHITESPACE.test(line)) continue;
5756
+ if (!/^(?:[A-Za-z0-9_"'-][^:]*:(?:\s|$)|\s+\S|-\s)/.test(line)) return null;
5757
+ sawContent = true;
5758
+ }
5759
+ return null;
5760
+ }
5761
+ /**
5762
+ * Backtick fence — the renderer splitter's close rules: JSON-string aware for
5763
+ * ```json, and THE nested-fence rule (source/fence-nesting.ts) for markdown
5764
+ * fences, with the splitter's strict-CommonMark retry when a nested fence is
5765
+ * still open at the end of the text.
5766
+ */
5767
+ backtickFence(p, li, t) {
5768
+ const openTicks = backtickRunLength(t, 0);
5769
+ const info = t.slice(openTicks).trim();
5770
+ const lang = info.split(/\s/)[0] ?? "";
5771
+ const isJson = lang === "json";
5772
+ const normalized = normalizeFenceLanguage(lang);
5773
+ const meta = { fence: "`", ticks: openTicks, lang };
5774
+ if (normalized && SPECIAL_CODE_LANGUAGES.has(normalized)) meta.special = normalized;
5775
+ const nesting = fenceNestsInnerFences(lang);
5776
+ let close = this.backtickFenceClose(li, openTicks, isJson, nesting);
5777
+ if (close === "retry-strict") close = this.backtickFenceClose(li, openTicks, isJson, false);
5778
+ if (typeof close === "number") {
5779
+ return this.fenceIsland(p, this.contentEnds[close], true, meta, li, close, isJson);
5780
+ }
5781
+ return this.fenceIsland(p, this.n, false, meta, li, this.lineCount, isJson);
5782
+ }
5783
+ /** The closing line of a backtick fence opened on line `li`, or null when it never closes. */
5784
+ backtickFenceClose(li, openTicks, isJson, nesting) {
5785
+ let state = { inString: false, escaped: false };
5786
+ let nestedDepth = 0;
5787
+ let sawNested = false;
5788
+ for (let k = li + 1; k < this.lineCount; k++) {
5789
+ const line = this.lineText(k);
5790
+ const trimmedLine = line.trim();
5791
+ if (trimmedLine.startsWith("```")) {
5792
+ const at2 = line.indexOf("```");
5793
+ if (isJson) {
5794
+ const probe = jsonStringState(line, 0, at2, state);
5795
+ if (probe.inString) {
5796
+ state = jsonStringState(line, at2, line.length, probe);
5797
+ continue;
5798
+ }
5799
+ }
5800
+ const kind = classifyInnerFenceLine(trimmedLine, openTicks, nesting, nestedDepth);
5801
+ if (kind === "close-outer") return k;
5802
+ if (kind === "open-nested") {
5803
+ nestedDepth++;
5804
+ sawNested = true;
5805
+ }
5806
+ if (kind === "close-nested") nestedDepth--;
5807
+ if (isJson) state = jsonStringState(line, 0, line.length, state);
5808
+ continue;
5809
+ }
5810
+ const at = line.indexOf("```");
5811
+ if (at !== -1) {
5812
+ if (isJson) {
5813
+ const probe = jsonStringState(line, 0, at, state);
5814
+ if (probe.inString) {
5815
+ state = jsonStringState(line, at, line.length, probe);
5816
+ continue;
5817
+ }
5818
+ }
5819
+ const closeTicks = backtickRunLength(line, at);
5820
+ const after = line.slice(at + closeTicks).trim();
5821
+ if (closeTicks >= openTicks && after === "" && nestedDepth === 0) return k;
5822
+ if (isJson) state = jsonStringState(line, 0, line.length, state);
5823
+ continue;
5824
+ }
5825
+ if (isJson) state = jsonStringState(line, 0, line.length, state);
5826
+ }
5827
+ return sawNested && nestedDepth > 0 ? "retry-strict" : null;
5828
+ }
5829
+ fenceIsland(p, end, complete, meta, openLine, closeLine, isJson) {
5830
+ if (isJson && openLine + 1 < this.lineCount) {
5831
+ const bodyEnd = closeLine < this.lineCount ? this.lineStarts[closeLine] : this.n;
5832
+ const body = this.text.slice(this.lineStarts[openLine + 1], Math.max(bodyEnd, this.lineStarts[openLine + 1]));
5833
+ if (body.trimStart().startsWith("{")) Object.assign(meta, jsonMeta(body));
5834
+ }
5835
+ return this.island("fence", p, end, complete, meta);
5836
+ }
5837
+ tildeFence(p, li, t) {
5838
+ const open = /^(~{3,})(.*)$/.exec(t);
5839
+ if (!open) return null;
5840
+ const ticks = open[1].length;
5841
+ const lang = open[2].trim().split(/\s/)[0] ?? "";
5842
+ const meta = { fence: "~", ticks, lang };
5843
+ const normalized = normalizeFenceLanguage(lang);
5844
+ if (normalized && SPECIAL_CODE_LANGUAGES.has(normalized)) meta.special = normalized;
5845
+ const close = new RegExp(`^ {0,3}~{${ticks},}[ \\t]*$`);
5846
+ for (let k = li + 1; k < this.lineCount; k++) {
5847
+ if (close.test(this.lineText(k))) {
5848
+ return this.island("fence", p, this.contentEnds[k], true, meta);
5849
+ }
5850
+ }
5851
+ return this.island("fence", p, this.n, false, meta);
5852
+ }
5853
+ /**
5854
+ * A line-leading `$$` that OPENS a math pair (source/math-pairs.ts — the
5855
+ * core's rule). A closer, an unpaired `$$`, or a prose pair is never a block:
5856
+ * a lone `$$` renders as literal text and locks nothing.
5857
+ */
5858
+ mathBlock(p, tp) {
5859
+ const close = this.mathPairs.get(tp);
5860
+ if (close === void 0) return null;
5861
+ const end = close + 2;
5862
+ const li = this.lineOf(tp);
5863
+ const ce = this.contentEnds[li];
5864
+ if (end <= ce && !this.isBlank(end, ce)) return null;
5865
+ const endLine = this.lineOf(close);
5866
+ const endCe = this.contentEnds[endLine];
5867
+ if (endLine !== li && !this.isBlank(end, endCe)) return null;
5868
+ return this.island("math_block", p, end, true, { delimiter: "$$" });
5869
+ }
5870
+ /** `<artifact …>`, `<decision …>`, … at the start of a line. */
5871
+ attributeXml(p, tp, t) {
5872
+ for (const name of ATTRIBUTE_XML_NAMES) {
5873
+ const prefix = `<${name}`;
5874
+ if (!t.startsWith(prefix)) continue;
5875
+ const next = t[prefix.length];
5876
+ if (next !== " " && next !== ">" && next !== "/" && next !== " ") continue;
5877
+ return this.attributeElement(name, p, tp, "xml_attr");
5878
+ }
5879
+ return null;
5880
+ }
5881
+ /** Opening tag at `tp` through its `</name>` (or to EOF when still streaming). */
5882
+ attributeElement(name, p, tp, type) {
5883
+ const li = this.lineOf(tp);
5884
+ const ce = this.contentEnds[li];
5885
+ const tag = readXmlTag(this.text, tp, this.finder);
5886
+ let openEnd;
5887
+ if (tag && !tag.isClosing) {
5888
+ if (tag.isSelfClosing) {
5889
+ return this.island(type, p, tp + tag.raw.length, true, { tag: name, selfClosing: true });
5890
+ }
5891
+ openEnd = tp + tag.raw.length;
5892
+ } else {
5893
+ const gt = this.next(">", tp);
5894
+ if (gt === -1) return this.island(type, p, this.n, false, { tag: name });
5895
+ if (gt >= ce) return null;
5896
+ openEnd = gt + 1;
5897
+ }
5898
+ const closer = `</${name}>`;
5899
+ const close = this.next(closer, openEnd);
5900
+ if (close === -1) return this.island(type, p, this.n, false, { tag: name });
5901
+ return this.island(type, p, close + closer.length, true, { tag: name });
5902
+ }
5903
+ /** `<thinking>`, `<flashcards>`, … — exact attribute-less openers. */
5904
+ xmlRegion(p, tp, t) {
5905
+ for (const name of XML_TAG_BLOCK_NAMES) {
5906
+ const opener = `<${name}>`;
5907
+ if (!t.startsWith(opener)) continue;
5908
+ const closer = `</${name}>`;
5909
+ const close = this.next(closer, tp + opener.length);
5910
+ if (close === -1) return this.island("xml_region", p, this.n, false, { tag: name });
5911
+ return this.island("xml_region", p, close + closer.length, true, { tag: name });
5912
+ }
5913
+ return null;
5914
+ }
5915
+ /** Line-leading unknown XML element — balanced by the renderer's own tracker. */
5916
+ genericXml(p, li, seg, indent) {
5917
+ const first = seg.slice(indent);
5918
+ const opening = readXmlTag(first, 0);
5919
+ if (opening && !opening.isClosing) {
5920
+ const root = opening.tagName;
5921
+ if (KNOWN_XML_TAG_NAMES.has(root) || ALLOWED_RAW_HTML_TAGS.has(root.toLowerCase())) {
5922
+ return null;
5923
+ }
5924
+ const tracker = new XmlContainerTracker(root);
5925
+ const firstEnd = tracker.consumeLine(seg, indent);
5926
+ if (firstEnd !== null) {
5927
+ return this.island("xml_container", p, p + firstEnd, true, { tag: root });
5928
+ }
5929
+ for (let k = li + 1; k < this.lineCount; k++) {
5930
+ const end = tracker.consumeLine(this.lineText(k));
5931
+ if (end !== null) {
5932
+ return this.island("xml_container", p, this.lineStarts[k] + end, true, {
5933
+ tag: root
5934
+ });
5935
+ }
5936
+ }
5937
+ return this.island("xml_container", p, this.n, false, { tag: root });
5938
+ }
5939
+ if (isUnclosedGenericXmlOpening(seg)) {
5940
+ return this.island("xml_container", p, this.n, false, {});
5941
+ }
5942
+ return null;
5943
+ }
5944
+ blockComment(p, tp, li) {
5945
+ const close = this.next("-->", tp + 4);
5946
+ if (close === -1) return this.island("html_comment", p, this.n, false);
5947
+ const end = close + 3;
5948
+ const raw = this.text.slice(tp, end);
5949
+ const anchor = PINNED_ANCHOR_RE.exec(raw);
5950
+ const ce = this.contentEnds[li];
5951
+ if (anchor) {
5952
+ if (end <= ce && !this.isBlank(end, ce)) return null;
5953
+ return this.island("anchor", p, end, true, { id: anchor[1] });
5954
+ }
5955
+ return this.island("html_comment", p, end, true);
5956
+ }
5957
+ htmlBlock(p, li, t, tp, atParaStart) {
5958
+ const tag = readXmlTag(t, 0);
5959
+ if (!tag) return null;
5960
+ const name = tag.tagName.toLowerCase();
5961
+ if (!ALLOWED_RAW_HTML_TAGS.has(name)) return null;
5962
+ if (name === "pre" && !tag.isClosing) {
5963
+ const closer = /<\/pre\s*>/gi;
5964
+ closer.lastIndex = tp;
5965
+ const close = closer.exec(this.text);
5966
+ if (!close) return this.island("html_block", p, this.n, false, { tag: name });
5967
+ return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
5968
+ }
5969
+ const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
5970
+ const typeSeven = atParaStart && t.trimEnd() === tag.raw;
5971
+ if (!typeSix && !typeSeven) return null;
5972
+ let end = this.contentEnds[li];
5973
+ for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
5974
+ end = this.contentEnds[k];
5975
+ }
5976
+ return this.island("html_block", p, end, true, { tag: name });
5977
+ }
5978
+ buildBraceTables() {
5979
+ const count = this.lineCount;
5980
+ const prefix = new Int32Array(count + 1);
5981
+ for (let i = 0; i < count; i++) {
5982
+ const { opens, closes } = countStructuralBraces(this.lineText(i));
5983
+ prefix[i + 1] = prefix[i] + opens - closes;
5984
+ }
5985
+ const stop = new Int32Array(count).fill(-1);
5986
+ const stack = [];
5987
+ for (let m = 0; m <= count; m++) {
5988
+ const value = prefix[m];
5989
+ while (stack.length && prefix[stack[stack.length - 1]] >= value) {
5990
+ const i = stack.pop();
5991
+ if (i < count) stop[i] = m - 1;
5992
+ }
5993
+ stack.push(m);
5994
+ }
5995
+ this.braceNet = prefix;
5996
+ this.braceStop = stop;
5997
+ }
5998
+ /** A line-leading bare JSON object — the splitter's structural brace walk. */
5999
+ bareJson(p, li, tp) {
6000
+ let lastLine = null;
6001
+ let net = 0;
6002
+ if (p === this.lineStarts[li]) {
6003
+ if (!this.braceStop || !this.braceNet) this.buildBraceTables();
6004
+ const stop = this.braceStop[li];
6005
+ if (stop !== -1) {
6006
+ lastLine = stop;
6007
+ net = this.braceNet[stop + 1] - this.braceNet[li];
6008
+ }
6009
+ } else {
6010
+ let running = 0;
6011
+ for (let k = li; k < this.lineCount; k++) {
6012
+ const line = k === li ? this.text.slice(tp, this.contentEnds[li]) : this.lineText(k);
6013
+ const { opens, closes } = countStructuralBraces(line);
6014
+ running += opens - closes;
6015
+ if (running <= 0) {
6016
+ lastLine = k;
6017
+ net = running;
6018
+ break;
6019
+ }
6020
+ }
6021
+ }
6022
+ if (lastLine === null) {
6023
+ if (isRecognizedJsonHead(this.text.slice(tp, tp + 512))) {
6024
+ return this.island("json", p, this.n, false, jsonMeta(this.text.slice(tp)));
6025
+ }
6026
+ return null;
6027
+ }
6028
+ if (net !== 0) return null;
6029
+ const end = this.contentEnds[lastLine];
6030
+ const content = this.text.slice(tp, end).trim();
6031
+ try {
6032
+ const parsed = JSON.parse(content);
6033
+ if (parsed === null || typeof parsed !== "object") return null;
6034
+ } catch {
6035
+ return null;
6036
+ }
6037
+ return this.island("json", p, end, true, jsonMeta(content));
6038
+ }
6039
+ tree(p, li) {
6040
+ let treeLines = 0;
6041
+ let lastTree = li;
6042
+ let k = li;
6043
+ while (k < this.lineCount) {
6044
+ if (this.lineIsBlank(k)) {
6045
+ k++;
6046
+ continue;
6047
+ }
6048
+ if (!TREE_GLYPHS.test(this.lineText(k))) break;
6049
+ treeLines++;
6050
+ lastTree = k;
6051
+ k++;
6052
+ }
6053
+ if (treeLines < 3) return null;
6054
+ return this.island("tree", p, this.contentEnds[lastTree], true);
6055
+ }
6056
+ // ── prose ──────────────────────────────────────────────────────────────
6057
+ paragraph(pos, li) {
6058
+ let end = this.contentEnds[li];
6059
+ let breakLine = -1;
6060
+ for (let k = li + 1; k < this.lineCount; k++) {
6061
+ if (this.lineIsBlank(k)) break;
6062
+ if (this.detectBlock(this.lineStarts[k], k, false)) {
6063
+ breakLine = k;
6064
+ break;
6065
+ }
6066
+ end = this.contentEnds[k];
6067
+ }
6068
+ if (breakLine !== -1) {
6069
+ const breakIsland = this.detectBlock(this.lineStarts[breakLine], breakLine, false);
6070
+ if (breakIsland?.type === "tree") {
6071
+ let root = breakLine;
6072
+ for (let j = breakLine - 1; j >= li; j--) {
6073
+ const trimmed = this.lineText(j).trim();
6074
+ if (!trimmed || isSplitterTreeLine(trimmed) || /^#{1,6}\s/.test(trimmed)) break;
6075
+ root = j;
6076
+ }
6077
+ if (root < breakLine) {
6078
+ const treeStart = root === li ? pos : this.lineStarts[root];
6079
+ const tree = { ...breakIsland, start: treeStart };
6080
+ if (treeStart > pos) {
6081
+ const proseEnd = this.contentEnds[root - 1];
6082
+ const scan2 = this.scanInline(pos, proseEnd);
6083
+ if (!scan2.breakIsland) {
6084
+ this.push({ kind: "prose", start: pos, end: proseEnd, island: null, inlines: scan2.inlines });
6085
+ this.push({ kind: "gap", start: proseEnd, end: treeStart, island: null, inlines: [] });
6086
+ this.push({ kind: "island", start: treeStart, end: tree.end, island: tree, inlines: [] });
6087
+ return tree.end;
6088
+ }
6089
+ } else {
6090
+ this.push({ kind: "island", start: treeStart, end: tree.end, island: tree, inlines: [] });
6091
+ return tree.end;
6092
+ }
6093
+ }
6094
+ }
6095
+ }
6096
+ const scan = this.scanInline(pos, end);
6097
+ if (!scan.breakIsland) {
6098
+ this.push({ kind: "prose", start: pos, end, island: null, inlines: scan.inlines });
6099
+ return end;
6100
+ }
6101
+ const br = scan.breakIsland;
6102
+ if (scan.orphan) {
6103
+ let start = pos;
6104
+ while (this.blocks.length) {
6105
+ const last = this.blocks[this.blocks.length - 1];
6106
+ if (last.kind === "island") break;
6107
+ this.blocks.pop();
6108
+ start = last.start;
6109
+ }
6110
+ const island = { ...br, start };
6111
+ this.push({ kind: "island", start, end: island.end, island, inlines: [] });
6112
+ return island.end;
6113
+ }
6114
+ this.push({
6115
+ kind: "prose",
6116
+ start: pos,
6117
+ end: br.start,
6118
+ island: null,
6119
+ inlines: scan.inlines.filter((inline) => inline.end <= br.start)
6120
+ });
6121
+ this.push({ kind: "island", start: br.start, end: br.end, island: br, inlines: [] });
6122
+ return br.end;
6123
+ }
6124
+ scanInline(ps, pe) {
6125
+ const text = this.text;
6126
+ const inlines = [];
6127
+ const hasKind = text.slice(ps, pe).includes("__kind");
6128
+ let kindBudget = 4 * (pe - ps) + 65536;
6129
+ const stop = (island, orphan = false) => ({ inlines, breakIsland: island, orphan });
6130
+ const within = (needle, from) => {
6131
+ const at = this.next(needle, from);
6132
+ return at !== -1 && at + needle.length <= pe ? at : -1;
6133
+ };
6134
+ let runs = null;
6135
+ const codeSpanClose = (n, from) => {
6136
+ if (!runs) {
6137
+ runs = /* @__PURE__ */ new Map();
6138
+ for (let k = ps; k < pe; ) {
6139
+ if (text.charCodeAt(k) !== 96) {
6140
+ k++;
6141
+ continue;
6142
+ }
6143
+ const len = backtickRunLength(text, k);
6144
+ const list2 = runs.get(len);
6145
+ if (list2) list2.push(k);
6146
+ else runs.set(len, [k]);
6147
+ k += len;
6148
+ }
6149
+ }
6150
+ const list = runs.get(n);
6151
+ if (!list) return -1;
6152
+ let lo = 0;
6153
+ let hi = list.length;
6154
+ while (lo < hi) {
6155
+ const mid = lo + hi >>> 1;
6156
+ if (list[mid] < from) lo = mid + 1;
6157
+ else hi = mid;
6158
+ }
6159
+ const at = list[lo];
6160
+ return at !== void 0 && at + n <= pe ? at : -1;
6161
+ };
6162
+ let i = ps;
6163
+ while (i < pe) {
6164
+ const ch = text[i];
6165
+ if (ch === "\\") {
6166
+ const nextCh = text[i + 1];
6167
+ if (nextCh === "(" || nextCh === "[") {
6168
+ const close = within(nextCh === "(" ? "\\)" : "\\]", i + 2);
6169
+ if (close !== -1) {
6170
+ inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: nextCh === "(" ? "\\(" : "\\[" }));
6171
+ i = close + 2;
6172
+ continue;
6173
+ }
6174
+ }
6175
+ i += 2;
6176
+ continue;
6177
+ }
6178
+ if (ch === "`") {
6179
+ const n = backtickRunLength(text, i);
6180
+ const close = codeSpanClose(n, i + n);
6181
+ i = close === -1 ? i + n : close + n;
6182
+ continue;
6183
+ }
6184
+ if (ch === "$") {
6185
+ if (text[i + 1] === "$") {
6186
+ const close = this.mathPairs.get(i);
6187
+ if (close === void 0) {
6188
+ i += 2;
6189
+ continue;
6190
+ }
6191
+ if (close + 2 > pe) return stop(this.island("math_block", i, close + 2, true, { delimiter: "$$" }));
6192
+ inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: "$$" }));
6193
+ i = close + 2;
6194
+ continue;
6195
+ }
6196
+ const end = singleDollarMathEnd(text, i, pe);
6197
+ if (end > 0) {
6198
+ inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
6199
+ i = end;
6200
+ continue;
6201
+ }
6202
+ i++;
6203
+ continue;
6204
+ }
6205
+ if (ch === "{") {
6206
+ if (text[i + 1] === "{") {
6207
+ const close = this.next("}}", i + 2);
6208
+ if (close !== -1 && close + 2 <= pe && close - i <= 200 && !text.slice(i, close).includes("\n")) {
6209
+ const raw = text.slice(i, close + 2);
6210
+ const strict = STRICT_VARIABLE_RE.exec(raw);
6211
+ inlines.push(
6212
+ this.island("variable", i, close + 2, true, strict ? { name: strict[1] } : { template: true })
6213
+ );
6214
+ i = close + 2;
6215
+ continue;
6216
+ }
6217
+ i += 2;
6218
+ continue;
6219
+ }
6220
+ if (hasKind && kindBudget > 0 && /^\{\s*"/.test(text.slice(i, i + 64))) {
6221
+ const limit = Math.min(pe, i + 65536);
6222
+ const end = matchingJsonObjectEnd(text, i, limit);
6223
+ kindBudget -= (end ?? limit) - i;
6224
+ if (end !== null) {
6225
+ const kind = declaredKind(text.slice(i, end));
6226
+ if (kind) {
6227
+ inlines.push(this.island("kind_json", i, end, true, jsonMeta(text.slice(i, end))));
6228
+ i = end;
6229
+ continue;
6230
+ }
6231
+ }
6232
+ }
6233
+ i++;
6234
+ continue;
6235
+ }
6236
+ if (ch === "[") {
6237
+ const media = MEDIA_REF_PREFIXES.find((prefix) => text.startsWith(prefix, i));
6238
+ if (media) {
6239
+ const close = within("]", i + media.length);
6240
+ const newline = this.next("\n", i);
6241
+ if (close !== -1 && (newline === -1 || newline > close)) {
6242
+ inlines.push(this.island("media_ref", i, close + 1, true, { media: media.slice(1, 6).toLowerCase() }));
6243
+ i = close + 1;
6244
+ continue;
6245
+ }
6246
+ }
6247
+ i++;
6248
+ continue;
6249
+ }
6250
+ if (ch === "<") {
6251
+ if (text.startsWith("<!--", i)) {
6252
+ const close = this.next("-->", i + 4);
6253
+ if (close === -1) return stop(this.island("html_comment", i, this.n, false));
6254
+ const end = close + 3;
6255
+ const anchor = end - i <= 64 ? PINNED_ANCHOR_RE.exec(text.slice(i, end)) : null;
6256
+ const type = anchor ? "anchor" : "html_comment";
6257
+ const meta = anchor ? { id: anchor[1] } : {};
6258
+ if (end > pe) return stop(this.island(type, i, end, true, meta));
6259
+ inlines.push(this.island(type, i, end, true, meta));
6260
+ i = end;
6261
+ continue;
6262
+ }
6263
+ const cite = CITE_RE.exec(text.slice(i, i + 64));
6264
+ if (cite) {
6265
+ inlines.push(this.island("cite", i, i + cite[0].length, true, { n: Number(cite[1]) }));
6266
+ i += cite[0].length;
6267
+ continue;
6268
+ }
6269
+ const tag = readXmlTag(text, i, this.finder);
6270
+ if (tag && i + tag.raw.length <= pe) {
6271
+ const name = tag.tagName;
6272
+ const tagEnd = i + tag.raw.length;
6273
+ const isAttr = ATTRIBUTE_XML_NAMES.includes(name);
6274
+ const isThinking = THINKING_FAMILY.includes(name) && tag.raw === `<${name}>`;
6275
+ if (!tag.isClosing && (isAttr || isThinking)) {
6276
+ if (tag.isSelfClosing) {
6277
+ inlines.push(this.island("xml_inline", i, tagEnd, true, { tag: name, selfClosing: true }));
6278
+ i = tagEnd;
6279
+ continue;
6280
+ }
6281
+ const closer = `</${name}>`;
6282
+ const close = this.next(closer, tagEnd);
6283
+ const blockType = isAttr ? "xml_attr" : "xml_region";
6284
+ if (close === -1) return stop(this.island(blockType, i, this.n, false, { tag: name }));
6285
+ const end = close + closer.length;
6286
+ if (end > pe) return stop(this.island(blockType, i, end, true, { tag: name }));
6287
+ inlines.push(this.island("xml_inline", i, end, true, { tag: name }));
6288
+ i = end;
6289
+ continue;
6290
+ }
6291
+ if (tag.isClosing && THINKING_FAMILY.includes(name)) {
6292
+ return stop(this.island("xml_region", i, tagEnd, true, { tag: name, continuation: true }), true);
6293
+ }
6294
+ const lower = name.toLowerCase();
6295
+ inlines.push(
6296
+ this.island(ALLOWED_RAW_HTML_TAGS.has(lower) ? "html_tag" : "xml_tag", i, tagEnd, true, {
6297
+ tag: name
6298
+ })
6299
+ );
6300
+ i = tagEnd;
6301
+ continue;
6302
+ }
6303
+ const pending = ATTRIBUTE_XML_NAMES.find(
6304
+ (name) => text.startsWith(`<${name}`, i) && /\s/.test(text[i + name.length + 1] ?? "")
6305
+ );
6306
+ if (pending && this.next(">", i) === -1) {
6307
+ return stop(this.island("xml_attr", i, this.n, false, { tag: pending }));
6308
+ }
6309
+ i++;
6310
+ continue;
6311
+ }
6312
+ i++;
6313
+ }
6314
+ return { inlines, breakIsland: null, orphan: false };
6315
+ }
6316
+ };
6317
+ function tokenizeSource(text) {
6318
+ const raw = new Tokenizer(text).run();
6319
+ const cp = buildCodePointIndex(text);
6320
+ const inline = (island) => ({
6321
+ islandType: island.type,
6322
+ inline: true,
6323
+ complete: island.complete,
6324
+ meta: island.meta,
6325
+ start: island.start,
6326
+ end: island.end,
6327
+ startCp: cp.toCodePoint(island.start),
6328
+ endCp: cp.toCodePoint(island.end),
6329
+ raw: text.slice(island.start, island.end)
6330
+ });
6331
+ return raw.map(
6332
+ (block) => ({
6333
+ kind: block.kind,
6334
+ islandType: block.island?.type ?? null,
6335
+ complete: block.island ? block.island.complete : true,
6336
+ meta: block.island?.meta ?? {},
6337
+ inlines: block.inlines.map(inline),
6338
+ start: block.start,
6339
+ end: block.end,
6340
+ startCp: cp.toCodePoint(block.start),
6341
+ endCp: cp.toCodePoint(block.end),
6342
+ raw: text.slice(block.start, block.end)
6343
+ })
6344
+ );
6345
+ }
6346
+ function joinSource(blocks) {
6347
+ let out = "";
6348
+ for (const block of blocks) out += block.raw;
6349
+ return out;
6350
+ }
6351
+ function listIslands(blocks) {
6352
+ const out = [];
6353
+ for (const block of blocks) {
6354
+ if (block.kind === "island" && block.islandType) {
6355
+ out.push({
6356
+ islandType: block.islandType,
6357
+ inline: false,
6358
+ complete: block.complete,
6359
+ meta: block.meta,
6360
+ start: block.start,
6361
+ end: block.end,
6362
+ startCp: block.startCp,
6363
+ endCp: block.endCp,
6364
+ raw: block.raw
6365
+ });
6366
+ } else {
6367
+ out.push(...block.inlines);
6368
+ }
6369
+ }
6370
+ return out;
6371
+ }
6372
+ function blockAt(blocks, offset) {
6373
+ let lo = 0;
6374
+ let hi = blocks.length - 1;
6375
+ while (lo <= hi) {
6376
+ const mid = lo + hi >>> 1;
6377
+ const block = blocks[mid];
6378
+ if (offset < block.start) hi = mid - 1;
6379
+ else if (offset >= block.end) lo = mid + 1;
6380
+ else return block;
6381
+ }
6382
+ return null;
6383
+ }
6384
+
6385
+ // source/splice.ts
6386
+ var SourceSpliceError = class extends Error {
6387
+ constructor(code, message) {
6388
+ super(message);
6389
+ this.code = code;
6390
+ this.name = "SourceSpliceError";
6391
+ }
6392
+ code;
6393
+ };
6394
+ function blockEdit(block, text) {
6395
+ return { start: block.start, end: block.end, text };
6396
+ }
6397
+ function islandEdit(island, text) {
6398
+ return { start: island.start, end: island.end, text, island: true };
6399
+ }
6400
+ function blockRangeEdit(first, last, text) {
6401
+ return { start: first.start, end: last.end, text };
6402
+ }
6403
+ function locateIsland(text, raw, from, expected, expectedFromEnd) {
6404
+ if (expected >= from && text.startsWith(raw, expected)) return expected;
6405
+ if (expectedFromEnd >= from && text.startsWith(raw, expectedFromEnd)) return expectedFromEnd;
6406
+ const after = text.indexOf(raw, Math.max(from, expected));
6407
+ const before = expected > from ? text.lastIndexOf(raw, expected) : -1;
6408
+ const beforeOk = before >= from ? before : -1;
6409
+ if (after === -1) return beforeOk;
6410
+ if (beforeOk === -1) return after;
6411
+ return expected - beforeOk <= after - expected ? beforeOk : after;
6412
+ }
6413
+ function commonPrefix(a, b) {
6414
+ const max = Math.min(a.length, b.length);
6415
+ let i = 0;
6416
+ while (i < max && a.charCodeAt(i) === b.charCodeAt(i)) i++;
6417
+ if (i > 0 && (splitsSurrogatePair(a, i) || splitsSurrogatePair(b, i))) i--;
6418
+ return i;
6419
+ }
6420
+ function commonSuffix(a, b, prefix) {
6421
+ const max = Math.min(a.length, b.length) - prefix;
6422
+ let i = 0;
6423
+ while (i < max && a.charCodeAt(a.length - 1 - i) === b.charCodeAt(b.length - 1 - i)) i++;
6424
+ if (i > 0 && (splitsSurrogatePair(a, a.length - i) || splitsSurrogatePair(b, b.length - i))) i--;
6425
+ return i;
6426
+ }
6427
+ function spliceSave(original, edits, options = {}) {
6428
+ const blocks = options.blocks ?? tokenizeSource(original);
6429
+ if (options.blocks && joinSource(blocks) !== original) {
6430
+ throw new SourceSpliceError("stale_blocks", "the blocks passed in were not cut from this original text");
6431
+ }
6432
+ const boundaries = /* @__PURE__ */ new Set([0, original.length]);
6433
+ for (const block of blocks) {
6434
+ boundaries.add(block.start);
6435
+ boundaries.add(block.end);
6436
+ }
6437
+ const islands = listIslands(blocks);
6438
+ const islandAt = /* @__PURE__ */ new Map();
6439
+ for (const island of islands) islandAt.set(`${island.start}:${island.end}`, island);
6440
+ const sorted = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);
6441
+ let previousEnd = -1;
6442
+ for (const edit of sorted) {
6443
+ if (edit.start < 0 || edit.end > original.length || edit.start > edit.end) {
6444
+ throw new SourceSpliceError("out_of_range", `edit [${edit.start}, ${edit.end}) is outside the text`);
6445
+ }
6446
+ if (edit.island) {
6447
+ if (!islandAt.has(`${edit.start}:${edit.end}`)) {
6448
+ throw new SourceSpliceError(
6449
+ "misaligned",
6450
+ `islandEdit [${edit.start}, ${edit.end}) does not name an island's exact span`
6451
+ );
6452
+ }
6453
+ } else if (!boundaries.has(edit.start) || !boundaries.has(edit.end)) {
6454
+ throw new SourceSpliceError(
6455
+ "misaligned",
6456
+ `edit [${edit.start}, ${edit.end}) does not start and end on block boundaries`
6457
+ );
6458
+ }
6459
+ if (edit.start < previousEnd) {
6460
+ throw new SourceSpliceError("overlap", `edit [${edit.start}, ${edit.end}) overlaps the previous edit`);
6461
+ }
6462
+ previousEnd = edit.end;
6463
+ }
6464
+ const effective = [];
6465
+ const replacedIslands = /* @__PURE__ */ new Set();
6466
+ const pushSegment = (oldStart, oldEnd, replacement) => {
6467
+ const old = original.slice(oldStart, oldEnd);
6468
+ if (old === replacement) return;
6469
+ const prefix = commonPrefix(old, replacement);
6470
+ const suffix = commonSuffix(old, replacement, prefix);
6471
+ effective.push({
6472
+ oldStart: oldStart + prefix,
6473
+ oldEnd: oldEnd - suffix,
6474
+ replacement: replacement.slice(prefix, replacement.length - suffix)
6475
+ });
6476
+ };
6477
+ for (const edit of sorted) {
6478
+ if (edit.island) {
6479
+ replacedIslands.add(`${edit.start}:${edit.end}`);
6480
+ pushSegment(edit.start, edit.end, edit.text);
6481
+ continue;
6482
+ }
6483
+ if (edit.text === original.slice(edit.start, edit.end)) continue;
6484
+ const inside = islands.filter((island) => island.start >= edit.start && island.end <= edit.end);
6485
+ let oldCursor2 = edit.start;
6486
+ let newCursor2 = 0;
6487
+ for (const island of inside) {
6488
+ const at = locateIsland(edit.text, island.raw, newCursor2, newCursor2 + (island.start - oldCursor2), edit.text.length - (edit.end - island.start));
6489
+ if (at === -1) {
6490
+ const name = island.meta.tag ?? island.meta.name ?? island.meta.lang ?? "";
6491
+ throw new SourceSpliceError(
6492
+ "island_edit",
6493
+ `edit [${edit.start}, ${edit.end}) changes or removes the protected ${island.islandType}${name ? ` (${String(name)})` : ""} island at [${island.start}, ${island.end}); islands change only through islandEdit()`
6494
+ );
6495
+ }
6496
+ pushSegment(oldCursor2, island.start, edit.text.slice(newCursor2, at));
6497
+ oldCursor2 = island.end;
6498
+ newCursor2 = at + island.raw.length;
6499
+ }
6500
+ pushSegment(oldCursor2, edit.end, edit.text.slice(newCursor2));
6501
+ }
6502
+ if (effective.length === 0) {
6503
+ return {
6504
+ text: original,
6505
+ changed: false,
6506
+ changes: [],
6507
+ integrity: { ok: true, bytesOutsideEditsIdentical: true, disturbed: [] },
6508
+ blocks
6509
+ };
6510
+ }
6511
+ let text = "";
6512
+ let cursor = 0;
6513
+ let delta = 0;
6514
+ const pending = [];
6515
+ for (const edit of effective) {
6516
+ text += original.slice(cursor, edit.oldStart);
6517
+ const newStart = edit.oldStart + delta;
6518
+ text += edit.replacement;
6519
+ const newEnd = newStart + edit.replacement.length;
6520
+ const owner = sorted.find((e) => e.start <= edit.oldStart && e.end >= edit.oldEnd);
6521
+ pending.push({
6522
+ blockStart: owner?.start ?? edit.oldStart,
6523
+ blockEnd: owner?.end ?? edit.oldEnd,
6524
+ oldStart: edit.oldStart,
6525
+ oldEnd: edit.oldEnd,
6526
+ newStart,
6527
+ newEnd
6528
+ });
6529
+ delta += edit.replacement.length - (edit.oldEnd - edit.oldStart);
6530
+ cursor = edit.oldEnd;
6531
+ }
6532
+ text += original.slice(cursor);
6533
+ const oldCp = buildCodePointIndex(original);
6534
+ const newCp = buildCodePointIndex(text);
6535
+ const changes = pending.map((change) => ({
6536
+ ...change,
6537
+ oldStartCp: oldCp.toCodePoint(change.oldStart),
6538
+ oldEndCp: oldCp.toCodePoint(change.oldEnd),
6539
+ newStartCp: newCp.toCodePoint(change.newStart),
6540
+ newEndCp: newCp.toCodePoint(change.newEnd)
6541
+ }));
6542
+ let bytesOutsideEditsIdentical = true;
6543
+ let oldCursor = 0;
6544
+ let newCursor = 0;
6545
+ for (const change of changes) {
6546
+ if (original.slice(oldCursor, change.oldStart) !== text.slice(newCursor, change.newStart)) {
6547
+ bytesOutsideEditsIdentical = false;
6548
+ }
6549
+ oldCursor = change.oldEnd;
6550
+ newCursor = change.newEnd;
6551
+ }
6552
+ if (original.slice(oldCursor) !== text.slice(newCursor)) bytesOutsideEditsIdentical = false;
6553
+ const newBlocks = tokenizeSource(text);
6554
+ const newIslandsByStart = /* @__PURE__ */ new Map();
6555
+ for (const island of listIslands(newBlocks)) {
6556
+ const list = newIslandsByStart.get(island.start);
6557
+ if (list) list.push(island.raw);
6558
+ else newIslandsByStart.set(island.start, [island.raw]);
6559
+ }
6560
+ const disturbed = [];
6561
+ for (const island of islands) {
6562
+ if (replacedIslands.has(`${island.start}:${island.end}`)) continue;
6563
+ const mappedStart = mapPosition(changes, island.start, { assoc: 1 }).pos;
6564
+ const candidates = newIslandsByStart.get(mappedStart);
6565
+ if (!candidates || !candidates.includes(island.raw)) {
6566
+ disturbed.push({
6567
+ islandType: island.islandType,
6568
+ inline: island.inline,
6569
+ start: island.start,
6570
+ end: island.end,
6571
+ mappedStart
6572
+ });
6573
+ }
6574
+ }
6575
+ const integrity = {
6576
+ ok: bytesOutsideEditsIdentical && disturbed.length === 0,
6577
+ bytesOutsideEditsIdentical,
6578
+ disturbed
6579
+ };
6580
+ if ((options.requireIntegrity ?? true) && !integrity.ok) {
6581
+ const named = disturbed.slice(0, 5).map((island) => `${island.islandType}@${island.start}`).join(", ");
6582
+ throw new SourceSpliceError(
6583
+ "integrity",
6584
+ `integrity: the save disturbed ${disturbed.length} protected island(s) it did not replace${named ? ` (${named}${disturbed.length > 5 ? ", \u2026" : ""})` : ""}${bytesOutsideEditsIdentical ? "" : "; bytes outside the edits changed"}`
6585
+ );
6586
+ }
6587
+ return { text, changed: true, changes, integrity, blocks: newBlocks };
6588
+ }
6589
+ function mapPosition(changes, pos, options = {}) {
6590
+ const assoc = options.assoc ?? 1;
6591
+ const cp = options.unit === "codepoint";
6592
+ let delta = 0;
6593
+ for (const change of changes) {
6594
+ const oldStart = cp ? change.oldStartCp : change.oldStart;
6595
+ const oldEnd = cp ? change.oldEndCp : change.oldEnd;
6596
+ const newStart = cp ? change.newStartCp : change.newStart;
6597
+ const newEnd = cp ? change.newEndCp : change.newEnd;
6598
+ if (pos < oldStart) break;
6599
+ if (pos > oldEnd) {
6600
+ delta = newEnd - oldEnd;
6601
+ continue;
6602
+ }
6603
+ if (oldStart === oldEnd) {
6604
+ return { pos: assoc < 0 ? newStart : newEnd, deleted: false };
6605
+ }
6606
+ if (pos === oldStart) return { pos: newStart, deleted: false };
6607
+ if (pos === oldEnd) return { pos: newEnd, deleted: false };
6608
+ return { pos: assoc < 0 ? newStart : newEnd, deleted: true };
6609
+ }
6610
+ return { pos: pos + delta, deleted: false };
6611
+ }
6612
+ function mapRange(changes, start, end, unit = "utf16") {
6613
+ const cp = unit === "codepoint";
6614
+ const mappedStart = mapPosition(changes, start, { assoc: 1, unit });
6615
+ const mappedEnd = mapPosition(changes, end, { assoc: -1, unit });
6616
+ const touched = changes.some((change) => {
6617
+ const oldStart = cp ? change.oldStartCp : change.oldStart;
6618
+ const oldEnd = cp ? change.oldEndCp : change.oldEnd;
6619
+ return oldStart < end && oldEnd > start;
6620
+ });
6621
+ const newStart = mappedStart.pos;
6622
+ const newEnd = Math.max(newStart, mappedEnd.pos);
6623
+ return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
6624
+ }
6625
+
4976
6626
  exports.ACTION_BY_CLASS = ACTION_BY_CLASS;
4977
6627
  exports.CAPABILITY_BY_CLASS = CAPABILITY_BY_CLASS;
4978
6628
  exports.CLASSES = CLASSES;
@@ -4989,6 +6639,7 @@ exports.JsonStreamTokenizer = JsonStreamTokenizer;
4989
6639
  exports.KIND_KEY = KIND_KEY;
4990
6640
  exports.KindStorageError = KindStorageError;
4991
6641
  exports.KindStreamParser = KindStreamParser;
6642
+ exports.NESTING_FENCE_LANGUAGES = NESTING_FENCE_LANGUAGES;
4992
6643
  exports.NODE_OUTCOME_KIND = NODE_OUTCOME_KIND;
4993
6644
  exports.ParseSession = ParseSession;
4994
6645
  exports.RESERVED_PREFIX = RESERVED_PREFIX;
@@ -4996,14 +6647,21 @@ exports.ROOT_STORAGE_NAME = ROOT_STORAGE_NAME;
4996
6647
  exports.RUN_RESULT_KIND = RUN_RESULT_KIND;
4997
6648
  exports.SIDE_EFFECT_CLASSES = SIDE_EFFECT_CLASSES;
4998
6649
  exports.SLUG_PREFIX = SLUG_PREFIX;
6650
+ exports.SourceSpliceError = SourceSpliceError;
6651
+ exports.XmlContainerTracker = XmlContainerTracker;
4999
6652
  exports.advancePartialKind = advancePartialKind;
5000
6653
  exports.asKindInstance = asKindInstance;
6654
+ exports.blockAt = blockAt;
6655
+ exports.blockEdit = blockEdit;
6656
+ exports.blockRangeEdit = blockRangeEdit;
5001
6657
  exports.buildAgentSchemaWithRenderBlockSupport = buildAgentSchemaWithRenderBlockSupport;
6658
+ exports.buildCodePointIndex = buildCodePointIndex;
5002
6659
  exports.buildCompliantKindSnapshot = buildCompliantKindSnapshot;
5003
6660
  exports.buildDirectiveSlug = buildDirectiveSlug;
5004
6661
  exports.buildKindDirective = buildKindDirective;
5005
6662
  exports.capabilityOf = capabilityOf;
5006
6663
  exports.classifyInboundEnvelopeMetadata = classifyInboundEnvelopeMetadata;
6664
+ exports.classifyInnerFenceLine = classifyInnerFenceLine;
5007
6665
  exports.collectReferencedKinds = collectReferencedKinds;
5008
6666
  exports.collectSchemaReferencedKinds = collectSchemaReferencedKinds;
5009
6667
  exports.compareWithExistingKindSchema = compareWithExistingKindSchema;
@@ -5023,6 +6681,7 @@ exports.envelopeCacheFromEnvelopes = envelopeCacheFromEnvelopes;
5023
6681
  exports.envelopeFromCompleteValue = envelopeFromCompleteValue;
5024
6682
  exports.executesAtOutputRoot = executesAtOutputRoot;
5025
6683
  exports.fenceDiscriminator = fenceDiscriminator;
6684
+ exports.fenceNestsInnerFences = fenceNestsInnerFences;
5026
6685
  exports.fieldsToDbPayload = fieldsToDbPayload;
5027
6686
  exports.fingerprintText = fingerprintText;
5028
6687
  exports.formatBlockLabel = formatBlockLabel;
@@ -5043,17 +6702,24 @@ exports.isLegacyShell = isLegacyShell;
5043
6702
  exports.isProvisionalKind = isProvisionalKind;
5044
6703
  exports.isReservedDirectiveSlug = isReservedDirectiveSlug;
5045
6704
  exports.isScalarArrayType = isScalarArrayType;
6705
+ exports.isSingleDollarMath = isSingleDollarMath;
5046
6706
  exports.isTerminalKindEvent = isTerminalKindEvent;
6707
+ exports.islandEdit = islandEdit;
5047
6708
  exports.itemFacts = itemFacts;
5048
6709
  exports.itemSubtitle = itemSubtitle;
5049
6710
  exports.itemTitle = itemTitle;
6711
+ exports.joinSource = joinSource;
5050
6712
  exports.kindSchemaFromJsonSchema = kindSchemaFromJsonSchema;
5051
6713
  exports.kindSchemaToJsonSchema = kindSchemaToJsonSchema;
5052
6714
  exports.kindSchemaToStorage = kindSchemaToStorage;
5053
6715
  exports.kindVerdictOf = kindVerdictOf;
5054
6716
  exports.legacyShellUses = legacyShellUses;
6717
+ exports.listIslands = listIslands;
5055
6718
  exports.looksLikeDirectiveHead = looksLikeDirectiveHead;
6719
+ exports.looksLikeDisplayMath = looksLikeDisplayMath;
5056
6720
  exports.makePartialKindStalenessGate = makePartialKindStalenessGate;
6721
+ exports.mapPosition = mapPosition;
6722
+ exports.mapRange = mapRange;
5057
6723
  exports.mergeResidueIntoValue = mergeResidueIntoValue;
5058
6724
  exports.normalizeAiSchemaInput = normalizeAiSchemaInput;
5059
6725
  exports.normalizeJsonRegion = normalizeJsonRegion;
@@ -5061,6 +6727,7 @@ exports.nounFamily = nounFamily;
5061
6727
  exports.nounLabel = nounLabel;
5062
6728
  exports.nounTitleColumn = nounTitleColumn;
5063
6729
  exports.openParseSession = openParseSession;
6730
+ exports.pairDisplayMath = pairDisplayMath;
5064
6731
  exports.parseDirectiveSlug = parseDirectiveSlug;
5065
6732
  exports.readEnvelope = readEnvelope;
5066
6733
  exports.readNodeOutcomeValue = readNodeOutcomeValue;
@@ -5068,6 +6735,7 @@ exports.readObjectKind = readObjectKind;
5068
6735
  exports.readOutputRef = readOutputRef;
5069
6736
  exports.readPartialKindEvent = readPartialKindEvent;
5070
6737
  exports.readRunResultValue = readRunResultValue;
6738
+ exports.readXmlTag = readXmlTag;
5071
6739
  exports.reconstructRegionValue = reconstructRegionValue;
5072
6740
  exports.rehydrateNodeOutcome = rehydrateNodeOutcome;
5073
6741
  exports.rehydrateRunResult = rehydrateRunResult;
@@ -5082,9 +6750,15 @@ exports.scalarArrayItemType = scalarArrayItemType;
5082
6750
  exports.schemaLayoutMode = schemaLayoutMode;
5083
6751
  exports.schemaStructureDepth = schemaStructureDepth;
5084
6752
  exports.setJsonRootKeyLookup = setJsonRootKeyLookup;
6753
+ exports.singleDollarMathEnd = singleDollarMathEnd;
6754
+ exports.spliceSave = spliceSave;
6755
+ exports.splitsSurrogatePair = splitsSurrogatePair;
5085
6756
  exports.storageToKindSchema = storageToKindSchema;
5086
6757
  exports.stripKindDeep = stripKindDeep;
5087
6758
  exports.titleCaseToken = titleCaseToken;
6759
+ exports.toCodePointOffset = toCodePointOffset;
6760
+ exports.toUtf16Offset = toUtf16Offset;
6761
+ exports.tokenizeSource = tokenizeSource;
5088
6762
  exports.tryDecodeDirective = tryDecodeDirective;
5089
6763
  exports.tryDecodeDirectiveContent = tryDecodeDirectiveContent;
5090
6764
  exports.validateBlockSchemaSavePlan = validateBlockSchemaSavePlan;