Files
orca/config/patches/@tiptap__extension-list@3.31.3.patch
T
OrcaWinandOrcaWin 5951dbbf92 fix(editor): task-list parsing fixes (ordered parents, wrapped markup, tight continuations, bare markers) (#35187)
* fix(editor): preserve sibling tasks beneath ordered list items

* fix(editor): preserve wrapped inline markup in task items

* fix(editor): keep nested task continuations valid and editable

* fix(editor): keep literal task markers out of mixed checklists

* fix(editor): apply review fixes to task-list parsing stack

- Trim synthetic test matrices to the behavioral cases
- Regenerate pnpm-lock (drops a stale github-slugger importer entry)
- Assert the plain bullet's node type under an ordered parent

* fix(editor): keep one-column-deeper ordered tasks as sibling checkboxes

Dedent an ordered item's task block by the first task's column instead of
keeping its leading whitespace. A task one column deeper stays a sibling
checkbox, and text at or within the first task's column stays nested as
before. Strip leftover paragraph indent from task children.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 17:38:19 -07:00

313 lines
14 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/dist/index.cjs b/dist/index.cjs
--- a/dist/index.cjs
+++ b/dist/index.cjs
@@ -245,10 +245,9 @@
];
const ALPHA_NUMERALS = "abcdefghijklmnopqrstuvwxyz";
/**
-* Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.
-* Roman is matched before alpha so "iii" is roman; invalid romans like "aa" fall through to alpha.
+* Orca patch: ordered-list markers are digits only, as in CommonMark, so "Dr." and "A." stay prose.
*/
-const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+|[ivxlcdmIVXLCDM]+|${"[a-zA-Z]{1,2}"}`;
+const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+`;
/**
* Convert a number to lowercase roman numerals.
* @example toRoman(1) // 'i'
@@ -897,6 +896,26 @@
};
}
/**
+* Orca patch: marker columns are counted without the delimiter, so trim() left later sibling tasks indented and
+* parseIndentedBlocks cut into them. Dedent by the first task; a task one column deeper is a sibling, and other
+* text at or within the first task's column stays nested under the task above.
+*/
+function dedentOrderedItemTaskBlock(blockLines) {
+ const isTaskLine = (line) => /^\s*[-+*]\s+\[[ xX]\][^\S\r\n]/.test(line);
+ const leadingWidth = (line) => line.length - line.trimStart().length;
+ const firstIndex = blockLines.findIndex((line) => line.trim() !== "");
+ if (firstIndex === -1 || !isTaskLine(blockLines[firstIndex])) return null;
+ const firstIndent = leadingWidth(blockLines[firstIndex]);
+ return blockLines.slice(firstIndex).map((line) => {
+ if (line.trim() === "") return "";
+ const indent = leadingWidth(line);
+ const depth = indent - firstIndent;
+ if (isTaskLine(line)) return depth === 1 ? line.trimStart() : line.slice(Math.min(indent, firstIndent));
+ if (depth > 0) return depth === 1 ? ` ${line.slice(firstIndent)}` : line.slice(firstIndent);
+ return indent > 0 ? ` ${line.trimStart()}` : line;
+ }).join("\n").trimEnd();
+}
+/**
* Recursively builds a nested structure from a flat array of list items
* based on their indentation levels. Creates proper markdown tokens with
* nested lists where appropriate.
@@ -920,7 +939,7 @@
raw: mainText,
tokens: lexer.inlineTokens(mainText)
});
- const additionalContent = blockLines.join("\n").trim();
+ const additionalContent = dedentOrderedItemTaskBlock(blockLines) ?? blockLines.join("\n").trim();
if (additionalContent) {
const blockTokens = lexer.blockTokens(additionalContent);
tokens.push(...blockTokens);
diff --git a/dist/index.js b/dist/index.js
--- a/dist/index.js
+++ b/dist/index.js
@@ -233,10 +233,9 @@
];
const ALPHA_NUMERALS = "abcdefghijklmnopqrstuvwxyz";
/**
-* Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.
-* Roman is matched before alpha so "iii" is roman; invalid romans like "aa" fall through to alpha.
+* Orca patch: ordered-list markers are digits only, as in CommonMark, so "Dr." and "A." stay prose.
*/
-const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+|[ivxlcdmIVXLCDM]+|${"[a-zA-Z]{1,2}"}`;
+const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+`;
/**
* Convert a number to lowercase roman numerals.
* @example toRoman(1) // 'i'
@@ -885,6 +884,26 @@
};
}
/**
+* Orca patch: marker columns are counted without the delimiter, so trim() left later sibling tasks indented and
+* parseIndentedBlocks cut into them. Dedent by the first task; a task one column deeper is a sibling, and other
+* text at or within the first task's column stays nested under the task above.
+*/
+function dedentOrderedItemTaskBlock(blockLines) {
+ const isTaskLine = (line) => /^\s*[-+*]\s+\[[ xX]\][^\S\r\n]/.test(line);
+ const leadingWidth = (line) => line.length - line.trimStart().length;
+ const firstIndex = blockLines.findIndex((line) => line.trim() !== "");
+ if (firstIndex === -1 || !isTaskLine(blockLines[firstIndex])) return null;
+ const firstIndent = leadingWidth(blockLines[firstIndex]);
+ return blockLines.slice(firstIndex).map((line) => {
+ if (line.trim() === "") return "";
+ const indent = leadingWidth(line);
+ const depth = indent - firstIndent;
+ if (isTaskLine(line)) return depth === 1 ? line.trimStart() : line.slice(Math.min(indent, firstIndent));
+ if (depth > 0) return depth === 1 ? ` ${line.slice(firstIndent)}` : line.slice(firstIndent);
+ return indent > 0 ? ` ${line.trimStart()}` : line;
+ }).join("\n").trimEnd();
+}
+/**
* Recursively builds a nested structure from a flat array of list items
* based on their indentation levels. Creates proper markdown tokens with
* nested lists where appropriate.
@@ -908,7 +927,7 @@
raw: mainText,
tokens: lexer.inlineTokens(mainText)
});
- const additionalContent = blockLines.join("\n").trim();
+ const additionalContent = dedentOrderedItemTaskBlock(blockLines) ?? blockLines.join("\n").trim();
if (additionalContent) {
const blockTokens = lexer.blockTokens(additionalContent);
tokens.push(...blockTokens);
diff --git a/dist/kit/index.cjs b/dist/kit/index.cjs
--- a/dist/kit/index.cjs
+++ b/dist/kit/index.cjs
@@ -233,10 +233,9 @@
];
const ALPHA_NUMERALS = "abcdefghijklmnopqrstuvwxyz";
/**
-* Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.
-* Roman is matched before alpha so "iii" is roman; invalid romans like "aa" fall through to alpha.
+* Orca patch: ordered-list markers are digits only, as in CommonMark, so "Dr." and "A." stay prose.
*/
-const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+|[ivxlcdmIVXLCDM]+|${"[a-zA-Z]{1,2}"}`;
+const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+`;
/**
* Convert a number to lowercase roman numerals.
* @example toRoman(1) // 'i'
@@ -839,6 +838,26 @@
};
}
/**
+* Orca patch: marker columns are counted without the delimiter, so trim() left later sibling tasks indented and
+* parseIndentedBlocks cut into them. Dedent by the first task; a task one column deeper is a sibling, and other
+* text at or within the first task's column stays nested under the task above.
+*/
+function dedentOrderedItemTaskBlock(blockLines) {
+ const isTaskLine = (line) => /^\s*[-+*]\s+\[[ xX]\][^\S\r\n]/.test(line);
+ const leadingWidth = (line) => line.length - line.trimStart().length;
+ const firstIndex = blockLines.findIndex((line) => line.trim() !== "");
+ if (firstIndex === -1 || !isTaskLine(blockLines[firstIndex])) return null;
+ const firstIndent = leadingWidth(blockLines[firstIndex]);
+ return blockLines.slice(firstIndex).map((line) => {
+ if (line.trim() === "") return "";
+ const indent = leadingWidth(line);
+ const depth = indent - firstIndent;
+ if (isTaskLine(line)) return depth === 1 ? line.trimStart() : line.slice(Math.min(indent, firstIndent));
+ if (depth > 0) return depth === 1 ? ` ${line.slice(firstIndent)}` : line.slice(firstIndent);
+ return indent > 0 ? ` ${line.trimStart()}` : line;
+ }).join("\n").trimEnd();
+}
+/**
* Recursively builds a nested structure from a flat array of list items
* based on their indentation levels. Creates proper markdown tokens with
* nested lists where appropriate.
@@ -862,7 +881,7 @@
raw: mainText,
tokens: lexer.inlineTokens(mainText)
});
- const additionalContent = blockLines.join("\n").trim();
+ const additionalContent = dedentOrderedItemTaskBlock(blockLines) ?? blockLines.join("\n").trim();
if (additionalContent) {
const blockTokens = lexer.blockTokens(additionalContent);
tokens.push(...blockTokens);
diff --git a/dist/kit/index.js b/dist/kit/index.js
--- a/dist/kit/index.js
+++ b/dist/kit/index.js
@@ -232,10 +232,9 @@
];
const ALPHA_NUMERALS = "abcdefghijklmnopqrstuvwxyz";
/**
-* Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.
-* Roman is matched before alpha so "iii" is roman; invalid romans like "aa" fall through to alpha.
+* Orca patch: ordered-list markers are digits only, as in CommonMark, so "Dr." and "A." stay prose.
*/
-const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+|[ivxlcdmIVXLCDM]+|${"[a-zA-Z]{1,2}"}`;
+const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+`;
/**
* Convert a number to lowercase roman numerals.
* @example toRoman(1) // 'i'
@@ -838,6 +837,26 @@
};
}
/**
+* Orca patch: marker columns are counted without the delimiter, so trim() left later sibling tasks indented and
+* parseIndentedBlocks cut into them. Dedent by the first task; a task one column deeper is a sibling, and other
+* text at or within the first task's column stays nested under the task above.
+*/
+function dedentOrderedItemTaskBlock(blockLines) {
+ const isTaskLine = (line) => /^\s*[-+*]\s+\[[ xX]\][^\S\r\n]/.test(line);
+ const leadingWidth = (line) => line.length - line.trimStart().length;
+ const firstIndex = blockLines.findIndex((line) => line.trim() !== "");
+ if (firstIndex === -1 || !isTaskLine(blockLines[firstIndex])) return null;
+ const firstIndent = leadingWidth(blockLines[firstIndex]);
+ return blockLines.slice(firstIndex).map((line) => {
+ if (line.trim() === "") return "";
+ const indent = leadingWidth(line);
+ const depth = indent - firstIndent;
+ if (isTaskLine(line)) return depth === 1 ? line.trimStart() : line.slice(Math.min(indent, firstIndent));
+ if (depth > 0) return depth === 1 ? ` ${line.slice(firstIndent)}` : line.slice(firstIndent);
+ return indent > 0 ? ` ${line.trimStart()}` : line;
+ }).join("\n").trimEnd();
+}
+/**
* Recursively builds a nested structure from a flat array of list items
* based on their indentation levels. Creates proper markdown tokens with
* nested lists where appropriate.
@@ -861,7 +880,7 @@
raw: mainText,
tokens: lexer.inlineTokens(mainText)
});
- const additionalContent = blockLines.join("\n").trim();
+ const additionalContent = dedentOrderedItemTaskBlock(blockLines) ?? blockLines.join("\n").trim();
if (additionalContent) {
const blockTokens = lexer.blockTokens(additionalContent);
tokens.push(...blockTokens);
diff --git a/dist/ordered-list/index.cjs b/dist/ordered-list/index.cjs
--- a/dist/ordered-list/index.cjs
+++ b/dist/ordered-list/index.cjs
@@ -19,10 +19,9 @@
];
const ALPHA_NUMERALS = "abcdefghijklmnopqrstuvwxyz";
/**
-* Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.
-* Roman is matched before alpha so "iii" is roman; invalid romans like "aa" fall through to alpha.
+* Orca patch: ordered-list markers are digits only, as in CommonMark, so "Dr." and "A." stay prose.
*/
-const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+|[ivxlcdmIVXLCDM]+|${"[a-zA-Z]{1,2}"}`;
+const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+`;
/**
* Convert a number to lowercase roman numerals.
* @example toRoman(1) // 'i'
@@ -333,6 +332,26 @@
};
}
/**
+* Orca patch: marker columns are counted without the delimiter, so trim() left later sibling tasks indented and
+* parseIndentedBlocks cut into them. Dedent by the first task; a task one column deeper is a sibling, and other
+* text at or within the first task's column stays nested under the task above.
+*/
+function dedentOrderedItemTaskBlock(blockLines) {
+ const isTaskLine = (line) => /^\s*[-+*]\s+\[[ xX]\][^\S\r\n]/.test(line);
+ const leadingWidth = (line) => line.length - line.trimStart().length;
+ const firstIndex = blockLines.findIndex((line) => line.trim() !== "");
+ if (firstIndex === -1 || !isTaskLine(blockLines[firstIndex])) return null;
+ const firstIndent = leadingWidth(blockLines[firstIndex]);
+ return blockLines.slice(firstIndex).map((line) => {
+ if (line.trim() === "") return "";
+ const indent = leadingWidth(line);
+ const depth = indent - firstIndent;
+ if (isTaskLine(line)) return depth === 1 ? line.trimStart() : line.slice(Math.min(indent, firstIndent));
+ if (depth > 0) return depth === 1 ? ` ${line.slice(firstIndent)}` : line.slice(firstIndent);
+ return indent > 0 ? ` ${line.trimStart()}` : line;
+ }).join("\n").trimEnd();
+}
+/**
* Recursively builds a nested structure from a flat array of list items
* based on their indentation levels. Creates proper markdown tokens with
* nested lists where appropriate.
@@ -356,7 +375,7 @@
raw: mainText,
tokens: lexer.inlineTokens(mainText)
});
- const additionalContent = blockLines.join("\n").trim();
+ const additionalContent = dedentOrderedItemTaskBlock(blockLines) ?? blockLines.join("\n").trim();
if (additionalContent) {
const blockTokens = lexer.blockTokens(additionalContent);
tokens.push(...blockTokens);
diff --git a/dist/ordered-list/index.js b/dist/ordered-list/index.js
--- a/dist/ordered-list/index.js
+++ b/dist/ordered-list/index.js
@@ -18,10 +18,9 @@
];
const ALPHA_NUMERALS = "abcdefghijklmnopqrstuvwxyz";
/**
-* Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.
-* Roman is matched before alpha so "iii" is roman; invalid romans like "aa" fall through to alpha.
+* Orca patch: ordered-list markers are digits only, as in CommonMark, so "Dr." and "A." stay prose.
*/
-const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+|[ivxlcdmIVXLCDM]+|${"[a-zA-Z]{1,2}"}`;
+const ORDERED_LIST_MARKER_PATTERN = String.raw`\d+`;
/**
* Convert a number to lowercase roman numerals.
* @example toRoman(1) // 'i'
@@ -332,6 +331,26 @@
};
}
/**
+* Orca patch: marker columns are counted without the delimiter, so trim() left later sibling tasks indented and
+* parseIndentedBlocks cut into them. Dedent by the first task; a task one column deeper is a sibling, and other
+* text at or within the first task's column stays nested under the task above.
+*/
+function dedentOrderedItemTaskBlock(blockLines) {
+ const isTaskLine = (line) => /^\s*[-+*]\s+\[[ xX]\][^\S\r\n]/.test(line);
+ const leadingWidth = (line) => line.length - line.trimStart().length;
+ const firstIndex = blockLines.findIndex((line) => line.trim() !== "");
+ if (firstIndex === -1 || !isTaskLine(blockLines[firstIndex])) return null;
+ const firstIndent = leadingWidth(blockLines[firstIndex]);
+ return blockLines.slice(firstIndex).map((line) => {
+ if (line.trim() === "") return "";
+ const indent = leadingWidth(line);
+ const depth = indent - firstIndent;
+ if (isTaskLine(line)) return depth === 1 ? line.trimStart() : line.slice(Math.min(indent, firstIndent));
+ if (depth > 0) return depth === 1 ? ` ${line.slice(firstIndent)}` : line.slice(firstIndent);
+ return indent > 0 ? ` ${line.trimStart()}` : line;
+ }).join("\n").trimEnd();
+}
+/**
* Recursively builds a nested structure from a flat array of list items
* based on their indentation levels. Creates proper markdown tokens with
* nested lists where appropriate.
@@ -355,7 +374,7 @@
raw: mainText,
tokens: lexer.inlineTokens(mainText)
});
- const additionalContent = blockLines.join("\n").trim();
+ const additionalContent = dedentOrderedItemTaskBlock(blockLines) ?? blockLines.join("\n").trim();
if (additionalContent) {
const blockTokens = lexer.blockTokens(additionalContent);
tokens.push(...blockTokens);