markdown-codec 6.7.5 → 6.7.6

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/emit/emit.js CHANGED
@@ -31,6 +31,10 @@ function renderSetextHeading(level, text) {
31
31
  const [firstLine] = splitLines(text, LINE_ENDING_PATTERN);
32
32
  return `${text}\n${underlineChar.repeat(Math.max(MIN_SETEXT_UNDERLINE_LENGTH, firstLine.length))}`;
33
33
  }
34
+ function renderAtxHeading(level, text) {
35
+ const collapsed = text.replace(ESCAPED_HARD_BREAK_PATTERN, " ").split(LINE_ENDING_PATTERN).join(" ");
36
+ return `${"#".repeat(level)} ${collapsed}`;
37
+ }
34
38
  const MIN_CODE_FENCE_LENGTH = 3;
35
39
  function longestRunLength(text, char) {
36
40
  let longest = 0;
@@ -64,7 +68,7 @@ function firstContentLineIndex(text) {
64
68
  }
65
69
  function leadingIndentReachesCodeThreshold(line) {
66
70
  let column = 0;
67
- while (column < line.length && line[column] === " ") column += 1;
71
+ while (line[column] === " ") column += 1;
68
72
  if (column >= 4) return true;
69
73
  return line[column] === " ";
70
74
  }
@@ -83,18 +87,16 @@ function tableDelimiterRowPromotesPrecedingLine(line, precedingLine) {
83
87
  return parseTableDelimiterRow(cursor.restFromNextNonspace())?.length === splitTableRow(precedingLine).length;
84
88
  }
85
89
  function unsafeSetextBreakReason(text) {
86
- let sawContentLine = false;
87
90
  let leadingBlankLines = 0;
88
- let precedingLine = "";
91
+ let precedingLine;
89
92
  for (const line of text.split(LINE_ENDING_PATTERN)) {
90
93
  const isBlank = BLANK_OR_WHITESPACE_ONLY_LINE.test(line);
91
- if (!sawContentLine) {
94
+ if (precedingLine === void 0) {
92
95
  if (isBlank) {
93
96
  leadingBlankLines += 1;
94
97
  if (leadingBlankLines > MAX_LEADING_BLANK_LINES_FOR_SETEXT) return "blank-line";
95
98
  continue;
96
99
  }
97
- sawContentLine = true;
98
100
  if (leadingIndentReachesCodeThreshold(line)) return "leading-indentation";
99
101
  if (interruptsSetextParagraph(line, true)) return "interrupting-line";
100
102
  precedingLine = line;
@@ -104,7 +106,7 @@ function unsafeSetextBreakReason(text) {
104
106
  if (interruptsSetextParagraph(line, false) || tableDelimiterRowPromotesPrecedingLine(line, precedingLine)) return "interrupting-line";
105
107
  precedingLine = line;
106
108
  }
107
- return sawContentLine ? void 0 : "blank-line";
109
+ return precedingLine === void 0 ? "blank-line" : void 0;
108
110
  }
109
111
  function embedsUnsafeBreakForSetext(text) {
110
112
  return unsafeSetextBreakReason(text) !== void 0;
@@ -177,18 +179,14 @@ function renderParagraphBody(paragraph, context) {
177
179
  severity: "info",
178
180
  message: unsafeSetextDiagnosticMessage(level, unsafeSetextReason, embedsLineBreak)
179
181
  });
180
- if (embedsLineBreak) return `${"#".repeat(level)} ${text.replace(ESCAPED_HARD_BREAK_PATTERN, " ").split(LINE_ENDING_PATTERN).join(" ")}`;
181
- return `${"#".repeat(level)} ${text}`;
182
+ return renderAtxHeading(level, text);
182
183
  }
183
- if (embedsLineBreak) {
184
- context.sink({
185
- code: MarkdownDiagnosticCodes.HEADING_LINE_BREAK_COLLAPSED,
186
- severity: "info",
187
- message: `a level ${String(level)} heading's own content contains a line break; only setext's own level-1/2 grammar can hold one, so ATX collapses it to a single space`
188
- });
189
- return `${"#".repeat(level)} ${text.replace(ESCAPED_HARD_BREAK_PATTERN, " ").split(LINE_ENDING_PATTERN).join(" ")}`;
190
- }
191
- return `${"#".repeat(level)} ${text}`;
184
+ if (embedsLineBreak) context.sink({
185
+ code: MarkdownDiagnosticCodes.HEADING_LINE_BREAK_COLLAPSED,
186
+ severity: "info",
187
+ message: `a level ${String(level)} heading's own content contains a line break; only setext's own level-1/2 grammar can hold one, so ATX collapses it to a single space`
188
+ });
189
+ return renderAtxHeading(level, text);
192
190
  }
193
191
  return emitRuns(paragraph.runs, context, paragraph.constructs);
194
192
  }
@@ -270,12 +268,12 @@ function firstBlockCheckbox(first, taskNumId) {
270
268
  checkboxText: "",
271
269
  strippedFirstBlock: void 0
272
270
  };
273
- const leading = first.block.runs[0]?.text ?? "";
274
- if (leading.startsWith(`☒ `)) return {
271
+ const leading = first.block.runs[0]?.text;
272
+ if (leading?.startsWith(`☒ `) === true) return {
275
273
  checkboxText: "[x] ",
276
274
  strippedFirstBlock: stripCheckboxRun(first.block)
277
275
  };
278
- if (leading.startsWith(`☐ `)) return {
276
+ if (leading?.startsWith(`☐ `) === true) return {
279
277
  checkboxText: "[ ] ",
280
278
  strippedFirstBlock: stripCheckboxRun(first.block)
281
279
  };
@@ -412,7 +410,7 @@ function renderListRegion(items, context) {
412
410
  const { checkboxText, strippedFirstBlock } = firstBlockCheckbox(first, info?.task === true);
413
411
  const marker = renderListItemMarker(numId, info, glyph, checkboxText, context);
414
412
  const indent = " ".repeat(marker.bareLength);
415
- let text = "";
413
+ let text = marker.full;
416
414
  let renderedFirstLine = false;
417
415
  let previousStyleId;
418
416
  for (const segment of segments) {
@@ -426,7 +424,7 @@ function renderListRegion(items, context) {
426
424
  for (const block of segment.blocks) {
427
425
  if (!renderedFirstLine) {
428
426
  const [firstLine, ...restLines] = splitLines(listRegionItemBody(block, context, strippedFirstBlock), "\n");
429
- text = [`${marker.full}${firstLine}`, ...restLines.map((line) => `${indent}${line}`)].join("\n");
427
+ text += [firstLine, ...restLines.map((line) => `${indent}${line}`)].join("\n");
430
428
  renderedFirstLine = true;
431
429
  previousStyleId = lastStyleIdOfRegionItem(block);
432
430
  continue;
@@ -447,9 +445,8 @@ function renderListRegion(items, context) {
447
445
  for (const [partIndex, part] of parts.entries()) {
448
446
  if (partIndex > 0) {
449
447
  const previous = parts[partIndex - 1];
450
- const sameList = previous.numId === part.numId;
451
- const loose = sameList && previous.numId !== void 0 && (parseListNumId(previous.numId)?.loose ?? false);
452
- out += sameList && !loose ? "\n" : "\n\n";
448
+ const continuesTightly = previous.numId === part.numId && (previous.numId === void 0 || parseListNumId(previous.numId)?.loose !== true);
449
+ out += continuesTightly ? "\n" : "\n\n";
453
450
  }
454
451
  out += part.text;
455
452
  }
@@ -458,10 +455,11 @@ function renderListRegion(items, context) {
458
455
  function isConstructItem(item) {
459
456
  return "descriptor" in item;
460
457
  }
458
+ const UNINDENTED_PT = 0;
461
459
  function isMaterialisedDivision(item) {
462
460
  return item.descriptor.kind === "division" && item.children.every((child) => {
463
461
  if (isConstructItem(child)) return true;
464
- return child.block.kind !== "paragraph" || child.block.indentLeftPt !== void 0 && child.block.indentLeftPt >= 36;
462
+ return child.block.kind !== "paragraph" || (child.block.indentLeftPt ?? UNINDENTED_PT) >= 36;
465
463
  });
466
464
  }
467
465
  function groupConstructItems(blocks, start) {
@@ -39,11 +39,12 @@ const ESCAPE_CHARS = /* @__PURE__ */ new Set([
39
39
  function escapeMarkdownText(text) {
40
40
  let out = "";
41
41
  let index = 0;
42
- while (index < text.length) {
43
- const char = text.charAt(index);
42
+ for (;;) {
43
+ const char = text[index];
44
+ if (char === void 0) break;
44
45
  if (char === "\n" || char === "\r") {
45
46
  out += "\\\n";
46
- index += char === "\r" && text.charAt(index + 1) === "\n" ? 2 : 1;
47
+ index += char === "\r" && text[index + 1] === "\n" ? 2 : 1;
47
48
  continue;
48
49
  }
49
50
  if (ESCAPE_CHARS.has(char)) {
@@ -64,9 +65,8 @@ function renderCodeSpan(text) {
64
65
  longestBacktickRun = Math.max(longestBacktickRun, current);
65
66
  } else current = 0;
66
67
  const fence = "`".repeat(longestBacktickRun + 1);
67
- const isAllSpaces = text.length > 0 && text.trim().length === 0;
68
68
  const risksFenceCollision = text.startsWith("`") || text.endsWith("`");
69
- const wouldBeStrippedOnReparse = !isAllSpaces && text.startsWith(" ") && text.endsWith(" ");
69
+ const wouldBeStrippedOnReparse = text.startsWith(" ") && text.endsWith(" ") && text.trim().length > 0;
70
70
  return risksFenceCollision || wouldBeStrippedOnReparse ? `${fence} ${text} ${fence}` : `${fence}${text}${fence}`;
71
71
  }
72
72
  function footnoteReferenceAt(constructs, index) {
@@ -102,12 +102,11 @@ function styleActive(run, key) {
102
102
  }
103
103
  const WORD_CHAR_PATTERN = /[\p{L}\p{N}]/u;
104
104
  function isIntrawordRisk(body) {
105
- if (body.length === 0) return false;
106
105
  return WORD_CHAR_PATTERN.test(body.charAt(0)) || WORD_CHAR_PATTERN.test(body.charAt(body.length - 1));
107
106
  }
108
107
  function hasMarkerConflict(body, candidate, precedingText) {
109
108
  if (candidate === "_" && isIntrawordRisk(body)) return true;
110
- if (body.length > 0 && (body.startsWith(candidate) || body.endsWith(candidate))) return true;
109
+ if (body.startsWith(candidate) || body.endsWith(candidate)) return true;
111
110
  return precedingText.endsWith(candidate);
112
111
  }
113
112
  function pickEmphasisMarker(body, configured, precedingText) {
@@ -135,7 +134,7 @@ function groupCount(runs, key) {
135
134
  function pickSplitKey(runs, remaining) {
136
135
  let best = remaining[0];
137
136
  let bestCount = groupCount(runs, best);
138
- for (const key of remaining.slice(1)) {
137
+ for (const key of remaining) {
139
138
  const count = groupCount(runs, key);
140
139
  if (count < bestCount) {
141
140
  best = key;
@@ -150,7 +149,7 @@ function renderNestedStyles(runs, remainingKeys, context, base, constructs) {
150
149
  const rest = remainingKeys.filter((candidate) => candidate !== key);
151
150
  let out = "";
152
151
  let index = 0;
153
- while (index < runs.length) {
152
+ for (;;) {
154
153
  const current = runs[index];
155
154
  if (current === void 0) break;
156
155
  const active = styleActive(current, key);
@@ -186,19 +185,26 @@ function linkTitleCovering(constructs, start, end) {
186
185
  function emitRuns(runs, context, constructs) {
187
186
  let out = "";
188
187
  let index = 0;
189
- while (index < runs.length) {
188
+ for (;;) {
190
189
  const run = runs[index];
191
190
  if (run === void 0) break;
192
191
  if (run.hyperlink === void 0) {
193
192
  let end = index + 1;
194
- while (end < runs.length && runs[end]?.hyperlink === void 0) end += 1;
193
+ for (;;) {
194
+ const next = runs[end];
195
+ if (next === void 0 || next.hyperlink !== void 0) break;
196
+ end += 1;
197
+ }
195
198
  out += renderNestedStyles(runs.slice(index, end), STYLE_KEYS, context, index, constructs);
196
199
  index = end;
197
200
  continue;
198
201
  }
199
202
  const hyperlink = run.hyperlink;
200
203
  let groupEnd = index + 1;
201
- while (groupEnd < runs.length && runs[groupEnd]?.hyperlink === hyperlink) groupEnd += 1;
204
+ for (;;) {
205
+ if (runs[groupEnd]?.hyperlink !== hyperlink) break;
206
+ groupEnd += 1;
207
+ }
202
208
  const group = runs.slice(index, groupEnd);
203
209
  if (group.length > 1) context.sink({
204
210
  code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.ADJACENT_LINKS_MERGED,
@@ -38,11 +38,12 @@ const ESCAPE_CHARS = /* @__PURE__ */ new Set([
38
38
  function escapeMarkdownText(text) {
39
39
  let out = "";
40
40
  let index = 0;
41
- while (index < text.length) {
42
- const char = text.charAt(index);
41
+ for (;;) {
42
+ const char = text[index];
43
+ if (char === void 0) break;
43
44
  if (char === "\n" || char === "\r") {
44
45
  out += "\\\n";
45
- index += char === "\r" && text.charAt(index + 1) === "\n" ? 2 : 1;
46
+ index += char === "\r" && text[index + 1] === "\n" ? 2 : 1;
46
47
  continue;
47
48
  }
48
49
  if (ESCAPE_CHARS.has(char)) {
@@ -63,9 +64,8 @@ function renderCodeSpan(text) {
63
64
  longestBacktickRun = Math.max(longestBacktickRun, current);
64
65
  } else current = 0;
65
66
  const fence = "`".repeat(longestBacktickRun + 1);
66
- const isAllSpaces = text.length > 0 && text.trim().length === 0;
67
67
  const risksFenceCollision = text.startsWith("`") || text.endsWith("`");
68
- const wouldBeStrippedOnReparse = !isAllSpaces && text.startsWith(" ") && text.endsWith(" ");
68
+ const wouldBeStrippedOnReparse = text.startsWith(" ") && text.endsWith(" ") && text.trim().length > 0;
69
69
  return risksFenceCollision || wouldBeStrippedOnReparse ? `${fence} ${text} ${fence}` : `${fence}${text}${fence}`;
70
70
  }
71
71
  function footnoteReferenceAt(constructs, index) {
@@ -101,12 +101,11 @@ function styleActive(run, key) {
101
101
  }
102
102
  const WORD_CHAR_PATTERN = /[\p{L}\p{N}]/u;
103
103
  function isIntrawordRisk(body) {
104
- if (body.length === 0) return false;
105
104
  return WORD_CHAR_PATTERN.test(body.charAt(0)) || WORD_CHAR_PATTERN.test(body.charAt(body.length - 1));
106
105
  }
107
106
  function hasMarkerConflict(body, candidate, precedingText) {
108
107
  if (candidate === "_" && isIntrawordRisk(body)) return true;
109
- if (body.length > 0 && (body.startsWith(candidate) || body.endsWith(candidate))) return true;
108
+ if (body.startsWith(candidate) || body.endsWith(candidate)) return true;
110
109
  return precedingText.endsWith(candidate);
111
110
  }
112
111
  function pickEmphasisMarker(body, configured, precedingText) {
@@ -134,7 +133,7 @@ function groupCount(runs, key) {
134
133
  function pickSplitKey(runs, remaining) {
135
134
  let best = remaining[0];
136
135
  let bestCount = groupCount(runs, best);
137
- for (const key of remaining.slice(1)) {
136
+ for (const key of remaining) {
138
137
  const count = groupCount(runs, key);
139
138
  if (count < bestCount) {
140
139
  best = key;
@@ -149,7 +148,7 @@ function renderNestedStyles(runs, remainingKeys, context, base, constructs) {
149
148
  const rest = remainingKeys.filter((candidate) => candidate !== key);
150
149
  let out = "";
151
150
  let index = 0;
152
- while (index < runs.length) {
151
+ for (;;) {
153
152
  const current = runs[index];
154
153
  if (current === void 0) break;
155
154
  const active = styleActive(current, key);
@@ -185,19 +184,26 @@ function linkTitleCovering(constructs, start, end) {
185
184
  function emitRuns(runs, context, constructs) {
186
185
  let out = "";
187
186
  let index = 0;
188
- while (index < runs.length) {
187
+ for (;;) {
189
188
  const run = runs[index];
190
189
  if (run === void 0) break;
191
190
  if (run.hyperlink === void 0) {
192
191
  let end = index + 1;
193
- while (end < runs.length && runs[end]?.hyperlink === void 0) end += 1;
192
+ for (;;) {
193
+ const next = runs[end];
194
+ if (next === void 0 || next.hyperlink !== void 0) break;
195
+ end += 1;
196
+ }
194
197
  out += renderNestedStyles(runs.slice(index, end), STYLE_KEYS, context, index, constructs);
195
198
  index = end;
196
199
  continue;
197
200
  }
198
201
  const hyperlink = run.hyperlink;
199
202
  let groupEnd = index + 1;
200
- while (groupEnd < runs.length && runs[groupEnd]?.hyperlink === hyperlink) groupEnd += 1;
203
+ for (;;) {
204
+ if (runs[groupEnd]?.hyperlink !== hyperlink) break;
205
+ groupEnd += 1;
206
+ }
201
207
  const group = runs.slice(index, groupEnd);
202
208
  if (group.length > 1) context.sink({
203
209
  code: MarkdownDiagnosticCodes.ADJACENT_LINKS_MERGED,
@@ -5,25 +5,21 @@ let document_schema_js = require("document-schema.js");
5
5
  //#region src/html/html-table.ts
6
6
  function findBalancedClose(text, openEnd, tagNames) {
7
7
  const names = tagNames.join("|");
8
- const openPattern = new RegExp(`<(?:${names})(?=[\\s/>])`, "gi");
9
- const closePattern = new RegExp(`</(?:${names})\\s*>`, "gi");
8
+ const tagPattern = new RegExp(`</(?:${names})\\s*>|<(?:${names})(?=[\\s/>])`, "gi");
10
9
  let depth = 1;
11
10
  let pos = openEnd;
12
- while (depth > 0) {
13
- openPattern.lastIndex = pos;
14
- closePattern.lastIndex = pos;
15
- const openMatch = openPattern.exec(text);
16
- const closeMatch = closePattern.exec(text);
17
- if (closeMatch === null) return;
18
- if (openMatch !== null && openMatch.index < closeMatch.index) {
11
+ for (;;) {
12
+ tagPattern.lastIndex = pos;
13
+ const match = tagPattern.exec(text);
14
+ if (match === null) return;
15
+ pos = match.index + match[0].length;
16
+ if (!match[0].startsWith("</")) {
19
17
  depth += 1;
20
- pos = openMatch.index + openMatch[0].length;
21
18
  continue;
22
19
  }
23
20
  depth -= 1;
24
- pos = closeMatch.index + closeMatch[0].length;
25
21
  if (depth === 0) return {
26
- start: closeMatch.index,
22
+ start: match.index,
27
23
  end: pos
28
24
  };
29
25
  }
@@ -37,7 +33,7 @@ function extractTopLevelElements(text, tagNames) {
37
33
  const match = openPattern.exec(text);
38
34
  if (match === null) break;
39
35
  if (text.slice(pos, match.index).trim().length > 0) return;
40
- const attrs = match[1] ?? "";
36
+ const attrs = match[1];
41
37
  const openEnd = match.index + match[0].length;
42
38
  const close = findBalancedClose(text, openEnd, tagNames);
43
39
  if (close === void 0) return;
@@ -136,15 +132,15 @@ function parseInlineHtml(text, style) {
136
132
  pushPlainRun(runs, rest, style);
137
133
  return runs;
138
134
  }
139
- pushPlainRun(runs, rest.slice(0, match.index), style);
140
135
  const tagName = match[1].toLowerCase();
141
- const attrs = match[2] ?? "";
136
+ const attrs = match[2];
142
137
  const openEnd = pos + match.index + match[0].length;
143
138
  const close = findBalancedClose(text, openEnd, [tagName]);
144
139
  if (close === void 0) {
145
140
  pushPlainRun(runs, rest, style);
146
141
  return runs;
147
142
  }
143
+ pushPlainRun(runs, rest.slice(0, match.index), style);
148
144
  runs.push(...parseInlineHtml(text.slice(openEnd, close.start), applyTagStyle(style, tagName, attrs)));
149
145
  pos = close.end;
150
146
  }
@@ -168,12 +164,10 @@ function parseHtmlImage(piece) {
168
164
  };
169
165
  }
170
166
  function parseCellBlocks(inner, contentWidthPt) {
171
- const trimmed = inner.trim();
172
- if (trimmed.length === 0) return [];
173
- const nestedTable = parseWholeTable(trimmed, contentWidthPt);
167
+ const nestedTable = parseWholeTable(inner, contentWidthPt);
174
168
  if (nestedTable !== void 0) return [nestedTable];
175
169
  const blocks = [];
176
- for (const segment of trimmed.split(/<br\s*\/?>/i)) {
170
+ for (const segment of inner.split(/<br\s*\/?>/i)) {
177
171
  const piece = segment.trim();
178
172
  if (piece.length === 0) continue;
179
173
  const image = parseHtmlImage(piece);
@@ -235,9 +229,7 @@ function parseWholeTable(text, contentWidthPt) {
235
229
  return rows === void 0 ? void 0 : buildContentTable(rows, contentWidthPt);
236
230
  }
237
231
  function parseHtmlTable(literal, contentWidthPt) {
238
- const trimmed = literal.trim();
239
- if (!/^<table\b/i.test(trimmed)) return;
240
- return parseWholeTable(trimmed, contentWidthPt);
232
+ return parseWholeTable(literal, contentWidthPt);
241
233
  }
242
234
  //#endregion
243
235
  exports.parseHtmlTable = parseHtmlTable;
@@ -4,25 +4,21 @@ import { rgbHexToColor } from "document-schema.js";
4
4
  //#region src/html/html-table.ts
5
5
  function findBalancedClose(text, openEnd, tagNames) {
6
6
  const names = tagNames.join("|");
7
- const openPattern = new RegExp(`<(?:${names})(?=[\\s/>])`, "gi");
8
- const closePattern = new RegExp(`</(?:${names})\\s*>`, "gi");
7
+ const tagPattern = new RegExp(`</(?:${names})\\s*>|<(?:${names})(?=[\\s/>])`, "gi");
9
8
  let depth = 1;
10
9
  let pos = openEnd;
11
- while (depth > 0) {
12
- openPattern.lastIndex = pos;
13
- closePattern.lastIndex = pos;
14
- const openMatch = openPattern.exec(text);
15
- const closeMatch = closePattern.exec(text);
16
- if (closeMatch === null) return;
17
- if (openMatch !== null && openMatch.index < closeMatch.index) {
10
+ for (;;) {
11
+ tagPattern.lastIndex = pos;
12
+ const match = tagPattern.exec(text);
13
+ if (match === null) return;
14
+ pos = match.index + match[0].length;
15
+ if (!match[0].startsWith("</")) {
18
16
  depth += 1;
19
- pos = openMatch.index + openMatch[0].length;
20
17
  continue;
21
18
  }
22
19
  depth -= 1;
23
- pos = closeMatch.index + closeMatch[0].length;
24
20
  if (depth === 0) return {
25
- start: closeMatch.index,
21
+ start: match.index,
26
22
  end: pos
27
23
  };
28
24
  }
@@ -36,7 +32,7 @@ function extractTopLevelElements(text, tagNames) {
36
32
  const match = openPattern.exec(text);
37
33
  if (match === null) break;
38
34
  if (text.slice(pos, match.index).trim().length > 0) return;
39
- const attrs = match[1] ?? "";
35
+ const attrs = match[1];
40
36
  const openEnd = match.index + match[0].length;
41
37
  const close = findBalancedClose(text, openEnd, tagNames);
42
38
  if (close === void 0) return;
@@ -135,15 +131,15 @@ function parseInlineHtml(text, style) {
135
131
  pushPlainRun(runs, rest, style);
136
132
  return runs;
137
133
  }
138
- pushPlainRun(runs, rest.slice(0, match.index), style);
139
134
  const tagName = match[1].toLowerCase();
140
- const attrs = match[2] ?? "";
135
+ const attrs = match[2];
141
136
  const openEnd = pos + match.index + match[0].length;
142
137
  const close = findBalancedClose(text, openEnd, [tagName]);
143
138
  if (close === void 0) {
144
139
  pushPlainRun(runs, rest, style);
145
140
  return runs;
146
141
  }
142
+ pushPlainRun(runs, rest.slice(0, match.index), style);
147
143
  runs.push(...parseInlineHtml(text.slice(openEnd, close.start), applyTagStyle(style, tagName, attrs)));
148
144
  pos = close.end;
149
145
  }
@@ -167,12 +163,10 @@ function parseHtmlImage(piece) {
167
163
  };
168
164
  }
169
165
  function parseCellBlocks(inner, contentWidthPt) {
170
- const trimmed = inner.trim();
171
- if (trimmed.length === 0) return [];
172
- const nestedTable = parseWholeTable(trimmed, contentWidthPt);
166
+ const nestedTable = parseWholeTable(inner, contentWidthPt);
173
167
  if (nestedTable !== void 0) return [nestedTable];
174
168
  const blocks = [];
175
- for (const segment of trimmed.split(/<br\s*\/?>/i)) {
169
+ for (const segment of inner.split(/<br\s*\/?>/i)) {
176
170
  const piece = segment.trim();
177
171
  if (piece.length === 0) continue;
178
172
  const image = parseHtmlImage(piece);
@@ -234,9 +228,7 @@ function parseWholeTable(text, contentWidthPt) {
234
228
  return rows === void 0 ? void 0 : buildContentTable(rows, contentWidthPt);
235
229
  }
236
230
  function parseHtmlTable(literal, contentWidthPt) {
237
- const trimmed = literal.trim();
238
- if (!/^<table\b/i.test(trimmed)) return;
239
- return parseWholeTable(trimmed, contentWidthPt);
231
+ return parseWholeTable(literal, contentWidthPt);
240
232
  }
241
233
  //#endregion
242
234
  export { parseHtmlTable };
@@ -18,9 +18,11 @@ const PNG_SIGNATURE = [
18
18
  ];
19
19
  const PNG_HEADER_BYTES = 24;
20
20
  function isPng(bytes) {
21
- if (bytes.length < PNG_SIGNATURE.length) return false;
22
21
  return PNG_SIGNATURE.every((byte, index) => bytes[index] === byte);
23
22
  }
23
+ function isJpeg(bytes) {
24
+ return bytes[0] === 255 && bytes[1] === 216;
25
+ }
24
26
  function readPngDimensions(bytes) {
25
27
  if (bytes.length < PNG_HEADER_BYTES) return;
26
28
  if (bytes[12] !== 73 || bytes[13] !== 72 || bytes[14] !== 68 || bytes[15] !== 82) return;
@@ -37,10 +39,12 @@ function hasNoLengthField(marker) {
37
39
  return marker === 216 || marker === 217 || marker === 1 || marker >= 208 && marker <= 215;
38
40
  }
39
41
  function readJpegDimensions(bytes) {
40
- if (bytes.length < 4 || bytes[0] !== 255 || bytes[1] !== 216) return;
42
+ if (!isJpeg(bytes)) return;
41
43
  let offset = 2;
42
- while (offset < bytes.length) {
43
- if (bytes[offset] !== 255) {
44
+ for (;;) {
45
+ const byte = bytes[offset];
46
+ if (byte === void 0) return;
47
+ if (byte !== 255) {
44
48
  offset += 1;
45
49
  continue;
46
50
  }
@@ -50,7 +54,6 @@ function readJpegDimensions(bytes) {
50
54
  if (marker === void 0) return;
51
55
  offset = markerOffset + 1;
52
56
  if (hasNoLengthField(marker)) continue;
53
- if (offset + 2 > bytes.length) return;
54
57
  const length = readUint16BE(bytes, offset);
55
58
  if (isStartOfFrameMarker(marker)) {
56
59
  if (offset + 7 > bytes.length) return;
@@ -64,9 +67,6 @@ function readJpegDimensions(bytes) {
64
67
  offset += length;
65
68
  }
66
69
  }
67
- function isJpeg(bytes) {
68
- return bytes.length >= 2 && bytes[0] === 255 && bytes[1] === 216;
69
- }
70
70
  function detectImageFormat(bytes) {
71
71
  if (isPng(bytes)) return "png";
72
72
  return isJpeg(bytes) ? "jpeg" : void 0;
@@ -17,9 +17,11 @@ const PNG_SIGNATURE = [
17
17
  ];
18
18
  const PNG_HEADER_BYTES = 24;
19
19
  function isPng(bytes) {
20
- if (bytes.length < PNG_SIGNATURE.length) return false;
21
20
  return PNG_SIGNATURE.every((byte, index) => bytes[index] === byte);
22
21
  }
22
+ function isJpeg(bytes) {
23
+ return bytes[0] === 255 && bytes[1] === 216;
24
+ }
23
25
  function readPngDimensions(bytes) {
24
26
  if (bytes.length < PNG_HEADER_BYTES) return;
25
27
  if (bytes[12] !== 73 || bytes[13] !== 72 || bytes[14] !== 68 || bytes[15] !== 82) return;
@@ -36,10 +38,12 @@ function hasNoLengthField(marker) {
36
38
  return marker === 216 || marker === 217 || marker === 1 || marker >= 208 && marker <= 215;
37
39
  }
38
40
  function readJpegDimensions(bytes) {
39
- if (bytes.length < 4 || bytes[0] !== 255 || bytes[1] !== 216) return;
41
+ if (!isJpeg(bytes)) return;
40
42
  let offset = 2;
41
- while (offset < bytes.length) {
42
- if (bytes[offset] !== 255) {
43
+ for (;;) {
44
+ const byte = bytes[offset];
45
+ if (byte === void 0) return;
46
+ if (byte !== 255) {
43
47
  offset += 1;
44
48
  continue;
45
49
  }
@@ -49,7 +53,6 @@ function readJpegDimensions(bytes) {
49
53
  if (marker === void 0) return;
50
54
  offset = markerOffset + 1;
51
55
  if (hasNoLengthField(marker)) continue;
52
- if (offset + 2 > bytes.length) return;
53
56
  const length = readUint16BE(bytes, offset);
54
57
  if (isStartOfFrameMarker(marker)) {
55
58
  if (offset + 7 > bytes.length) return;
@@ -63,9 +66,6 @@ function readJpegDimensions(bytes) {
63
66
  offset += length;
64
67
  }
65
68
  }
66
- function isJpeg(bytes) {
67
- return bytes.length >= 2 && bytes[0] === 255 && bytes[1] === 216;
68
- }
69
69
  function detectImageFormat(bytes) {
70
70
  if (isPng(bytes)) return "png";
71
71
  return isJpeg(bytes) ? "jpeg" : void 0;
@@ -1,9 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_inline_chars = require("./chars.cjs");
3
3
  //#region src/inline/delimiter.ts
4
- function isDelimiterChar(char) {
5
- return char === "*" || char === "_" || char === "~";
6
- }
7
4
  const MAX_STRIKETHROUGH_RUN = 2;
8
5
  function scanDelimiterRun(text, start, char) {
9
6
  let count = 0;
@@ -124,6 +121,5 @@ function processEmphasis(stack, stackBottom, createWrapper) {
124
121
  //#endregion
125
122
  exports.DelimiterStack = DelimiterStack;
126
123
  exports.closerSignature = closerSignature;
127
- exports.isDelimiterChar = isDelimiterChar;
128
124
  exports.processEmphasis = processEmphasis;
129
125
  exports.scanDelimiterRun = scanDelimiterRun;
@@ -1,7 +1,6 @@
1
1
  import { InlineNode } from "./node.cjs";
2
2
  //#region src/inline/delimiter.d.ts
3
3
  type DelimiterChar = "*" | "_" | "~";
4
- declare function isDelimiterChar(char: string): char is DelimiterChar;
5
4
  interface Delimiter {
6
5
  readonly char: DelimiterChar;
7
6
  count: number;
@@ -27,4 +26,4 @@ declare function closerSignature(closer: Delimiter): string;
27
26
  type EmphasisWrapperFactory = (kind: "emphasis" | "strong" | "strikethrough", marker: DelimiterChar) => InlineNode;
28
27
  declare function processEmphasis(stack: DelimiterStack, stackBottom: Delimiter | undefined, createWrapper: EmphasisWrapperFactory): void;
29
28
  //#endregion
30
- export { Delimiter, DelimiterChar, DelimiterRun, DelimiterStack, EmphasisWrapperFactory, closerSignature, isDelimiterChar, processEmphasis, scanDelimiterRun };
29
+ export { Delimiter, DelimiterChar, DelimiterRun, DelimiterStack, EmphasisWrapperFactory, closerSignature, processEmphasis, scanDelimiterRun };
@@ -1,7 +1,6 @@
1
1
  import { InlineNode } from "./node.js";
2
2
  //#region src/inline/delimiter.d.ts
3
3
  type DelimiterChar = "*" | "_" | "~";
4
- declare function isDelimiterChar(char: string): char is DelimiterChar;
5
4
  interface Delimiter {
6
5
  readonly char: DelimiterChar;
7
6
  count: number;
@@ -27,4 +26,4 @@ declare function closerSignature(closer: Delimiter): string;
27
26
  type EmphasisWrapperFactory = (kind: "emphasis" | "strong" | "strikethrough", marker: DelimiterChar) => InlineNode;
28
27
  declare function processEmphasis(stack: DelimiterStack, stackBottom: Delimiter | undefined, createWrapper: EmphasisWrapperFactory): void;
29
28
  //#endregion
30
- export { Delimiter, DelimiterChar, DelimiterRun, DelimiterStack, EmphasisWrapperFactory, closerSignature, isDelimiterChar, processEmphasis, scanDelimiterRun };
29
+ export { Delimiter, DelimiterChar, DelimiterRun, DelimiterStack, EmphasisWrapperFactory, closerSignature, processEmphasis, scanDelimiterRun };
@@ -1,8 +1,5 @@
1
1
  import { codePointAt, codePointBefore, isUnicodePunctuation, isUnicodeWhitespace } from "./chars.js";
2
2
  //#region src/inline/delimiter.ts
3
- function isDelimiterChar(char) {
4
- return char === "*" || char === "_" || char === "~";
5
- }
6
3
  const MAX_STRIKETHROUGH_RUN = 2;
7
4
  function scanDelimiterRun(text, start, char) {
8
5
  let count = 0;
@@ -121,4 +118,4 @@ function processEmphasis(stack, stackBottom, createWrapper) {
121
118
  while (stack.top !== void 0 && stack.top !== stackBottom) stack.remove(stack.top);
122
119
  }
123
120
  //#endregion
124
- export { DelimiterStack, closerSignature, isDelimiterChar, processEmphasis, scanDelimiterRun };
121
+ export { DelimiterStack, closerSignature, processEmphasis, scanDelimiterRun };