@wdprlib/parser 5.1.6 → 5.2.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.
Files changed (52) hide show
  1. package/dist/index.cjs +655 -435
  2. package/dist/index.d.cts +11 -4
  3. package/dist/index.d.ts +11 -4
  4. package/dist/index.js +653 -435
  5. package/package.json +2 -2
  6. package/src/build-info.generated.ts +11 -0
  7. package/src/index.ts +2 -0
  8. package/src/lexer/lexer.ts +6 -4
  9. package/src/lexer/punctuation.ts +2 -1
  10. package/src/lexer/spacing-actions.ts +15 -0
  11. package/src/lexer/state.ts +30 -4
  12. package/src/lexer/token-factory.ts +15 -2
  13. package/src/lexer/tokens.ts +4 -3
  14. package/src/parser/rules/block/blockquote/build.ts +81 -37
  15. package/src/parser/rules/block/blockquote/index.ts +5 -6
  16. package/src/parser/rules/block/blockquote/line.ts +11 -10
  17. package/src/parser/rules/block/blockquote/lines.ts +102 -4
  18. package/src/parser/rules/block/code/content.ts +0 -3
  19. package/src/parser/rules/block/code/index.ts +14 -10
  20. package/src/parser/rules/block/definition-list/index.ts +4 -10
  21. package/src/parser/rules/block/definition-list/item-value.ts +2 -11
  22. package/src/parser/rules/block/definition-list/items.ts +1 -2
  23. package/src/parser/rules/block/embed-block/index.ts +30 -30
  24. package/src/parser/rules/block/heading/index.ts +7 -0
  25. package/src/parser/rules/block/paragraph/index.ts +41 -10
  26. package/src/parser/rules/block/parsing/content.ts +18 -1
  27. package/src/parser/rules/block/table/pipe/cell.ts +36 -1
  28. package/src/parser/rules/block/table/pipe/row.ts +21 -1
  29. package/src/parser/rules/block/toc/element.ts +2 -2
  30. package/src/parser/rules/block/toc/index.ts +2 -2
  31. package/src/parser/rules/block/toc/open.ts +5 -18
  32. package/src/parser/rules/contracts/scope.ts +4 -0
  33. package/src/parser/rules/inline/bold.ts +5 -5
  34. package/src/parser/rules/inline/color/syntax.ts +5 -8
  35. package/src/parser/rules/inline/formatting/close.ts +39 -0
  36. package/src/parser/rules/inline/formatting/container.ts +7 -4
  37. package/src/parser/rules/inline/index.ts +2 -0
  38. package/src/parser/rules/inline/italic.ts +5 -5
  39. package/src/parser/rules/inline/monospace.ts +5 -5
  40. package/src/parser/rules/inline/parsing/block-start-predicates.ts +2 -0
  41. package/src/parser/rules/inline/parsing/inline-content.ts +58 -4
  42. package/src/parser/rules/inline/raw/end.ts +28 -0
  43. package/src/parser/rules/inline/span/content.ts +32 -1
  44. package/src/parser/rules/inline/strikethrough/index.ts +1 -1
  45. package/src/parser/rules/inline/strikethrough/parse.ts +2 -9
  46. package/src/parser/rules/inline/strikethrough/syntax.ts +3 -20
  47. package/src/parser/rules/inline/subscript.ts +5 -5
  48. package/src/parser/rules/inline/superscript.ts +5 -5
  49. package/src/parser/rules/inline/underline/index.ts +5 -78
  50. package/src/parser/rules/tokens.ts +6 -15
  51. package/src/parser/rules/inline/underline/child.ts +0 -26
  52. package/src/parser/rules/inline/underline/content.ts +0 -29
package/dist/index.cjs CHANGED
@@ -71,6 +71,7 @@ __export(exports_src, {
71
71
  container: () => import_ast9.container,
72
72
  compileTemplate: () => compileTemplate,
73
73
  compileListUsersTemplate: () => compileListUsersTemplate,
74
+ buildInfo: () => buildInfo,
74
75
  bold: () => import_ast9.bold,
75
76
  STYLE_SLOT_PREFIX: () => import_ast4.STYLE_SLOT_PREFIX,
76
77
  Parser: () => Parser,
@@ -78,6 +79,15 @@ __export(exports_src, {
78
79
  DEFAULT_SETTINGS: () => import_ast10.DEFAULT_SETTINGS
79
80
  });
80
81
  module.exports = __toCommonJS(exports_src);
82
+
83
+ // packages/parser/src/build-info.generated.ts
84
+ var buildInfo = Object.freeze({
85
+ version: "5.2.0",
86
+ sha: "cc290b0d882de3ed9ea33ec060ddfc8a7b9da59a",
87
+ dirty: false
88
+ });
89
+
90
+ // packages/parser/src/index.ts
81
91
  var import_ast9 = require("@wdprlib/ast");
82
92
  var import_ast10 = require("@wdprlib/ast");
83
93
 
@@ -85,49 +95,6 @@ var import_ast10 = require("@wdprlib/ast");
85
95
  function createToken(type, value, position, lineStart = false) {
86
96
  return { type, value, position, lineStart };
87
97
  }
88
- // packages/parser/src/lexer/token-factory.ts
89
- var ZERO_POSITION = {
90
- start: { line: 0, column: 0, offset: 0 },
91
- end: { line: 0, column: 0, offset: 0 }
92
- };
93
- function createLexerToken(state, type, value, trackPositions) {
94
- return {
95
- type,
96
- value,
97
- position: trackPositions ? currentTokenPosition(state, value) : ZERO_POSITION,
98
- lineStart: isTokenAtLineStart(state)
99
- };
100
- }
101
- function updateLastNonWhitespaceType(current, type) {
102
- return type === "WHITESPACE" ? current : type;
103
- }
104
- function nextBlockOpenerDepth(current, type) {
105
- if (type === "BLOCK_OPEN" || type === "BLOCK_END_OPEN") {
106
- return current + 1;
107
- }
108
- if (type === "BLOCK_CLOSE" && current > 0) {
109
- return current - 1;
110
- }
111
- return current;
112
- }
113
- function currentTokenPosition(state, value) {
114
- return {
115
- start: {
116
- line: state.line,
117
- column: state.column - value.length,
118
- offset: state.pos - value.length
119
- },
120
- end: {
121
- line: state.line,
122
- column: state.column,
123
- offset: state.pos
124
- }
125
- };
126
- }
127
- function isTokenAtLineStart(state) {
128
- return state.tokens.length === 0 || state.tokens[state.tokens.length - 1]?.type === "NEWLINE";
129
- }
130
-
131
98
  // packages/parser/src/lexer/state.ts
132
99
  function createInitialLexerState(source) {
133
100
  return {
@@ -136,9 +103,16 @@ function createInitialLexerState(source) {
136
103
  line: 1,
137
104
  column: 1,
138
105
  lineStart: true,
106
+ quoteContentStart: false,
139
107
  tokens: []
140
108
  };
141
109
  }
110
+ function isSyntaxLineStart(state) {
111
+ return state.lineStart || state.quoteContentStart;
112
+ }
113
+ function isLineStartQuoteMarker(token) {
114
+ return token?.type === "BLOCKQUOTE_MARKER" && token.lineStart;
115
+ }
142
116
  function isAtEnd(state) {
143
117
  return state.pos >= state.source.length;
144
118
  }
@@ -152,18 +126,25 @@ function advance(state, n = 1) {
152
126
  updatePosition(state, start, end);
153
127
  return value;
154
128
  }
155
- function advanceByToken(state, type, length) {
129
+ function advanceByToken(state, type, length, value = "") {
130
+ const afterQuoteMarker = isLineStartQuoteMarker(state.tokens[state.tokens.length - 1]);
156
131
  state.pos += length;
157
132
  if (type === "NEWLINE") {
158
133
  state.line++;
159
134
  state.column = 1;
160
135
  state.lineStart = true;
136
+ state.quoteContentStart = false;
161
137
  return;
162
138
  }
163
139
  state.column += length;
164
- if (type !== "WHITESPACE") {
165
- state.lineStart = false;
140
+ if (type === "WHITESPACE") {
141
+ if (afterQuoteMarker && value === " ") {
142
+ state.quoteContentStart = true;
143
+ }
144
+ return;
166
145
  }
146
+ state.lineStart = false;
147
+ state.quoteContentStart = false;
167
148
  }
168
149
  function updatePosition(state, start, end) {
169
150
  state.pos = end;
@@ -174,8 +155,9 @@ function updatePositionFromValue(state, value) {
174
155
  `);
175
156
  if (firstNewline === -1) {
176
157
  state.column += value.length;
177
- if (state.lineStart && hasNonLineStartSpacing(value, 0)) {
158
+ if (hasNonLineStartSpacing(value, 0)) {
178
159
  state.lineStart = false;
160
+ state.quoteContentStart = false;
179
161
  }
180
162
  return;
181
163
  }
@@ -194,6 +176,7 @@ function updatePositionFromValue(state, value) {
194
176
  state.line += newlineCount;
195
177
  state.column = value.length - lastNewline;
196
178
  state.lineStart = !hasNonLineStartSpacing(value, lastNewline + 1);
179
+ state.quoteContentStart = false;
197
180
  }
198
181
  function hasNonLineStartSpacing(value, start) {
199
182
  for (let i = start;i < value.length; i++) {
@@ -205,6 +188,56 @@ function hasNonLineStartSpacing(value, start) {
205
188
  return false;
206
189
  }
207
190
 
191
+ // packages/parser/src/lexer/token-factory.ts
192
+ var ZERO_POSITION = {
193
+ start: { line: 0, column: 0, offset: 0 },
194
+ end: { line: 0, column: 0, offset: 0 }
195
+ };
196
+ function createLexerToken(state, type, value, trackPositions) {
197
+ return {
198
+ type,
199
+ value,
200
+ position: trackPositions ? currentTokenPosition(state, value) : ZERO_POSITION,
201
+ lineStart: isTokenAtLineStart(state)
202
+ };
203
+ }
204
+ function updateLastNonWhitespaceType(current2, type) {
205
+ return type === "WHITESPACE" ? current2 : type;
206
+ }
207
+ function nextBlockOpenerDepth(current2, type) {
208
+ if (type === "BLOCK_OPEN" || type === "BLOCK_END_OPEN") {
209
+ return current2 + 1;
210
+ }
211
+ if (type === "BLOCK_CLOSE" && current2 > 0) {
212
+ return current2 - 1;
213
+ }
214
+ return current2;
215
+ }
216
+ function currentTokenPosition(state, value) {
217
+ return {
218
+ start: {
219
+ line: state.line,
220
+ column: state.column - value.length,
221
+ offset: state.pos - value.length
222
+ },
223
+ end: {
224
+ line: state.line,
225
+ column: state.column,
226
+ offset: state.pos
227
+ }
228
+ };
229
+ }
230
+ function isTokenAtLineStart(state) {
231
+ if (state.tokens.length === 0) {
232
+ return true;
233
+ }
234
+ const last = state.tokens[state.tokens.length - 1];
235
+ if (last?.type === "NEWLINE") {
236
+ return true;
237
+ }
238
+ return last?.type === "WHITESPACE" && last.value === " " && isLineStartQuoteMarker(state.tokens[state.tokens.length - 2]);
239
+ }
240
+
208
241
  // packages/parser/src/lexer/anchor.ts
209
242
  function findInvalidAnchorNameEnd(src, pos) {
210
243
  if (src[pos] !== "[" || src[pos + 1] !== "[" || src[pos + 2] !== "#") {
@@ -521,7 +554,7 @@ function scanPunctuationToken(input) {
521
554
  case "@":
522
555
  return { handled: true, actions: scanAtToken(source, pos) };
523
556
  case ">":
524
- return { handled: true, actions: scanGreaterToken(source, pos, lineStart) };
557
+ return { handled: true, actions: scanGreaterToken(source, pos, input.physicalLineStart) };
525
558
  case "-":
526
559
  return { handled: true, actions: scanDashToken(source, pos, lineStart) };
527
560
  case "~": {
@@ -563,6 +596,15 @@ function runToken3(src, pos, end, type) {
563
596
  }
564
597
 
565
598
  // packages/parser/src/lexer/spacing-actions.ts
599
+ function limitBlockquotePrefixSpace(action, previous) {
600
+ if (!isLineStartQuoteMarker(previous) || action.type !== "WHITESPACE") {
601
+ return action;
602
+ }
603
+ if (action.length <= 1 || !action.value.startsWith(" ")) {
604
+ return action;
605
+ }
606
+ return { type: "WHITESPACE", value: " ", length: 1 };
607
+ }
566
608
  function scanSpacingToken(src, pos) {
567
609
  const char = src[pos];
568
610
  if (char === `
@@ -624,7 +666,7 @@ class Lexer {
624
666
  this.blockOpenerDepth = nextBlockOpenerDepth(this.blockOpenerDepth, type);
625
667
  }
626
668
  emitTokenAction(action) {
627
- advanceByToken(this.state, action.type, action.length);
669
+ advanceByToken(this.state, action.type, action.length, action.value);
628
670
  this.addToken(action.type, action.value);
629
671
  }
630
672
  emitTokenActions(actions) {
@@ -638,11 +680,11 @@ class Lexer {
638
680
  }
639
681
  scanToken() {
640
682
  const char = this.current();
641
- const isLineStart = this.state.lineStart;
683
+ const isLineStart = isSyntaxLineStart(this.state);
642
684
  const src = this.state.source;
643
685
  const spacingAction = scanSpacingToken(src, this.state.pos);
644
686
  if (spacingAction) {
645
- this.emitTokenAction(spacingAction);
687
+ this.emitTokenAction(limitBlockquotePrefixSpace(spacingAction, this.state.tokens.at(-1)));
646
688
  return;
647
689
  }
648
690
  const punctuation = scanPunctuationToken({
@@ -650,6 +692,7 @@ class Lexer {
650
692
  source: src,
651
693
  pos: this.state.pos,
652
694
  lineStart: isLineStart,
695
+ physicalLineStart: this.state.lineStart,
653
696
  splitBlockClose: this.splitBlockClosePositions.has(this.state.pos),
654
697
  findInvalidAnchorNameEnd: () => this.findInvalidAnchorNameEnd()
655
698
  });
@@ -866,7 +909,7 @@ function parseBlocksUntil(ctx, closeCondition, options) {
866
909
  const elements = [];
867
910
  let consumed = 0;
868
911
  let pos = ctx.pos;
869
- const excluded = options?.excludedBlockNames;
912
+ const excluded = mergeExcludedBlockNames(ctx.scope.excludedBlockNames, options?.excludedBlockNames);
870
913
  const blockRules = excluded ? getExcludedBlockRules(ctx.blockRules, excluded) : ctx.blockRules;
871
914
  const blockScope = {
872
915
  ...ctx.scope,
@@ -908,6 +951,13 @@ function parseBlocksUntil(ctx, closeCondition, options) {
908
951
  }
909
952
  return { elements, consumed };
910
953
  }
954
+ function mergeExcludedBlockNames(inherited, added) {
955
+ if (!inherited?.size)
956
+ return added;
957
+ if (!added?.size)
958
+ return inherited;
959
+ return new Set([...inherited, ...added]);
960
+ }
911
961
  function getExcludedBlockRules(blockRules, excluded) {
912
962
  let byExcluded = excludedBlockRulesCache.get(blockRules);
913
963
  if (!byExcluded) {
@@ -944,6 +994,31 @@ function getCandidateInlineRules(inlineRules, tokenType) {
944
994
  byType.set(tokenType, candidates);
945
995
  return candidates;
946
996
  }
997
+ // packages/parser/src/parser/rules/inline/raw/end.ts
998
+ function rawRegionEnd(tokens, start, end) {
999
+ const type = tokens[start]?.type;
1000
+ const close = type === "RAW_OPEN" ? "RAW_OPEN" : type === "RAW_BLOCK_OPEN" ? "RAW_BLOCK_CLOSE" : null;
1001
+ if (!close)
1002
+ return start;
1003
+ for (let pos = start + 1;pos < end; pos++) {
1004
+ if (tokens[pos]?.type === "NEWLINE" || tokens[pos]?.type === "EOF")
1005
+ break;
1006
+ if (tokens[pos]?.type === close)
1007
+ return pos + 1;
1008
+ }
1009
+ return start;
1010
+ }
1011
+ function protectedInlineRegionEnd(tokens, start, end) {
1012
+ const rawEnd = rawRegionEnd(tokens, start, end);
1013
+ if (rawEnd > start || tokens[start]?.type !== "COMMENT_OPEN")
1014
+ return rawEnd;
1015
+ for (let pos = start + 1;pos < end; pos++) {
1016
+ if (tokens[pos]?.type === "COMMENT_CLOSE")
1017
+ return pos + 1;
1018
+ }
1019
+ return start;
1020
+ }
1021
+
947
1022
  // packages/parser/src/parser/rules/inline/parsing/plain-text.ts
948
1023
  var MIN_INLINE_TEXT_RUN_LENGTH = 32;
949
1024
  var MIN_INLINE_TEXT_RUN_DOCUMENT_TOKENS = 1e5;
@@ -986,6 +1061,135 @@ function isPlainTextRunToken(ctx, pos) {
986
1061
  return token5.value !== "(";
987
1062
  }
988
1063
 
1064
+ // packages/parser/src/parser/rules/inline/image/attributes.ts
1065
+ function parseImageAttributes(ctx, startPos) {
1066
+ const result = parseAttributesRaw(ctx, startPos, false);
1067
+ const link = result.attrs.link ?? null;
1068
+ const { link: _link, ...htmlAttributes } = result.attrs;
1069
+ return {
1070
+ attributes: filterUnsafeAttributes(htmlAttributes),
1071
+ link,
1072
+ consumed: result.consumed
1073
+ };
1074
+ }
1075
+
1076
+ // packages/parser/src/parser/rules/inline/image/body.ts
1077
+ function parseImageSourceText(ctx, startPos) {
1078
+ let pos = startPos;
1079
+ let consumed = 0;
1080
+ while (ctx.tokens[pos]?.type === "WHITESPACE") {
1081
+ pos++;
1082
+ consumed++;
1083
+ }
1084
+ let sourceText = "";
1085
+ while (pos < ctx.tokens.length) {
1086
+ const token5 = ctx.tokens[pos];
1087
+ if (!token5 || token5.type === "WHITESPACE" || token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
1088
+ break;
1089
+ }
1090
+ sourceText += token5.value;
1091
+ pos++;
1092
+ consumed++;
1093
+ }
1094
+ return { sourceText, consumed };
1095
+ }
1096
+
1097
+ // packages/parser/src/parser/rules/inline/image/syntax.ts
1098
+ var IMAGE_BLOCK_NAMES = new Set([
1099
+ "image",
1100
+ "=image",
1101
+ "<image",
1102
+ ">image",
1103
+ "f<image",
1104
+ "f>image",
1105
+ "f=image"
1106
+ ]);
1107
+ function parseImageBlockName(ctx, startPos) {
1108
+ let pos = startPos;
1109
+ let consumed = 0;
1110
+ while (ctx.tokens[pos]?.type === "WHITESPACE") {
1111
+ pos++;
1112
+ consumed++;
1113
+ }
1114
+ const prefixResult = parseImagePrefix(ctx, pos);
1115
+ const prefix = prefixResult.prefix;
1116
+ pos += prefixResult.consumed;
1117
+ consumed += prefixResult.consumed;
1118
+ const nameToken = ctx.tokens[pos];
1119
+ if (!nameToken || nameToken.type !== "TEXT" && nameToken.type !== "IDENTIFIER") {
1120
+ return null;
1121
+ }
1122
+ return { name: prefix + nameToken.value.toLowerCase(), consumed: consumed + 1 };
1123
+ }
1124
+ function isImageBlockName(blockName) {
1125
+ return IMAGE_BLOCK_NAMES.has(blockName);
1126
+ }
1127
+ function parseImagePrefix(ctx, pos) {
1128
+ const token5 = ctx.tokens[pos];
1129
+ if (token5?.type === "EQUALS") {
1130
+ return { prefix: "=", consumed: 1 };
1131
+ }
1132
+ if (token5?.type === "TEXT" && token5.value === "<") {
1133
+ return { prefix: "<", consumed: 1 };
1134
+ }
1135
+ if ((token5?.type === "TEXT" || token5?.type === "BLOCKQUOTE_MARKER") && token5.value === ">") {
1136
+ return { prefix: ">", consumed: 1 };
1137
+ }
1138
+ if (token5?.type === "IDENTIFIER" && token5.value.toLowerCase() === "f") {
1139
+ return parseFloatPrefix(ctx, pos + 1);
1140
+ }
1141
+ return { prefix: "", consumed: 0 };
1142
+ }
1143
+ function parseFloatPrefix(ctx, pos) {
1144
+ const token5 = ctx.tokens[pos];
1145
+ if (token5?.type === "TEXT" && token5.value === "<") {
1146
+ return { prefix: "f<", consumed: 2 };
1147
+ }
1148
+ if ((token5?.type === "TEXT" || token5?.type === "BLOCKQUOTE_MARKER") && token5.value === ">") {
1149
+ return { prefix: "f>", consumed: 2 };
1150
+ }
1151
+ if (token5?.type === "EQUALS") {
1152
+ return { prefix: "f=", consumed: 2 };
1153
+ }
1154
+ return { prefix: "", consumed: 0 };
1155
+ }
1156
+
1157
+ // packages/parser/src/parser/rules/inline/image/open.ts
1158
+ function parseImageOpen(ctx) {
1159
+ if (ctx.tokens[ctx.pos]?.type !== "BLOCK_OPEN") {
1160
+ return null;
1161
+ }
1162
+ let pos = ctx.pos + 1;
1163
+ let consumed = 1;
1164
+ const nameResult = parseImageBlockName(ctx, pos);
1165
+ if (!nameResult || !isImageBlockName(nameResult.name)) {
1166
+ return null;
1167
+ }
1168
+ pos += nameResult.consumed;
1169
+ consumed += nameResult.consumed;
1170
+ const sourceText = parseImageSourceText(ctx, pos);
1171
+ pos += sourceText.consumed;
1172
+ consumed += sourceText.consumed;
1173
+ const attrs = parseImageAttributes(ctx, pos);
1174
+ pos += attrs.consumed;
1175
+ consumed += attrs.consumed;
1176
+ if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
1177
+ return null;
1178
+ }
1179
+ pos++;
1180
+ consumed++;
1181
+ if (!sourceText.sourceText) {
1182
+ return null;
1183
+ }
1184
+ return {
1185
+ blockName: nameResult.name,
1186
+ sourceText: sourceText.sourceText,
1187
+ link: attrs.link,
1188
+ attributes: attrs.attributes,
1189
+ consumed
1190
+ };
1191
+ }
1192
+
989
1193
  // packages/parser/src/parser/constants.ts
990
1194
  var BLOCK_START_TOKENS = [
991
1195
  "BLOCKQUOTE_MARKER",
@@ -1116,7 +1320,7 @@ function isParagraphBreakingBlockStart(ctx, newlinePos, lookAhead) {
1116
1320
  if (!nextMeaningfulToken.lineStart && !isIndentedBlockOpener) {
1117
1321
  return false;
1118
1322
  }
1119
- return !isOrphanCloseSpan(ctx, nextPos) && !isAnchorName(ctx, nextPos) && !isInvalidBlockOpen(ctx, nextPos) && !isInvalidHeading(ctx, nextPos) && !isExcludedBlockStart(ctx, nextPos) && !isUnknownBlockStart(ctx, nextPos);
1323
+ return !parseImageOpen({ ...ctx, pos: nextPos }) && !isOrphanCloseSpan(ctx, nextPos) && !isAnchorName(ctx, nextPos) && !isInvalidBlockOpen(ctx, nextPos) && !isInvalidHeading(ctx, nextPos) && !isExcludedBlockStart(ctx, nextPos) && !isUnknownBlockStart(ctx, nextPos);
1120
1324
  }
1121
1325
  function isOrphanCloseSpan(ctx, blockEndOpenPos) {
1122
1326
  const token5 = ctx.tokens[blockEndOpenPos];
@@ -1226,27 +1430,45 @@ function parseInlineUntil(ctx, endType) {
1226
1430
  let consumed = 0;
1227
1431
  let pos = ctx.pos;
1228
1432
  const paragraphMode = endType === "PARAGRAPH_BREAK";
1433
+ const multiline = paragraphMode || FORMATTING_CLOSE_TOKENS.has(endType);
1434
+ let inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
1435
+ if (!multiline) {
1436
+ for (let end = ctx.pos;end < inlineEnd; end++) {
1437
+ const protectedEnd = protectedInlineRegionEnd(ctx.tokens, end, inlineEnd);
1438
+ if (protectedEnd > end) {
1439
+ end = protectedEnd - 1;
1440
+ continue;
1441
+ }
1442
+ if (ctx.tokens[end]?.type === "NEWLINE" && ctx.tokens[end - 1]?.type === "UNDERSCORE" && ctx.tokens[end - 2]?.type === "WHITESPACE")
1443
+ continue;
1444
+ if (ctx.tokens[end]?.type === "NEWLINE" || ctx.tokens[end]?.type === endType) {
1445
+ inlineEnd = end;
1446
+ break;
1447
+ }
1448
+ }
1449
+ }
1229
1450
  const { inlineRules } = ctx;
1230
1451
  const inlineCtx = {
1231
1452
  ...ctx,
1232
- pos
1453
+ pos,
1454
+ scope: { ...ctx.scope, inlineEnd }
1233
1455
  };
1234
1456
  const canCollectLongPlainTextRuns = ctx.tokens.length >= MIN_INLINE_TEXT_RUN_DOCUMENT_TOKENS;
1235
- while (pos < ctx.tokens.length) {
1457
+ while (pos < inlineEnd) {
1236
1458
  const token5 = ctx.tokens[pos];
1237
1459
  if (!token5 || token5.type === "EOF") {
1238
1460
  break;
1239
1461
  }
1240
- if (paragraphMode && ctx.scope.blockCloseCondition) {
1462
+ if (ctx.scope.blockCloseCondition) {
1241
1463
  const checkCtx = { ...ctx, pos };
1242
1464
  if (ctx.scope.blockCloseCondition(checkCtx)) {
1243
1465
  break;
1244
1466
  }
1245
1467
  }
1246
- if (!paragraphMode && token5.type === "NEWLINE") {
1468
+ if (!multiline && token5.type === "NEWLINE") {
1247
1469
  break;
1248
1470
  }
1249
- if (paragraphMode && token5.type === "NEWLINE") {
1471
+ if (multiline && token5.type === "NEWLINE" && !ctx.scope.tableFormatting) {
1250
1472
  const boundary = getParagraphNewlineBoundary(ctx, pos, nodes.length > 0);
1251
1473
  if (boundary.shouldBreak) {
1252
1474
  if (boundary.preservePrecedingLineBreak) {
@@ -1256,6 +1478,11 @@ function parseInlineUntil(ctx, endType) {
1256
1478
  break;
1257
1479
  }
1258
1480
  }
1481
+ if (ctx.scope.tableFormatting?.suppressedClosers.has(pos)) {
1482
+ pos++;
1483
+ consumed++;
1484
+ continue;
1485
+ }
1259
1486
  if (token5.type === endType) {
1260
1487
  break;
1261
1488
  }
@@ -1280,6 +1507,24 @@ function parseInlineUntil(ctx, endType) {
1280
1507
  for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
1281
1508
  const result = rule.parse(inlineCtx);
1282
1509
  if (result.success) {
1510
+ if (rule.name === "comment") {
1511
+ let after = pos + result.consumed;
1512
+ while (ctx.tokens[after]?.type === "WHITESPACE")
1513
+ after++;
1514
+ if (ctx.tokens[after]?.type === "NEWLINE" || ctx.tokens[after]?.type === "EOF") {
1515
+ while (nodes.at(-1)?.element === "text") {
1516
+ const last = nodes.at(-1);
1517
+ if (last.element !== "text")
1518
+ break;
1519
+ last.data = last.data.trimEnd();
1520
+ if (last.data)
1521
+ break;
1522
+ nodes.pop();
1523
+ }
1524
+ if (nodes.at(-1)?.element === "line-break")
1525
+ nodes.pop();
1526
+ }
1527
+ }
1283
1528
  nodes.push(...result.elements);
1284
1529
  consumed += result.consumed;
1285
1530
  pos += result.consumed;
@@ -1295,6 +1540,16 @@ function parseInlineUntil(ctx, endType) {
1295
1540
  }
1296
1541
  return { elements: nodes, consumed };
1297
1542
  }
1543
+ var FORMATTING_CLOSE_TOKENS = new Set([
1544
+ "BOLD_MARKER",
1545
+ "ITALIC_MARKER",
1546
+ "UNDERLINE_MARKER",
1547
+ "STRIKE_MARKER",
1548
+ "SUPER_MARKER",
1549
+ "SUB_MARKER",
1550
+ "MONO_CLOSE",
1551
+ "COLOR_MARKER"
1552
+ ]);
1298
1553
  // packages/parser/src/parser/rules/block/parsing/attributes/names.ts
1299
1554
  function consumeAttributeName(ctx, startPos, startConsumed, startName, options) {
1300
1555
  if (startName === "_" && isAttributeWordToken(ctx.tokens[startPos])) {
@@ -1470,7 +1725,7 @@ function eofToken() {
1470
1725
  }
1471
1726
  function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
1472
1727
  let pos = ctx.pos;
1473
- while (pos < ctx.tokens.length) {
1728
+ while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
1474
1729
  const token5 = ctx.tokens[pos];
1475
1730
  if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
1476
1731
  return false;
@@ -1484,31 +1739,6 @@ function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
1484
1739
  }
1485
1740
  return false;
1486
1741
  }
1487
- function hasClosingMarkerBeforeParagraphBreak(ctx, markerType, markerValue) {
1488
- let pos = ctx.pos;
1489
- while (pos < ctx.tokens.length) {
1490
- const token5 = ctx.tokens[pos];
1491
- if (!token5 || token5.type === "EOF") {
1492
- return false;
1493
- }
1494
- if (token5.type === "NEWLINE") {
1495
- let lookAhead = 1;
1496
- while (ctx.tokens[pos + lookAhead]?.type === "WHITESPACE") {
1497
- lookAhead++;
1498
- }
1499
- if (ctx.tokens[pos + lookAhead]?.type === "NEWLINE" || ctx.tokens[pos + lookAhead]?.type === "EOF" || !ctx.tokens[pos + lookAhead]) {
1500
- return false;
1501
- }
1502
- }
1503
- if (token5.type === markerType) {
1504
- if (markerValue === undefined || token5.value === markerValue) {
1505
- return true;
1506
- }
1507
- }
1508
- pos++;
1509
- }
1510
- return false;
1511
- }
1512
1742
  // packages/parser/src/parser/rules/block/heading/open.ts
1513
1743
  function parseHeadingOpen(ctx) {
1514
1744
  const marker = ctx.tokens[ctx.pos];
@@ -1575,6 +1805,15 @@ var headingRule = {
1575
1805
  const inlineCtx = { ...ctx, pos };
1576
1806
  const inlineResult = parseInlineUntil(inlineCtx, "NEWLINE");
1577
1807
  const children = inlineResult.elements;
1808
+ while (children.at(-1)?.element === "text") {
1809
+ const last = children.at(-1);
1810
+ if (last.element !== "text")
1811
+ break;
1812
+ last.data = last.data.trimEnd();
1813
+ if (last.data)
1814
+ break;
1815
+ children.pop();
1816
+ }
1578
1817
  consumed += inlineResult.consumed;
1579
1818
  pos += inlineResult.consumed;
1580
1819
  if (ctx.tokens[pos]?.type === "NEWLINE") {
@@ -2374,17 +2613,15 @@ function parseBlockquoteLine(ctx, startPos) {
2374
2613
  if (ctx.tokens[pos]?.type !== "WHITESPACE") {
2375
2614
  return { kind: "skipped", consumed: consumeLineRemainder(ctx, pos) + consumed };
2376
2615
  }
2377
- while (ctx.tokens[pos]?.type === "WHITESPACE") {
2616
+ pos++;
2617
+ consumed++;
2618
+ const contentStart = pos;
2619
+ while (pos < ctx.tokens.length && ctx.tokens[pos]?.type !== "NEWLINE" && ctx.tokens[pos]?.type !== "EOF") {
2378
2620
  pos++;
2379
2621
  consumed++;
2380
2622
  }
2381
- const inlineCtx = { ...ctx, pos };
2382
- const inlineResult = parseInlineUntil(inlineCtx, "NEWLINE");
2383
- consumed += inlineResult.consumed;
2384
- pos += inlineResult.consumed;
2385
- let hasLineBreak = false;
2386
2623
  if (ctx.tokens[pos]?.type === "NEWLINE") {
2387
- hasLineBreak = true;
2624
+ pos++;
2388
2625
  consumed++;
2389
2626
  }
2390
2627
  return {
@@ -2392,7 +2629,7 @@ function parseBlockquoteLine(ctx, startPos) {
2392
2629
  line: {
2393
2630
  depth: depth - 1,
2394
2631
  ltype: null,
2395
- value: { elements: inlineResult.elements, hasLineBreak }
2632
+ value: { start: contentStart, end: pos }
2396
2633
  },
2397
2634
  consumed
2398
2635
  };
@@ -2411,47 +2648,43 @@ function consumeLineRemainder(ctx, startPos) {
2411
2648
  }
2412
2649
 
2413
2650
  // packages/parser/src/parser/rules/block/blockquote/build.ts
2414
- function buildBlockquoteElements(lines) {
2651
+ var EXCLUDED_BLOCK_NAMES = new Set([
2652
+ "bibliography",
2653
+ "code",
2654
+ "html",
2655
+ "include",
2656
+ "math",
2657
+ "module"
2658
+ ]);
2659
+ var NEVER_CLOSES = () => false;
2660
+ function buildBlockquoteElements(ctx, lines) {
2415
2661
  const depthTrees = processDepths(null, lines);
2416
- return depthTrees.map(({ list }) => buildBlockquoteElement(list));
2662
+ return depthTrees.map(({ list }) => buildBlockquoteElement(ctx, list)).filter((element) => element !== null);
2417
2663
  }
2418
- function buildBlockquoteElement(list) {
2664
+ function buildBlockquoteElement(ctx, list) {
2419
2665
  const children = [];
2420
- let currentParagraphChildren = [];
2421
- function flushParagraph() {
2422
- if (currentParagraphChildren.length > 0) {
2423
- while (currentParagraphChildren.length > 0 && currentParagraphChildren[currentParagraphChildren.length - 1]?.element === "line-break") {
2424
- currentParagraphChildren.pop();
2425
- }
2426
- if (currentParagraphChildren.length > 0) {
2427
- children.push({
2428
- element: "container",
2429
- data: {
2430
- type: "paragraph",
2431
- attributes: {},
2432
- elements: currentParagraphChildren
2433
- }
2434
- });
2435
- }
2436
- currentParagraphChildren = [];
2437
- }
2666
+ let pending = [];
2667
+ function flushPending() {
2668
+ if (pending.length === 0)
2669
+ return;
2670
+ children.push(...parseLines(ctx, pending));
2671
+ pending = [];
2438
2672
  }
2439
2673
  for (const item of list) {
2440
2674
  if (item.kind === "item") {
2441
- if (item.value.elements.length === 0) {
2442
- flushParagraph();
2443
- continue;
2444
- }
2445
- currentParagraphChildren.push(...item.value.elements);
2446
- if (item.value.hasLineBreak) {
2447
- currentParagraphChildren.push({ element: "line-break" });
2448
- }
2449
- } else {
2450
- flushParagraph();
2451
- children.push(buildBlockquoteElement(item.children));
2675
+ pending.push(item.value);
2676
+ continue;
2452
2677
  }
2678
+ flushPending();
2679
+ const nested = buildBlockquoteElement(ctx, item.children);
2680
+ if (nested) {
2681
+ children.push(nested);
2682
+ }
2683
+ }
2684
+ flushPending();
2685
+ if (children.length === 0) {
2686
+ return null;
2453
2687
  }
2454
- flushParagraph();
2455
2688
  return {
2456
2689
  element: "container",
2457
2690
  data: {
@@ -2461,6 +2694,31 @@ function buildBlockquoteElement(list) {
2461
2694
  }
2462
2695
  };
2463
2696
  }
2697
+ function parseLines(ctx, lines) {
2698
+ const tokens = sliceLineTokens(ctx, lines);
2699
+ const lineCtx = { ...ctx, tokens, pos: 0 };
2700
+ return parseBlocksUntil(lineCtx, NEVER_CLOSES, {
2701
+ excludedBlockNames: EXCLUDED_BLOCK_NAMES
2702
+ }).elements;
2703
+ }
2704
+ function sliceLineTokens(ctx, lines) {
2705
+ const tokens = [];
2706
+ for (const { start, end } of lines) {
2707
+ for (let pos = start;pos < end; pos++) {
2708
+ const token5 = ctx.tokens[pos];
2709
+ if (token5) {
2710
+ tokens.push(token5);
2711
+ }
2712
+ }
2713
+ }
2714
+ const last = tokens[tokens.length - 1];
2715
+ tokens.push(createToken("EOF", "", last?.position ?? ZERO_POSITION2));
2716
+ return tokens;
2717
+ }
2718
+ var ZERO_POSITION2 = {
2719
+ start: { line: 0, column: 0, offset: 0 },
2720
+ end: { line: 0, column: 0, offset: 0 }
2721
+ };
2464
2722
 
2465
2723
  // packages/parser/src/parser/rules/block/blockquote/lines.ts
2466
2724
  function collectBlockquoteLines(ctx) {
@@ -2469,16 +2727,90 @@ function collectBlockquoteLines(ctx) {
2469
2727
  let consumed = 0;
2470
2728
  while (pos < ctx.tokens.length) {
2471
2729
  const result = parseBlockquoteLine(ctx, pos);
2472
- if (result.kind === "stop")
2473
- break;
2730
+ if (result.kind === "stop") {
2731
+ const resumed = extendToCommentClose(ctx, lines, pos);
2732
+ if (resumed === pos)
2733
+ break;
2734
+ consumed += resumed - pos;
2735
+ pos = resumed;
2736
+ continue;
2737
+ }
2474
2738
  pos += result.consumed;
2475
2739
  consumed += result.consumed;
2476
2740
  if (result.kind === "parsed") {
2477
2741
  lines.push(result.line);
2478
2742
  }
2479
2743
  }
2744
+ blankCommentOnlyLines(ctx, lines);
2480
2745
  return { lines, consumed };
2481
2746
  }
2747
+ function extendToCommentClose(ctx, lines, stopPos) {
2748
+ const last = lines[lines.length - 1];
2749
+ if (!last || !endsInsideComment(ctx, lines)) {
2750
+ return stopPos;
2751
+ }
2752
+ let pos = stopPos;
2753
+ while (pos < ctx.tokens.length && ctx.tokens[pos]?.type !== "COMMENT_CLOSE") {
2754
+ if (ctx.tokens[pos]?.type === "EOF")
2755
+ return stopPos;
2756
+ pos++;
2757
+ }
2758
+ while (pos < ctx.tokens.length && ctx.tokens[pos]?.type !== "EOF") {
2759
+ pos++;
2760
+ if (ctx.tokens[pos - 1]?.type === "NEWLINE")
2761
+ break;
2762
+ }
2763
+ last.value.end = pos;
2764
+ return pos;
2765
+ }
2766
+ function endsInsideComment(ctx, lines) {
2767
+ let open = false;
2768
+ for (const { value } of lines) {
2769
+ for (let pos = value.start;pos < value.end; pos++) {
2770
+ const type = ctx.tokens[pos]?.type;
2771
+ if (type === "COMMENT_OPEN")
2772
+ open = true;
2773
+ else if (type === "COMMENT_CLOSE")
2774
+ open = false;
2775
+ }
2776
+ }
2777
+ return open;
2778
+ }
2779
+ function blankCommentOnlyLines(ctx, lines) {
2780
+ const positions = [];
2781
+ lines.forEach((line, index) => {
2782
+ for (let pos = line.value.start;pos < line.value.end; pos++) {
2783
+ if (ctx.tokens[pos]?.type !== "NEWLINE") {
2784
+ positions.push({ line: index, pos });
2785
+ }
2786
+ }
2787
+ });
2788
+ const commented = Array.from({ length: positions.length }, () => false);
2789
+ for (let open = 0;open < positions.length; open++) {
2790
+ if (ctx.tokens[positions[open].pos]?.type !== "COMMENT_OPEN")
2791
+ continue;
2792
+ let close = open + 1;
2793
+ while (close < positions.length && ctx.tokens[positions[close].pos]?.type !== "COMMENT_CLOSE") {
2794
+ close++;
2795
+ }
2796
+ if (close === positions.length)
2797
+ break;
2798
+ commented.fill(true, open, close + 1);
2799
+ open = close;
2800
+ }
2801
+ const hasContent = Array.from({ length: lines.length }, () => false);
2802
+ positions.forEach(({ line, pos }, index) => {
2803
+ if (commented[index] || ctx.tokens[pos]?.type === "WHITESPACE")
2804
+ return;
2805
+ hasContent[line] = true;
2806
+ });
2807
+ lines.forEach((line, index) => {
2808
+ if (hasContent[index])
2809
+ return;
2810
+ const { end } = line.value;
2811
+ line.value.start = ctx.tokens[end - 1]?.type === "NEWLINE" ? end - 1 : end;
2812
+ });
2813
+ }
2482
2814
 
2483
2815
  // packages/parser/src/parser/rules/block/blockquote/index.ts
2484
2816
  var blockquoteRule = {
@@ -2497,9 +2829,9 @@ var blockquoteRule = {
2497
2829
  }
2498
2830
  return { success: false };
2499
2831
  }
2500
- const blockquotes = buildBlockquoteElements(blockquoteLines.lines);
2832
+ const blockquotes = buildBlockquoteElements(ctx, blockquoteLines.lines);
2501
2833
  if (blockquotes.length === 0) {
2502
- return { success: false };
2834
+ return { success: true, elements: [], consumed: blockquoteLines.consumed };
2503
2835
  }
2504
2836
  return {
2505
2837
  success: true,
@@ -2594,17 +2926,8 @@ function parseDefinitionItemValue(ctx, startPos) {
2594
2926
  break;
2595
2927
  }
2596
2928
  if (token5.type === "NEWLINE") {
2597
- const nextToken = ctx.tokens[pos + 1];
2598
- if (nextToken?.type === "COLON" && nextToken.lineStart) {
2599
- pos++;
2600
- consumed++;
2601
- break;
2602
- }
2603
- if (nextToken?.type === "NEWLINE" || !nextToken || nextToken.type === "EOF") {
2604
- pos++;
2605
- consumed++;
2606
- break;
2607
- }
2929
+ consumed++;
2930
+ break;
2608
2931
  }
2609
2932
  const inlineCtx = { ...ctx, pos };
2610
2933
  const result = parseInlineUntil(inlineCtx, "NEWLINE");
@@ -2682,14 +3005,10 @@ var definitionListRule = {
2682
3005
  if (result.items.length === 0) {
2683
3006
  return { success: false };
2684
3007
  }
3008
+ const items = toDefinitionListItems(result.items.filter((item) => item.value.length > 0));
2685
3009
  return {
2686
3010
  success: true,
2687
- elements: [
2688
- {
2689
- element: "definition-list",
2690
- data: toDefinitionListItems(result.items)
2691
- }
2692
- ],
3011
+ elements: items.length > 0 ? [{ element: "definition-list", data: items }] : [],
2693
3012
  consumed: result.consumed
2694
3013
  };
2695
3014
  }
@@ -2794,20 +3113,49 @@ var paragraphRule = {
2794
3113
  }
2795
3114
  return {
2796
3115
  success: true,
2797
- elements: [
2798
- {
2799
- element: "container",
2800
- data: {
2801
- type: "paragraph",
2802
- attributes: {},
2803
- elements
2804
- }
2805
- }
2806
- ],
3116
+ elements: wrapParagraphElements(elements),
2807
3117
  consumed: result.consumed
2808
3118
  };
2809
3119
  }
2810
3120
  };
3121
+ function wrapParagraphElements(elements) {
3122
+ const output = [];
3123
+ let group = [];
3124
+ let bare = false;
3125
+ const flush = (trimBreaks = false) => {
3126
+ const content = trimBreaks ? normalizeParagraphElements(group) : group;
3127
+ while (content[0]?.element === "line-break")
3128
+ content.shift();
3129
+ while (content.length) {
3130
+ const last = content.at(-1);
3131
+ if (last.element !== "text" || last.data.trim() !== "")
3132
+ break;
3133
+ content.pop();
3134
+ }
3135
+ while (content[0]?.element === "text" && content[0].data.trim() === "")
3136
+ content.shift();
3137
+ if (content[0]?.element === "text")
3138
+ content[0] = { element: "text", data: content[0].data.trimStart() };
3139
+ if (content.length)
3140
+ output.push(...bare || content.some((el) => el.element === "image") ? content : [
3141
+ {
3142
+ element: "container",
3143
+ data: { type: "paragraph", attributes: {}, elements: content }
3144
+ }
3145
+ ]);
3146
+ group = [];
3147
+ };
3148
+ for (const el of elements) {
3149
+ if (el.element === "image" && el.data.alignment !== null || el.element === "embed-block") {
3150
+ flush(el.element === "image");
3151
+ output.push(el);
3152
+ bare = el.element === "embed-block";
3153
+ } else
3154
+ group.push(el);
3155
+ }
3156
+ flush();
3157
+ return output;
3158
+ }
2811
3159
 
2812
3160
  // packages/parser/src/parser/rules/block/div/close.ts
2813
3161
  function isDivClose(ctx) {
@@ -3173,9 +3521,6 @@ function consumeCodeClose(ctx, startPos, closeNameConsumed) {
3173
3521
  pos++;
3174
3522
  consumed++;
3175
3523
  }
3176
- if (ctx.tokens[pos]?.type === "NEWLINE") {
3177
- consumed++;
3178
- }
3179
3524
  return consumed;
3180
3525
  }
3181
3526
 
@@ -3232,16 +3577,13 @@ var codeBlockRule = {
3232
3577
  name: attrResult.attrs.name ?? null
3233
3578
  };
3234
3579
  ctx.codeBlocks.push(codeBlockData);
3235
- return {
3236
- success: true,
3237
- elements: [
3238
- {
3239
- element: "code",
3240
- data: codeBlockData
3241
- }
3242
- ],
3243
- consumed
3244
- };
3580
+ const elements = [{ element: "code", data: codeBlockData }];
3581
+ if (ctx.tokens[pos]?.type === "NEWLINE" && !getParagraphNewlineBoundary(ctx, pos, false).shouldBreak && !ctx.scope.blockCloseCondition?.({ ...ctx, pos: pos + 1 })) {
3582
+ const after = parseInlineUntil({ ...ctx, pos: pos + 1 }, "PARAGRAPH_BREAK");
3583
+ elements.push({ element: "line-break" }, ...normalizeParagraphElements(after.elements));
3584
+ consumed += 1 + after.consumed;
3585
+ }
3586
+ return { success: true, elements, consumed };
3245
3587
  }
3246
3588
  };
3247
3589
 
@@ -3620,7 +3962,30 @@ function parseTableCell(ctx, startPos, cellStart) {
3620
3962
  consumed++;
3621
3963
  }
3622
3964
  const { inlineRules } = ctx;
3623
- const inlineCtx = { ...ctx, pos };
3965
+ let inlineEnd = pos;
3966
+ while (inlineEnd < ctx.tokens.length) {
3967
+ const rawEnd = protectedInlineRegionEnd(ctx.tokens, inlineEnd, ctx.tokens.length);
3968
+ if (rawEnd > inlineEnd) {
3969
+ inlineEnd = rawEnd;
3970
+ continue;
3971
+ }
3972
+ const token5 = ctx.tokens[inlineEnd];
3973
+ if (!token5 || token5.type === "EOF" || token5.type === "NEWLINE" || isPipeTableToken(token5.type))
3974
+ break;
3975
+ if (token5.type === "WHITESPACE" && ctx.tokens[inlineEnd + 1]?.type === "UNDERSCORE" && ctx.tokens[inlineEnd + 2]?.type === "NEWLINE")
3976
+ inlineEnd += 3;
3977
+ else
3978
+ inlineEnd++;
3979
+ }
3980
+ const inlineCtx = {
3981
+ ...ctx,
3982
+ pos,
3983
+ scope: {
3984
+ ...ctx.scope,
3985
+ inlineEnd,
3986
+ tableFormatting: isPipeTableToken(ctx.tokens[inlineEnd]?.type ?? "EOF") ? ctx.scope.tableFormatting : undefined
3987
+ }
3988
+ };
3624
3989
  while (pos < ctx.tokens.length) {
3625
3990
  const token5 = ctx.tokens[pos];
3626
3991
  if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
@@ -3629,6 +3994,11 @@ function parseTableCell(ctx, startPos, cellStart) {
3629
3994
  if (isPipeTableToken(token5.type)) {
3630
3995
  break;
3631
3996
  }
3997
+ if (ctx.scope.tableFormatting?.suppressedClosers.has(pos)) {
3998
+ pos++;
3999
+ consumed++;
4000
+ continue;
4001
+ }
3632
4002
  if (tryConsumeUnderscoreLineBreak(ctx, pos, children)) {
3633
4003
  pos += 3;
3634
4004
  consumed += 3;
@@ -3688,6 +4058,21 @@ function tryConsumeUnderscoreLineBreak(ctx, pos, children) {
3688
4058
 
3689
4059
  // packages/parser/src/parser/rules/block/table/pipe/row.ts
3690
4060
  function parsePipeTableRows(ctx, startPos) {
4061
+ let end = startPos;
4062
+ while (end < ctx.tokens.length && ctx.tokens[end]?.type !== "EOF") {
4063
+ const protectedEnd = protectedInlineRegionEnd(ctx.tokens, end, ctx.tokens.length);
4064
+ if (protectedEnd > end) {
4065
+ end = protectedEnd;
4066
+ continue;
4067
+ }
4068
+ if (ctx.tokens[end]?.type === "NEWLINE" && !isPipeTableToken(ctx.tokens[end + 1]?.type ?? "EOF") && !(ctx.tokens[end - 1]?.type === "UNDERSCORE" && ctx.tokens[end - 2]?.type === "WHITESPACE"))
4069
+ break;
4070
+ end++;
4071
+ }
4072
+ const tableCtx = {
4073
+ ...ctx,
4074
+ scope: { ...ctx.scope, tableFormatting: { end, suppressedClosers: new Set } }
4075
+ };
3691
4076
  const rows = [];
3692
4077
  let pos = startPos;
3693
4078
  let consumed = 0;
@@ -3696,7 +4081,7 @@ function parsePipeTableRows(ctx, startPos) {
3696
4081
  if (!token5 || !token5.lineStart || !isPipeTableToken(token5.type)) {
3697
4082
  break;
3698
4083
  }
3699
- const rowResult = parseTableRow(ctx, pos);
4084
+ const rowResult = parseTableRow(tableCtx, pos);
3700
4085
  rows.push(rowResult.row);
3701
4086
  pos += rowResult.consumed;
3702
4087
  consumed += rowResult.consumed;
@@ -9124,6 +9509,8 @@ var embedBlockRule = {
9124
9509
  name: "embed-block",
9125
9510
  startTokens: ["BLOCK_OPEN"],
9126
9511
  requiresLineStart: false,
9512
+ preservesPrecedingLineBreak: true,
9513
+ isStartPattern: (ctx, pos) => parseEmbedBlockOpen(ctx, pos) !== null,
9127
9514
  parse(ctx) {
9128
9515
  const openToken = currentToken(ctx);
9129
9516
  if (openToken.type !== "BLOCK_OPEN") {
@@ -9139,38 +9526,30 @@ var embedBlockRule = {
9139
9526
  pos += contentResult.consumed;
9140
9527
  consumed += contentResult.consumed;
9141
9528
  if (!contentResult.foundClose) {
9142
- ctx.diagnostics.push({
9143
- severity: "warning",
9144
- code: "unclosed-block",
9145
- message: `Missing closing tag [[/${openResult.blockName}]] for [[${openResult.blockName}]]`,
9146
- position: openToken.position
9147
- });
9529
+ if (!ctx.diagnostics.some((d) => d.code === "unclosed-block" && d.position === openToken.position))
9530
+ ctx.diagnostics.push({
9531
+ severity: "warning",
9532
+ code: "unclosed-block",
9533
+ message: `Missing closing tag [[/${openResult.blockName}]] for [[${openResult.blockName}]]`,
9534
+ position: openToken.position
9535
+ });
9148
9536
  return { success: false };
9149
9537
  }
9150
9538
  const closeConsumed = consumeEmbedClose(ctx, pos);
9151
9539
  pos += closeConsumed;
9152
9540
  consumed += closeConsumed;
9153
- return {
9154
- success: true,
9155
- elements: [
9156
- {
9157
- element: "container",
9158
- data: {
9159
- type: "paragraph",
9160
- attributes: {},
9161
- elements: [
9162
- {
9163
- element: "embed-block",
9164
- data: {
9165
- contents: contentResult.contents.trim()
9166
- }
9167
- }
9168
- ]
9169
- }
9170
- }
9171
- ],
9172
- consumed
9173
- };
9541
+ const elements = [
9542
+ { element: "embed-block", data: { contents: contentResult.contents.trim() } }
9543
+ ];
9544
+ if (ctx.scope.inlineEnd === undefined && ctx.tokens[pos]?.type !== "NEWLINE" && ctx.tokens[pos]?.type !== "EOF") {
9545
+ const after = parseInlineUntil({ ...ctx, pos }, "PARAGRAPH_BREAK");
9546
+ const tail = normalizeParagraphElements(after.elements);
9547
+ if (tail[0]?.element === "text")
9548
+ tail[0].data = tail[0].data.trimStart();
9549
+ elements.push(...tail);
9550
+ consumed += after.consumed;
9551
+ }
9552
+ return { success: true, elements, consumed };
9174
9553
  }
9175
9554
  };
9176
9555
 
@@ -9484,11 +9863,11 @@ var iftagsRule = {
9484
9863
  };
9485
9864
 
9486
9865
  // packages/parser/src/parser/rules/block/toc/element.ts
9487
- function createTocElement(align) {
9866
+ function createTocElement(align, title) {
9488
9867
  return {
9489
9868
  element: "table-of-contents",
9490
9869
  data: {
9491
- attributes: {},
9870
+ attributes: title === undefined ? {} : { title },
9492
9871
  align
9493
9872
  }
9494
9873
  };
@@ -9531,26 +9910,17 @@ function parseTocOpen(ctx, startPos) {
9531
9910
  } else {
9532
9911
  return null;
9533
9912
  }
9534
- pos = skipUntilClose(ctx, pos);
9913
+ const attributes = parseAttributes(ctx, pos);
9914
+ pos += attributes.consumed;
9535
9915
  if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
9536
9916
  return null;
9537
9917
  }
9538
9918
  return {
9539
9919
  align,
9920
+ title: attributes.attrs.title,
9540
9921
  consumed: pos + 1 - startPos
9541
9922
  };
9542
9923
  }
9543
- function skipUntilClose(ctx, startPos) {
9544
- let pos = startPos;
9545
- while (pos < ctx.tokens.length) {
9546
- const token5 = ctx.tokens[pos];
9547
- if (!token5 || token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
9548
- break;
9549
- }
9550
- pos++;
9551
- }
9552
- return pos;
9553
- }
9554
9924
  function isNameToken(token5) {
9555
9925
  return token5?.type === "TEXT" || token5?.type === "IDENTIFIER";
9556
9926
  }
@@ -9574,7 +9944,7 @@ var tocRule = {
9574
9944
  }
9575
9945
  return {
9576
9946
  success: true,
9577
- elements: [createTocElement(openResult.align)],
9947
+ elements: [createTocElement(openResult.align, openResult.title)],
9578
9948
  consumed: openResult.consumed
9579
9949
  };
9580
9950
  }
@@ -10175,6 +10545,31 @@ var blockRules = [
10175
10545
  galleryRule,
10176
10546
  divRule
10177
10547
  ];
10548
+ // packages/parser/src/parser/rules/inline/formatting/close.ts
10549
+ function findFormattingClose(ctx, start, marker) {
10550
+ const table = ctx.scope.tableFormatting;
10551
+ const end = table?.end ?? ctx.scope.inlineEnd ?? ctx.tokens.length;
10552
+ for (let pos = start;pos < end; pos++) {
10553
+ const token5 = ctx.tokens[pos];
10554
+ if (!token5 || token5.type === "EOF" || ctx.scope.blockCloseCondition?.({ ...ctx, pos }))
10555
+ return null;
10556
+ if (!table && token5.type === "NEWLINE" && getParagraphNewlineBoundary(ctx, pos, true).shouldBreak)
10557
+ return null;
10558
+ if (token5.type === marker && !table?.suppressedClosers.has(pos))
10559
+ return pos;
10560
+ const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
10561
+ if (protectedEnd > pos)
10562
+ pos = protectedEnd - 1;
10563
+ }
10564
+ return null;
10565
+ }
10566
+ function consumeFormattingClose(ctx, close, contentEnd) {
10567
+ if (close === contentEnd)
10568
+ return 1;
10569
+ ctx.scope.tableFormatting?.suppressedClosers.add(close);
10570
+ return 0;
10571
+ }
10572
+
10178
10573
  // packages/parser/src/parser/rules/inline/formatting/container.ts
10179
10574
  function createInlineContainer(type, elements) {
10180
10575
  return {
@@ -10186,9 +10581,10 @@ function createInlineContainer(type, elements) {
10186
10581
  }
10187
10582
  };
10188
10583
  }
10189
- function parseSameLineDelimitedContainer(ctx, closeToken, type, options = {}) {
10584
+ function parseDelimitedContainer(ctx, closeToken, type, options = {}) {
10190
10585
  const startToken = currentToken(ctx);
10191
- if (!hasClosingMarkerBeforeNewline({ ...ctx, pos: ctx.pos + 1 }, closeToken)) {
10586
+ const close = findFormattingClose(ctx, ctx.pos + 1, closeToken);
10587
+ if (close === null) {
10192
10588
  return {
10193
10589
  success: true,
10194
10590
  elements: [{ element: "text", data: startToken.value }],
@@ -10196,7 +10592,7 @@ function parseSameLineDelimitedContainer(ctx, closeToken, type, options = {}) {
10196
10592
  };
10197
10593
  }
10198
10594
  const result = parseInlineUntil({ ...ctx, pos: ctx.pos + 1 }, closeToken);
10199
- const consumed = 1 + result.consumed + 1;
10595
+ const consumed = 1 + result.consumed + consumeFormattingClose(ctx, close, ctx.pos + 1 + result.consumed);
10200
10596
  if (options.discardEmpty === true && result.elements.length === 0) {
10201
10597
  return {
10202
10598
  success: true,
@@ -10216,7 +10612,7 @@ var boldRule = {
10216
10612
  name: "bold",
10217
10613
  startTokens: ["BOLD_MARKER"],
10218
10614
  parse(ctx) {
10219
- return parseSameLineDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
10615
+ return parseDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
10220
10616
  }
10221
10617
  };
10222
10618
 
@@ -10225,102 +10621,28 @@ var italicRule = {
10225
10621
  name: "italic",
10226
10622
  startTokens: ["ITALIC_MARKER"],
10227
10623
  parse(ctx) {
10228
- return parseSameLineDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
10624
+ return parseDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
10229
10625
  }
10230
10626
  };
10231
10627
 
10232
- // packages/parser/src/parser/rules/inline/underline/child.ts
10233
- function parseUnderlineChild(ctx, pos) {
10234
- const token5 = ctx.tokens[pos];
10235
- if (!token5) {
10236
- return { elements: [], consumed: 0 };
10237
- }
10238
- if (token5.type === "NEWLINE") {
10239
- return { elements: [{ element: "line-break" }], consumed: 1 };
10240
- }
10241
- const result = parseInlineUntil({ ...ctx, pos }, "UNDERLINE_MARKER");
10242
- if (result.elements.length > 0) {
10243
- return { elements: result.elements, consumed: result.consumed };
10244
- }
10245
- return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
10246
- }
10247
-
10248
- // packages/parser/src/parser/rules/inline/underline/content.ts
10249
- function parseUnderlineContent(ctx, startPos) {
10250
- const children = [];
10251
- let pos = startPos;
10252
- let consumed = 1;
10253
- while (pos < ctx.tokens.length) {
10254
- const token5 = ctx.tokens[pos];
10255
- if (!token5 || token5.type === "EOF")
10256
- break;
10257
- if (token5.type === "UNDERLINE_MARKER") {
10258
- consumed++;
10259
- break;
10260
- }
10261
- const child = parseUnderlineChild(ctx, pos);
10262
- children.push(...child.elements);
10263
- pos += child.consumed;
10264
- consumed += child.consumed;
10265
- }
10266
- return { children, consumed };
10267
- }
10268
-
10269
10628
  // packages/parser/src/parser/rules/inline/underline/index.ts
10270
10629
  var underlineRule = {
10271
10630
  name: "underline",
10272
10631
  startTokens: ["UNDERLINE_MARKER"],
10273
10632
  parse(ctx) {
10274
- const startToken = currentToken(ctx);
10275
- if (!hasClosingMarkerBeforeParagraphBreak({ ...ctx, pos: ctx.pos + 1 }, "UNDERLINE_MARKER")) {
10276
- return {
10277
- success: true,
10278
- elements: [{ element: "text", data: startToken.value }],
10279
- consumed: 1
10280
- };
10281
- }
10282
- const { children, consumed } = parseUnderlineContent(ctx, ctx.pos + 1);
10283
- if (children.length === 0) {
10284
- return {
10285
- success: true,
10286
- elements: [],
10287
- consumed
10288
- };
10289
- }
10290
- return {
10291
- success: true,
10292
- elements: [createInlineContainer("underline", children)],
10293
- consumed
10294
- };
10633
+ return parseDelimitedContainer(ctx, "UNDERLINE_MARKER", "underline", { discardEmpty: true });
10295
10634
  }
10296
10635
  };
10297
10636
 
10298
10637
  // packages/parser/src/parser/rules/inline/strikethrough/parse.ts
10299
10638
  function parseStrikethroughContent(ctx) {
10300
- const result = parseInlineUntil({ ...ctx, pos: ctx.pos + 1 }, "STRIKE_MARKER");
10301
- return {
10302
- success: true,
10303
- elements: [createInlineContainer("strikethrough", result.elements)],
10304
- consumed: 1 + result.consumed + 1
10305
- };
10639
+ return parseDelimitedContainer(ctx, "STRIKE_MARKER", "strikethrough");
10306
10640
  }
10307
10641
 
10308
10642
  // packages/parser/src/parser/rules/inline/strikethrough/syntax.ts
10309
10643
  function hasValidStrikethroughClose(ctx) {
10310
- let pos = ctx.pos + 1;
10311
- let prevWasWhitespace = false;
10312
- while (pos < ctx.tokens.length) {
10313
- const token5 = ctx.tokens[pos];
10314
- if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
10315
- return false;
10316
- }
10317
- if (token5.type === "STRIKE_MARKER") {
10318
- return !prevWasWhitespace;
10319
- }
10320
- prevWasWhitespace = token5.type === "WHITESPACE";
10321
- pos++;
10322
- }
10323
- return false;
10644
+ const close = findFormattingClose(ctx, ctx.pos + 1, "STRIKE_MARKER");
10645
+ return close !== null && close > ctx.pos + 1 && ctx.tokens[close - 1]?.type !== "WHITESPACE";
10324
10646
  }
10325
10647
 
10326
10648
  // packages/parser/src/parser/rules/inline/strikethrough/index.ts
@@ -10344,7 +10666,7 @@ var superscriptRule = {
10344
10666
  name: "superscript",
10345
10667
  startTokens: ["SUPER_MARKER"],
10346
10668
  parse(ctx) {
10347
- return parseSameLineDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
10669
+ return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
10348
10670
  discardEmpty: true
10349
10671
  });
10350
10672
  }
@@ -10355,7 +10677,7 @@ var subscriptRule = {
10355
10677
  name: "subscript",
10356
10678
  startTokens: ["SUB_MARKER"],
10357
10679
  parse(ctx) {
10358
- return parseSameLineDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
10680
+ return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
10359
10681
  }
10360
10682
  };
10361
10683
 
@@ -10364,7 +10686,7 @@ var monospaceRule = {
10364
10686
  name: "monospace",
10365
10687
  startTokens: ["MONO_MARKER"],
10366
10688
  parse(ctx) {
10367
- return parseSameLineDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
10689
+ return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
10368
10690
  }
10369
10691
  };
10370
10692
 
@@ -10725,13 +11047,14 @@ var linkStarRule = {
10725
11047
 
10726
11048
  // packages/parser/src/parser/rules/inline/color/syntax.ts
10727
11049
  function parseColorContent(ctx) {
10728
- if (!hasClosingMarkerBeforeNewline({ ...ctx, pos: ctx.pos + 1 }, "COLOR_MARKER")) {
11050
+ const close = findFormattingClose(ctx, ctx.pos + 1, "COLOR_MARKER");
11051
+ if (close === null) {
10729
11052
  return null;
10730
11053
  }
10731
11054
  let pos = ctx.pos + 1;
10732
11055
  let consumed = 1;
10733
11056
  let colorSpec = "";
10734
- while (pos < ctx.tokens.length) {
11057
+ while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
10735
11058
  const token5 = ctx.tokens[pos];
10736
11059
  if (!token5 || token5.type === "PIPE" || token5.type === "COLOR_MARKER" || token5.type === "NEWLINE" || token5.type === "EOF") {
10737
11060
  break;
@@ -10748,14 +11071,11 @@ function parseColorContent(ctx) {
10748
11071
  const contentResult = parseInlineUntil({ ...ctx, pos }, "COLOR_MARKER");
10749
11072
  pos += contentResult.consumed;
10750
11073
  consumed += contentResult.consumed;
10751
- if (ctx.tokens[pos]?.type !== "COLOR_MARKER") {
10752
- return null;
10753
- }
10754
- consumed++;
10755
11074
  const color = colorSpec.trim();
10756
11075
  if (color === "" || contentResult.elements.length === 0) {
10757
11076
  return null;
10758
11077
  }
11078
+ consumed += consumeFormattingClose(ctx, close, pos);
10759
11079
  return {
10760
11080
  color: hexifyColor(color),
10761
11081
  elements: contentResult.elements,
@@ -11378,14 +11698,19 @@ function parseSpanContent(ctx, startPos, blockName) {
11378
11698
  const escapedChildren = [];
11379
11699
  const splitSpans = [];
11380
11700
  let foundClose = false;
11701
+ let forcedClose = false;
11381
11702
  let afterBlankLine = false;
11382
11703
  let consumed = 0;
11383
11704
  let pos = startPos;
11384
- while (pos < ctx.tokens.length) {
11705
+ while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
11385
11706
  const token5 = ctx.tokens[pos];
11386
11707
  if (!token5 || token5.type === "EOF") {
11387
11708
  break;
11388
11709
  }
11710
+ if (ctx.scope.tableFormatting?.suppressedClosers.has(pos)) {
11711
+ forcedClose = true;
11712
+ break;
11713
+ }
11389
11714
  const close = parseCloseSpan(ctx, pos);
11390
11715
  if (close.success) {
11391
11716
  pos += close.consumed;
@@ -11410,6 +11735,29 @@ function parseSpanContent(ctx, startPos, blockName) {
11410
11735
  pos += parsed.consumed;
11411
11736
  consumed += parsed.consumed;
11412
11737
  }
11738
+ if (!foundClose && ctx.scope.tableFormatting && (pos === ctx.scope.inlineEnd || forcedClose)) {
11739
+ let depth = 0;
11740
+ for (let next = pos;next < ctx.scope.tableFormatting.end; next++) {
11741
+ const rawEnd = rawRegionEnd(ctx.tokens, next, ctx.scope.tableFormatting.end);
11742
+ if (rawEnd > next) {
11743
+ next = rawEnd - 1;
11744
+ continue;
11745
+ }
11746
+ if (ctx.tokens[next]?.type === "BLOCK_OPEN" && /^span_?$/i.test(ctx.tokens[next + 1]?.value ?? ""))
11747
+ depth++;
11748
+ const close = parseCloseSpan(ctx, next);
11749
+ if (!close.success)
11750
+ continue;
11751
+ if (depth > 0) {
11752
+ depth--;
11753
+ continue;
11754
+ }
11755
+ for (let offset = 0;offset < close.consumed; offset++)
11756
+ ctx.scope.tableFormatting.suppressedClosers.add(next + offset);
11757
+ foundClose = true;
11758
+ break;
11759
+ }
11760
+ }
11413
11761
  return { children, escapedChildren, splitSpans, consumed, foundClose };
11414
11762
  }
11415
11763
  function parseOneSpanChild(ctx, pos, targetChildren) {
@@ -11821,135 +12169,6 @@ var footnoteRule = {
11821
12169
  }
11822
12170
  };
11823
12171
 
11824
- // packages/parser/src/parser/rules/inline/image/attributes.ts
11825
- function parseImageAttributes(ctx, startPos) {
11826
- const result = parseAttributesRaw(ctx, startPos, false);
11827
- const link = result.attrs.link ?? null;
11828
- const { link: _link, ...htmlAttributes } = result.attrs;
11829
- return {
11830
- attributes: filterUnsafeAttributes(htmlAttributes),
11831
- link,
11832
- consumed: result.consumed
11833
- };
11834
- }
11835
-
11836
- // packages/parser/src/parser/rules/inline/image/body.ts
11837
- function parseImageSourceText(ctx, startPos) {
11838
- let pos = startPos;
11839
- let consumed = 0;
11840
- while (ctx.tokens[pos]?.type === "WHITESPACE") {
11841
- pos++;
11842
- consumed++;
11843
- }
11844
- let sourceText = "";
11845
- while (pos < ctx.tokens.length) {
11846
- const token5 = ctx.tokens[pos];
11847
- if (!token5 || token5.type === "WHITESPACE" || token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
11848
- break;
11849
- }
11850
- sourceText += token5.value;
11851
- pos++;
11852
- consumed++;
11853
- }
11854
- return { sourceText, consumed };
11855
- }
11856
-
11857
- // packages/parser/src/parser/rules/inline/image/syntax.ts
11858
- var IMAGE_BLOCK_NAMES = new Set([
11859
- "image",
11860
- "=image",
11861
- "<image",
11862
- ">image",
11863
- "f<image",
11864
- "f>image",
11865
- "f=image"
11866
- ]);
11867
- function parseImageBlockName(ctx, startPos) {
11868
- let pos = startPos;
11869
- let consumed = 0;
11870
- while (ctx.tokens[pos]?.type === "WHITESPACE") {
11871
- pos++;
11872
- consumed++;
11873
- }
11874
- const prefixResult = parseImagePrefix(ctx, pos);
11875
- const prefix = prefixResult.prefix;
11876
- pos += prefixResult.consumed;
11877
- consumed += prefixResult.consumed;
11878
- const nameToken = ctx.tokens[pos];
11879
- if (!nameToken || nameToken.type !== "TEXT" && nameToken.type !== "IDENTIFIER") {
11880
- return null;
11881
- }
11882
- return { name: prefix + nameToken.value.toLowerCase(), consumed: consumed + 1 };
11883
- }
11884
- function isImageBlockName(blockName) {
11885
- return IMAGE_BLOCK_NAMES.has(blockName);
11886
- }
11887
- function parseImagePrefix(ctx, pos) {
11888
- const token5 = ctx.tokens[pos];
11889
- if (token5?.type === "EQUALS") {
11890
- return { prefix: "=", consumed: 1 };
11891
- }
11892
- if (token5?.type === "TEXT" && token5.value === "<") {
11893
- return { prefix: "<", consumed: 1 };
11894
- }
11895
- if ((token5?.type === "TEXT" || token5?.type === "BLOCKQUOTE_MARKER") && token5.value === ">") {
11896
- return { prefix: ">", consumed: 1 };
11897
- }
11898
- if (token5?.type === "IDENTIFIER" && token5.value.toLowerCase() === "f") {
11899
- return parseFloatPrefix(ctx, pos + 1);
11900
- }
11901
- return { prefix: "", consumed: 0 };
11902
- }
11903
- function parseFloatPrefix(ctx, pos) {
11904
- const token5 = ctx.tokens[pos];
11905
- if (token5?.type === "TEXT" && token5.value === "<") {
11906
- return { prefix: "f<", consumed: 2 };
11907
- }
11908
- if ((token5?.type === "TEXT" || token5?.type === "BLOCKQUOTE_MARKER") && token5.value === ">") {
11909
- return { prefix: "f>", consumed: 2 };
11910
- }
11911
- if (token5?.type === "EQUALS") {
11912
- return { prefix: "f=", consumed: 2 };
11913
- }
11914
- return { prefix: "", consumed: 0 };
11915
- }
11916
-
11917
- // packages/parser/src/parser/rules/inline/image/open.ts
11918
- function parseImageOpen(ctx) {
11919
- if (ctx.tokens[ctx.pos]?.type !== "BLOCK_OPEN") {
11920
- return null;
11921
- }
11922
- let pos = ctx.pos + 1;
11923
- let consumed = 1;
11924
- const nameResult = parseImageBlockName(ctx, pos);
11925
- if (!nameResult || !isImageBlockName(nameResult.name)) {
11926
- return null;
11927
- }
11928
- pos += nameResult.consumed;
11929
- consumed += nameResult.consumed;
11930
- const sourceText = parseImageSourceText(ctx, pos);
11931
- pos += sourceText.consumed;
11932
- consumed += sourceText.consumed;
11933
- const attrs = parseImageAttributes(ctx, pos);
11934
- pos += attrs.consumed;
11935
- consumed += attrs.consumed;
11936
- if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
11937
- return null;
11938
- }
11939
- pos++;
11940
- consumed++;
11941
- if (!sourceText.sourceText) {
11942
- return null;
11943
- }
11944
- return {
11945
- blockName: nameResult.name,
11946
- sourceText: sourceText.sourceText,
11947
- link: attrs.link,
11948
- attributes: attrs.attributes,
11949
- consumed
11950
- };
11951
- }
11952
-
11953
12172
  // packages/parser/src/parser/rules/inline/image/source.ts
11954
12173
  function parseImageSource(src) {
11955
12174
  if (src.startsWith("http://") || src.startsWith("https://") || src.startsWith("/")) {
@@ -13000,6 +13219,7 @@ var inlineRules = [
13000
13219
  htmlInlineRule,
13001
13220
  rawRule,
13002
13221
  imageRule,
13222
+ embedBlockRule,
13003
13223
  sizeRule,
13004
13224
  footnoteRule,
13005
13225
  spanRule,