@jxsuite/parser 2.0.1 → 4.0.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/markdown.js CHANGED
@@ -58,6 +58,77 @@ var __esm = (fn, res, err) => () => {
58
58
  };
59
59
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
60
60
 
61
+ // ../../packages/schema/src/guards.ts
62
+ function isString(value) {
63
+ return typeof value === "string";
64
+ }
65
+ function isNumber(value) {
66
+ return typeof value === "number";
67
+ }
68
+ function isBoolean(value) {
69
+ return typeof value === "boolean";
70
+ }
71
+ function isNonNullObject(value) {
72
+ return typeof value === "object" && value !== null;
73
+ }
74
+ function isJsonObject(value) {
75
+ return typeof value === "object" && value !== null && !Array.isArray(value);
76
+ }
77
+ function isRef(value) {
78
+ return isJsonObject(value) && typeof value.$ref === "string";
79
+ }
80
+ function isNodeObject(value) {
81
+ return isJsonObject(value);
82
+ }
83
+ function isPlainTagName(tagName) {
84
+ return typeof tagName === "string";
85
+ }
86
+ function isTagExpression(tagName) {
87
+ if (typeof tagName !== "object" || tagName === null || Array.isArray(tagName) || !isJsonObject(tagName.$expression)) {
88
+ return false;
89
+ }
90
+ const expression = tagName.$expression;
91
+ if (expression.operator === "?:") {
92
+ return typeof expression.value === "string" && typeof expression.initial === "string";
93
+ }
94
+ if (expression.operator === "switch") {
95
+ return isJsonObject(expression.cases) && Object.values(expression.cases).every((tag) => isString(tag)) && typeof expression.default === "string";
96
+ }
97
+ return false;
98
+ }
99
+ function tagNameCandidates(tagName) {
100
+ if (isPlainTagName(tagName)) {
101
+ return [tagName];
102
+ }
103
+ if (!isTagExpression(tagName)) {
104
+ return [];
105
+ }
106
+ const expression = tagName.$expression;
107
+ if (expression.operator === "?:") {
108
+ return [...new Set([expression.value, expression.initial])];
109
+ }
110
+ return [...new Set([...Object.values(expression.cases), expression.default])];
111
+ }
112
+ var SCHEMA_KEYWORDS;
113
+ var init_guards = __esm(() => {
114
+ SCHEMA_KEYWORDS = new Set([
115
+ "type",
116
+ "enum",
117
+ "minimum",
118
+ "maximum",
119
+ "minLength",
120
+ "maxLength",
121
+ "pattern",
122
+ "format",
123
+ "items",
124
+ "properties",
125
+ "required",
126
+ "description",
127
+ "title",
128
+ "$comment"
129
+ ]);
130
+ });
131
+
61
132
  // src/content-rules.ts
62
133
  function escapeRegExp(text) {
63
134
  return text.replaceAll(REGEXP_SPECIAL, String.raw`\$&`);
@@ -192,7 +263,7 @@ function compileExclude(patterns) {
192
263
  const dirs = [];
193
264
  let everything = false;
194
265
  for (const pattern of patterns) {
195
- if (typeof pattern !== "string" || pattern.trim() === "") {
266
+ if (!isString(pattern) || pattern.trim() === "") {
196
267
  throw new TypeError(`"exclude" entries must be non-empty strings, got ${JSON.stringify(pattern)}`);
197
268
  }
198
269
  if (pattern.startsWith("!")) {
@@ -266,21 +337,21 @@ function readField(data, key) {
266
337
  if (!key.includes(".")) {
267
338
  return;
268
339
  }
269
- let current = data;
270
- for (const part of key.split(".")) {
271
- if (!isPlainObject(current) || !Object.hasOwn(current, part)) {
272
- return;
273
- }
274
- current = current[part];
340
+ return readPath(data, key.split("."));
341
+ }
342
+ function readPath(holder, [part, ...rest]) {
343
+ if (part === undefined || !isPlainObject(holder) || !Object.hasOwn(holder, part)) {
344
+ return;
275
345
  }
276
- return current;
346
+ const value = holder[part];
347
+ return rest.length === 0 ? value : readPath(value, rest);
277
348
  }
278
349
  function order(actual, operand) {
279
350
  const a = comparable(actual);
280
- if (typeof a === "number" && typeof operand === "number") {
351
+ if (isNumber(a) && isNumber(operand)) {
281
352
  return a - operand;
282
353
  }
283
- if (typeof a === "string" && typeof operand === "string") {
354
+ if (isString(a) && isString(operand)) {
284
355
  return a < operand ? -1 : a > operand ? 1 : 0;
285
356
  }
286
357
  return;
@@ -302,13 +373,13 @@ function operatorTest(where, op, operand) {
302
373
  return op === "$in" ? hit : (actual) => !hit(actual);
303
374
  }
304
375
  case "$exists": {
305
- if (typeof operand !== "boolean") {
376
+ if (!isBoolean(operand)) {
306
377
  throw new TypeError(`${where}.$exists: expected true or false, got ${JSON.stringify(operand)}`);
307
378
  }
308
379
  return (actual) => (actual !== undefined && actual !== null) === operand;
309
380
  }
310
381
  default: {
311
- if (typeof operand !== "string" && typeof operand !== "number") {
382
+ if (!isString(operand) && !isNumber(operand)) {
312
383
  throw new TypeError(`${where}.${op}: expected a string or number, got ${JSON.stringify(operand)}`);
313
384
  }
314
385
  const test = (diff) => op === "$gt" ? diff > 0 : op === "$gte" ? diff >= 0 : op === "$lt" ? diff < 0 : diff <= 0;
@@ -366,6 +437,7 @@ function compileWhere(where) {
366
437
  }
367
438
  var nothing = () => {}, REGEXP_SPECIAL, MAX_STAR_RUNS = 4, OPERATORS;
368
439
  var init_content_rules = __esm(() => {
440
+ init_guards();
369
441
  REGEXP_SPECIAL = /[$()*+.?[\\\]^{|}]/g;
370
442
  OPERATORS = new Set(["$eq", "$ne", "$in", "$nin", "$exists", "$gt", "$gte", "$lt", "$lte"]);
371
443
  });
@@ -25426,14 +25498,14 @@ var init_decode_codepoint = __esm(() => {
25426
25498
  });
25427
25499
 
25428
25500
  // ../../node_modules/parse5/node_modules/entities/dist/esm/decode.js
25429
- function isNumber(code) {
25501
+ function isNumber2(code) {
25430
25502
  return code >= CharCodes.ZERO && code <= CharCodes.NINE;
25431
25503
  }
25432
25504
  function isHexadecimalCharacter(code) {
25433
25505
  return code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_F || code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_F;
25434
25506
  }
25435
25507
  function isAsciiAlphaNumeric(code) {
25436
- return code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z || code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z || isNumber(code);
25508
+ return code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z || code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z || isNumber2(code);
25437
25509
  }
25438
25510
  function isEntityInAttributeInvalidEnd(code) {
25439
25511
  return code === CharCodes.EQUALS || isAsciiAlphaNumeric(code);
@@ -25507,7 +25579,7 @@ class EntityDecoder {
25507
25579
  const startIndex = offset;
25508
25580
  while (offset < input.length) {
25509
25581
  const char = input.charCodeAt(offset);
25510
- if (isNumber(char) || isHexadecimalCharacter(char)) {
25582
+ if (isNumber2(char) || isHexadecimalCharacter(char)) {
25511
25583
  offset += 1;
25512
25584
  } else {
25513
25585
  this.addToNumericResult(input, startIndex, offset, 16);
@@ -25521,7 +25593,7 @@ class EntityDecoder {
25521
25593
  const startIndex = offset;
25522
25594
  while (offset < input.length) {
25523
25595
  const char = input.charCodeAt(offset);
25524
- if (isNumber(char)) {
25596
+ if (isNumber2(char)) {
25525
25597
  offset += 1;
25526
25598
  } else {
25527
25599
  this.addToNumericResult(input, startIndex, offset, 10);
@@ -32957,11 +33029,11 @@ function convertHastNode(node) {
32957
33029
  if (whitespace(node)) {
32958
33030
  return null;
32959
33031
  }
32960
- return node.value ?? null;
33032
+ return node.value;
32961
33033
  }
32962
33034
  if (node.type === "element") {
32963
33035
  const el = { tagName: node.tagName };
32964
- if (node.properties && Object.keys(node.properties).length > 0) {
33036
+ if (Object.keys(node.properties).length > 0) {
32965
33037
  const { style, attrs } = hastPropsToJx(node.properties);
32966
33038
  if (Object.keys(attrs).length > 0) {
32967
33039
  el.attributes = attrs;
@@ -32970,8 +33042,8 @@ function convertHastNode(node) {
32970
33042
  el.style = style;
32971
33043
  }
32972
33044
  }
32973
- const kids = node.children ? convertHastChildren(node.children) : [];
32974
- if (kids.length === 1 && typeof kids[0] === "string") {
33045
+ const kids = convertHastChildren(node.children);
33046
+ if (kids.length === 1 && isString(kids[0])) {
32975
33047
  [el.textContent] = kids;
32976
33048
  } else if (kids.length > 0) {
32977
33049
  el.children = kids;
@@ -32989,7 +33061,7 @@ function hastPropsToJx(properties) {
32989
33061
  }
32990
33062
  const info = find(html3, key);
32991
33063
  const name = info.attribute;
32992
- if (name === "style" && typeof value === "string") {
33064
+ if (name === "style" && isString(value)) {
32993
33065
  parseInlineStyle(value, style);
32994
33066
  continue;
32995
33067
  }
@@ -33020,6 +33092,7 @@ var init_html_to_jx = __esm(() => {
33020
33092
  init_hast_util_from_html();
33021
33093
  init_hast_util_whitespace();
33022
33094
  init_property_information();
33095
+ init_guards();
33023
33096
  });
33024
33097
 
33025
33098
  // src/alerts.ts
@@ -33032,7 +33105,7 @@ function normalizeAlerts(config, where = "alerts") {
33032
33105
  if (config === undefined || config === true) {
33033
33106
  return { disabled, types };
33034
33107
  }
33035
- if (typeof config !== "object" || config === null || Array.isArray(config)) {
33108
+ if (!isJsonObject(config)) {
33036
33109
  throw new TypeError(`${where}: expected an object mapping alert types to element names, or false`);
33037
33110
  }
33038
33111
  for (const [type, element] of Object.entries(config)) {
@@ -33045,7 +33118,7 @@ function normalizeAlerts(config, where = "alerts") {
33045
33118
  disabled.add(key);
33046
33119
  } else if (element === true) {
33047
33120
  types.set(key, null);
33048
- } else if (typeof element === "string" && TAG_NAME.test(element)) {
33121
+ } else if (isString(element) && TAG_NAME.test(element)) {
33049
33122
  types.set(key, element);
33050
33123
  } else {
33051
33124
  throw new TypeError(`${where}.${type}: expected an element name such as "doc-note", true or false, got ${JSON.stringify(element)}`);
@@ -33056,7 +33129,7 @@ function normalizeAlerts(config, where = "alerts") {
33056
33129
  function inlineText(nodes) {
33057
33130
  let out = "";
33058
33131
  for (const node of nodes) {
33059
- if (typeof node.value === "string") {
33132
+ if (node.value !== undefined) {
33060
33133
  out += node.value;
33061
33134
  } else if (node.children) {
33062
33135
  out += inlineText(node.children);
@@ -33069,7 +33142,7 @@ function textNode(value) {
33069
33142
  }
33070
33143
  function markerOf(paragraph) {
33071
33144
  const [first] = paragraph.children ?? [];
33072
- if (first?.type !== "text" || typeof first.value !== "string") {
33145
+ if (first?.type !== "text" || first.value === undefined) {
33073
33146
  return null;
33074
33147
  }
33075
33148
  const match = MARKER2.exec(first.value);
@@ -33095,7 +33168,7 @@ function splitMarker(paragraph, settings) {
33095
33168
  const take = (node) => {
33096
33169
  if (inTitle && node.type === "break") {
33097
33170
  inTitle = false;
33098
- } else if (inTitle && node.type === "text" && typeof node.value === "string") {
33171
+ } else if (inTitle && node.type === "text" && node.value !== undefined) {
33099
33172
  const lineEnd = LINE_END.exec(node.value);
33100
33173
  if (lineEnd === null) {
33101
33174
  title.push(node);
@@ -33152,6 +33225,7 @@ function transformAlerts(tree, settings, onUnknown) {
33152
33225
  }
33153
33226
  var DEFAULT_ALERT_TITLES, ALERT_NODE = "jxAlert", TAG_NAME, MARKER2, LINE_END;
33154
33227
  var init_alerts = __esm(() => {
33228
+ init_guards();
33155
33229
  DEFAULT_ALERT_TITLES = {
33156
33230
  caution: "Caution",
33157
33231
  important: "Important",
@@ -33177,21 +33251,24 @@ function jxKey(key) {
33177
33251
  function expandDotPaths(attrs) {
33178
33252
  const result = {};
33179
33253
  for (const [key, value] of Object.entries(attrs)) {
33180
- const dotIndex = key.indexOf(".");
33181
- if (dotIndex === -1) {
33254
+ const lastDot = key.lastIndexOf(".");
33255
+ if (lastDot === -1) {
33182
33256
  result[jxKey(key)] = value;
33183
33257
  continue;
33184
33258
  }
33185
- const segments = key.split(".");
33186
33259
  let target = result;
33187
- for (let i = 0;i < segments.length - 1; i++) {
33188
- const seg = jxKey(segments[i]);
33189
- if (!(seg in target) || typeof target[seg] !== "object") {
33190
- target[seg] = {};
33260
+ for (const segment of key.slice(0, lastDot).split(".")) {
33261
+ const seg = jxKey(segment);
33262
+ const existing = seg in target ? target[seg] : undefined;
33263
+ if (isNonNullObject(existing)) {
33264
+ target = existing;
33265
+ } else {
33266
+ const nested = {};
33267
+ target[seg] = nested;
33268
+ target = nested;
33191
33269
  }
33192
- target = target[seg];
33193
33270
  }
33194
- target[jxKey(segments.at(-1))] = value;
33271
+ target[jxKey(key.slice(lastDot + 1))] = value;
33195
33272
  }
33196
33273
  return result;
33197
33274
  }
@@ -33212,22 +33289,34 @@ function applyStyleKeyMapping(styleObj) {
33212
33289
  }
33213
33290
  function routeAttributes(attrs) {
33214
33291
  const expanded = expandDotPaths(attrs);
33215
- if (expanded.style && typeof expanded.style === "object") {
33216
- expanded.style = applyStyleKeyMapping(expanded.style);
33292
+ const { style } = expanded;
33293
+ if (isNonNullObject(style)) {
33294
+ expanded.style = applyStyleKeyMapping(style);
33217
33295
  }
33218
33296
  const props = {};
33219
33297
  const attributes = {};
33220
33298
  for (const [key, value] of Object.entries(expanded)) {
33221
33299
  if (HTML_ATTR_PATTERN.test(key)) {
33222
- attributes[key] = value;
33300
+ attributes[key] = attributeValue(value);
33223
33301
  } else {
33224
33302
  props[key] = value;
33225
33303
  }
33226
33304
  }
33227
33305
  return { attributes, props };
33228
33306
  }
33307
+ function attributeValue(value) {
33308
+ return value;
33309
+ }
33310
+ function setContent(el, children) {
33311
+ const [only] = children;
33312
+ if (children.length === 1 && isString(only)) {
33313
+ el.textContent = only;
33314
+ } else if (children.length > 0) {
33315
+ el.children = children;
33316
+ }
33317
+ }
33229
33318
  function mdastNodeToJx(node) {
33230
- if (!node || typeof node !== "object") {
33319
+ if (!node) {
33231
33320
  return null;
33232
33321
  }
33233
33322
  if (node.type === "yaml" || node.type === "toml") {
@@ -33248,7 +33337,7 @@ function mdastNodeToJx(node) {
33248
33337
  }
33249
33338
  return null;
33250
33339
  }
33251
- const tagFn = JX_TAG_MAP[node.type];
33340
+ const tagFn = JX_TAG_MAP.get(node.type);
33252
33341
  if (!tagFn) {
33253
33342
  return null;
33254
33343
  }
@@ -33264,12 +33353,7 @@ function mdastNodeToJx(node) {
33264
33353
  case "listItem":
33265
33354
  case "tableRow":
33266
33355
  case "tableCell": {
33267
- const children = convertChildren(node.children ?? []);
33268
- if (children.length === 1 && typeof children[0] === "string") {
33269
- [el.textContent] = children;
33270
- } else if (children.length > 0) {
33271
- el.children = children;
33272
- }
33356
+ setContent(el, convertChildren(node.children ?? []));
33273
33357
  break;
33274
33358
  }
33275
33359
  case "inlineCode": {
@@ -33277,34 +33361,18 @@ function mdastNodeToJx(node) {
33277
33361
  break;
33278
33362
  }
33279
33363
  case "link": {
33280
- {
33281
- const linkAttrs = {
33282
- href: node.url ?? ""
33283
- };
33284
- if (node.title) {
33285
- linkAttrs.title = node.title;
33286
- }
33287
- el.attributes = linkAttrs;
33288
- }
33289
- {
33290
- const children = convertChildren(node.children ?? []);
33291
- if (children.length === 1 && typeof children[0] === "string") {
33292
- [el.textContent] = children;
33293
- } else if (children.length > 0) {
33294
- el.children = children;
33295
- }
33364
+ el.attributes = { href: node.url ?? "" };
33365
+ if (node.title) {
33366
+ el.attributes.title = node.title;
33296
33367
  }
33368
+ setContent(el, convertChildren(node.children ?? []));
33297
33369
  break;
33298
33370
  }
33299
33371
  case "image": {
33300
- const imageAttrs = {
33301
- alt: node.alt ?? "",
33302
- src: node.url ?? ""
33303
- };
33372
+ el.attributes = { alt: node.alt ?? "", src: node.url ?? "" };
33304
33373
  if (node.title) {
33305
- imageAttrs.title = node.title;
33374
+ el.attributes.title = node.title;
33306
33375
  }
33307
- el.attributes = imageAttrs;
33308
33376
  break;
33309
33377
  }
33310
33378
  case "list": {
@@ -33317,13 +33385,11 @@ function mdastNodeToJx(node) {
33317
33385
  break;
33318
33386
  }
33319
33387
  case "code": {
33320
- el.children = [
33321
- {
33322
- tagName: "code",
33323
- textContent: node.value ?? null,
33324
- ...node.lang ? { className: `language-${node.lang}` } : {}
33325
- }
33326
- ];
33388
+ const code = { tagName: "code", textContent: node.value ?? null };
33389
+ if (node.lang) {
33390
+ code.className = `language-${node.lang}`;
33391
+ }
33392
+ el.children = [code];
33327
33393
  break;
33328
33394
  }
33329
33395
  case "thematicBreak":
@@ -33333,16 +33399,21 @@ function mdastNodeToJx(node) {
33333
33399
  case "table": {
33334
33400
  const rows = convertChildren(node.children ?? []);
33335
33401
  const [headerRow] = rows;
33336
- if (headerRow && typeof headerRow === "object" && Array.isArray(headerRow.children)) {
33402
+ if (isNonNullObject(headerRow) && Array.isArray(headerRow.children)) {
33337
33403
  for (const cell of headerRow.children) {
33338
- if (cell && typeof cell === "object" && cell.tagName === "td") {
33404
+ if (isNonNullObject(cell) && cell.tagName === "td") {
33339
33405
  cell.tagName = "th";
33340
33406
  }
33341
33407
  }
33342
33408
  }
33343
- const thead = rows.length > 0 ? { children: [rows[0]], tagName: "thead" } : null;
33344
- const tbody = rows.length > 1 ? { children: rows.slice(1), tagName: "tbody" } : null;
33345
- el.children = [thead, tbody].filter(Boolean);
33409
+ const sections = [];
33410
+ if (headerRow !== undefined) {
33411
+ sections.push({ children: [headerRow], tagName: "thead" });
33412
+ }
33413
+ if (rows.length > 1) {
33414
+ sections.push({ children: rows.slice(1), tagName: "tbody" });
33415
+ }
33416
+ el.children = sections;
33346
33417
  break;
33347
33418
  }
33348
33419
  default: {
@@ -33354,10 +33425,7 @@ function mdastNodeToJx(node) {
33354
33425
  function alertToJx(node) {
33355
33426
  const body = convertChildren(node.children ?? []);
33356
33427
  if (node.element) {
33357
- const attributes = { "data-alert": node.alert };
33358
- if (node.titleNodes) {
33359
- attributes["data-title"] = inlineText(node.titleNodes).trim();
33360
- }
33428
+ const attributes = node.titleNodes ? { "data-alert": node.alert, "data-title": inlineText(node.titleNodes).trim() } : { "data-alert": node.alert };
33361
33429
  const el = { attributes, tagName: node.element };
33362
33430
  if (body.length > 0) {
33363
33431
  el.children = body;
@@ -33367,8 +33435,9 @@ function alertToJx(node) {
33367
33435
  const title = { className: "jx-alert-title", tagName: "p" };
33368
33436
  if (node.titleNodes) {
33369
33437
  const inline = convertChildren(node.titleNodes);
33370
- if (inline.length === 1 && typeof inline[0] === "string") {
33371
- [title.textContent] = inline;
33438
+ const [only] = inline;
33439
+ if (inline.length === 1 && isString(only)) {
33440
+ title.textContent = only;
33372
33441
  } else {
33373
33442
  title.children = inline;
33374
33443
  }
@@ -33383,13 +33452,14 @@ function alertToJx(node) {
33383
33452
  };
33384
33453
  }
33385
33454
  function directiveToJx(node) {
33386
- if (PROTOTYPE_DIRECTIVE_NAMES.has(node.name)) {
33387
- return prototypeDirectiveToJx(node);
33455
+ const name = node.name;
33456
+ if (PROTOTYPE_DIRECTIVE_NAMES.has(name)) {
33457
+ return prototypeDirectiveToJx(node, name);
33388
33458
  }
33389
- const el = { tagName: node.name };
33459
+ const el = { tagName: name };
33390
33460
  if (node.attributes && Object.keys(node.attributes).length > 0) {
33391
33461
  const { props, attributes } = routeAttributes(node.attributes);
33392
- const isCustomElement = node.name.includes("-");
33462
+ const isCustomElement = name.includes("-");
33393
33463
  if (isCustomElement) {
33394
33464
  for (const [key, value] of Object.entries(props)) {
33395
33465
  if (key === "style" || key === "children" || key === "textContent" || key === "innerHTML" || key.startsWith("$")) {
@@ -33398,7 +33468,7 @@ function directiveToJx(node) {
33398
33468
  if (!el.attributes) {
33399
33469
  el.attributes = {};
33400
33470
  }
33401
- el.attributes[key] = value;
33471
+ el.attributes[key] = attributeValue(value);
33402
33472
  }
33403
33473
  }
33404
33474
  } else {
@@ -33409,7 +33479,7 @@ function directiveToJx(node) {
33409
33479
  if (!el.attributes) {
33410
33480
  el.attributes = {};
33411
33481
  }
33412
- el.attributes[key] = value;
33482
+ el.attributes[key] = attributeValue(value);
33413
33483
  }
33414
33484
  }
33415
33485
  }
@@ -33419,12 +33489,7 @@ function directiveToJx(node) {
33419
33489
  }
33420
33490
  if (node.type === "textDirective") {
33421
33491
  if (node.children && node.children.length > 0) {
33422
- const children = convertChildren(node.children ?? []);
33423
- if (children.length === 1 && typeof children[0] === "string") {
33424
- [el.textContent] = children;
33425
- } else if (children.length > 0) {
33426
- el.children = children;
33427
- }
33492
+ setContent(el, convertChildren(node.children));
33428
33493
  }
33429
33494
  return el;
33430
33495
  }
@@ -33433,7 +33498,7 @@ function directiveToJx(node) {
33433
33498
  }
33434
33499
  if (node.children && node.children.length > 0) {
33435
33500
  const jxChildren = [];
33436
- const isPhrasingParent = PHRASING_ELEMENTS.has(node.name);
33501
+ const isPhrasingParent = PHRASING_ELEMENTS.has(name);
33437
33502
  for (const child of node.children) {
33438
33503
  if (isPhrasingParent && child.type === "paragraph") {
33439
33504
  for (const inline of child.children ?? []) {
@@ -33459,16 +33524,14 @@ function directiveToJx(node) {
33459
33524
  }
33460
33525
  }
33461
33526
  }
33462
- if (el.children && typeof el.children === "object" && !Array.isArray(el.children)) {} else if (jxChildren.length === 1 && typeof jxChildren[0] === "string") {
33463
- [el.textContent] = jxChildren;
33464
- } else if (jxChildren.length > 0) {
33465
- el.children = jxChildren;
33527
+ if (!isNonNullObject(el.children) || Array.isArray(el.children)) {
33528
+ setContent(el, jxChildren);
33466
33529
  }
33467
33530
  }
33468
33531
  return el;
33469
33532
  }
33470
- function prototypeDirectiveToJx(node) {
33471
- const el = { $prototype: node.name };
33533
+ function prototypeDirectiveToJx(node, name) {
33534
+ const el = { $prototype: name };
33472
33535
  if (node.attributes && Object.keys(node.attributes).length > 0) {
33473
33536
  const expanded = expandDotPaths(node.attributes);
33474
33537
  for (const [key, value] of Object.entries(expanded)) {
@@ -33479,7 +33542,7 @@ function prototypeDirectiveToJx(node) {
33479
33542
  }
33480
33543
  }
33481
33544
  const children = convertChildren(node.children ?? []);
33482
- const template = children.find((c) => c != null && typeof c === "object");
33545
+ const template = children.find((c) => !isString(c));
33483
33546
  if (template) {
33484
33547
  el.map = template;
33485
33548
  }
@@ -33489,17 +33552,19 @@ function convertChildren(children) {
33489
33552
  if (!children) {
33490
33553
  return [];
33491
33554
  }
33492
- return children.flatMap((n) => mdastNodeToJx(n)).filter((c) => c != null);
33555
+ return children.flatMap((n) => mdastNodeToJx(n) ?? []);
33493
33556
  }
33494
33557
  function transpileJxMarkdown(source) {
33495
33558
  const processor = unified().use(remarkParse).use(remarkFrontmatter, ["yaml"]).use(import_remark_parse_frontmatter.default).use(remarkGfm).use(remarkDirective);
33496
33559
  const tree = processor.parse(source);
33497
33560
  const vfile = { data: {} };
33498
33561
  processor.runSync(tree, vfile);
33499
- const frontmatter = vfile.data?.frontmatter ?? {};
33562
+ const frontmatter = vfile.data.frontmatter ?? {};
33500
33563
  const doc = {};
33501
- for (const [key, value] of Object.entries(frontmatter)) {
33502
- doc[key] = value;
33564
+ if (!isNumber(frontmatter) && !isBoolean(frontmatter)) {
33565
+ for (const [key, value] of Object.entries(frontmatter)) {
33566
+ doc[key] = value;
33567
+ }
33503
33568
  }
33504
33569
  const bodyNodes = tree.children.filter((n) => n.type !== "yaml" && n.type !== "toml");
33505
33570
  const children = [];
@@ -33523,10 +33588,10 @@ function slugifyHeading(text) {
33523
33588
  return text.normalize("NFC").toLowerCase().replaceAll(/[^\p{L}\p{N}_\s-]/gu, "").replaceAll(/\s+/gu, "-").replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "");
33524
33589
  }
33525
33590
  function jxNodeText(node) {
33526
- if (typeof node === "string") {
33591
+ if (isString(node)) {
33527
33592
  return node;
33528
33593
  }
33529
- let out = typeof node.textContent === "string" ? node.textContent : "";
33594
+ let out = isString(node.textContent) ? node.textContent : "";
33530
33595
  if (Array.isArray(node.children)) {
33531
33596
  for (const child of node.children) {
33532
33597
  out += jxNodeText(child);
@@ -33539,13 +33604,13 @@ function assignHeadingIds(children) {
33539
33604
  const seen = new Map;
33540
33605
  function walk(nodes) {
33541
33606
  for (const node of nodes) {
33542
- if (typeof node !== "object" || node === null) {
33607
+ if (!isNonNullObject(node)) {
33543
33608
  continue;
33544
33609
  }
33545
- const tag = typeof node.tagName === "string" ? node.tagName : "";
33610
+ const tag = isString(node.tagName) ? node.tagName : "";
33546
33611
  if (tag && HEADING_TAGS.has(tag)) {
33547
33612
  const text = jxNodeText(node).trim();
33548
- let id = typeof node.id === "string" && node.id.length > 0 ? node.id : "";
33613
+ let id = isString(node.id) && node.id.length > 0 ? node.id : "";
33549
33614
  if (id) {
33550
33615
  seen.set(id, (seen.get(id) ?? 0) + 1);
33551
33616
  } else {
@@ -33575,6 +33640,7 @@ var init_transpile = __esm(() => {
33575
33640
  init_remark_gfm();
33576
33641
  init_remark_directive();
33577
33642
  init_html_to_jx();
33643
+ init_guards();
33578
33644
  init_alerts();
33579
33645
  init_html_to_jx();
33580
33646
  import_remark_parse_frontmatter = __toESM(require_dist2(), 1);
@@ -33642,79 +33708,26 @@ var init_transpile = __esm(() => {
33642
33708
  "summary",
33643
33709
  "dt"
33644
33710
  ]);
33645
- JX_TAG_MAP = {
33646
- blockquote: () => "blockquote",
33647
- break: () => "br",
33648
- code: () => "pre",
33649
- delete: () => "del",
33650
- emphasis: () => "em",
33651
- heading: (n) => `h${n.depth}`,
33652
- image: () => "img",
33653
- inlineCode: () => "code",
33654
- link: () => "a",
33655
- list: (n) => n.ordered ? "ol" : "ul",
33656
- listItem: () => "li",
33657
- paragraph: () => "p",
33658
- strong: () => "strong",
33659
- table: () => "table",
33660
- tableCell: (n) => n.isHeader ? "th" : "td",
33661
- tableRow: () => "tr",
33662
- thematicBreak: () => "hr"
33663
- };
33664
- HEADING_TAGS = new Set(["h1", "h2", "h3", "h4", "h5", "h6"]);
33665
- });
33666
-
33667
- // ../../packages/schema/src/guards.ts
33668
- function isJsonObject(value) {
33669
- return typeof value === "object" && value !== null && !Array.isArray(value);
33670
- }
33671
- function isRef(value) {
33672
- return isJsonObject(value) && typeof value.$ref === "string";
33673
- }
33674
- function isTagExpression(tagName) {
33675
- if (!isJsonObject(tagName) || !isJsonObject(tagName.$expression)) {
33676
- return false;
33677
- }
33678
- const expression = tagName.$expression;
33679
- if (expression.operator === "?:") {
33680
- return typeof expression.value === "string" && typeof expression.initial === "string";
33681
- }
33682
- if (expression.operator === "switch") {
33683
- return isJsonObject(expression.cases) && Object.values(expression.cases).every((tag) => typeof tag === "string") && typeof expression.default === "string";
33684
- }
33685
- return false;
33686
- }
33687
- function tagNameCandidates(tagName) {
33688
- if (typeof tagName === "string") {
33689
- return [tagName];
33690
- }
33691
- if (!isTagExpression(tagName)) {
33692
- return [];
33693
- }
33694
- const expression = tagName.$expression;
33695
- if (expression.operator === "?:") {
33696
- return [...new Set([expression.value, expression.initial])];
33697
- }
33698
- return [...new Set([...Object.values(expression.cases), expression.default])];
33699
- }
33700
- var SCHEMA_KEYWORDS;
33701
- var init_guards = __esm(() => {
33702
- SCHEMA_KEYWORDS = new Set([
33703
- "type",
33704
- "enum",
33705
- "minimum",
33706
- "maximum",
33707
- "minLength",
33708
- "maxLength",
33709
- "pattern",
33710
- "format",
33711
- "items",
33712
- "properties",
33713
- "required",
33714
- "description",
33715
- "title",
33716
- "$comment"
33711
+ JX_TAG_MAP = new Map([
33712
+ ["blockquote", () => "blockquote"],
33713
+ ["break", () => "br"],
33714
+ ["code", () => "pre"],
33715
+ ["delete", () => "del"],
33716
+ ["emphasis", () => "em"],
33717
+ ["heading", (n) => `h${n.depth}`],
33718
+ ["image", () => "img"],
33719
+ ["inlineCode", () => "code"],
33720
+ ["link", () => "a"],
33721
+ ["list", (n) => n.ordered ? "ol" : "ul"],
33722
+ ["listItem", () => "li"],
33723
+ ["paragraph", () => "p"],
33724
+ ["strong", () => "strong"],
33725
+ ["table", () => "table"],
33726
+ ["tableCell", (n) => n.isHeader ? "th" : "td"],
33727
+ ["tableRow", () => "tr"],
33728
+ ["thematicBreak", () => "hr"]
33717
33729
  ]);
33730
+ HEADING_TAGS = new Set(["h1", "h2", "h3", "h4", "h5", "h6"]);
33718
33731
  });
33719
33732
 
33720
33733
  // ../../node_modules/remark-stringify/lib/index.js
@@ -40729,9 +40742,152 @@ var init_dist3 = __esm(() => {
40729
40742
  $visitAsync = visit2.visitAsync;
40730
40743
  });
40731
40744
 
40745
+ // src/source-style.ts
40746
+ function frontmatterText(source) {
40747
+ const match = FRONTMATTER_RE.exec(source);
40748
+ if (!match) {
40749
+ return null;
40750
+ }
40751
+ return match[1] ?? "";
40752
+ }
40753
+ function bodyText(source) {
40754
+ return source.replace(FRONTMATTER_RE, "");
40755
+ }
40756
+ function sameValue2(a, b) {
40757
+ if (a === b) {
40758
+ return true;
40759
+ }
40760
+ if (Array.isArray(a) || Array.isArray(b)) {
40761
+ return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, index) => sameValue2(item, b[index]));
40762
+ }
40763
+ if (!isJsonObject(a) || !isJsonObject(b)) {
40764
+ return false;
40765
+ }
40766
+ const keys = Object.keys(a).filter((key) => a[key] !== undefined);
40767
+ const otherKeys = Object.keys(b).filter((key) => b[key] !== undefined);
40768
+ return keys.length === otherKeys.length && keys.every((key) => sameValue2(a[key], b[key]));
40769
+ }
40770
+ function lineStart(text, offset) {
40771
+ return text.lastIndexOf(`
40772
+ `, offset - 1) + 1;
40773
+ }
40774
+ function lineEnd(text, offset) {
40775
+ const newline = text.indexOf(`
40776
+ `, offset);
40777
+ return newline === -1 ? text.length : newline + 1;
40778
+ }
40779
+ function sourceEntries(text) {
40780
+ const doc = $parseDocument(text);
40781
+ if (doc.errors.length > 0 || doc.warnings.length > 0) {
40782
+ return null;
40783
+ }
40784
+ const { contents } = doc;
40785
+ if (!$isMap(contents) || contents.flow === true) {
40786
+ return null;
40787
+ }
40788
+ const pairs = contents.items;
40789
+ const keys = [];
40790
+ for (const { key } of pairs) {
40791
+ if (!$isScalar(key) || !key.range || !isString(key.value)) {
40792
+ return null;
40793
+ }
40794
+ keys.push({ name: key.value, range: key.range });
40795
+ }
40796
+ const js = doc.toJS();
40797
+ const values = isJsonObject(js) ? js : {};
40798
+ const entries = [];
40799
+ for (const [index, { name, range }] of keys.entries()) {
40800
+ const end = pairs[index]?.value?.range?.[1] ?? range[1];
40801
+ entries.push({
40802
+ key: name,
40803
+ start: lineStart(text, range[0]),
40804
+ value: values[name],
40805
+ valueEnd: lineEnd(text, Math.max(end - 1, range[0]))
40806
+ });
40807
+ }
40808
+ return entries;
40809
+ }
40810
+ function spliceFrontmatter(frontmatter, source, write) {
40811
+ const entries = sourceEntries(source);
40812
+ if (!entries) {
40813
+ return null;
40814
+ }
40815
+ const present = (key) => Object.hasOwn(frontmatter, key) && frontmatter[key] !== undefined;
40816
+ const segments = [];
40817
+ const head = source.slice(0, entries[0]?.start ?? source.length);
40818
+ if (head.trim().length > 0) {
40819
+ segments.push(head);
40820
+ }
40821
+ for (const [index, entry] of entries.entries()) {
40822
+ const chunkEnd = entries[index + 1]?.start ?? source.length;
40823
+ if (!present(entry.key)) {
40824
+ continue;
40825
+ }
40826
+ if (sameValue2(entry.value, frontmatter[entry.key])) {
40827
+ segments.push(source.slice(entry.start, chunkEnd));
40828
+ continue;
40829
+ }
40830
+ const tail = source.slice(Math.min(entry.valueEnd, chunkEnd), chunkEnd);
40831
+ segments.push(`${write({ [entry.key]: frontmatter[entry.key] })}
40832
+ ${tail}`);
40833
+ }
40834
+ const known = new Set(entries.map((entry) => entry.key));
40835
+ const added = {};
40836
+ for (const [key, value] of Object.entries(frontmatter)) {
40837
+ if (!known.has(key) && value !== undefined) {
40838
+ added[key] = value;
40839
+ }
40840
+ }
40841
+ if (Object.keys(added).length > 0) {
40842
+ segments.push(write(added));
40843
+ }
40844
+ return segments.map((segment) => segment.endsWith(`
40845
+ `) ? segment : `${segment}
40846
+ `).join("").replace(/\s+$/u, "");
40847
+ }
40848
+ function startOffset(node) {
40849
+ const position = node.position;
40850
+ const offset = position?.start?.offset;
40851
+ return isNumber(offset) ? offset : null;
40852
+ }
40853
+ function markdownMarkers(tree, source) {
40854
+ const markers = { bullet: "-", emphasis: "*", strong: "*" };
40855
+ const seen = new Set;
40856
+ const visit = (node) => {
40857
+ const offset = startOffset(node);
40858
+ if (offset !== null && !seen.has(node.type)) {
40859
+ const char = source[offset];
40860
+ if ((node.type === "emphasis" || node.type === "strong") && (char === "*" || char === "_")) {
40861
+ markers[node.type] = char;
40862
+ seen.add(node.type);
40863
+ } else if (node.type === "listItem" && (char === "-" || char === "*" || char === "+")) {
40864
+ markers.bullet = char;
40865
+ seen.add(node.type);
40866
+ }
40867
+ }
40868
+ for (const child of node.children ?? []) {
40869
+ visit(child);
40870
+ }
40871
+ };
40872
+ visit(tree);
40873
+ return markers;
40874
+ }
40875
+ var FRONTMATTER_RE;
40876
+ var init_source_style = __esm(() => {
40877
+ init_dist3();
40878
+ init_guards();
40879
+ FRONTMATTER_RE = /^---\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n|$)/u;
40880
+ });
40881
+
40732
40882
  // src/serialize.ts
40733
40883
  function textOf(el) {
40734
- return el && typeof el.textContent === "string" ? el.textContent : undefined;
40884
+ return el && isString(el.textContent) ? el.textContent : undefined;
40885
+ }
40886
+ function childList(el) {
40887
+ return Array.isArray(el.children) ? el.children : [];
40888
+ }
40889
+ function hasMdastType(tag) {
40890
+ return tag in TAG_MDAST_MAP;
40735
40891
  }
40736
40892
  function isInlineType(type) {
40737
40893
  return ["text", "emphasis", "strong", "delete", "inlineCode", "link", "image", "break"].includes(type);
@@ -40741,14 +40897,23 @@ function codeLang(codeChild) {
40741
40897
  const lang = String(cls).replace("language-", "");
40742
40898
  return lang || null;
40743
40899
  }
40900
+ function hasJxTagName(type) {
40901
+ return type in MDAST_TAG_MAP;
40902
+ }
40744
40903
  function mdastToJx(mdast) {
40745
40904
  if (mdast.type === "root") {
40746
40905
  return {
40747
- children: (mdast.children ?? []).filter((n) => n.type !== "yaml" && n.type !== "toml").flatMap((n) => convertMdastNode(n)).filter(Boolean)
40906
+ children: convertMdastChildren((mdast.children ?? []).filter((n) => n.type !== "yaml" && n.type !== "toml"))
40748
40907
  };
40749
40908
  }
40750
40909
  return convertMdastNode(mdast);
40751
40910
  }
40911
+ function convertMdastChildren(nodes) {
40912
+ return nodes.flatMap((n) => {
40913
+ const converted = convertMdastNode(n);
40914
+ return converted ? [converted] : [];
40915
+ });
40916
+ }
40752
40917
  function convertMdastNode(node) {
40753
40918
  if (!node) {
40754
40919
  return null;
@@ -40761,15 +40926,16 @@ function convertMdastNode(node) {
40761
40926
  return null;
40762
40927
  }
40763
40928
  const nodes = htmlToJx(node.value);
40764
- return nodes.length === 1 ? nodes[0] : { children: nodes, tagName: "div" };
40929
+ const [only] = nodes;
40930
+ return nodes.length === 1 && only !== undefined ? only : { children: nodes, tagName: "div" };
40765
40931
  }
40766
- const tagFn = MDAST_TAG_MAP[node.type];
40932
+ const tagFn = hasJxTagName(node.type) ? MDAST_TAG_MAP[node.type] : undefined;
40767
40933
  if (!tagFn) {
40768
40934
  return null;
40769
40935
  }
40770
40936
  const tag = tagFn(node);
40771
40937
  const el = { tagName: tag };
40772
- const childNodes = () => (node.children ?? []).flatMap((n) => convertMdastNode(n)).filter(Boolean);
40938
+ const childNodes = () => convertMdastChildren(node.children ?? []);
40773
40939
  const flattenOrChildren = () => {
40774
40940
  if (node.children?.length === 1 && node.children[0].type === "text") {
40775
40941
  el.textContent = node.children[0].value ?? null;
@@ -40825,13 +40991,11 @@ function convertMdastNode(node) {
40825
40991
  break;
40826
40992
  }
40827
40993
  case "code": {
40828
- el.children = [
40829
- {
40830
- tagName: "code",
40831
- textContent: node.value ?? null,
40832
- ...node.lang ? { className: `language-${node.lang}` } : {}
40833
- }
40834
- ];
40994
+ const code = { tagName: "code", textContent: node.value ?? null };
40995
+ if (node.lang) {
40996
+ code.className = `language-${node.lang}`;
40997
+ }
40998
+ el.children = [code];
40835
40999
  break;
40836
41000
  }
40837
41001
  case "thematicBreak":
@@ -40839,13 +41003,15 @@ function convertMdastNode(node) {
40839
41003
  break;
40840
41004
  }
40841
41005
  case "table": {
40842
- const rows = childNodes();
40843
- const thead = rows.length > 0 ? { children: [rows[0]], tagName: "thead" } : null;
40844
- const tbody = rows.length > 1 ? {
40845
- children: rows.slice(1),
40846
- tagName: "tbody"
40847
- } : null;
40848
- el.children = [thead, tbody].filter(Boolean);
41006
+ const [headRow, ...bodyRows] = childNodes();
41007
+ const sections = [];
41008
+ if (headRow !== undefined) {
41009
+ sections.push({ children: [headRow], tagName: "thead" });
41010
+ }
41011
+ if (bodyRows.length > 0) {
41012
+ sections.push({ children: bodyRows, tagName: "tbody" });
41013
+ }
41014
+ el.children = sections;
40849
41015
  break;
40850
41016
  }
40851
41017
  default: {
@@ -40856,7 +41022,7 @@ function convertMdastNode(node) {
40856
41022
  }
40857
41023
  function convertDirective(node) {
40858
41024
  if (node.name && PROTOTYPE_DIRECTIVE_NAMES2.has(node.name)) {
40859
- return prototypeDirectiveToJx2(node);
41025
+ return prototypeDirectiveToJx2(node, node.name);
40860
41026
  }
40861
41027
  const el = { tagName: node.name ?? "div" };
40862
41028
  if (node.attributes && Object.keys(node.attributes).length > 0) {
@@ -40866,15 +41032,15 @@ function convertDirective(node) {
40866
41032
  if (node.children?.length === 1 && node.children[0].type === "text") {
40867
41033
  el.textContent = node.children[0].value ?? null;
40868
41034
  } else if (node.children?.length) {
40869
- el.children = node.children.flatMap((n) => convertMdastNode(n)).filter(Boolean);
41035
+ el.children = convertMdastChildren(node.children);
40870
41036
  }
40871
41037
  } else if (node.type === "containerDirective" && node.children?.length) {
40872
- el.children = node.children.flatMap((n) => convertMdastNode(n)).filter(Boolean);
41038
+ el.children = convertMdastChildren(node.children);
40873
41039
  }
40874
41040
  return el;
40875
41041
  }
40876
- function prototypeDirectiveToJx2(node) {
40877
- const el = { $prototype: node.name };
41042
+ function prototypeDirectiveToJx2(node, name) {
41043
+ const el = { $prototype: name };
40878
41044
  if (node.attributes && Object.keys(node.attributes).length > 0) {
40879
41045
  const expanded = expandDotPaths(node.attributes);
40880
41046
  for (const [key, value] of Object.entries(expanded)) {
@@ -40885,8 +41051,7 @@ function prototypeDirectiveToJx2(node) {
40885
41051
  }
40886
41052
  }
40887
41053
  if (node.children?.length) {
40888
- const children = node.children.flatMap((n) => convertMdastNode(n)).filter(Boolean);
40889
- const template = children.find((c) => c != null && typeof c === "object");
41054
+ const template = convertMdastChildren(node.children).find((child) => isNodeObject(child));
40890
41055
  if (template) {
40891
41056
  el.map = template;
40892
41057
  }
@@ -40895,9 +41060,19 @@ function prototypeDirectiveToJx2(node) {
40895
41060
  }
40896
41061
  function jxToMdast(jx, opts = {}) {
40897
41062
  const allowlist = normalizeAllowlist(opts.allowlist);
40898
- const childArray = Array.isArray(jx.children) ? jx.children : [];
40899
- const children = childArray.map((child) => convertJxNode(child, true, allowlist)).filter(Boolean);
40900
- return { children, type: "root" };
41063
+ return { children: convertJxChildren(childList(jx), true, allowlist), type: "root" };
41064
+ }
41065
+ function convertJxChildren(children, isBlock, allowlist) {
41066
+ return children.flatMap((child) => {
41067
+ const converted = convertJxNode(child, isBlock, allowlist);
41068
+ return converted ? [converted] : [];
41069
+ });
41070
+ }
41071
+ function attributeText(value) {
41072
+ return isString(value) ? value : value ? String(value) : "";
41073
+ }
41074
+ function attributeTitle(value) {
41075
+ return isString(value) ? value : value ? String(value) : null;
40901
41076
  }
40902
41077
  function normalizeAllowlist(allowlist) {
40903
41078
  if (!allowlist) {
@@ -40914,18 +41089,86 @@ function hasJxProps(el) {
40914
41089
  }
40915
41090
  return false;
40916
41091
  }
40917
- function convertJxNode(el, isBlock, allowlist) {
40918
- if (typeof el === "string" || typeof el === "number") {
40919
- return { type: "text", value: String(el) };
41092
+ function hasOnlyMarkdownAttributes(el, tag) {
41093
+ const allowed = MD_ATTRIBUTES.get(tag);
41094
+ return Object.keys(el.attributes ?? {}).every((name) => allowed?.has(name) ?? false);
41095
+ }
41096
+ function partChildren(el) {
41097
+ return childList(el).filter((child) => !isString(child) || child.trim() !== "");
41098
+ }
41099
+ function plainPart(slot, tag) {
41100
+ if (slot === undefined || isString(slot) || slot.tagName !== tag) {
41101
+ return null;
41102
+ }
41103
+ const attributes = Object.keys(slot.attributes ?? {});
41104
+ return attributes.length === 0 && !hasJxProps(slot) ? slot : null;
41105
+ }
41106
+ function isGfmCell(cell) {
41107
+ if (cell.textContent != null) {
41108
+ return !String(cell.textContent).includes(`
41109
+ `);
41110
+ }
41111
+ return childList(cell).every((child) => isString(child) ? !child.includes(`
41112
+ `) : isString(child.tagName) && (MD_INLINE.has(child.tagName) || child.tagName === "span"));
41113
+ }
41114
+ function gfmRowCells(row, cellTag) {
41115
+ const tr = plainPart(row, "tr");
41116
+ if (!tr || tr.textContent != null) {
41117
+ return null;
41118
+ }
41119
+ const cells = [];
41120
+ for (const slot of partChildren(tr)) {
41121
+ const cell = plainPart(slot, cellTag);
41122
+ if (!cell || !isGfmCell(cell)) {
41123
+ return null;
41124
+ }
41125
+ cells.push(cell);
41126
+ }
41127
+ return cells.length > 0 ? cells : null;
41128
+ }
41129
+ function gfmTableRows(el) {
41130
+ if (el.textContent != null) {
41131
+ return null;
41132
+ }
41133
+ const [headSlot, bodySlot, ...rest] = partChildren(el);
41134
+ const thead = plainPart(headSlot, "thead");
41135
+ if (!thead || rest.length > 0) {
41136
+ return null;
41137
+ }
41138
+ const headRows = partChildren(thead);
41139
+ const head = headRows.length === 1 ? gfmRowCells(headRows[0], "th") : null;
41140
+ if (!head) {
41141
+ return null;
41142
+ }
41143
+ if (bodySlot === undefined) {
41144
+ return { body: [], head };
41145
+ }
41146
+ const tbody = plainPart(bodySlot, "tbody");
41147
+ const rows = tbody ? partChildren(tbody) : [];
41148
+ const body = [];
41149
+ for (const row of rows) {
41150
+ const cells = gfmRowCells(row, "td");
41151
+ if (!cells || cells.length !== head.length) {
41152
+ return null;
41153
+ }
41154
+ body.push(cells);
41155
+ }
41156
+ return body.length > 0 ? { body, head } : null;
41157
+ }
41158
+ function convertJxNode(slot, isBlock, allowlist) {
41159
+ if (isString(slot) || isNumber(slot)) {
41160
+ return { type: "text", value: String(slot) };
40920
41161
  }
40921
- if (!el || typeof el !== "object") {
41162
+ if (!isNonNullObject(slot)) {
40922
41163
  return null;
40923
41164
  }
41165
+ const el = slot;
40924
41166
  const tag = serializableTag(el.tagName) || "div";
40925
- if (!allowlist.has(tag) || hasJxProps(el)) {
41167
+ const tableRows = tag === "table" ? gfmTableRows(el) : null;
41168
+ if (!allowlist.has(tag) || hasJxProps(el) || !hasOnlyMarkdownAttributes(el, tag) || TABLE_PARTS.has(tag) || tag === "table" && tableRows === null || isBlock && tag === "img") {
40926
41169
  return convertToDirective(el, isBlock, allowlist);
40927
41170
  }
40928
- const mdastType = TAG_MDAST_MAP[tag];
41171
+ const mdastType = hasMdastType(tag) ? TAG_MDAST_MAP[tag] : undefined;
40929
41172
  if (!mdastType) {
40930
41173
  return null;
40931
41174
  }
@@ -40933,7 +41176,7 @@ function convertJxNode(el, isBlock, allowlist) {
40933
41176
  if (e.textContent != null) {
40934
41177
  return [{ type: "text", value: String(e.textContent) }];
40935
41178
  }
40936
- return (e.children ?? []).map((c) => convertJxNode(c, false, allowlist)).filter(Boolean);
41179
+ return convertJxChildren(childList(e), false, allowlist);
40937
41180
  };
40938
41181
  const block = (e) => {
40939
41182
  if (e.textContent != null) {
@@ -40944,7 +41187,7 @@ function convertJxNode(el, isBlock, allowlist) {
40944
41187
  }
40945
41188
  ];
40946
41189
  }
40947
- return (e.children ?? []).map((c) => convertJxNode(c, true, allowlist)).filter(Boolean);
41190
+ return convertJxChildren(childList(e), true, allowlist);
40948
41191
  };
40949
41192
  switch (mdastType) {
40950
41193
  case "heading": {
@@ -40971,17 +41214,17 @@ function convertJxNode(el, isBlock, allowlist) {
40971
41214
  case "link": {
40972
41215
  return {
40973
41216
  children: inline(el),
40974
- title: el.attributes?.title ?? null,
41217
+ title: attributeTitle(el.attributes?.title),
40975
41218
  type: "link",
40976
- url: el.attributes?.href ?? ""
41219
+ url: attributeText(el.attributes?.href)
40977
41220
  };
40978
41221
  }
40979
41222
  case "image": {
40980
41223
  return {
40981
- alt: el.attributes?.alt ?? "",
40982
- title: el.attributes?.title ?? null,
41224
+ alt: attributeText(el.attributes?.alt),
41225
+ title: attributeTitle(el.attributes?.title),
40983
41226
  type: "image",
40984
- url: el.attributes?.src ?? ""
41227
+ url: attributeText(el.attributes?.src)
40985
41228
  };
40986
41229
  }
40987
41230
  case "blockquote": {
@@ -40989,7 +41232,7 @@ function convertJxNode(el, isBlock, allowlist) {
40989
41232
  }
40990
41233
  case "list": {
40991
41234
  return {
40992
- children: (el.children ?? []).map((c) => convertJxNode(c, true, allowlist)).filter(Boolean),
41235
+ children: convertJxChildren(childList(el), true, allowlist),
40993
41236
  ordered: tag === "ol",
40994
41237
  spread: false,
40995
41238
  start: tag === "ol" ? Math.trunc(Number(el.attributes?.start)) || 1 : null,
@@ -41000,7 +41243,8 @@ function convertJxNode(el, isBlock, allowlist) {
41000
41243
  return { children: block(el), spread: false, type: "listItem" };
41001
41244
  }
41002
41245
  case "code": {
41003
- const codeChild = Array.isArray(el.children) ? el.children[0] : undefined;
41246
+ const [first] = childList(el);
41247
+ const codeChild = isString(first) ? undefined : first;
41004
41248
  return {
41005
41249
  lang: codeLang(codeChild),
41006
41250
  type: "code",
@@ -41014,36 +41258,20 @@ function convertJxNode(el, isBlock, allowlist) {
41014
41258
  return { type: "break" };
41015
41259
  }
41016
41260
  case "table": {
41017
- const rows = [];
41018
- for (const section of el.children ?? []) {
41019
- if (typeof section === "string") {
41020
- continue;
41021
- }
41022
- if (section.tagName === "thead" || section.tagName === "tbody") {
41023
- for (const row of section.children ?? []) {
41024
- const mdRow = convertJxNode(row, true, allowlist);
41025
- if (mdRow) {
41026
- if (section.tagName === "thead") {
41027
- for (const cell of mdRow.children ?? []) {
41028
- cell.isHeader = true;
41029
- }
41030
- }
41031
- rows.push(mdRow);
41032
- }
41033
- }
41034
- }
41035
- }
41036
- return { children: rows, type: "table" };
41037
- }
41038
- case "tableRow": {
41039
- return {
41040
- children: (el.children ?? []).map((c) => convertJxNode(c, false, allowlist)).filter(Boolean),
41261
+ const { body, head } = tableRows ?? { body: [], head: [] };
41262
+ const row = (cells, isHeader) => ({
41263
+ children: cells.map((cell) => ({
41264
+ children: inline(cell),
41265
+ type: "tableCell",
41266
+ ...isHeader && { isHeader: true }
41267
+ })),
41041
41268
  type: "tableRow"
41269
+ });
41270
+ return {
41271
+ children: [row(head, true), ...body.map((cells) => row(cells, false))],
41272
+ type: "table"
41042
41273
  };
41043
41274
  }
41044
- case "tableCell": {
41045
- return { children: inline(el), type: "tableCell" };
41046
- }
41047
41275
  default: {
41048
41276
  break;
41049
41277
  }
@@ -41051,7 +41279,7 @@ function convertJxNode(el, isBlock, allowlist) {
41051
41279
  return null;
41052
41280
  }
41053
41281
  function serializableTag(tagName) {
41054
- if (typeof tagName === "string") {
41282
+ if (isString(tagName)) {
41055
41283
  return tagName;
41056
41284
  }
41057
41285
  if (tagName == null) {
@@ -41066,7 +41294,7 @@ function collectDirectiveAttrs(el) {
41066
41294
  continue;
41067
41295
  }
41068
41296
  if (key === "children") {
41069
- if (value && typeof value === "object" && !Array.isArray(value)) {
41297
+ if (isJsonObject(value)) {
41070
41298
  propsObj.children = value;
41071
41299
  }
41072
41300
  continue;
@@ -41081,22 +41309,20 @@ function collectDirectiveAttrs(el) {
41081
41309
  return collapsePropsToAttrMap(propsObj);
41082
41310
  }
41083
41311
  function convertToDirective(el, isBlock, allowlist) {
41084
- if (!el.tagName && typeof el.$prototype === "string" && PROTOTYPE_DIRECTIVE_NAMES2.has(el.$prototype)) {
41085
- return prototypeToDirective(el, isBlock, allowlist);
41312
+ if (!el.tagName && isString(el.$prototype) && PROTOTYPE_DIRECTIVE_NAMES2.has(el.$prototype)) {
41313
+ return prototypeToDirective(el, el.$prototype, isBlock, allowlist);
41086
41314
  }
41087
- const tag = el.tagName ?? "div";
41315
+ const tag = isString(el.tagName) ? el.tagName : "div";
41088
41316
  const attrs = collectDirectiveAttrs(el);
41089
41317
  if (!isBlock) {
41090
41318
  return {
41091
41319
  attributes: attrs,
41092
- children: el.textContent != null ? [{ type: "text", value: String(el.textContent) }] : (el.children ?? []).map((c) => convertJxNode(c, false, allowlist)).filter(Boolean),
41320
+ children: el.textContent != null ? [{ type: "text", value: String(el.textContent) }] : convertJxChildren(childList(el), false, allowlist),
41093
41321
  name: tag,
41094
41322
  type: "textDirective"
41095
41323
  };
41096
41324
  }
41097
- const rawChildren = el.children;
41098
- const childrenIsObject = rawChildren && typeof rawChildren === "object" && !Array.isArray(rawChildren);
41099
- const childArray = childrenIsObject ? undefined : rawChildren;
41325
+ const childArray = Array.isArray(el.children) ? el.children : undefined;
41100
41326
  if (!childArray?.length && el.textContent == null) {
41101
41327
  return {
41102
41328
  attributes: attrs,
@@ -41114,10 +41340,10 @@ function convertToDirective(el, isBlock, allowlist) {
41114
41340
  }
41115
41341
  ];
41116
41342
  } else if (INLINE_CONTENT_TAGS.has(tag)) {
41117
- const inlineNodes = (el.children ?? []).map((c) => convertJxNode(c, false, allowlist)).filter(Boolean);
41343
+ const inlineNodes = convertJxChildren(childList(el), false, allowlist);
41118
41344
  directiveChildren = inlineNodes.length > 0 ? [{ children: inlineNodes, type: "paragraph" }] : [];
41119
41345
  } else {
41120
- directiveChildren = (el.children ?? []).map((c) => convertJxNode(c, true, allowlist)).filter(Boolean);
41346
+ directiveChildren = convertJxChildren(childList(el), true, allowlist);
41121
41347
  }
41122
41348
  return {
41123
41349
  attributes: attrs,
@@ -41126,7 +41352,7 @@ function convertToDirective(el, isBlock, allowlist) {
41126
41352
  type: "containerDirective"
41127
41353
  };
41128
41354
  }
41129
- function prototypeToDirective(el, isBlock, allowlist) {
41355
+ function prototypeToDirective(el, prototype, isBlock, allowlist) {
41130
41356
  const propsObj = {};
41131
41357
  for (const [key, value] of Object.entries(el)) {
41132
41358
  if (key === "$prototype" || key === "map" || key === "tagName") {
@@ -41140,7 +41366,7 @@ function prototypeToDirective(el, isBlock, allowlist) {
41140
41366
  return {
41141
41367
  attributes: attrs,
41142
41368
  children,
41143
- name: el.$prototype,
41369
+ name: prototype,
41144
41370
  type: isBlock ? "containerDirective" : "textDirective"
41145
41371
  };
41146
41372
  }
@@ -41159,7 +41385,7 @@ function collapsePropsToAttrMap(propsObj) {
41159
41385
  mdAttrKey = key.slice(1);
41160
41386
  }
41161
41387
  if (key === "@") {
41162
- if (value && typeof value === "object" && !Array.isArray(value)) {
41388
+ if (isJsonObject(value)) {
41163
41389
  walk(value, prefix);
41164
41390
  }
41165
41391
  continue;
@@ -41168,7 +41394,7 @@ function collapsePropsToAttrMap(propsObj) {
41168
41394
  mdAttrKey = key.slice(1);
41169
41395
  }
41170
41396
  const fullKey = prefix ? `${prefix}.${mdAttrKey}` : mdAttrKey;
41171
- if (value && typeof value === "object" && !Array.isArray(value)) {
41397
+ if (isJsonObject(value)) {
41172
41398
  walk(value, fullKey);
41173
41399
  } else {
41174
41400
  result[fullKey] = String(value);
@@ -41179,13 +41405,13 @@ function collapsePropsToAttrMap(propsObj) {
41179
41405
  return result;
41180
41406
  }
41181
41407
  function nodeToMdast(node, ctx, scope) {
41182
- if (typeof node === "string") {
41408
+ if (isString(node)) {
41183
41409
  return node.trim() ? [{ type: "text", value: node }] : [];
41184
41410
  }
41185
- if (typeof node === "number") {
41411
+ if (isNumber(node)) {
41186
41412
  return [{ type: "text", value: String(node) }];
41187
41413
  }
41188
- if (!node || typeof node !== "object") {
41414
+ if (!isNodeObject(node)) {
41189
41415
  return [];
41190
41416
  }
41191
41417
  if (node.$prototype === "Array") {
@@ -41193,7 +41419,7 @@ function nodeToMdast(node, ctx, scope) {
41193
41419
  }
41194
41420
  const tag = serializableTag(node.tagName) || "div";
41195
41421
  const text = resolveText(node.textContent, ctx, scope);
41196
- if (typeof node.innerHTML === "string" && node.innerHTML.trim()) {
41422
+ if (isString(node.innerHTML) && node.innerHTML.trim()) {
41197
41423
  const htmlNodes = htmlToMdast(node.innerHTML);
41198
41424
  if (htmlNodes.length > 0) {
41199
41425
  return htmlNodes;
@@ -41208,7 +41434,7 @@ function nodeToMdast(node, ctx, scope) {
41208
41434
  }
41209
41435
  return exportChildren(node, ctx, scope);
41210
41436
  }
41211
- const mdastType = TAG_MDAST_MAP[tag];
41437
+ const mdastType = hasMdastType(tag) ? TAG_MDAST_MAP[tag] : undefined;
41212
41438
  if (!mdastType) {
41213
41439
  if (text != null) {
41214
41440
  return text.trim() ? [{ children: [{ type: "text", value: text }], type: "paragraph" }] : [];
@@ -41239,14 +41465,14 @@ function nodeToMdast(node, ctx, scope) {
41239
41465
  }
41240
41466
  case "link": {
41241
41467
  const href = String(node.attributes?.href ?? "");
41242
- const title = node.attributes?.title ?? null;
41468
+ const title = attributeTitle(node.attributes?.title);
41243
41469
  const children = text != null ? [{ type: "text", value: text }] : exportChildren(node, ctx, scope);
41244
41470
  return [{ children, title, type: "link", url: href }];
41245
41471
  }
41246
41472
  case "image": {
41247
41473
  const src = String(node.attributes?.src ?? "");
41248
41474
  const alt = String(node.attributes?.alt ?? "");
41249
- const title = node.attributes?.title ?? null;
41475
+ const title = attributeTitle(node.attributes?.title);
41250
41476
  return [{ alt, title, type: "image", url: src }];
41251
41477
  }
41252
41478
  case "blockquote": {
@@ -41271,7 +41497,7 @@ function nodeToMdast(node, ctx, scope) {
41271
41497
  return [{ children, spread: false, type: "listItem" }];
41272
41498
  }
41273
41499
  case "code": {
41274
- const codeChild = Array.isArray(node.children) ? node.children.find((c) => c?.tagName === "code") : null;
41500
+ const codeChild = childList(node).find((c) => isNodeObject(c) && c.tagName === "code");
41275
41501
  const value = textOf(codeChild) ?? text ?? "";
41276
41502
  return [
41277
41503
  {
@@ -41340,7 +41566,7 @@ function inlineComponent(node, tag, ctx) {
41340
41566
  for (const [key, value] of Object.entries(props)) {
41341
41567
  if (key in stateDefs) {
41342
41568
  const existing = stateDefs[key];
41343
- stateDefs[key] = existing && typeof existing === "object" && !Array.isArray(existing) && "default" in existing ? { ...existing, default: value } : value;
41569
+ stateDefs[key] = isJsonObject(existing) && "default" in existing ? { ...existing, default: value } : value;
41344
41570
  } else {
41345
41571
  stateDefs[key] = value;
41346
41572
  }
@@ -41352,7 +41578,7 @@ function inlineComponent(node, tag, ctx) {
41352
41578
  const resolved = deepResolve(def.children, scope ?? {}, ctx);
41353
41579
  const instanceChildren = node.children;
41354
41580
  return resolved.flatMap((child) => {
41355
- if (typeof child !== "string" && child?.tagName === "slot" && Array.isArray(instanceChildren)) {
41581
+ if (isNodeObject(child) && child.tagName === "slot" && Array.isArray(instanceChildren)) {
41356
41582
  return instanceChildren.flatMap((c) => nodeToMdast(c, ctx));
41357
41583
  }
41358
41584
  return nodeToMdast(child, ctx, scope);
@@ -41362,21 +41588,21 @@ function deepResolve(nodes, scope, ctx) {
41362
41588
  return nodes.map((node) => resolveNode(node, scope, ctx));
41363
41589
  }
41364
41590
  function resolveNode(node, scope, ctx) {
41365
- if (typeof node === "string") {
41591
+ if (isString(node)) {
41366
41592
  const evaluated = ctx.evaluateTemplate?.(node, scope);
41367
41593
  return evaluated !== undefined ? String(evaluated) : node;
41368
41594
  }
41369
- if (!node || typeof node !== "object") {
41595
+ if (!isNonNullObject(node)) {
41370
41596
  return node;
41371
41597
  }
41372
41598
  const result = { ...node };
41373
- if (typeof result.textContent === "string") {
41599
+ if (isString(result.textContent)) {
41374
41600
  const evaluated = ctx.evaluateTemplate?.(result.textContent, scope);
41375
41601
  if (evaluated !== undefined) {
41376
41602
  result.textContent = String(evaluated);
41377
41603
  }
41378
41604
  }
41379
- if (typeof result.innerHTML === "string") {
41605
+ if (isString(result.innerHTML)) {
41380
41606
  const evaluated = ctx.evaluateTemplate?.(result.innerHTML, scope);
41381
41607
  if (evaluated !== undefined) {
41382
41608
  result.innerHTML = String(evaluated);
@@ -41385,7 +41611,7 @@ function resolveNode(node, scope, ctx) {
41385
41611
  if (result.attributes) {
41386
41612
  result.attributes = { ...result.attributes };
41387
41613
  for (const [k, v] of Object.entries(result.attributes)) {
41388
- if (typeof v === "string") {
41614
+ if (isString(v)) {
41389
41615
  const evaluated = ctx.evaluateTemplate?.(v, scope);
41390
41616
  if (evaluated !== undefined) {
41391
41617
  result.attributes[k] = evaluated;
@@ -41412,42 +41638,33 @@ function expandArray(arrayDef, ctx, scope) {
41412
41638
  if (!mapTemplate) {
41413
41639
  return [];
41414
41640
  }
41415
- return items.flatMap((item) => {
41416
- const resolved = resolveMapNode(mapTemplate, item);
41641
+ return items.flatMap((row) => {
41642
+ const resolved = isNodeObject(mapTemplate) ? resolveMapNode(mapTemplate, row) : mapTemplate;
41417
41643
  return nodeToMdast(resolved, ctx, scope);
41418
41644
  });
41419
41645
  }
41420
- function resolveMapNode(node, item) {
41421
- if (typeof node === "string") {
41422
- return node;
41423
- }
41424
- if (!node || typeof node !== "object") {
41425
- return node;
41426
- }
41646
+ function resolveMapNode(node, row) {
41427
41647
  const result = { ...node };
41428
41648
  for (const [key, value] of Object.entries(result)) {
41429
- if (value && typeof value === "object" && value.$ref) {
41430
- const ref = value.$ref;
41431
- if (ref.startsWith("$map/")) {
41432
- const path = ref.slice("$map/".length);
41433
- result[key] = resolvePath(item, path.startsWith("item/") ? path.slice("item/".length) : path);
41434
- }
41649
+ if (isRef(value) && value.$ref.startsWith("$map/")) {
41650
+ const path = value.$ref.slice("$map/".length);
41651
+ result[key] = resolvePath(row, path.startsWith("item/") ? path.slice("item/".length) : path);
41435
41652
  }
41436
41653
  }
41437
- if (result.$props) {
41438
- result.$props = resolveMapNode(result.$props, item);
41654
+ if (isNodeObject(result.$props)) {
41655
+ result.$props = resolveMapNode(result.$props, row);
41439
41656
  }
41440
- if (typeof result.textContent === "string" && result.textContent.startsWith("$map/")) {
41441
- result.textContent = resolvePath(item, result.textContent.slice("$map/".length));
41657
+ if (isString(result.textContent) && result.textContent.startsWith("$map/")) {
41658
+ result.textContent = resolvePath(row, result.textContent.slice("$map/".length));
41442
41659
  }
41443
41660
  if (Array.isArray(result.children)) {
41444
- result.children = result.children.map((c) => resolveMapNode(c, item));
41661
+ result.children = result.children.map((c) => isNodeObject(c) ? resolveMapNode(c, row) : c);
41445
41662
  }
41446
41663
  return result;
41447
41664
  }
41448
- function resolvePath(obj, path) {
41665
+ function resolvePath(root, path) {
41449
41666
  const parts = path.split(/[/.]/);
41450
- let current = obj;
41667
+ let current = root;
41451
41668
  for (const part of parts) {
41452
41669
  if (current == null) {
41453
41670
  return;
@@ -41457,16 +41674,14 @@ function resolvePath(obj, path) {
41457
41674
  return current;
41458
41675
  }
41459
41676
  function resolveRef(ref, scope) {
41460
- if (ref.startsWith("#/state/")) {
41461
- return resolvePath(scope, ref.slice("#/state/".length));
41462
- }
41463
- return resolvePath(scope, ref);
41677
+ const path = ref.startsWith("#/state/") ? ref.slice("#/state/".length) : ref;
41678
+ return resolvePath(scope, path);
41464
41679
  }
41465
41680
  function resolveText(value, ctx, scope) {
41466
41681
  if (value == null) {
41467
41682
  return null;
41468
41683
  }
41469
- if (typeof value === "string") {
41684
+ if (isString(value)) {
41470
41685
  if (scope) {
41471
41686
  const evaluated = ctx.evaluateTemplate?.(value, scope);
41472
41687
  if (evaluated !== undefined) {
@@ -41741,6 +41956,9 @@ function serializeJxMarkdown(doc, opts = {}) {
41741
41956
  }
41742
41957
  return serializeRoundtrip(doc, opts);
41743
41958
  }
41959
+ function createProcessor() {
41960
+ return unified();
41961
+ }
41744
41962
  function serializeRoundtrip(doc, opts) {
41745
41963
  const lines = [];
41746
41964
  if (opts.frontmatter !== false) {
@@ -41752,21 +41970,31 @@ function serializeRoundtrip(doc, opts) {
41752
41970
  frontmatter[key] = value;
41753
41971
  }
41754
41972
  if (Object.keys(frontmatter).length > 0) {
41755
- lines.push("---", $stringify(frontmatter).trim(), "---", "");
41973
+ const sourceYaml = opts.source === undefined ? null : frontmatterText(opts.source);
41974
+ const spliced = sourceYaml === null ? null : spliceFrontmatter(frontmatter, sourceYaml, (values) => stringifyFrontmatter(values));
41975
+ lines.push("---", spliced ?? stringifyFrontmatter(frontmatter), "---", "");
41756
41976
  }
41757
41977
  }
41758
41978
  if (Array.isArray(doc.children) && doc.children.length > 0) {
41759
41979
  const mdast = jxToMdast(doc, opts);
41760
- const processor = unified().use(remarkGfm).use(remarkDirective).use(remarkStringify, { bullet: "-", emphasis: "*", strong: "*" });
41761
- const md = processor.stringify(mdast);
41762
- lines.push(md);
41980
+ const markers = opts.source === undefined ? { bullet: "-", emphasis: "*", strong: "*" } : sourceMarkers(opts.source);
41981
+ const processor = createProcessor().use(remarkGfm).use(remarkDirective).use(remarkStringifyPlugin, { ...markers });
41982
+ lines.push(processor.stringify(mdast).replaceAll(/\n{3,}/g, `
41983
+
41984
+ `));
41763
41985
  }
41764
41986
  return `${lines.join(`
41765
- `).replaceAll(/\n{3,}/g, `
41766
-
41767
41987
  `).trim()}
41768
41988
  `;
41769
41989
  }
41990
+ function sourceMarkers(source) {
41991
+ const body = bodyText(source);
41992
+ const tree = createProcessor().use(remarkParsePlugin).use(remarkGfm).use(remarkDirective).parse(body);
41993
+ return markdownMarkers(tree, body);
41994
+ }
41995
+ function stringifyFrontmatter(frontmatter) {
41996
+ return $stringify(frontmatter, { lineWidth: 0, version: "1.1" }).trim();
41997
+ }
41770
41998
  function serializeExport(doc, opts) {
41771
41999
  if (!Array.isArray(doc.children) || doc.children.length === 0) {
41772
42000
  return "";
@@ -41799,7 +42027,7 @@ function serializeExport(doc, opts) {
41799
42027
  children: cleaned,
41800
42028
  type: "root"
41801
42029
  };
41802
- const processor = unified().use(remarkGfm).use(remarkStringify, {
42030
+ const processor = createProcessor().use(remarkGfm).use(remarkStringifyPlugin, {
41803
42031
  bullet: "-",
41804
42032
  emphasis: "*",
41805
42033
  setext: false,
@@ -41811,16 +42039,18 @@ function serializeExport(doc, opts) {
41811
42039
  `).trim()}
41812
42040
  `;
41813
42041
  }
41814
- var MD_ELEMENTS, MD_BLOCK, MD_INLINE, MD_ALL, MD_VOID, MD_TEXT_ONLY, TAG_MDAST_MAP, WRAPPER_TAGS, INLINE_CONTENT_TAGS, MDAST_TAG_MAP, CSS_PSEUDO_NAMES2, JX_DOLLAR_KEYS2, PROTOTYPE_DIRECTIVE_NAMES2, JX_ANNOTATION_KEYS2;
42042
+ var MD_ELEMENTS, MD_BLOCK, MD_INLINE, MD_ALL, MD_VOID, MD_TEXT_ONLY, TAG_MDAST_MAP, WRAPPER_TAGS, INLINE_CONTENT_TAGS, MDAST_TAG_MAP, MD_ATTRIBUTES, TABLE_PARTS, CSS_PSEUDO_NAMES2, JX_DOLLAR_KEYS2, PROTOTYPE_DIRECTIVE_NAMES2, JX_ANNOTATION_KEYS2, remarkStringifyPlugin, remarkParsePlugin;
41815
42043
  var init_serialize = __esm(() => {
41816
42044
  init_unified();
41817
42045
  init_guards();
42046
+ init_remark_parse();
41818
42047
  init_remark_stringify();
41819
42048
  init_remark_directive();
41820
42049
  init_remark_gfm();
41821
42050
  init_dist3();
41822
42051
  init_html_to_jx();
41823
42052
  init_transpile();
42053
+ init_source_style();
41824
42054
  MD_ELEMENTS = {
41825
42055
  block: [
41826
42056
  "h1",
@@ -41955,6 +42185,12 @@ var init_serialize = __esm(() => {
41955
42185
  text: () => "span",
41956
42186
  thematicBreak: () => "hr"
41957
42187
  };
42188
+ MD_ATTRIBUTES = new Map([
42189
+ ["a", new Set(["href", "title"])],
42190
+ ["img", new Set(["alt", "src", "title"])],
42191
+ ["ol", new Set(["start"])]
42192
+ ]);
42193
+ TABLE_PARTS = new Set(["tbody", "td", "th", "thead", "tr"]);
41958
42194
  CSS_PSEUDO_NAMES2 = new Set([
41959
42195
  "hover",
41960
42196
  "focus",
@@ -41985,6 +42221,8 @@ var init_serialize = __esm(() => {
41985
42221
  ]);
41986
42222
  PROTOTYPE_DIRECTIVE_NAMES2 = new Set(["Array"]);
41987
42223
  JX_ANNOTATION_KEYS2 = new Set(["$title", "$description"]);
42224
+ remarkStringifyPlugin = remarkStringify;
42225
+ remarkParsePlugin = remarkParse;
41988
42226
  });
41989
42227
 
41990
42228
  // src/walk.ts
@@ -53933,6 +54171,11 @@ function getHighlighter() {
53933
54171
  ],
53934
54172
  themes: [github_light_default_default, github_dark_default_default]
53935
54173
  });
54174
+ _highlighter.codeToTokens("const a = 1;", {
54175
+ defaultColor: false,
54176
+ lang: "javascript",
54177
+ themes: THEMES
54178
+ });
53936
54179
  return _highlighter;
53937
54180
  }
53938
54181
  function highlightFence(code, info) {
@@ -53941,7 +54184,12 @@ function highlightFence(code, info) {
53941
54184
  if (!h.getLoadedLanguages().includes(lang)) {
53942
54185
  return null;
53943
54186
  }
53944
- const { tokens } = h.codeToTokens(code, { defaultColor: false, lang, themes: THEMES });
54187
+ const { tokens } = h.codeToTokens(code, {
54188
+ defaultColor: false,
54189
+ lang,
54190
+ themes: THEMES,
54191
+ tokenizeTimeLimit: 0
54192
+ });
53945
54193
  const out = [];
53946
54194
  for (const [i, line] of tokens.entries()) {
53947
54195
  if (i > 0) {
@@ -53960,17 +54208,17 @@ function highlightFence(code, info) {
53960
54208
  }
53961
54209
  function highlightCodeBlocks(nodes) {
53962
54210
  for (const node of nodes) {
53963
- if (!node || typeof node !== "object") {
54211
+ if (!isNonNullObject(node)) {
53964
54212
  continue;
53965
54213
  }
53966
54214
  if (node.tagName === "pre" && Array.isArray(node.children)) {
53967
54215
  for (const child of node.children) {
53968
- if (!child || typeof child !== "object" || child.tagName !== "code") {
54216
+ if (!isNonNullObject(child) || child.tagName !== "code") {
53969
54217
  continue;
53970
54218
  }
53971
54219
  const lang = /^language-(\S+)/.exec(child.className ?? "")?.[1];
53972
54220
  const code = child.textContent;
53973
- if (!lang || typeof code !== "string" || code.length === 0) {
54221
+ if (!lang || !isString(code) || code.length === 0) {
53974
54222
  continue;
53975
54223
  }
53976
54224
  const spans = highlightFence(code, lang);
@@ -54014,6 +54262,7 @@ var init_highlight = __esm(() => {
54014
54262
  init_typescript();
54015
54263
  init_xml2();
54016
54264
  init_yaml();
54265
+ init_guards();
54017
54266
  init_caddyfile();
54018
54267
  THEMES = { dark: "github-dark-default", light: "github-light-default" };
54019
54268
  });
@@ -54027,7 +54276,7 @@ function neutralizeTemplateAttribute(value) {
54027
54276
  }
54028
54277
  function makeTemplatesInert(nodes) {
54029
54278
  for (const [i, node] of nodes.entries()) {
54030
- if (typeof node === "string") {
54279
+ if (isString(node)) {
54031
54280
  if (node.includes("${")) {
54032
54281
  nodes[i] = { innerHTML: escapeTemplateText(node), tagName: "span" };
54033
54282
  }
@@ -54037,10 +54286,10 @@ function makeTemplatesInert(nodes) {
54037
54286
  makeTemplatesInert(node);
54038
54287
  continue;
54039
54288
  }
54040
- if (typeof node !== "object" || node === null) {
54289
+ if (!isNonNullObject(node)) {
54041
54290
  continue;
54042
54291
  }
54043
- if (typeof node.textContent === "string" && node.textContent.includes("${")) {
54292
+ if (isString(node.textContent) && node.textContent.includes("${")) {
54044
54293
  node.innerHTML = escapeTemplateText(node.textContent);
54045
54294
  delete node.textContent;
54046
54295
  }
@@ -54048,7 +54297,7 @@ function makeTemplatesInert(nodes) {
54048
54297
  if (attributes) {
54049
54298
  for (const name of PROSE_ATTRIBUTES) {
54050
54299
  const value = attributes[name];
54051
- if (typeof value === "string" && value.includes("${")) {
54300
+ if (isString(value) && value.includes("${")) {
54052
54301
  attributes[name] = neutralizeTemplateAttribute(value);
54053
54302
  }
54054
54303
  }
@@ -54060,36 +54309,25 @@ function makeTemplatesInert(nodes) {
54060
54309
  }
54061
54310
  var PROSE_ATTRIBUTES;
54062
54311
  var init_inert = __esm(() => {
54312
+ init_guards();
54063
54313
  PROSE_ATTRIBUTES = ["alt", "title", "data-title"];
54064
54314
  });
54065
54315
 
54066
54316
  // src/md.ts
54067
- import { basename as basename2, extname, relative, resolve as resolvePath2 } from "node:path";
54068
- function visit3(tree, typeOrVisitor, maybeVisitor) {
54069
- const type = typeof typeOrVisitor === "string" ? typeOrVisitor : null;
54070
- const visitor = type ? maybeVisitor : typeOrVisitor;
54071
- function walk(node) {
54072
- if (!node || typeof node !== "object") {
54073
- return;
54074
- }
54075
- if (!type || node.type === type) {
54076
- visitor(node);
54077
- }
54078
- if (Array.isArray(node.children)) {
54079
- for (const child of node.children) {
54080
- walk(child);
54081
- }
54317
+ import { basename as basename2, extname, relative, resolve } from "node:path";
54318
+ function findFirst(node, type) {
54319
+ if (node.type === type) {
54320
+ return node;
54321
+ }
54322
+ for (const child of node.children ?? []) {
54323
+ const found = findFirst(child, type);
54324
+ if (found) {
54325
+ return found;
54082
54326
  }
54083
54327
  }
54084
- walk(tree);
54328
+ return null;
54085
54329
  }
54086
54330
  function mdastToString(node) {
54087
- if (!node) {
54088
- return "";
54089
- }
54090
- if (typeof node === "string") {
54091
- return node;
54092
- }
54093
54331
  if (node.value) {
54094
54332
  return node.value;
54095
54333
  }
@@ -54111,12 +54349,7 @@ function readingTime(text) {
54111
54349
  return Math.max(1, Math.ceil(countWords(text) / WORDS_PER_MINUTE));
54112
54350
  }
54113
54351
  function extractExcerpt(tree) {
54114
- let firstParagraph = null;
54115
- visit3(tree, "paragraph", (node) => {
54116
- if (!firstParagraph) {
54117
- firstParagraph = node;
54118
- }
54119
- });
54352
+ const firstParagraph = findFirst(tree, "paragraph");
54120
54353
  if (!firstParagraph) {
54121
54354
  return "";
54122
54355
  }
@@ -54135,8 +54368,37 @@ function deriveSlug(filePath, sourceRoot) {
54135
54368
  }
54136
54369
  return basename2(filePath, extname(filePath));
54137
54370
  }
54371
+ function frontmatterEnd(source) {
54372
+ const firstBreak = source.indexOf(`
54373
+ `);
54374
+ if (firstBreak === -1 || !FENCE_LINE.test(source.slice(0, firstBreak))) {
54375
+ return 0;
54376
+ }
54377
+ let start = firstBreak + 1;
54378
+ while (start < source.length) {
54379
+ const lineEnd = source.indexOf(`
54380
+ `, start);
54381
+ const end = lineEnd === -1 ? source.length : lineEnd;
54382
+ if (FENCE_LINE.test(source.slice(start, end))) {
54383
+ return end;
54384
+ }
54385
+ start = end + 1;
54386
+ }
54387
+ return 0;
54388
+ }
54389
+ function readFrontmatter(source, filePath, sourceRoot) {
54390
+ const slug = deriveSlug(filePath, sourceRoot);
54391
+ const end = frontmatterEnd(source);
54392
+ if (end === 0) {
54393
+ return { frontmatter: {}, slug };
54394
+ }
54395
+ const processor = createProcessor2().use(remarkParse).use(remarkFrontmatter, ["yaml"]).use(import_remark_parse_frontmatter2.default);
54396
+ const vfile = { data: {} };
54397
+ processor.runSync(processor.parse(source.slice(0, end)), vfile);
54398
+ return { frontmatter: vfile.data.frontmatter ?? {}, slug };
54399
+ }
54138
54400
  function processMarkdown(source, filePath, config = {}) {
54139
- let processor = unified().use(remarkParse).use(remarkFrontmatter, ["yaml"]).use(import_remark_parse_frontmatter2.default).use(remarkGfm);
54401
+ let processor = createProcessor2().use(remarkParse).use(remarkFrontmatter, ["yaml"]).use(import_remark_parse_frontmatter2.default).use(remarkGfm);
54140
54402
  if (config.directives || config.directiveOptions) {
54141
54403
  processor = processor.use(remarkDirective);
54142
54404
  }
@@ -54147,13 +54409,11 @@ function processMarkdown(source, filePath, config = {}) {
54147
54409
  if (alerts) {
54148
54410
  transformAlerts(tree, alerts, config.onUnknownAlert);
54149
54411
  }
54150
- const vfileData = vfile.data;
54151
- const frontmatter = vfileData.frontmatter ?? {};
54152
- const mdTree = tree;
54153
- const plainText = mdastToString(mdTree);
54412
+ const frontmatter = vfile.data.frontmatter ?? {};
54413
+ const plainText = mdastToString(tree);
54154
54414
  const excerpt = extractExcerpt(tree);
54155
54415
  const slug = deriveSlug(filePath, config.sourceRoot);
54156
- const bodyNodes = tree.children.filter((n) => n.type !== "yaml" && n.type !== "toml");
54416
+ const bodyNodes = (tree.children ?? []).filter((n) => n.type !== "yaml" && n.type !== "toml");
54157
54417
  const $children = bodyNodes.map((n) => mdastNodeToJx(n)).filter(Boolean);
54158
54418
  highlightCodeBlocks($children);
54159
54419
  const toc = assignHeadingIds($children);
@@ -54169,7 +54429,7 @@ function processMarkdown(source, filePath, config = {}) {
54169
54429
  slug
54170
54430
  };
54171
54431
  }
54172
- var import_remark_parse_frontmatter2, WORDS_PER_MINUTE = 200, WORD_SEGMENTER, WORD_LIKE;
54432
+ var import_remark_parse_frontmatter2, createProcessor2, WORDS_PER_MINUTE = 200, WORD_SEGMENTER, WORD_LIKE, FENCE_LINE;
54173
54433
  var init_md = __esm(() => {
54174
54434
  init_unified();
54175
54435
  init_remark_parse();
@@ -54182,11 +54442,14 @@ var init_md = __esm(() => {
54182
54442
  init_transpile();
54183
54443
  init_highlight();
54184
54444
  init_inert();
54445
+ init_guards();
54185
54446
  init_markdown2();
54186
54447
  init_transpile();
54187
54448
  import_remark_parse_frontmatter2 = __toESM(require_dist2(), 1);
54449
+ createProcessor2 = unified;
54188
54450
  WORD_SEGMENTER = new Intl.Segmenter(DEFAULT_FORMAT_LOCALE, { granularity: "word" });
54189
54451
  WORD_LIKE = /[\p{L}\p{N}]/u;
54452
+ FENCE_LINE = /^---[ \t]*\r?$/;
54190
54453
  });
54191
54454
 
54192
54455
  // src/markdown.ts
@@ -54215,6 +54478,14 @@ class Markdown {
54215
54478
  await Promise.resolve().then(() => init_md());
54216
54479
  const { readFileSync, statSync } = await import("node:fs");
54217
54480
  const source = readFileSync(path, "utf8");
54481
+ const _meta = {};
54482
+ try {
54483
+ _meta.mtime = statSync(path).mtime.toISOString().replace(/\.\d{3}Z$/, "Z");
54484
+ } catch {}
54485
+ if (options.deferBody) {
54486
+ const { frontmatter, slug } = readFrontmatter(source, path, options.sourceRoot);
54487
+ return [{ _meta, body: source, data: frontmatter, id: slug }];
54488
+ }
54218
54489
  const result = processMarkdown(source, path, {
54219
54490
  ...options.directives !== undefined && { directives: options.directives },
54220
54491
  ...options.directiveOptions !== undefined && {
@@ -54224,22 +54495,10 @@ class Markdown {
54224
54495
  ...options.alerts !== undefined && { alerts: options.alerts },
54225
54496
  ...options.onUnknownAlert !== undefined && { onUnknownAlert: options.onUnknownAlert }
54226
54497
  });
54227
- const _meta = {};
54228
- try {
54229
- _meta.mtime = statSync(path).mtime.toISOString().replace(/\.\d{3}Z$/, "Z");
54230
- } catch {}
54231
- if (result.$excerpt != null) {
54232
- _meta.excerpt = result.$excerpt;
54233
- }
54234
- if (result.$toc != null) {
54235
- _meta.toc = result.$toc;
54236
- }
54237
- if (result.$readingTime != null) {
54238
- _meta.readingTime = result.$readingTime;
54239
- }
54240
- if (result.$wordCount != null) {
54241
- _meta.wordCount = result.$wordCount;
54242
- }
54498
+ _meta.excerpt = result.$excerpt;
54499
+ _meta.toc = result.$toc;
54500
+ _meta.readingTime = result.$readingTime;
54501
+ _meta.wordCount = result.$wordCount;
54243
54502
  return [
54244
54503
  {
54245
54504
  $children: result.$children,