@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/CHANGELOG.md +94 -0
- package/README.md +2 -0
- package/dist/index.cjs +1682 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1659 -9
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +1678 -0
- package/dist/source.cjs.map +1 -0
- package/dist/source.d.cts +374 -0
- package/dist/source.d.ts +374 -0
- package/dist/source.js +1653 -0
- package/dist/source.js.map +1 -0
- package/package.json +14 -1
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
|
|
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 (!
|
|
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 && !
|
|
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 (!
|
|
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(
|
|
3213
|
-
if (ctx.blockSchemas.some((draft) => draft.slug ===
|
|
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:
|
|
3232
|
-
label: formatBlockLabel(
|
|
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;
|