@tiptap/extension-list 3.27.1 → 3.27.3

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.
@@ -235,18 +235,24 @@ var ORDERED_LIST_LINE_START_REGEX = new RegExp(
235
235
  `^(\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\s+`
236
236
  );
237
237
  var INDENTED_LINE_REGEX = /^\s/;
238
+ var PARAGRAPH_INTERRUPTERS = {
239
+ heading: /^#{1,6}(?:\s|$)/,
240
+ bulletItem: /^[-+*]\s+/,
241
+ codeFence: /^(?:```|~~~)/,
242
+ thematicBreak: /^(?:(?:-[ \t]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})$/
243
+ };
238
244
  function isOrderedListMarkerLine(line) {
239
245
  return ORDERED_LIST_ITEM_REGEX.test(line.trimStart());
240
246
  }
241
247
  function isBlockContentLine(line) {
242
248
  const trimmedLine = line.trimStart();
243
- return (
244
- // oxlint-disable-next-line prefer-string-starts-ends-with
245
- /^[-+*]\s+/.test(trimmedLine) || isOrderedListMarkerLine(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
246
- /^>\s?/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
247
- /^```/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
248
- /^~~~/.test(trimmedLine)
249
- );
249
+ return PARAGRAPH_INTERRUPTERS.bulletItem.test(trimmedLine) || isOrderedListMarkerLine(trimmedLine) || PARAGRAPH_INTERRUPTERS.heading.test(trimmedLine) || // dash breaks are excluded: "---" directly below paragraph text is a
250
+ // setext heading underline, not a thematic break
251
+ PARAGRAPH_INTERRUPTERS.thematicBreak.test(trimmedLine) && !trimmedLine.startsWith("-") || // oxlint-disable-next-line prefer-string-starts-ends-with
252
+ /^>\s?/.test(trimmedLine) || PARAGRAPH_INTERRUPTERS.codeFence.test(trimmedLine);
253
+ }
254
+ function interruptsLazyContinuation(line) {
255
+ return Object.values(PARAGRAPH_INTERRUPTERS).some((pattern) => pattern.test(line));
250
256
  }
251
257
  function splitItemContent(contentLines) {
252
258
  const paragraphLines = [];
@@ -311,7 +317,7 @@ function collectOrderedListItems(lines) {
311
317
  itemContentLines.push(nextLine.slice(Math.min(leadingWhitespace, contentIndent)));
312
318
  nextLineIndex += 1;
313
319
  } else {
314
- if (sawBlankLine) {
320
+ if (sawBlankLine || interruptsLazyContinuation(nextLine)) {
315
321
  break;
316
322
  }
317
323
  itemLines.push(nextLine);
@@ -594,7 +600,7 @@ var OrderedList = import_core.Node.create({
594
600
  if (listItems.length === 0) {
595
601
  return void 0;
596
602
  }
597
- const items = buildNestedStructure(listItems, 0, lexer);
603
+ const items = buildNestedStructure(listItems, listItems[0].indent, lexer);
598
604
  if (items.length === 0) {
599
605
  return void 0;
600
606
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ordered-list/index.ts","../../src/ordered-list/ordered-list.ts","../../src/ordered-list/roman.ts","../../src/ordered-list/utils.ts"],"sourcesContent":["export * from './ordered-list.js'\nexport {\n areOrderedListMarkersSequential,\n buildOrderedListAttrsFromMarker,\n detectMarkerType,\n getListMarker,\n markerToStart,\n ORDERED_LIST_MARKER_PATTERN,\n parseListMarker,\n toRoman,\n toRomanUpper,\n} from './roman.js'\nexport { parsePlainTextOrderedListPaste } from './utils.js'\n","import type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Plugin } from '@tiptap/pm/state'\n\nimport { mergeAttributes, Node, wrappingInputRule } from '@tiptap/core'\n\nimport {\n buildNestedStructure,\n collectOrderedListItems,\n ORDERED_LIST_LINE_START_REGEX,\n parseListItems,\n parsePlainTextOrderedListPaste,\n} from './utils.js'\n\nconst ListItemName = 'listItem'\nconst TextStyleName = 'textStyle'\n\nexport interface OrderedListOptions {\n /**\n * The node type name for list items.\n * @default 'listItem'\n * @example 'myListItem'\n */\n itemTypeName: string\n\n /**\n * The HTML attributes for an ordered list node.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * Keep the marks when splitting a list item.\n * @default false\n * @example true\n */\n keepMarks: boolean\n\n /**\n * Keep the attributes when splitting a list item.\n * @default false\n * @example true\n */\n keepAttributes: boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n orderedList: {\n /**\n * Toggle an ordered list\n * @example editor.commands.toggleOrderedList()\n */\n toggleOrderedList: () => ReturnType\n }\n }\n}\n\n/**\n * Matches an ordered list to a 1. on input (or any number followed by a dot).\n */\nexport const orderedListInputRegex = /^(\\d+)\\.\\s$/\n\n/**\n * Maps CSS list-style-type values to HTML type attribute values.\n * Google Docs and Word often use CSS instead of the HTML type attribute.\n */\nfunction cssListStyleTypeToHtmlType(style: string): string | null {\n const match = style.match(/list-style-type\\s*:\\s*([^;]+)/i)\n if (!match) {\n return null\n }\n\n const cssValue = match[1].trim().toLowerCase()\n\n switch (cssValue) {\n case 'upper-roman':\n return 'I'\n case 'lower-roman':\n return 'i'\n case 'upper-alpha':\n case 'upper-latin':\n return 'A'\n case 'lower-alpha':\n case 'lower-latin':\n return 'a'\n default:\n return null\n }\n}\n\n/**\n * This extension allows you to create ordered lists.\n * This requires the ListItem extension\n * @see https://www.tiptap.dev/api/nodes/ordered-list\n * @see https://www.tiptap.dev/api/nodes/list-item\n */\nexport const OrderedList = Node.create<OrderedListOptions>({\n name: 'orderedList',\n\n addOptions() {\n return {\n itemTypeName: 'listItem',\n HTMLAttributes: {},\n keepMarks: false,\n keepAttributes: false,\n }\n },\n\n group: 'block list',\n\n content() {\n return `${this.options.itemTypeName}+`\n },\n\n addAttributes() {\n return {\n start: {\n default: 1,\n parseHTML: element => {\n return element.hasAttribute('start')\n ? parseInt(element.getAttribute('start') || '', 10)\n : 1\n },\n },\n type: {\n default: null,\n parseHTML: element => {\n // 1. Check the HTML type attribute on <ol>\n const htmlType = element.getAttribute('type')\n if (htmlType) {\n return htmlType\n }\n\n // 2. Check CSS list-style-type on the <ol> element's style attribute\n const style = element.getAttribute('style')\n if (style) {\n const mappedFromOl = cssListStyleTypeToHtmlType(style)\n if (mappedFromOl) {\n return mappedFromOl\n }\n }\n\n // 3. Check the first <li> child for list-style-type (Google Docs pattern)\n const firstLi = element.querySelector('li')\n if (firstLi) {\n const liStyle = firstLi.getAttribute('style')\n if (liStyle) {\n const mappedFromLi = cssListStyleTypeToHtmlType(liStyle)\n if (mappedFromLi) {\n return mappedFromLi\n }\n }\n }\n\n return null\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'ol',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n const { start, type, ...attributesWithoutType } = HTMLAttributes\n\n const attrs = mergeAttributes(this.options.HTMLAttributes, attributesWithoutType)\n\n if (start !== 1) {\n attrs.start = start\n }\n\n if (type && type !== '1') {\n attrs.type = type\n }\n\n return ['ol', attrs, 0]\n },\n\n markdownTokenName: 'list',\n\n parseMarkdown: (token, helpers) => {\n if (token.type !== 'list' || !token.ordered) {\n return []\n }\n\n const startValue = token.start || 1\n const typeValue = token.typeMarker as string | undefined\n const content = token.items ? parseListItems(token.items, helpers) : []\n\n // Build attrs only when they differ from defaults\n const attrs: Record<string, unknown> = {}\n\n if (startValue !== 1) {\n attrs.start = startValue\n }\n\n if (typeValue) {\n attrs.type = typeValue\n }\n\n if (Object.keys(attrs).length > 0) {\n return {\n type: 'orderedList',\n attrs,\n content,\n }\n }\n\n return {\n type: 'orderedList',\n content,\n }\n },\n\n renderMarkdown: (node, h) => {\n if (!node.content) {\n return ''\n }\n\n return h.renderChildren(node.content, '\\n')\n },\n\n markdownTokenizer: {\n name: 'orderedList',\n level: 'block',\n start: (src: string) => {\n const match = src.match(ORDERED_LIST_LINE_START_REGEX)\n const index = match?.index\n return index !== undefined ? index : -1\n },\n tokenize: (src: string, _tokens, lexer) => {\n const lines = src.split('\\n')\n const [listItems, consumed] = collectOrderedListItems(lines)\n\n if (listItems.length === 0) {\n return undefined\n }\n\n const items = buildNestedStructure(listItems, 0, lexer)\n\n if (items.length === 0) {\n return undefined\n }\n\n const startValue = listItems[0]?.number || 1\n const typeMarker = listItems[0]?.type\n\n return {\n type: 'list',\n ordered: true,\n start: startValue,\n typeMarker,\n items,\n raw: lines.slice(0, consumed).join('\\n'),\n } as unknown as object\n },\n },\n\n markdownOptions: {\n indentsContent: true,\n },\n\n addCommands() {\n return {\n toggleOrderedList:\n () =>\n ({ commands, chain }) => {\n if (this.options.keepAttributes) {\n return chain()\n .toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n .updateAttributes(ListItemName, this.editor.getAttributes(TextStyleName))\n .run()\n }\n return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Shift-7': () => this.editor.commands.toggleOrderedList(),\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handlePaste: (view, event) => {\n const html = event.clipboardData?.getData('text/html')\n\n if (html?.trim()) {\n return false\n }\n\n const text = event.clipboardData?.getData('text/plain')\n\n if (!text) {\n return false\n }\n\n const orderedListContent = parsePlainTextOrderedListPaste(text)\n\n if (!orderedListContent) {\n return false\n }\n\n try {\n const orderedListNode = view.state.schema.nodeFromJSON(orderedListContent)\n const tr = view.state.tr.replaceSelectionWith(orderedListNode)\n\n view.dispatch(tr)\n\n return true\n } catch {\n return false\n }\n },\n },\n }),\n ]\n },\n\n addInputRules() {\n const joinPredicate = (match: RegExpMatchArray, node: ProseMirrorNode) => {\n // Only join if the existing list has a default type\n // (not a typed list like \"a\" or \"i\" which should stay separate)\n const hasDefaultType = !node.attrs.type || node.attrs.type === '1'\n\n return hasDefaultType && node.childCount + node.attrs.start === +match[1]\n }\n\n let inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n getAttributes: match => ({ start: +match[1] }),\n joinPredicate,\n })\n\n if (this.options.keepMarks || this.options.keepAttributes) {\n inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n keepMarks: this.options.keepMarks,\n keepAttributes: this.options.keepAttributes,\n getAttributes: match => ({ start: +match[1], ...this.editor.getAttributes(TextStyleName) }),\n joinPredicate,\n editor: this.editor,\n })\n }\n return [inputRule]\n },\n})\n","const ROMAN_NUMERALS: [number, string][] = [\n [1000, 'm'],\n [900, 'cm'],\n [500, 'd'],\n [400, 'cd'],\n [100, 'c'],\n [90, 'xc'],\n [50, 'l'],\n [40, 'xl'],\n [10, 'x'],\n [9, 'ix'],\n [5, 'v'],\n [4, 'iv'],\n [1, 'i'],\n]\n\nconst ALPHA_NUMERALS = 'abcdefghijklmnopqrstuvwxyz'\n\n/** Alpha list markers support at most 2 letters (a–z, aa–zz), matching {@link fromAlpha}. */\nexport const ORDERED_LIST_ALPHA_MARKER_PATTERN = '[a-zA-Z]{1,2}'\n\n/**\n * Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.\n * Roman is matched before alpha so \"iii\" is roman; invalid romans like \"aa\" fall through to alpha.\n */\nexport const ORDERED_LIST_MARKER_PATTERN = String.raw`\\d+|[ivxlcdmIVXLCDM]+|${ORDERED_LIST_ALPHA_MARKER_PATTERN}`\n\n/**\n * Convert a number to lowercase roman numerals.\n * @example toRoman(1) // 'i'\n * @example toRoman(4) // 'iv'\n */\nexport function toRoman(num: number): string {\n let remaining = num\n let result = ''\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n while (remaining >= value) {\n result += numeral\n remaining -= value\n }\n }\n\n return result\n}\n\n/**\n * Convert a number to uppercase roman numerals.\n * @example toRomanUpper(1) // 'I'\n * @example toRomanUpper(4) // 'IV'\n */\nexport function toRomanUpper(num: number): string {\n return toRoman(num).toUpperCase()\n}\n\nfunction fromRoman(roman: string): number {\n const lower = roman.toLowerCase()\n let index = 0\n let result = 0\n\n while (index < lower.length) {\n let matched = false\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n if (lower.startsWith(numeral, index)) {\n result += value\n index += numeral.length\n matched = true\n break\n }\n }\n\n if (!matched) {\n return 0\n }\n }\n\n return result\n}\n\nfunction isValidRoman(marker: string): boolean {\n if (!/^[ivxlcdmIVXLCDM]+$/.test(marker)) {\n return false\n }\n\n const value = fromRoman(marker)\n\n if (value <= 0) {\n return false\n }\n\n const expected = marker === marker.toLowerCase() ? toRoman(value) : toRomanUpper(value)\n\n return expected === marker\n}\n\nfunction fromAlpha(marker: string): number {\n const lower = marker.toLowerCase()\n\n if (lower.length === 1) {\n return lower.charCodeAt(0) - 'a'.charCodeAt(0) + 1\n }\n\n if (lower.length === 2) {\n const first = lower.charCodeAt(0) - 'a'.charCodeAt(0)\n const second = lower.charCodeAt(1) - 'a'.charCodeAt(0)\n\n return (first + 1) * 26 + second + 1\n }\n\n return 0\n}\n\nfunction toRomanAlpha(num: number): string {\n if (num <= 26) {\n return ALPHA_NUMERALS[num - 1]\n }\n\n const first = Math.floor((num - 1) / 26) - 1\n const second = (num - 1) % 26\n\n if (first < 0) {\n return ALPHA_NUMERALS[second]\n }\n\n return ALPHA_NUMERALS[first] + ALPHA_NUMERALS[second]\n}\n\n/**\n * Extract the list marker type from a marker string.\n * Supports \"1\", \"a\", \"A\", \"i\", \"I\" marker styles.\n *\n * @param marker The text content of the list marker (e.g. \"a\", \"1\", \"iii\", \"b\")\n * @returns The normalized type string, or undefined for default numeric type\n */\nexport function detectMarkerType(marker: string): string | undefined {\n if (!marker || /^\\d+$/.test(marker)) {\n return undefined\n }\n\n if (isValidRoman(marker)) {\n return marker === marker.toLowerCase() ? 'i' : 'I'\n }\n\n if (/^[a-z]{1,2}$/.test(marker)) {\n return 'a'\n }\n\n if (/^[A-Z]{1,2}$/.test(marker)) {\n return 'A'\n }\n\n return undefined\n}\n\n/**\n * Convert a list marker string to its numeric start position.\n *\n * @param marker The text content of the list marker (e.g. \"3\", \"b\", \"II\")\n * @returns The 1-based start value for the ordered list\n */\nexport function markerToStart(marker: string): number {\n if (/^\\d+$/.test(marker)) {\n return parseInt(marker, 10)\n }\n\n const type = detectMarkerType(marker)\n\n if (type === 'i' || type === 'I') {\n return fromRoman(marker)\n }\n\n if (type === 'a' || type === 'A') {\n const start = fromAlpha(marker)\n\n return start > 0 ? start : 1\n }\n\n const parsed = parseInt(marker, 10)\n\n return Number.isNaN(parsed) ? 1 : parsed\n}\n\nfunction startToMarker(type: string, start: number): string {\n if (type === 'numeric') {\n return String(start)\n }\n\n switch (type) {\n case 'a':\n return toRomanAlpha(start)\n case 'A':\n return toRomanAlpha(start).toUpperCase()\n case 'i':\n return toRoman(start)\n case 'I':\n return toRomanUpper(start)\n default:\n return String(start)\n }\n}\n\n/**\n * Returns true when all markers share the same style and increment by 1.\n * Style is inferred from the first marker so ambiguous letters (e.g. \"c\", \"i\")\n * are not re-classified differently on later lines.\n */\nexport function areOrderedListMarkersSequential(markers: string[]): boolean {\n if (markers.length === 0) {\n return false\n }\n\n const firstType = detectMarkerType(markers[0]) ?? 'numeric'\n const firstStart = markerToStart(markers[0])\n\n if (firstStart < 1) {\n return false\n }\n\n for (let i = 0; i < markers.length; i++) {\n const expected = startToMarker(firstType, firstStart + i)\n\n if (markers[i] !== expected) {\n return false\n }\n }\n\n return true\n}\n\nexport interface ParsedListMarker {\n type?: string\n start: number\n}\n\n/**\n * Parse a list marker into HTML ordered-list attrs (type + start).\n */\nexport function parseListMarker(marker: string): ParsedListMarker {\n return {\n type: detectMarkerType(marker),\n start: markerToStart(marker),\n }\n}\n\n/**\n * Build orderedList node attrs from the first list item marker.\n */\nexport function buildOrderedListAttrsFromMarker(marker: string): Record<string, string | number> {\n const { type, start } = parseListMarker(marker)\n const attrs: Record<string, string | number> = {}\n\n if (type) {\n attrs.type = type\n }\n\n if (start !== 1) {\n attrs.start = start\n }\n\n return attrs\n}\n\n/**\n * Returns the list marker prefix for a given item at a given index.\n *\n * @param type The list type attribute (e.g. \"a\", \"A\", \"i\", \"I\", null/undefined for default)\n * @param index The zero-based index of the list item\n * @param separator The separator to use (default: \". \")\n * @returns The marker string (e.g. \"a. \", \"I. \", \"1. \")\n */\nexport function getListMarker(\n type: string | null | undefined,\n index: number,\n separator = '. ',\n): string {\n const position = index + 1\n\n if (!type || type === '1') {\n return `${position}${separator}`\n }\n\n switch (type) {\n case 'a':\n return `${toRomanAlpha(position)}${separator}`\n case 'A':\n return `${toRomanAlpha(position).toUpperCase()}${separator}`\n case 'i':\n return `${toRoman(position)}${separator}`\n case 'I':\n return `${toRomanUpper(position)}${separator}`\n default:\n return `${position}${separator}`\n }\n}\n","import type {\n JSONContent,\n MarkdownLexerConfiguration,\n MarkdownParseHelpers,\n MarkdownToken,\n} from '@tiptap/core'\n\nimport {\n areOrderedListMarkersSequential,\n buildOrderedListAttrsFromMarker,\n detectMarkerType,\n markerToStart,\n ORDERED_LIST_MARKER_PATTERN,\n} from './roman.js'\n\nexport { ORDERED_LIST_MARKER_PATTERN }\n\n/**\n * Matches an ordered list item line with optional leading whitespace.\n * Captures: (1) indentation spaces, (2) item marker (number, letter, or roman numeral),\n * (3) separator (. or )), (4) content after marker\n *\n * Examples: \"1. Item\", \" a) Nested item\", \" I. Roman item\", \"iii. Another\", \"aa. Item 27\"\n */\nexport const ORDERED_LIST_ITEM_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.*)$`,\n)\n\n/**\n * Matches the start of an ordered list line (used by markdown tokenizer).\n */\nexport const ORDERED_LIST_LINE_START_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+`,\n)\n\n/**\n * Matches any line that starts with whitespace (indented content).\n * Used to identify continuation content that belongs to a list item.\n */\nconst INDENTED_LINE_REGEX = /^\\s/\n\n/**\n * Represents a parsed ordered list item with indentation information\n */\nexport interface OrderedListItem {\n indent: number\n number: number\n type?: string\n content: string\n contentLines: string[]\n raw: string\n}\n\nfunction isOrderedListMarkerLine(line: string): boolean {\n return ORDERED_LIST_ITEM_REGEX.test(line.trimStart())\n}\n\nfunction isBlockContentLine(line: string): boolean {\n const trimmedLine = line.trimStart()\n\n return (\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^[-+*]\\s+/.test(trimmedLine) ||\n isOrderedListMarkerLine(trimmedLine) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^>\\s?/.test(trimmedLine) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^```/.test(trimmedLine) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^~~~/.test(trimmedLine)\n )\n}\n\nfunction splitItemContent(contentLines: string[]): {\n paragraphLines: string[]\n blockLines: string[]\n} {\n const paragraphLines: string[] = []\n const blockLines: string[] = []\n let reachedBlockBoundary = false\n\n contentLines.forEach(line => {\n if (reachedBlockBoundary) {\n blockLines.push(line)\n return\n }\n\n if (line.trim() === '') {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n if (paragraphLines.length > 0 && isBlockContentLine(line)) {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n paragraphLines.push(line)\n })\n\n return {\n paragraphLines,\n blockLines,\n }\n}\n\n/**\n * Collects all ordered list items from lines, parsing them into a flat array\n * with indentation information. Stops collecting continuation content when\n * encountering nested list items, allowing them to be processed separately.\n *\n * @param lines - Array of source lines to parse\n * @returns Tuple of [listItems array, number of lines consumed]\n */\nexport function collectOrderedListItems(lines: string[]): [OrderedListItem[], number] {\n const listItems: OrderedListItem[] = []\n let currentLineIndex = 0\n let consumed = 0\n\n while (currentLineIndex < lines.length) {\n const line = lines[currentLineIndex]\n const match = line.match(ORDERED_LIST_ITEM_REGEX)\n\n if (!match) {\n break\n }\n\n const [, indent, marker, _separator, content] = match\n const indentLevel = indent.length\n const number = parseInt(marker, 10)\n\n const markerType = isNaN(number) ? detectMarkerType(marker) : undefined\n const itemNumber = isNaN(number) ? markerToStart(marker) : number\n\n const itemContentLines = [content]\n let nextLineIndex = currentLineIndex + 1\n const itemLines = [line]\n let sawBlankLine = false\n\n // Collect continuation lines for this item (but NOT nested list items)\n while (nextLineIndex < lines.length) {\n const nextLine = lines[nextLineIndex]\n const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX)\n\n // If it's another list item (nested or not), stop collecting\n if (nextMatch) {\n break\n }\n\n // Check for continuation content (non-list content)\n if (nextLine.trim() === '') {\n // Empty line\n itemLines.push(nextLine)\n itemContentLines.push('')\n sawBlankLine = true\n nextLineIndex += 1\n } else if (nextLine.match(INDENTED_LINE_REGEX)) {\n // Indented content - part of this item (but not a list item).\n // Strip the indentation only up to the whitespace that is actually present,\n // so an under-indented line (e.g. a single leading space) keeps its first character.\n const leadingWhitespace = nextLine.length - nextLine.trimStart().length\n const contentIndent = indentLevel + marker.length + 1\n itemLines.push(nextLine)\n itemContentLines.push(nextLine.slice(Math.min(leadingWhitespace, contentIndent)))\n nextLineIndex += 1\n } else {\n if (sawBlankLine) {\n break\n }\n\n itemLines.push(nextLine)\n itemContentLines.push(nextLine)\n nextLineIndex += 1\n }\n }\n\n listItems.push({\n indent: indentLevel,\n number: itemNumber,\n type: markerType,\n content: itemContentLines.join('\\n').trim(),\n contentLines: itemContentLines,\n raw: itemLines.join('\\n'),\n })\n\n consumed = nextLineIndex\n currentLineIndex = nextLineIndex\n }\n\n return [listItems, consumed]\n}\n\nconst PLAIN_TEXT_ORDERED_LIST_LINE_REGEX = new RegExp(\n `^(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.+)$`,\n)\n\n/**\n * Parse plain-text pasted ordered list lines into JSONContent, or null if not a typed list.\n */\nexport function parsePlainTextOrderedListPaste(text: string): JSONContent | null {\n const lines = text.split('\\n').filter(l => l.trim().length > 0)\n\n if (lines.length === 0) {\n return null\n }\n\n const parsedItems: Array<{ marker: string; content: string }> = []\n\n for (const line of lines) {\n const match = line.trim().match(PLAIN_TEXT_ORDERED_LIST_LINE_REGEX)\n\n if (!match) {\n return null\n }\n\n parsedItems.push({\n marker: match[1],\n content: match[3],\n })\n }\n\n const markers = parsedItems.map(item => item.marker)\n\n if (!areOrderedListMarkersSequential(markers)) {\n return null\n }\n\n const attrs = buildOrderedListAttrsFromMarker(parsedItems[0].marker)\n\n return {\n type: 'orderedList',\n attrs,\n content: parsedItems.map(item => ({\n type: 'listItem',\n content: [\n {\n type: 'paragraph',\n content: [{ type: 'text', text: item.content }],\n },\n ],\n })),\n }\n}\n\n/**\n * Recursively builds a nested structure from a flat array of list items\n * based on their indentation levels. Creates proper markdown tokens with\n * nested lists where appropriate.\n *\n * @param items - Flat array of list items with indentation info\n * @param baseIndent - The indentation level to process at this recursion level\n * @param lexer - Markdown lexer for parsing inline and block content\n * @returns Array of list_item tokens with proper nesting\n */\nexport function buildNestedStructure(\n items: OrderedListItem[],\n baseIndent: number,\n lexer: MarkdownLexerConfiguration,\n): unknown[] {\n const result: unknown[] = []\n let currentIndex = 0\n\n while (currentIndex < items.length) {\n const item = items[currentIndex]\n\n if (item.indent === baseIndent) {\n // This item belongs at the current level\n const { paragraphLines, blockLines } = splitItemContent(item.contentLines)\n const mainText = paragraphLines.join('\\n').trim()\n\n const tokens = []\n\n // Always wrap the main text in a paragraph token\n if (mainText) {\n tokens.push({\n type: 'paragraph',\n raw: mainText,\n tokens: lexer.inlineTokens(mainText),\n })\n }\n\n const additionalContent = blockLines.join('\\n').trim()\n if (additionalContent) {\n const blockTokens = lexer.blockTokens(additionalContent)\n tokens.push(...blockTokens)\n }\n\n // Look ahead to find nested items at deeper indent levels\n let lookAheadIndex = currentIndex + 1\n const nestedItems = []\n\n while (lookAheadIndex < items.length && items[lookAheadIndex].indent > baseIndent) {\n nestedItems.push(items[lookAheadIndex])\n lookAheadIndex += 1\n }\n\n // If we have nested items, recursively build their structure\n if (nestedItems.length > 0) {\n // Find the next indent level (immediate children)\n const nextIndent = Math.min(...nestedItems.map(nestedItem => nestedItem.indent))\n\n // Build the nested list recursively with all nested items\n // The recursive call will handle further nesting\n const nestedListItems = buildNestedStructure(nestedItems, nextIndent, lexer)\n\n // Create a nested list token\n tokens.push({\n type: 'list',\n ordered: true,\n start: nestedItems[0].number,\n typeMarker: nestedItems[0].type,\n items: nestedListItems,\n raw: nestedItems.map(nestedItem => nestedItem.raw).join('\\n'),\n })\n }\n\n result.push({\n type: 'list_item',\n raw: item.raw,\n tokens,\n })\n\n // Skip the nested items we just processed\n currentIndex = lookAheadIndex\n } else {\n // This item has deeper indent than we're currently processing\n // It should be handled by a recursive call\n currentIndex += 1\n }\n }\n\n return result\n}\n\n/**\n * Parses markdown list item tokens into Tiptap JSONContent structure,\n * ensuring text content is properly wrapped in paragraph nodes.\n *\n * @param items - Array of markdown tokens representing list items\n * @param helpers - Markdown parse helpers for recursive parsing\n * @returns Array of listItem JSONContent nodes\n */\nexport function parseListItems(\n items: MarkdownToken[],\n helpers: MarkdownParseHelpers,\n): JSONContent[] {\n return items.map(item => {\n if (item.type !== 'list_item') {\n return helpers.parseChildren([item])[0]\n }\n\n // Parse the tokens within the list item\n const content: JSONContent[] = []\n\n if (item.tokens && item.tokens.length > 0) {\n item.tokens.forEach(itemToken => {\n // If it's already a proper block node (paragraph, list, etc.), parse it directly\n if (\n itemToken.type === 'paragraph' ||\n itemToken.type === 'list' ||\n itemToken.type === 'blockquote' ||\n itemToken.type === 'code'\n ) {\n content.push(...helpers.parseChildren([itemToken]))\n } else if (itemToken.type === 'text' && itemToken.tokens) {\n // If it's inline text tokens, wrap them in a paragraph\n const inlineContent = helpers.parseChildren([itemToken])\n content.push({\n type: 'paragraph',\n content: inlineContent,\n })\n } else {\n // For any other content, try to parse it\n const parsed = helpers.parseChildren([itemToken])\n if (parsed.length > 0) {\n content.push(...parsed)\n }\n }\n })\n }\n\n return {\n type: 'listItem',\n content,\n }\n })\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/ordered-list/index.ts","../../src/ordered-list/ordered-list.ts","../../src/ordered-list/roman.ts","../../src/ordered-list/utils.ts"],"sourcesContent":["export * from './ordered-list.js'\nexport {\n areOrderedListMarkersSequential,\n buildOrderedListAttrsFromMarker,\n detectMarkerType,\n getListMarker,\n markerToStart,\n ORDERED_LIST_MARKER_PATTERN,\n parseListMarker,\n toRoman,\n toRomanUpper,\n} from './roman.js'\nexport { parsePlainTextOrderedListPaste } from './utils.js'\n","import type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Plugin } from '@tiptap/pm/state'\n\nimport { mergeAttributes, Node, wrappingInputRule } from '@tiptap/core'\n\nimport {\n buildNestedStructure,\n collectOrderedListItems,\n ORDERED_LIST_LINE_START_REGEX,\n parseListItems,\n parsePlainTextOrderedListPaste,\n} from './utils.js'\n\nconst ListItemName = 'listItem'\nconst TextStyleName = 'textStyle'\n\nexport interface OrderedListOptions {\n /**\n * The node type name for list items.\n * @default 'listItem'\n * @example 'myListItem'\n */\n itemTypeName: string\n\n /**\n * The HTML attributes for an ordered list node.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * Keep the marks when splitting a list item.\n * @default false\n * @example true\n */\n keepMarks: boolean\n\n /**\n * Keep the attributes when splitting a list item.\n * @default false\n * @example true\n */\n keepAttributes: boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n orderedList: {\n /**\n * Toggle an ordered list\n * @example editor.commands.toggleOrderedList()\n */\n toggleOrderedList: () => ReturnType\n }\n }\n}\n\n/**\n * Matches an ordered list to a 1. on input (or any number followed by a dot).\n */\nexport const orderedListInputRegex = /^(\\d+)\\.\\s$/\n\n/**\n * Maps CSS list-style-type values to HTML type attribute values.\n * Google Docs and Word often use CSS instead of the HTML type attribute.\n */\nfunction cssListStyleTypeToHtmlType(style: string): string | null {\n const match = style.match(/list-style-type\\s*:\\s*([^;]+)/i)\n if (!match) {\n return null\n }\n\n const cssValue = match[1].trim().toLowerCase()\n\n switch (cssValue) {\n case 'upper-roman':\n return 'I'\n case 'lower-roman':\n return 'i'\n case 'upper-alpha':\n case 'upper-latin':\n return 'A'\n case 'lower-alpha':\n case 'lower-latin':\n return 'a'\n default:\n return null\n }\n}\n\n/**\n * This extension allows you to create ordered lists.\n * This requires the ListItem extension\n * @see https://www.tiptap.dev/api/nodes/ordered-list\n * @see https://www.tiptap.dev/api/nodes/list-item\n */\nexport const OrderedList = Node.create<OrderedListOptions>({\n name: 'orderedList',\n\n addOptions() {\n return {\n itemTypeName: 'listItem',\n HTMLAttributes: {},\n keepMarks: false,\n keepAttributes: false,\n }\n },\n\n group: 'block list',\n\n content() {\n return `${this.options.itemTypeName}+`\n },\n\n addAttributes() {\n return {\n start: {\n default: 1,\n parseHTML: element => {\n return element.hasAttribute('start')\n ? parseInt(element.getAttribute('start') || '', 10)\n : 1\n },\n },\n type: {\n default: null,\n parseHTML: element => {\n // 1. Check the HTML type attribute on <ol>\n const htmlType = element.getAttribute('type')\n if (htmlType) {\n return htmlType\n }\n\n // 2. Check CSS list-style-type on the <ol> element's style attribute\n const style = element.getAttribute('style')\n if (style) {\n const mappedFromOl = cssListStyleTypeToHtmlType(style)\n if (mappedFromOl) {\n return mappedFromOl\n }\n }\n\n // 3. Check the first <li> child for list-style-type (Google Docs pattern)\n const firstLi = element.querySelector('li')\n if (firstLi) {\n const liStyle = firstLi.getAttribute('style')\n if (liStyle) {\n const mappedFromLi = cssListStyleTypeToHtmlType(liStyle)\n if (mappedFromLi) {\n return mappedFromLi\n }\n }\n }\n\n return null\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'ol',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n const { start, type, ...attributesWithoutType } = HTMLAttributes\n\n const attrs = mergeAttributes(this.options.HTMLAttributes, attributesWithoutType)\n\n if (start !== 1) {\n attrs.start = start\n }\n\n if (type && type !== '1') {\n attrs.type = type\n }\n\n return ['ol', attrs, 0]\n },\n\n markdownTokenName: 'list',\n\n parseMarkdown: (token, helpers) => {\n if (token.type !== 'list' || !token.ordered) {\n return []\n }\n\n const startValue = token.start || 1\n const typeValue = token.typeMarker as string | undefined\n const content = token.items ? parseListItems(token.items, helpers) : []\n\n // Build attrs only when they differ from defaults\n const attrs: Record<string, unknown> = {}\n\n if (startValue !== 1) {\n attrs.start = startValue\n }\n\n if (typeValue) {\n attrs.type = typeValue\n }\n\n if (Object.keys(attrs).length > 0) {\n return {\n type: 'orderedList',\n attrs,\n content,\n }\n }\n\n return {\n type: 'orderedList',\n content,\n }\n },\n\n renderMarkdown: (node, h) => {\n if (!node.content) {\n return ''\n }\n\n return h.renderChildren(node.content, '\\n')\n },\n\n markdownTokenizer: {\n name: 'orderedList',\n level: 'block',\n start: (src: string) => {\n const match = src.match(ORDERED_LIST_LINE_START_REGEX)\n const index = match?.index\n return index !== undefined ? index : -1\n },\n tokenize: (src: string, _tokens, lexer) => {\n const lines = src.split('\\n')\n const [listItems, consumed] = collectOrderedListItems(lines)\n\n if (listItems.length === 0) {\n return undefined\n }\n\n // buildNestedStructure() only includes an item when item.indent matches\n // the base indent it's given, so the base must be this list's own\n // indentation level (that of its first collected item, e.g. 1 for a\n // line with a single leading space) rather than always 0 — a nested\n // list is not necessarily flush with the start of the line.\n const items = buildNestedStructure(listItems, listItems[0].indent, lexer)\n\n if (items.length === 0) {\n return undefined\n }\n\n const startValue = listItems[0]?.number || 1\n const typeMarker = listItems[0]?.type\n\n return {\n type: 'list',\n ordered: true,\n start: startValue,\n typeMarker,\n items,\n raw: lines.slice(0, consumed).join('\\n'),\n } as unknown as object\n },\n },\n\n markdownOptions: {\n indentsContent: true,\n },\n\n addCommands() {\n return {\n toggleOrderedList:\n () =>\n ({ commands, chain }) => {\n if (this.options.keepAttributes) {\n return chain()\n .toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n .updateAttributes(ListItemName, this.editor.getAttributes(TextStyleName))\n .run()\n }\n return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Shift-7': () => this.editor.commands.toggleOrderedList(),\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handlePaste: (view, event) => {\n const html = event.clipboardData?.getData('text/html')\n\n if (html?.trim()) {\n return false\n }\n\n const text = event.clipboardData?.getData('text/plain')\n\n if (!text) {\n return false\n }\n\n const orderedListContent = parsePlainTextOrderedListPaste(text)\n\n if (!orderedListContent) {\n return false\n }\n\n try {\n const orderedListNode = view.state.schema.nodeFromJSON(orderedListContent)\n const tr = view.state.tr.replaceSelectionWith(orderedListNode)\n\n view.dispatch(tr)\n\n return true\n } catch {\n return false\n }\n },\n },\n }),\n ]\n },\n\n addInputRules() {\n const joinPredicate = (match: RegExpMatchArray, node: ProseMirrorNode) => {\n // Only join if the existing list has a default type\n // (not a typed list like \"a\" or \"i\" which should stay separate)\n const hasDefaultType = !node.attrs.type || node.attrs.type === '1'\n\n return hasDefaultType && node.childCount + node.attrs.start === +match[1]\n }\n\n let inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n getAttributes: match => ({ start: +match[1] }),\n joinPredicate,\n })\n\n if (this.options.keepMarks || this.options.keepAttributes) {\n inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n keepMarks: this.options.keepMarks,\n keepAttributes: this.options.keepAttributes,\n getAttributes: match => ({ start: +match[1], ...this.editor.getAttributes(TextStyleName) }),\n joinPredicate,\n editor: this.editor,\n })\n }\n return [inputRule]\n },\n})\n","const ROMAN_NUMERALS: [number, string][] = [\n [1000, 'm'],\n [900, 'cm'],\n [500, 'd'],\n [400, 'cd'],\n [100, 'c'],\n [90, 'xc'],\n [50, 'l'],\n [40, 'xl'],\n [10, 'x'],\n [9, 'ix'],\n [5, 'v'],\n [4, 'iv'],\n [1, 'i'],\n]\n\nconst ALPHA_NUMERALS = 'abcdefghijklmnopqrstuvwxyz'\n\n/** Alpha list markers support at most 2 letters (a–z, aa–zz), matching {@link fromAlpha}. */\nexport const ORDERED_LIST_ALPHA_MARKER_PATTERN = '[a-zA-Z]{1,2}'\n\n/**\n * Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.\n * Roman is matched before alpha so \"iii\" is roman; invalid romans like \"aa\" fall through to alpha.\n */\nexport const ORDERED_LIST_MARKER_PATTERN = String.raw`\\d+|[ivxlcdmIVXLCDM]+|${ORDERED_LIST_ALPHA_MARKER_PATTERN}`\n\n/**\n * Convert a number to lowercase roman numerals.\n * @example toRoman(1) // 'i'\n * @example toRoman(4) // 'iv'\n */\nexport function toRoman(num: number): string {\n let remaining = num\n let result = ''\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n while (remaining >= value) {\n result += numeral\n remaining -= value\n }\n }\n\n return result\n}\n\n/**\n * Convert a number to uppercase roman numerals.\n * @example toRomanUpper(1) // 'I'\n * @example toRomanUpper(4) // 'IV'\n */\nexport function toRomanUpper(num: number): string {\n return toRoman(num).toUpperCase()\n}\n\nfunction fromRoman(roman: string): number {\n const lower = roman.toLowerCase()\n let index = 0\n let result = 0\n\n while (index < lower.length) {\n let matched = false\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n if (lower.startsWith(numeral, index)) {\n result += value\n index += numeral.length\n matched = true\n break\n }\n }\n\n if (!matched) {\n return 0\n }\n }\n\n return result\n}\n\nfunction isValidRoman(marker: string): boolean {\n if (!/^[ivxlcdmIVXLCDM]+$/.test(marker)) {\n return false\n }\n\n const value = fromRoman(marker)\n\n if (value <= 0) {\n return false\n }\n\n const expected = marker === marker.toLowerCase() ? toRoman(value) : toRomanUpper(value)\n\n return expected === marker\n}\n\nfunction fromAlpha(marker: string): number {\n const lower = marker.toLowerCase()\n\n if (lower.length === 1) {\n return lower.charCodeAt(0) - 'a'.charCodeAt(0) + 1\n }\n\n if (lower.length === 2) {\n const first = lower.charCodeAt(0) - 'a'.charCodeAt(0)\n const second = lower.charCodeAt(1) - 'a'.charCodeAt(0)\n\n return (first + 1) * 26 + second + 1\n }\n\n return 0\n}\n\nfunction toRomanAlpha(num: number): string {\n if (num <= 26) {\n return ALPHA_NUMERALS[num - 1]\n }\n\n const first = Math.floor((num - 1) / 26) - 1\n const second = (num - 1) % 26\n\n if (first < 0) {\n return ALPHA_NUMERALS[second]\n }\n\n return ALPHA_NUMERALS[first] + ALPHA_NUMERALS[second]\n}\n\n/**\n * Extract the list marker type from a marker string.\n * Supports \"1\", \"a\", \"A\", \"i\", \"I\" marker styles.\n *\n * @param marker The text content of the list marker (e.g. \"a\", \"1\", \"iii\", \"b\")\n * @returns The normalized type string, or undefined for default numeric type\n */\nexport function detectMarkerType(marker: string): string | undefined {\n if (!marker || /^\\d+$/.test(marker)) {\n return undefined\n }\n\n if (isValidRoman(marker)) {\n return marker === marker.toLowerCase() ? 'i' : 'I'\n }\n\n if (/^[a-z]{1,2}$/.test(marker)) {\n return 'a'\n }\n\n if (/^[A-Z]{1,2}$/.test(marker)) {\n return 'A'\n }\n\n return undefined\n}\n\n/**\n * Convert a list marker string to its numeric start position.\n *\n * @param marker The text content of the list marker (e.g. \"3\", \"b\", \"II\")\n * @returns The 1-based start value for the ordered list\n */\nexport function markerToStart(marker: string): number {\n if (/^\\d+$/.test(marker)) {\n return parseInt(marker, 10)\n }\n\n const type = detectMarkerType(marker)\n\n if (type === 'i' || type === 'I') {\n return fromRoman(marker)\n }\n\n if (type === 'a' || type === 'A') {\n const start = fromAlpha(marker)\n\n return start > 0 ? start : 1\n }\n\n const parsed = parseInt(marker, 10)\n\n return Number.isNaN(parsed) ? 1 : parsed\n}\n\nfunction startToMarker(type: string, start: number): string {\n if (type === 'numeric') {\n return String(start)\n }\n\n switch (type) {\n case 'a':\n return toRomanAlpha(start)\n case 'A':\n return toRomanAlpha(start).toUpperCase()\n case 'i':\n return toRoman(start)\n case 'I':\n return toRomanUpper(start)\n default:\n return String(start)\n }\n}\n\n/**\n * Returns true when all markers share the same style and increment by 1.\n * Style is inferred from the first marker so ambiguous letters (e.g. \"c\", \"i\")\n * are not re-classified differently on later lines.\n */\nexport function areOrderedListMarkersSequential(markers: string[]): boolean {\n if (markers.length === 0) {\n return false\n }\n\n const firstType = detectMarkerType(markers[0]) ?? 'numeric'\n const firstStart = markerToStart(markers[0])\n\n if (firstStart < 1) {\n return false\n }\n\n for (let i = 0; i < markers.length; i++) {\n const expected = startToMarker(firstType, firstStart + i)\n\n if (markers[i] !== expected) {\n return false\n }\n }\n\n return true\n}\n\nexport interface ParsedListMarker {\n type?: string\n start: number\n}\n\n/**\n * Parse a list marker into HTML ordered-list attrs (type + start).\n */\nexport function parseListMarker(marker: string): ParsedListMarker {\n return {\n type: detectMarkerType(marker),\n start: markerToStart(marker),\n }\n}\n\n/**\n * Build orderedList node attrs from the first list item marker.\n */\nexport function buildOrderedListAttrsFromMarker(marker: string): Record<string, string | number> {\n const { type, start } = parseListMarker(marker)\n const attrs: Record<string, string | number> = {}\n\n if (type) {\n attrs.type = type\n }\n\n if (start !== 1) {\n attrs.start = start\n }\n\n return attrs\n}\n\n/**\n * Returns the list marker prefix for a given item at a given index.\n *\n * @param type The list type attribute (e.g. \"a\", \"A\", \"i\", \"I\", null/undefined for default)\n * @param index The zero-based index of the list item\n * @param separator The separator to use (default: \". \")\n * @returns The marker string (e.g. \"a. \", \"I. \", \"1. \")\n */\nexport function getListMarker(\n type: string | null | undefined,\n index: number,\n separator = '. ',\n): string {\n const position = index + 1\n\n if (!type || type === '1') {\n return `${position}${separator}`\n }\n\n switch (type) {\n case 'a':\n return `${toRomanAlpha(position)}${separator}`\n case 'A':\n return `${toRomanAlpha(position).toUpperCase()}${separator}`\n case 'i':\n return `${toRoman(position)}${separator}`\n case 'I':\n return `${toRomanUpper(position)}${separator}`\n default:\n return `${position}${separator}`\n }\n}\n","import type {\n JSONContent,\n MarkdownLexerConfiguration,\n MarkdownParseHelpers,\n MarkdownToken,\n} from '@tiptap/core'\n\nimport {\n areOrderedListMarkersSequential,\n buildOrderedListAttrsFromMarker,\n detectMarkerType,\n markerToStart,\n ORDERED_LIST_MARKER_PATTERN,\n} from './roman.js'\n\nexport { ORDERED_LIST_MARKER_PATTERN }\n\n/**\n * Matches an ordered list item line with optional leading whitespace.\n * Captures: (1) indentation spaces, (2) item marker (number, letter, or roman numeral),\n * (3) separator (. or )), (4) content after marker\n *\n * Examples: \"1. Item\", \" a) Nested item\", \" I. Roman item\", \"iii. Another\", \"aa. Item 27\"\n */\nexport const ORDERED_LIST_ITEM_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.*)$`,\n)\n\n/**\n * Matches the start of an ordered list line (used by markdown tokenizer).\n */\nexport const ORDERED_LIST_LINE_START_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+`,\n)\n\n/**\n * Matches any line that starts with whitespace (indented content).\n * Used to identify continuation content that belongs to a list item.\n */\nconst INDENTED_LINE_REGEX = /^\\s/\n\n/**\n * This are blocks that can interrupt a paragraph, so a line starting with one of\n * them can never be lazy continuation text of a list item\n */\nconst PARAGRAPH_INTERRUPTERS = {\n heading: /^#{1,6}(?:\\s|$)/,\n bulletItem: /^[-+*]\\s+/,\n codeFence: /^(?:```|~~~)/,\n thematicBreak: /^(?:(?:-[ \\t]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})$/,\n}\n\n/**\n * Represents a parsed ordered list item with indentation information\n */\nexport interface OrderedListItem {\n indent: number\n number: number\n type?: string\n content: string\n contentLines: string[]\n raw: string\n}\n\nfunction isOrderedListMarkerLine(line: string): boolean {\n return ORDERED_LIST_ITEM_REGEX.test(line.trimStart())\n}\n\nfunction isBlockContentLine(line: string): boolean {\n const trimmedLine = line.trimStart()\n\n return (\n PARAGRAPH_INTERRUPTERS.bulletItem.test(trimmedLine) ||\n isOrderedListMarkerLine(trimmedLine) ||\n PARAGRAPH_INTERRUPTERS.heading.test(trimmedLine) ||\n // dash breaks are excluded: \"---\" directly below paragraph text is a\n // setext heading underline, not a thematic break\n (PARAGRAPH_INTERRUPTERS.thematicBreak.test(trimmedLine) && !trimmedLine.startsWith('-')) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^>\\s?/.test(trimmedLine) ||\n PARAGRAPH_INTERRUPTERS.codeFence.test(trimmedLine)\n )\n}\n\nfunction interruptsLazyContinuation(line: string): boolean {\n return Object.values(PARAGRAPH_INTERRUPTERS).some(pattern => pattern.test(line))\n}\n\nfunction splitItemContent(contentLines: string[]): {\n paragraphLines: string[]\n blockLines: string[]\n} {\n const paragraphLines: string[] = []\n const blockLines: string[] = []\n let reachedBlockBoundary = false\n\n contentLines.forEach(line => {\n if (reachedBlockBoundary) {\n blockLines.push(line)\n return\n }\n\n if (line.trim() === '') {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n if (paragraphLines.length > 0 && isBlockContentLine(line)) {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n paragraphLines.push(line)\n })\n\n return {\n paragraphLines,\n blockLines,\n }\n}\n\n/**\n * Collects all ordered list items from lines, parsing them into a flat array\n * with indentation information. Stops collecting continuation content when\n * encountering nested list items, allowing them to be processed separately.\n *\n * @param lines - Array of source lines to parse\n * @returns Tuple of [listItems array, number of lines consumed]\n */\nexport function collectOrderedListItems(lines: string[]): [OrderedListItem[], number] {\n const listItems: OrderedListItem[] = []\n let currentLineIndex = 0\n let consumed = 0\n\n while (currentLineIndex < lines.length) {\n const line = lines[currentLineIndex]\n const match = line.match(ORDERED_LIST_ITEM_REGEX)\n\n if (!match) {\n break\n }\n\n const [, indent, marker, _separator, content] = match\n const indentLevel = indent.length\n const number = parseInt(marker, 10)\n\n const markerType = isNaN(number) ? detectMarkerType(marker) : undefined\n const itemNumber = isNaN(number) ? markerToStart(marker) : number\n\n const itemContentLines = [content]\n let nextLineIndex = currentLineIndex + 1\n const itemLines = [line]\n let sawBlankLine = false\n\n // Collect continuation lines for this item (but NOT nested list items)\n while (nextLineIndex < lines.length) {\n const nextLine = lines[nextLineIndex]\n const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX)\n\n // If it's another list item (nested or not), stop collecting\n if (nextMatch) {\n break\n }\n\n // Check for continuation content (non-list content)\n if (nextLine.trim() === '') {\n // Empty line\n itemLines.push(nextLine)\n itemContentLines.push('')\n sawBlankLine = true\n nextLineIndex += 1\n } else if (nextLine.match(INDENTED_LINE_REGEX)) {\n // Indented content - part of this item (but not a list item).\n // Strip the indentation only up to the whitespace that is actually present,\n // so an under-indented line (e.g. a single leading space) keeps its first character.\n const leadingWhitespace = nextLine.length - nextLine.trimStart().length\n const contentIndent = indentLevel + marker.length + 1\n itemLines.push(nextLine)\n itemContentLines.push(nextLine.slice(Math.min(leadingWhitespace, contentIndent)))\n nextLineIndex += 1\n } else {\n if (sawBlankLine || interruptsLazyContinuation(nextLine)) {\n break\n }\n\n itemLines.push(nextLine)\n itemContentLines.push(nextLine)\n nextLineIndex += 1\n }\n }\n\n listItems.push({\n indent: indentLevel,\n number: itemNumber,\n type: markerType,\n content: itemContentLines.join('\\n').trim(),\n contentLines: itemContentLines,\n raw: itemLines.join('\\n'),\n })\n\n consumed = nextLineIndex\n currentLineIndex = nextLineIndex\n }\n\n return [listItems, consumed]\n}\n\nconst PLAIN_TEXT_ORDERED_LIST_LINE_REGEX = new RegExp(\n `^(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.+)$`,\n)\n\n/**\n * Parse plain-text pasted ordered list lines into JSONContent, or null if not a typed list.\n */\nexport function parsePlainTextOrderedListPaste(text: string): JSONContent | null {\n const lines = text.split('\\n').filter(l => l.trim().length > 0)\n\n if (lines.length === 0) {\n return null\n }\n\n const parsedItems: Array<{ marker: string; content: string }> = []\n\n for (const line of lines) {\n const match = line.trim().match(PLAIN_TEXT_ORDERED_LIST_LINE_REGEX)\n\n if (!match) {\n return null\n }\n\n parsedItems.push({\n marker: match[1],\n content: match[3],\n })\n }\n\n const markers = parsedItems.map(item => item.marker)\n\n if (!areOrderedListMarkersSequential(markers)) {\n return null\n }\n\n const attrs = buildOrderedListAttrsFromMarker(parsedItems[0].marker)\n\n return {\n type: 'orderedList',\n attrs,\n content: parsedItems.map(item => ({\n type: 'listItem',\n content: [\n {\n type: 'paragraph',\n content: [{ type: 'text', text: item.content }],\n },\n ],\n })),\n }\n}\n\n/**\n * Recursively builds a nested structure from a flat array of list items\n * based on their indentation levels. Creates proper markdown tokens with\n * nested lists where appropriate.\n *\n * @param items - Flat array of list items with indentation info\n * @param baseIndent - The indentation level to process at this recursion level\n * @param lexer - Markdown lexer for parsing inline and block content\n * @returns Array of list_item tokens with proper nesting\n */\nexport function buildNestedStructure(\n items: OrderedListItem[],\n baseIndent: number,\n lexer: MarkdownLexerConfiguration,\n): unknown[] {\n const result: unknown[] = []\n let currentIndex = 0\n\n while (currentIndex < items.length) {\n const item = items[currentIndex]\n\n if (item.indent === baseIndent) {\n // This item belongs at the current level\n const { paragraphLines, blockLines } = splitItemContent(item.contentLines)\n const mainText = paragraphLines.join('\\n').trim()\n\n const tokens = []\n\n // Always wrap the main text in a paragraph token\n if (mainText) {\n tokens.push({\n type: 'paragraph',\n raw: mainText,\n tokens: lexer.inlineTokens(mainText),\n })\n }\n\n const additionalContent = blockLines.join('\\n').trim()\n if (additionalContent) {\n const blockTokens = lexer.blockTokens(additionalContent)\n tokens.push(...blockTokens)\n }\n\n // Look ahead to find nested items at deeper indent levels\n let lookAheadIndex = currentIndex + 1\n const nestedItems = []\n\n while (lookAheadIndex < items.length && items[lookAheadIndex].indent > baseIndent) {\n nestedItems.push(items[lookAheadIndex])\n lookAheadIndex += 1\n }\n\n // If we have nested items, recursively build their structure\n if (nestedItems.length > 0) {\n // Find the next indent level (immediate children)\n const nextIndent = Math.min(...nestedItems.map(nestedItem => nestedItem.indent))\n\n // Build the nested list recursively with all nested items\n // The recursive call will handle further nesting\n const nestedListItems = buildNestedStructure(nestedItems, nextIndent, lexer)\n\n // Create a nested list token\n tokens.push({\n type: 'list',\n ordered: true,\n start: nestedItems[0].number,\n typeMarker: nestedItems[0].type,\n items: nestedListItems,\n raw: nestedItems.map(nestedItem => nestedItem.raw).join('\\n'),\n })\n }\n\n result.push({\n type: 'list_item',\n raw: item.raw,\n tokens,\n })\n\n // Skip the nested items we just processed\n currentIndex = lookAheadIndex\n } else {\n // This item has deeper indent than we're currently processing\n // It should be handled by a recursive call\n currentIndex += 1\n }\n }\n\n return result\n}\n\n/**\n * Parses markdown list item tokens into Tiptap JSONContent structure,\n * ensuring text content is properly wrapped in paragraph nodes.\n *\n * @param items - Array of markdown tokens representing list items\n * @param helpers - Markdown parse helpers for recursive parsing\n * @returns Array of listItem JSONContent nodes\n */\nexport function parseListItems(\n items: MarkdownToken[],\n helpers: MarkdownParseHelpers,\n): JSONContent[] {\n return items.map(item => {\n if (item.type !== 'list_item') {\n return helpers.parseChildren([item])[0]\n }\n\n // Parse the tokens within the list item\n const content: JSONContent[] = []\n\n if (item.tokens && item.tokens.length > 0) {\n item.tokens.forEach(itemToken => {\n // If it's already a proper block node (paragraph, list, etc.), parse it directly\n if (\n itemToken.type === 'paragraph' ||\n itemToken.type === 'list' ||\n itemToken.type === 'blockquote' ||\n itemToken.type === 'code'\n ) {\n content.push(...helpers.parseChildren([itemToken]))\n } else if (itemToken.type === 'text' && itemToken.tokens) {\n // If it's inline text tokens, wrap them in a paragraph\n const inlineContent = helpers.parseChildren([itemToken])\n content.push({\n type: 'paragraph',\n content: inlineContent,\n })\n } else {\n // For any other content, try to parse it\n const parsed = helpers.parseChildren([itemToken])\n if (parsed.length > 0) {\n content.push(...parsed)\n }\n }\n })\n }\n\n return {\n type: 'listItem',\n content,\n }\n })\n}\n"],"mappings":"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","names":[]}
@@ -198,18 +198,24 @@ var ORDERED_LIST_LINE_START_REGEX = new RegExp(
198
198
  `^(\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\s+`
199
199
  );
200
200
  var INDENTED_LINE_REGEX = /^\s/;
201
+ var PARAGRAPH_INTERRUPTERS = {
202
+ heading: /^#{1,6}(?:\s|$)/,
203
+ bulletItem: /^[-+*]\s+/,
204
+ codeFence: /^(?:```|~~~)/,
205
+ thematicBreak: /^(?:(?:-[ \t]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})$/
206
+ };
201
207
  function isOrderedListMarkerLine(line) {
202
208
  return ORDERED_LIST_ITEM_REGEX.test(line.trimStart());
203
209
  }
204
210
  function isBlockContentLine(line) {
205
211
  const trimmedLine = line.trimStart();
206
- return (
207
- // oxlint-disable-next-line prefer-string-starts-ends-with
208
- /^[-+*]\s+/.test(trimmedLine) || isOrderedListMarkerLine(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
209
- /^>\s?/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
210
- /^```/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
211
- /^~~~/.test(trimmedLine)
212
- );
212
+ return PARAGRAPH_INTERRUPTERS.bulletItem.test(trimmedLine) || isOrderedListMarkerLine(trimmedLine) || PARAGRAPH_INTERRUPTERS.heading.test(trimmedLine) || // dash breaks are excluded: "---" directly below paragraph text is a
213
+ // setext heading underline, not a thematic break
214
+ PARAGRAPH_INTERRUPTERS.thematicBreak.test(trimmedLine) && !trimmedLine.startsWith("-") || // oxlint-disable-next-line prefer-string-starts-ends-with
215
+ /^>\s?/.test(trimmedLine) || PARAGRAPH_INTERRUPTERS.codeFence.test(trimmedLine);
216
+ }
217
+ function interruptsLazyContinuation(line) {
218
+ return Object.values(PARAGRAPH_INTERRUPTERS).some((pattern) => pattern.test(line));
213
219
  }
214
220
  function splitItemContent(contentLines) {
215
221
  const paragraphLines = [];
@@ -274,7 +280,7 @@ function collectOrderedListItems(lines) {
274
280
  itemContentLines.push(nextLine.slice(Math.min(leadingWhitespace, contentIndent)));
275
281
  nextLineIndex += 1;
276
282
  } else {
277
- if (sawBlankLine) {
283
+ if (sawBlankLine || interruptsLazyContinuation(nextLine)) {
278
284
  break;
279
285
  }
280
286
  itemLines.push(nextLine);
@@ -557,7 +563,7 @@ var OrderedList = Node.create({
557
563
  if (listItems.length === 0) {
558
564
  return void 0;
559
565
  }
560
- const items = buildNestedStructure(listItems, 0, lexer);
566
+ const items = buildNestedStructure(listItems, listItems[0].indent, lexer);
561
567
  if (items.length === 0) {
562
568
  return void 0;
563
569
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ordered-list/ordered-list.ts","../../src/ordered-list/roman.ts","../../src/ordered-list/utils.ts"],"sourcesContent":["import type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Plugin } from '@tiptap/pm/state'\n\nimport { mergeAttributes, Node, wrappingInputRule } from '@tiptap/core'\n\nimport {\n buildNestedStructure,\n collectOrderedListItems,\n ORDERED_LIST_LINE_START_REGEX,\n parseListItems,\n parsePlainTextOrderedListPaste,\n} from './utils.js'\n\nconst ListItemName = 'listItem'\nconst TextStyleName = 'textStyle'\n\nexport interface OrderedListOptions {\n /**\n * The node type name for list items.\n * @default 'listItem'\n * @example 'myListItem'\n */\n itemTypeName: string\n\n /**\n * The HTML attributes for an ordered list node.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * Keep the marks when splitting a list item.\n * @default false\n * @example true\n */\n keepMarks: boolean\n\n /**\n * Keep the attributes when splitting a list item.\n * @default false\n * @example true\n */\n keepAttributes: boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n orderedList: {\n /**\n * Toggle an ordered list\n * @example editor.commands.toggleOrderedList()\n */\n toggleOrderedList: () => ReturnType\n }\n }\n}\n\n/**\n * Matches an ordered list to a 1. on input (or any number followed by a dot).\n */\nexport const orderedListInputRegex = /^(\\d+)\\.\\s$/\n\n/**\n * Maps CSS list-style-type values to HTML type attribute values.\n * Google Docs and Word often use CSS instead of the HTML type attribute.\n */\nfunction cssListStyleTypeToHtmlType(style: string): string | null {\n const match = style.match(/list-style-type\\s*:\\s*([^;]+)/i)\n if (!match) {\n return null\n }\n\n const cssValue = match[1].trim().toLowerCase()\n\n switch (cssValue) {\n case 'upper-roman':\n return 'I'\n case 'lower-roman':\n return 'i'\n case 'upper-alpha':\n case 'upper-latin':\n return 'A'\n case 'lower-alpha':\n case 'lower-latin':\n return 'a'\n default:\n return null\n }\n}\n\n/**\n * This extension allows you to create ordered lists.\n * This requires the ListItem extension\n * @see https://www.tiptap.dev/api/nodes/ordered-list\n * @see https://www.tiptap.dev/api/nodes/list-item\n */\nexport const OrderedList = Node.create<OrderedListOptions>({\n name: 'orderedList',\n\n addOptions() {\n return {\n itemTypeName: 'listItem',\n HTMLAttributes: {},\n keepMarks: false,\n keepAttributes: false,\n }\n },\n\n group: 'block list',\n\n content() {\n return `${this.options.itemTypeName}+`\n },\n\n addAttributes() {\n return {\n start: {\n default: 1,\n parseHTML: element => {\n return element.hasAttribute('start')\n ? parseInt(element.getAttribute('start') || '', 10)\n : 1\n },\n },\n type: {\n default: null,\n parseHTML: element => {\n // 1. Check the HTML type attribute on <ol>\n const htmlType = element.getAttribute('type')\n if (htmlType) {\n return htmlType\n }\n\n // 2. Check CSS list-style-type on the <ol> element's style attribute\n const style = element.getAttribute('style')\n if (style) {\n const mappedFromOl = cssListStyleTypeToHtmlType(style)\n if (mappedFromOl) {\n return mappedFromOl\n }\n }\n\n // 3. Check the first <li> child for list-style-type (Google Docs pattern)\n const firstLi = element.querySelector('li')\n if (firstLi) {\n const liStyle = firstLi.getAttribute('style')\n if (liStyle) {\n const mappedFromLi = cssListStyleTypeToHtmlType(liStyle)\n if (mappedFromLi) {\n return mappedFromLi\n }\n }\n }\n\n return null\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'ol',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n const { start, type, ...attributesWithoutType } = HTMLAttributes\n\n const attrs = mergeAttributes(this.options.HTMLAttributes, attributesWithoutType)\n\n if (start !== 1) {\n attrs.start = start\n }\n\n if (type && type !== '1') {\n attrs.type = type\n }\n\n return ['ol', attrs, 0]\n },\n\n markdownTokenName: 'list',\n\n parseMarkdown: (token, helpers) => {\n if (token.type !== 'list' || !token.ordered) {\n return []\n }\n\n const startValue = token.start || 1\n const typeValue = token.typeMarker as string | undefined\n const content = token.items ? parseListItems(token.items, helpers) : []\n\n // Build attrs only when they differ from defaults\n const attrs: Record<string, unknown> = {}\n\n if (startValue !== 1) {\n attrs.start = startValue\n }\n\n if (typeValue) {\n attrs.type = typeValue\n }\n\n if (Object.keys(attrs).length > 0) {\n return {\n type: 'orderedList',\n attrs,\n content,\n }\n }\n\n return {\n type: 'orderedList',\n content,\n }\n },\n\n renderMarkdown: (node, h) => {\n if (!node.content) {\n return ''\n }\n\n return h.renderChildren(node.content, '\\n')\n },\n\n markdownTokenizer: {\n name: 'orderedList',\n level: 'block',\n start: (src: string) => {\n const match = src.match(ORDERED_LIST_LINE_START_REGEX)\n const index = match?.index\n return index !== undefined ? index : -1\n },\n tokenize: (src: string, _tokens, lexer) => {\n const lines = src.split('\\n')\n const [listItems, consumed] = collectOrderedListItems(lines)\n\n if (listItems.length === 0) {\n return undefined\n }\n\n const items = buildNestedStructure(listItems, 0, lexer)\n\n if (items.length === 0) {\n return undefined\n }\n\n const startValue = listItems[0]?.number || 1\n const typeMarker = listItems[0]?.type\n\n return {\n type: 'list',\n ordered: true,\n start: startValue,\n typeMarker,\n items,\n raw: lines.slice(0, consumed).join('\\n'),\n } as unknown as object\n },\n },\n\n markdownOptions: {\n indentsContent: true,\n },\n\n addCommands() {\n return {\n toggleOrderedList:\n () =>\n ({ commands, chain }) => {\n if (this.options.keepAttributes) {\n return chain()\n .toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n .updateAttributes(ListItemName, this.editor.getAttributes(TextStyleName))\n .run()\n }\n return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Shift-7': () => this.editor.commands.toggleOrderedList(),\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handlePaste: (view, event) => {\n const html = event.clipboardData?.getData('text/html')\n\n if (html?.trim()) {\n return false\n }\n\n const text = event.clipboardData?.getData('text/plain')\n\n if (!text) {\n return false\n }\n\n const orderedListContent = parsePlainTextOrderedListPaste(text)\n\n if (!orderedListContent) {\n return false\n }\n\n try {\n const orderedListNode = view.state.schema.nodeFromJSON(orderedListContent)\n const tr = view.state.tr.replaceSelectionWith(orderedListNode)\n\n view.dispatch(tr)\n\n return true\n } catch {\n return false\n }\n },\n },\n }),\n ]\n },\n\n addInputRules() {\n const joinPredicate = (match: RegExpMatchArray, node: ProseMirrorNode) => {\n // Only join if the existing list has a default type\n // (not a typed list like \"a\" or \"i\" which should stay separate)\n const hasDefaultType = !node.attrs.type || node.attrs.type === '1'\n\n return hasDefaultType && node.childCount + node.attrs.start === +match[1]\n }\n\n let inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n getAttributes: match => ({ start: +match[1] }),\n joinPredicate,\n })\n\n if (this.options.keepMarks || this.options.keepAttributes) {\n inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n keepMarks: this.options.keepMarks,\n keepAttributes: this.options.keepAttributes,\n getAttributes: match => ({ start: +match[1], ...this.editor.getAttributes(TextStyleName) }),\n joinPredicate,\n editor: this.editor,\n })\n }\n return [inputRule]\n },\n})\n","const ROMAN_NUMERALS: [number, string][] = [\n [1000, 'm'],\n [900, 'cm'],\n [500, 'd'],\n [400, 'cd'],\n [100, 'c'],\n [90, 'xc'],\n [50, 'l'],\n [40, 'xl'],\n [10, 'x'],\n [9, 'ix'],\n [5, 'v'],\n [4, 'iv'],\n [1, 'i'],\n]\n\nconst ALPHA_NUMERALS = 'abcdefghijklmnopqrstuvwxyz'\n\n/** Alpha list markers support at most 2 letters (a–z, aa–zz), matching {@link fromAlpha}. */\nexport const ORDERED_LIST_ALPHA_MARKER_PATTERN = '[a-zA-Z]{1,2}'\n\n/**\n * Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.\n * Roman is matched before alpha so \"iii\" is roman; invalid romans like \"aa\" fall through to alpha.\n */\nexport const ORDERED_LIST_MARKER_PATTERN = String.raw`\\d+|[ivxlcdmIVXLCDM]+|${ORDERED_LIST_ALPHA_MARKER_PATTERN}`\n\n/**\n * Convert a number to lowercase roman numerals.\n * @example toRoman(1) // 'i'\n * @example toRoman(4) // 'iv'\n */\nexport function toRoman(num: number): string {\n let remaining = num\n let result = ''\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n while (remaining >= value) {\n result += numeral\n remaining -= value\n }\n }\n\n return result\n}\n\n/**\n * Convert a number to uppercase roman numerals.\n * @example toRomanUpper(1) // 'I'\n * @example toRomanUpper(4) // 'IV'\n */\nexport function toRomanUpper(num: number): string {\n return toRoman(num).toUpperCase()\n}\n\nfunction fromRoman(roman: string): number {\n const lower = roman.toLowerCase()\n let index = 0\n let result = 0\n\n while (index < lower.length) {\n let matched = false\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n if (lower.startsWith(numeral, index)) {\n result += value\n index += numeral.length\n matched = true\n break\n }\n }\n\n if (!matched) {\n return 0\n }\n }\n\n return result\n}\n\nfunction isValidRoman(marker: string): boolean {\n if (!/^[ivxlcdmIVXLCDM]+$/.test(marker)) {\n return false\n }\n\n const value = fromRoman(marker)\n\n if (value <= 0) {\n return false\n }\n\n const expected = marker === marker.toLowerCase() ? toRoman(value) : toRomanUpper(value)\n\n return expected === marker\n}\n\nfunction fromAlpha(marker: string): number {\n const lower = marker.toLowerCase()\n\n if (lower.length === 1) {\n return lower.charCodeAt(0) - 'a'.charCodeAt(0) + 1\n }\n\n if (lower.length === 2) {\n const first = lower.charCodeAt(0) - 'a'.charCodeAt(0)\n const second = lower.charCodeAt(1) - 'a'.charCodeAt(0)\n\n return (first + 1) * 26 + second + 1\n }\n\n return 0\n}\n\nfunction toRomanAlpha(num: number): string {\n if (num <= 26) {\n return ALPHA_NUMERALS[num - 1]\n }\n\n const first = Math.floor((num - 1) / 26) - 1\n const second = (num - 1) % 26\n\n if (first < 0) {\n return ALPHA_NUMERALS[second]\n }\n\n return ALPHA_NUMERALS[first] + ALPHA_NUMERALS[second]\n}\n\n/**\n * Extract the list marker type from a marker string.\n * Supports \"1\", \"a\", \"A\", \"i\", \"I\" marker styles.\n *\n * @param marker The text content of the list marker (e.g. \"a\", \"1\", \"iii\", \"b\")\n * @returns The normalized type string, or undefined for default numeric type\n */\nexport function detectMarkerType(marker: string): string | undefined {\n if (!marker || /^\\d+$/.test(marker)) {\n return undefined\n }\n\n if (isValidRoman(marker)) {\n return marker === marker.toLowerCase() ? 'i' : 'I'\n }\n\n if (/^[a-z]{1,2}$/.test(marker)) {\n return 'a'\n }\n\n if (/^[A-Z]{1,2}$/.test(marker)) {\n return 'A'\n }\n\n return undefined\n}\n\n/**\n * Convert a list marker string to its numeric start position.\n *\n * @param marker The text content of the list marker (e.g. \"3\", \"b\", \"II\")\n * @returns The 1-based start value for the ordered list\n */\nexport function markerToStart(marker: string): number {\n if (/^\\d+$/.test(marker)) {\n return parseInt(marker, 10)\n }\n\n const type = detectMarkerType(marker)\n\n if (type === 'i' || type === 'I') {\n return fromRoman(marker)\n }\n\n if (type === 'a' || type === 'A') {\n const start = fromAlpha(marker)\n\n return start > 0 ? start : 1\n }\n\n const parsed = parseInt(marker, 10)\n\n return Number.isNaN(parsed) ? 1 : parsed\n}\n\nfunction startToMarker(type: string, start: number): string {\n if (type === 'numeric') {\n return String(start)\n }\n\n switch (type) {\n case 'a':\n return toRomanAlpha(start)\n case 'A':\n return toRomanAlpha(start).toUpperCase()\n case 'i':\n return toRoman(start)\n case 'I':\n return toRomanUpper(start)\n default:\n return String(start)\n }\n}\n\n/**\n * Returns true when all markers share the same style and increment by 1.\n * Style is inferred from the first marker so ambiguous letters (e.g. \"c\", \"i\")\n * are not re-classified differently on later lines.\n */\nexport function areOrderedListMarkersSequential(markers: string[]): boolean {\n if (markers.length === 0) {\n return false\n }\n\n const firstType = detectMarkerType(markers[0]) ?? 'numeric'\n const firstStart = markerToStart(markers[0])\n\n if (firstStart < 1) {\n return false\n }\n\n for (let i = 0; i < markers.length; i++) {\n const expected = startToMarker(firstType, firstStart + i)\n\n if (markers[i] !== expected) {\n return false\n }\n }\n\n return true\n}\n\nexport interface ParsedListMarker {\n type?: string\n start: number\n}\n\n/**\n * Parse a list marker into HTML ordered-list attrs (type + start).\n */\nexport function parseListMarker(marker: string): ParsedListMarker {\n return {\n type: detectMarkerType(marker),\n start: markerToStart(marker),\n }\n}\n\n/**\n * Build orderedList node attrs from the first list item marker.\n */\nexport function buildOrderedListAttrsFromMarker(marker: string): Record<string, string | number> {\n const { type, start } = parseListMarker(marker)\n const attrs: Record<string, string | number> = {}\n\n if (type) {\n attrs.type = type\n }\n\n if (start !== 1) {\n attrs.start = start\n }\n\n return attrs\n}\n\n/**\n * Returns the list marker prefix for a given item at a given index.\n *\n * @param type The list type attribute (e.g. \"a\", \"A\", \"i\", \"I\", null/undefined for default)\n * @param index The zero-based index of the list item\n * @param separator The separator to use (default: \". \")\n * @returns The marker string (e.g. \"a. \", \"I. \", \"1. \")\n */\nexport function getListMarker(\n type: string | null | undefined,\n index: number,\n separator = '. ',\n): string {\n const position = index + 1\n\n if (!type || type === '1') {\n return `${position}${separator}`\n }\n\n switch (type) {\n case 'a':\n return `${toRomanAlpha(position)}${separator}`\n case 'A':\n return `${toRomanAlpha(position).toUpperCase()}${separator}`\n case 'i':\n return `${toRoman(position)}${separator}`\n case 'I':\n return `${toRomanUpper(position)}${separator}`\n default:\n return `${position}${separator}`\n }\n}\n","import type {\n JSONContent,\n MarkdownLexerConfiguration,\n MarkdownParseHelpers,\n MarkdownToken,\n} from '@tiptap/core'\n\nimport {\n areOrderedListMarkersSequential,\n buildOrderedListAttrsFromMarker,\n detectMarkerType,\n markerToStart,\n ORDERED_LIST_MARKER_PATTERN,\n} from './roman.js'\n\nexport { ORDERED_LIST_MARKER_PATTERN }\n\n/**\n * Matches an ordered list item line with optional leading whitespace.\n * Captures: (1) indentation spaces, (2) item marker (number, letter, or roman numeral),\n * (3) separator (. or )), (4) content after marker\n *\n * Examples: \"1. Item\", \" a) Nested item\", \" I. Roman item\", \"iii. Another\", \"aa. Item 27\"\n */\nexport const ORDERED_LIST_ITEM_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.*)$`,\n)\n\n/**\n * Matches the start of an ordered list line (used by markdown tokenizer).\n */\nexport const ORDERED_LIST_LINE_START_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+`,\n)\n\n/**\n * Matches any line that starts with whitespace (indented content).\n * Used to identify continuation content that belongs to a list item.\n */\nconst INDENTED_LINE_REGEX = /^\\s/\n\n/**\n * Represents a parsed ordered list item with indentation information\n */\nexport interface OrderedListItem {\n indent: number\n number: number\n type?: string\n content: string\n contentLines: string[]\n raw: string\n}\n\nfunction isOrderedListMarkerLine(line: string): boolean {\n return ORDERED_LIST_ITEM_REGEX.test(line.trimStart())\n}\n\nfunction isBlockContentLine(line: string): boolean {\n const trimmedLine = line.trimStart()\n\n return (\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^[-+*]\\s+/.test(trimmedLine) ||\n isOrderedListMarkerLine(trimmedLine) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^>\\s?/.test(trimmedLine) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^```/.test(trimmedLine) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^~~~/.test(trimmedLine)\n )\n}\n\nfunction splitItemContent(contentLines: string[]): {\n paragraphLines: string[]\n blockLines: string[]\n} {\n const paragraphLines: string[] = []\n const blockLines: string[] = []\n let reachedBlockBoundary = false\n\n contentLines.forEach(line => {\n if (reachedBlockBoundary) {\n blockLines.push(line)\n return\n }\n\n if (line.trim() === '') {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n if (paragraphLines.length > 0 && isBlockContentLine(line)) {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n paragraphLines.push(line)\n })\n\n return {\n paragraphLines,\n blockLines,\n }\n}\n\n/**\n * Collects all ordered list items from lines, parsing them into a flat array\n * with indentation information. Stops collecting continuation content when\n * encountering nested list items, allowing them to be processed separately.\n *\n * @param lines - Array of source lines to parse\n * @returns Tuple of [listItems array, number of lines consumed]\n */\nexport function collectOrderedListItems(lines: string[]): [OrderedListItem[], number] {\n const listItems: OrderedListItem[] = []\n let currentLineIndex = 0\n let consumed = 0\n\n while (currentLineIndex < lines.length) {\n const line = lines[currentLineIndex]\n const match = line.match(ORDERED_LIST_ITEM_REGEX)\n\n if (!match) {\n break\n }\n\n const [, indent, marker, _separator, content] = match\n const indentLevel = indent.length\n const number = parseInt(marker, 10)\n\n const markerType = isNaN(number) ? detectMarkerType(marker) : undefined\n const itemNumber = isNaN(number) ? markerToStart(marker) : number\n\n const itemContentLines = [content]\n let nextLineIndex = currentLineIndex + 1\n const itemLines = [line]\n let sawBlankLine = false\n\n // Collect continuation lines for this item (but NOT nested list items)\n while (nextLineIndex < lines.length) {\n const nextLine = lines[nextLineIndex]\n const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX)\n\n // If it's another list item (nested or not), stop collecting\n if (nextMatch) {\n break\n }\n\n // Check for continuation content (non-list content)\n if (nextLine.trim() === '') {\n // Empty line\n itemLines.push(nextLine)\n itemContentLines.push('')\n sawBlankLine = true\n nextLineIndex += 1\n } else if (nextLine.match(INDENTED_LINE_REGEX)) {\n // Indented content - part of this item (but not a list item).\n // Strip the indentation only up to the whitespace that is actually present,\n // so an under-indented line (e.g. a single leading space) keeps its first character.\n const leadingWhitespace = nextLine.length - nextLine.trimStart().length\n const contentIndent = indentLevel + marker.length + 1\n itemLines.push(nextLine)\n itemContentLines.push(nextLine.slice(Math.min(leadingWhitespace, contentIndent)))\n nextLineIndex += 1\n } else {\n if (sawBlankLine) {\n break\n }\n\n itemLines.push(nextLine)\n itemContentLines.push(nextLine)\n nextLineIndex += 1\n }\n }\n\n listItems.push({\n indent: indentLevel,\n number: itemNumber,\n type: markerType,\n content: itemContentLines.join('\\n').trim(),\n contentLines: itemContentLines,\n raw: itemLines.join('\\n'),\n })\n\n consumed = nextLineIndex\n currentLineIndex = nextLineIndex\n }\n\n return [listItems, consumed]\n}\n\nconst PLAIN_TEXT_ORDERED_LIST_LINE_REGEX = new RegExp(\n `^(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.+)$`,\n)\n\n/**\n * Parse plain-text pasted ordered list lines into JSONContent, or null if not a typed list.\n */\nexport function parsePlainTextOrderedListPaste(text: string): JSONContent | null {\n const lines = text.split('\\n').filter(l => l.trim().length > 0)\n\n if (lines.length === 0) {\n return null\n }\n\n const parsedItems: Array<{ marker: string; content: string }> = []\n\n for (const line of lines) {\n const match = line.trim().match(PLAIN_TEXT_ORDERED_LIST_LINE_REGEX)\n\n if (!match) {\n return null\n }\n\n parsedItems.push({\n marker: match[1],\n content: match[3],\n })\n }\n\n const markers = parsedItems.map(item => item.marker)\n\n if (!areOrderedListMarkersSequential(markers)) {\n return null\n }\n\n const attrs = buildOrderedListAttrsFromMarker(parsedItems[0].marker)\n\n return {\n type: 'orderedList',\n attrs,\n content: parsedItems.map(item => ({\n type: 'listItem',\n content: [\n {\n type: 'paragraph',\n content: [{ type: 'text', text: item.content }],\n },\n ],\n })),\n }\n}\n\n/**\n * Recursively builds a nested structure from a flat array of list items\n * based on their indentation levels. Creates proper markdown tokens with\n * nested lists where appropriate.\n *\n * @param items - Flat array of list items with indentation info\n * @param baseIndent - The indentation level to process at this recursion level\n * @param lexer - Markdown lexer for parsing inline and block content\n * @returns Array of list_item tokens with proper nesting\n */\nexport function buildNestedStructure(\n items: OrderedListItem[],\n baseIndent: number,\n lexer: MarkdownLexerConfiguration,\n): unknown[] {\n const result: unknown[] = []\n let currentIndex = 0\n\n while (currentIndex < items.length) {\n const item = items[currentIndex]\n\n if (item.indent === baseIndent) {\n // This item belongs at the current level\n const { paragraphLines, blockLines } = splitItemContent(item.contentLines)\n const mainText = paragraphLines.join('\\n').trim()\n\n const tokens = []\n\n // Always wrap the main text in a paragraph token\n if (mainText) {\n tokens.push({\n type: 'paragraph',\n raw: mainText,\n tokens: lexer.inlineTokens(mainText),\n })\n }\n\n const additionalContent = blockLines.join('\\n').trim()\n if (additionalContent) {\n const blockTokens = lexer.blockTokens(additionalContent)\n tokens.push(...blockTokens)\n }\n\n // Look ahead to find nested items at deeper indent levels\n let lookAheadIndex = currentIndex + 1\n const nestedItems = []\n\n while (lookAheadIndex < items.length && items[lookAheadIndex].indent > baseIndent) {\n nestedItems.push(items[lookAheadIndex])\n lookAheadIndex += 1\n }\n\n // If we have nested items, recursively build their structure\n if (nestedItems.length > 0) {\n // Find the next indent level (immediate children)\n const nextIndent = Math.min(...nestedItems.map(nestedItem => nestedItem.indent))\n\n // Build the nested list recursively with all nested items\n // The recursive call will handle further nesting\n const nestedListItems = buildNestedStructure(nestedItems, nextIndent, lexer)\n\n // Create a nested list token\n tokens.push({\n type: 'list',\n ordered: true,\n start: nestedItems[0].number,\n typeMarker: nestedItems[0].type,\n items: nestedListItems,\n raw: nestedItems.map(nestedItem => nestedItem.raw).join('\\n'),\n })\n }\n\n result.push({\n type: 'list_item',\n raw: item.raw,\n tokens,\n })\n\n // Skip the nested items we just processed\n currentIndex = lookAheadIndex\n } else {\n // This item has deeper indent than we're currently processing\n // It should be handled by a recursive call\n currentIndex += 1\n }\n }\n\n return result\n}\n\n/**\n * Parses markdown list item tokens into Tiptap JSONContent structure,\n * ensuring text content is properly wrapped in paragraph nodes.\n *\n * @param items - Array of markdown tokens representing list items\n * @param helpers - Markdown parse helpers for recursive parsing\n * @returns Array of listItem JSONContent nodes\n */\nexport function parseListItems(\n items: MarkdownToken[],\n helpers: MarkdownParseHelpers,\n): JSONContent[] {\n return items.map(item => {\n if (item.type !== 'list_item') {\n return helpers.parseChildren([item])[0]\n }\n\n // Parse the tokens within the list item\n const content: JSONContent[] = []\n\n if (item.tokens && item.tokens.length > 0) {\n item.tokens.forEach(itemToken => {\n // If it's already a proper block node (paragraph, list, etc.), parse it directly\n if (\n itemToken.type === 'paragraph' ||\n itemToken.type === 'list' ||\n itemToken.type === 'blockquote' ||\n itemToken.type === 'code'\n ) {\n content.push(...helpers.parseChildren([itemToken]))\n } else if (itemToken.type === 'text' && itemToken.tokens) {\n // If it's inline text tokens, wrap them in a paragraph\n const inlineContent = helpers.parseChildren([itemToken])\n content.push({\n type: 'paragraph',\n content: inlineContent,\n })\n } else {\n // For any other content, try to parse it\n const parsed = helpers.parseChildren([itemToken])\n if (parsed.length > 0) {\n content.push(...parsed)\n }\n }\n })\n }\n\n return {\n type: 'listItem',\n content,\n }\n })\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/ordered-list/ordered-list.ts","../../src/ordered-list/roman.ts","../../src/ordered-list/utils.ts"],"sourcesContent":["import type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Plugin } from '@tiptap/pm/state'\n\nimport { mergeAttributes, Node, wrappingInputRule } from '@tiptap/core'\n\nimport {\n buildNestedStructure,\n collectOrderedListItems,\n ORDERED_LIST_LINE_START_REGEX,\n parseListItems,\n parsePlainTextOrderedListPaste,\n} from './utils.js'\n\nconst ListItemName = 'listItem'\nconst TextStyleName = 'textStyle'\n\nexport interface OrderedListOptions {\n /**\n * The node type name for list items.\n * @default 'listItem'\n * @example 'myListItem'\n */\n itemTypeName: string\n\n /**\n * The HTML attributes for an ordered list node.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * Keep the marks when splitting a list item.\n * @default false\n * @example true\n */\n keepMarks: boolean\n\n /**\n * Keep the attributes when splitting a list item.\n * @default false\n * @example true\n */\n keepAttributes: boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n orderedList: {\n /**\n * Toggle an ordered list\n * @example editor.commands.toggleOrderedList()\n */\n toggleOrderedList: () => ReturnType\n }\n }\n}\n\n/**\n * Matches an ordered list to a 1. on input (or any number followed by a dot).\n */\nexport const orderedListInputRegex = /^(\\d+)\\.\\s$/\n\n/**\n * Maps CSS list-style-type values to HTML type attribute values.\n * Google Docs and Word often use CSS instead of the HTML type attribute.\n */\nfunction cssListStyleTypeToHtmlType(style: string): string | null {\n const match = style.match(/list-style-type\\s*:\\s*([^;]+)/i)\n if (!match) {\n return null\n }\n\n const cssValue = match[1].trim().toLowerCase()\n\n switch (cssValue) {\n case 'upper-roman':\n return 'I'\n case 'lower-roman':\n return 'i'\n case 'upper-alpha':\n case 'upper-latin':\n return 'A'\n case 'lower-alpha':\n case 'lower-latin':\n return 'a'\n default:\n return null\n }\n}\n\n/**\n * This extension allows you to create ordered lists.\n * This requires the ListItem extension\n * @see https://www.tiptap.dev/api/nodes/ordered-list\n * @see https://www.tiptap.dev/api/nodes/list-item\n */\nexport const OrderedList = Node.create<OrderedListOptions>({\n name: 'orderedList',\n\n addOptions() {\n return {\n itemTypeName: 'listItem',\n HTMLAttributes: {},\n keepMarks: false,\n keepAttributes: false,\n }\n },\n\n group: 'block list',\n\n content() {\n return `${this.options.itemTypeName}+`\n },\n\n addAttributes() {\n return {\n start: {\n default: 1,\n parseHTML: element => {\n return element.hasAttribute('start')\n ? parseInt(element.getAttribute('start') || '', 10)\n : 1\n },\n },\n type: {\n default: null,\n parseHTML: element => {\n // 1. Check the HTML type attribute on <ol>\n const htmlType = element.getAttribute('type')\n if (htmlType) {\n return htmlType\n }\n\n // 2. Check CSS list-style-type on the <ol> element's style attribute\n const style = element.getAttribute('style')\n if (style) {\n const mappedFromOl = cssListStyleTypeToHtmlType(style)\n if (mappedFromOl) {\n return mappedFromOl\n }\n }\n\n // 3. Check the first <li> child for list-style-type (Google Docs pattern)\n const firstLi = element.querySelector('li')\n if (firstLi) {\n const liStyle = firstLi.getAttribute('style')\n if (liStyle) {\n const mappedFromLi = cssListStyleTypeToHtmlType(liStyle)\n if (mappedFromLi) {\n return mappedFromLi\n }\n }\n }\n\n return null\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'ol',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n const { start, type, ...attributesWithoutType } = HTMLAttributes\n\n const attrs = mergeAttributes(this.options.HTMLAttributes, attributesWithoutType)\n\n if (start !== 1) {\n attrs.start = start\n }\n\n if (type && type !== '1') {\n attrs.type = type\n }\n\n return ['ol', attrs, 0]\n },\n\n markdownTokenName: 'list',\n\n parseMarkdown: (token, helpers) => {\n if (token.type !== 'list' || !token.ordered) {\n return []\n }\n\n const startValue = token.start || 1\n const typeValue = token.typeMarker as string | undefined\n const content = token.items ? parseListItems(token.items, helpers) : []\n\n // Build attrs only when they differ from defaults\n const attrs: Record<string, unknown> = {}\n\n if (startValue !== 1) {\n attrs.start = startValue\n }\n\n if (typeValue) {\n attrs.type = typeValue\n }\n\n if (Object.keys(attrs).length > 0) {\n return {\n type: 'orderedList',\n attrs,\n content,\n }\n }\n\n return {\n type: 'orderedList',\n content,\n }\n },\n\n renderMarkdown: (node, h) => {\n if (!node.content) {\n return ''\n }\n\n return h.renderChildren(node.content, '\\n')\n },\n\n markdownTokenizer: {\n name: 'orderedList',\n level: 'block',\n start: (src: string) => {\n const match = src.match(ORDERED_LIST_LINE_START_REGEX)\n const index = match?.index\n return index !== undefined ? index : -1\n },\n tokenize: (src: string, _tokens, lexer) => {\n const lines = src.split('\\n')\n const [listItems, consumed] = collectOrderedListItems(lines)\n\n if (listItems.length === 0) {\n return undefined\n }\n\n // buildNestedStructure() only includes an item when item.indent matches\n // the base indent it's given, so the base must be this list's own\n // indentation level (that of its first collected item, e.g. 1 for a\n // line with a single leading space) rather than always 0 — a nested\n // list is not necessarily flush with the start of the line.\n const items = buildNestedStructure(listItems, listItems[0].indent, lexer)\n\n if (items.length === 0) {\n return undefined\n }\n\n const startValue = listItems[0]?.number || 1\n const typeMarker = listItems[0]?.type\n\n return {\n type: 'list',\n ordered: true,\n start: startValue,\n typeMarker,\n items,\n raw: lines.slice(0, consumed).join('\\n'),\n } as unknown as object\n },\n },\n\n markdownOptions: {\n indentsContent: true,\n },\n\n addCommands() {\n return {\n toggleOrderedList:\n () =>\n ({ commands, chain }) => {\n if (this.options.keepAttributes) {\n return chain()\n .toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n .updateAttributes(ListItemName, this.editor.getAttributes(TextStyleName))\n .run()\n }\n return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Shift-7': () => this.editor.commands.toggleOrderedList(),\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handlePaste: (view, event) => {\n const html = event.clipboardData?.getData('text/html')\n\n if (html?.trim()) {\n return false\n }\n\n const text = event.clipboardData?.getData('text/plain')\n\n if (!text) {\n return false\n }\n\n const orderedListContent = parsePlainTextOrderedListPaste(text)\n\n if (!orderedListContent) {\n return false\n }\n\n try {\n const orderedListNode = view.state.schema.nodeFromJSON(orderedListContent)\n const tr = view.state.tr.replaceSelectionWith(orderedListNode)\n\n view.dispatch(tr)\n\n return true\n } catch {\n return false\n }\n },\n },\n }),\n ]\n },\n\n addInputRules() {\n const joinPredicate = (match: RegExpMatchArray, node: ProseMirrorNode) => {\n // Only join if the existing list has a default type\n // (not a typed list like \"a\" or \"i\" which should stay separate)\n const hasDefaultType = !node.attrs.type || node.attrs.type === '1'\n\n return hasDefaultType && node.childCount + node.attrs.start === +match[1]\n }\n\n let inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n getAttributes: match => ({ start: +match[1] }),\n joinPredicate,\n })\n\n if (this.options.keepMarks || this.options.keepAttributes) {\n inputRule = wrappingInputRule({\n find: orderedListInputRegex,\n type: this.type,\n keepMarks: this.options.keepMarks,\n keepAttributes: this.options.keepAttributes,\n getAttributes: match => ({ start: +match[1], ...this.editor.getAttributes(TextStyleName) }),\n joinPredicate,\n editor: this.editor,\n })\n }\n return [inputRule]\n },\n})\n","const ROMAN_NUMERALS: [number, string][] = [\n [1000, 'm'],\n [900, 'cm'],\n [500, 'd'],\n [400, 'cd'],\n [100, 'c'],\n [90, 'xc'],\n [50, 'l'],\n [40, 'xl'],\n [10, 'x'],\n [9, 'ix'],\n [5, 'v'],\n [4, 'iv'],\n [1, 'i'],\n]\n\nconst ALPHA_NUMERALS = 'abcdefghijklmnopqrstuvwxyz'\n\n/** Alpha list markers support at most 2 letters (a–z, aa–zz), matching {@link fromAlpha}. */\nexport const ORDERED_LIST_ALPHA_MARKER_PATTERN = '[a-zA-Z]{1,2}'\n\n/**\n * Marker segment for ordered list lines: numeric, roman, or 1–2 letter alpha.\n * Roman is matched before alpha so \"iii\" is roman; invalid romans like \"aa\" fall through to alpha.\n */\nexport const ORDERED_LIST_MARKER_PATTERN = String.raw`\\d+|[ivxlcdmIVXLCDM]+|${ORDERED_LIST_ALPHA_MARKER_PATTERN}`\n\n/**\n * Convert a number to lowercase roman numerals.\n * @example toRoman(1) // 'i'\n * @example toRoman(4) // 'iv'\n */\nexport function toRoman(num: number): string {\n let remaining = num\n let result = ''\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n while (remaining >= value) {\n result += numeral\n remaining -= value\n }\n }\n\n return result\n}\n\n/**\n * Convert a number to uppercase roman numerals.\n * @example toRomanUpper(1) // 'I'\n * @example toRomanUpper(4) // 'IV'\n */\nexport function toRomanUpper(num: number): string {\n return toRoman(num).toUpperCase()\n}\n\nfunction fromRoman(roman: string): number {\n const lower = roman.toLowerCase()\n let index = 0\n let result = 0\n\n while (index < lower.length) {\n let matched = false\n\n for (const [value, numeral] of ROMAN_NUMERALS) {\n if (lower.startsWith(numeral, index)) {\n result += value\n index += numeral.length\n matched = true\n break\n }\n }\n\n if (!matched) {\n return 0\n }\n }\n\n return result\n}\n\nfunction isValidRoman(marker: string): boolean {\n if (!/^[ivxlcdmIVXLCDM]+$/.test(marker)) {\n return false\n }\n\n const value = fromRoman(marker)\n\n if (value <= 0) {\n return false\n }\n\n const expected = marker === marker.toLowerCase() ? toRoman(value) : toRomanUpper(value)\n\n return expected === marker\n}\n\nfunction fromAlpha(marker: string): number {\n const lower = marker.toLowerCase()\n\n if (lower.length === 1) {\n return lower.charCodeAt(0) - 'a'.charCodeAt(0) + 1\n }\n\n if (lower.length === 2) {\n const first = lower.charCodeAt(0) - 'a'.charCodeAt(0)\n const second = lower.charCodeAt(1) - 'a'.charCodeAt(0)\n\n return (first + 1) * 26 + second + 1\n }\n\n return 0\n}\n\nfunction toRomanAlpha(num: number): string {\n if (num <= 26) {\n return ALPHA_NUMERALS[num - 1]\n }\n\n const first = Math.floor((num - 1) / 26) - 1\n const second = (num - 1) % 26\n\n if (first < 0) {\n return ALPHA_NUMERALS[second]\n }\n\n return ALPHA_NUMERALS[first] + ALPHA_NUMERALS[second]\n}\n\n/**\n * Extract the list marker type from a marker string.\n * Supports \"1\", \"a\", \"A\", \"i\", \"I\" marker styles.\n *\n * @param marker The text content of the list marker (e.g. \"a\", \"1\", \"iii\", \"b\")\n * @returns The normalized type string, or undefined for default numeric type\n */\nexport function detectMarkerType(marker: string): string | undefined {\n if (!marker || /^\\d+$/.test(marker)) {\n return undefined\n }\n\n if (isValidRoman(marker)) {\n return marker === marker.toLowerCase() ? 'i' : 'I'\n }\n\n if (/^[a-z]{1,2}$/.test(marker)) {\n return 'a'\n }\n\n if (/^[A-Z]{1,2}$/.test(marker)) {\n return 'A'\n }\n\n return undefined\n}\n\n/**\n * Convert a list marker string to its numeric start position.\n *\n * @param marker The text content of the list marker (e.g. \"3\", \"b\", \"II\")\n * @returns The 1-based start value for the ordered list\n */\nexport function markerToStart(marker: string): number {\n if (/^\\d+$/.test(marker)) {\n return parseInt(marker, 10)\n }\n\n const type = detectMarkerType(marker)\n\n if (type === 'i' || type === 'I') {\n return fromRoman(marker)\n }\n\n if (type === 'a' || type === 'A') {\n const start = fromAlpha(marker)\n\n return start > 0 ? start : 1\n }\n\n const parsed = parseInt(marker, 10)\n\n return Number.isNaN(parsed) ? 1 : parsed\n}\n\nfunction startToMarker(type: string, start: number): string {\n if (type === 'numeric') {\n return String(start)\n }\n\n switch (type) {\n case 'a':\n return toRomanAlpha(start)\n case 'A':\n return toRomanAlpha(start).toUpperCase()\n case 'i':\n return toRoman(start)\n case 'I':\n return toRomanUpper(start)\n default:\n return String(start)\n }\n}\n\n/**\n * Returns true when all markers share the same style and increment by 1.\n * Style is inferred from the first marker so ambiguous letters (e.g. \"c\", \"i\")\n * are not re-classified differently on later lines.\n */\nexport function areOrderedListMarkersSequential(markers: string[]): boolean {\n if (markers.length === 0) {\n return false\n }\n\n const firstType = detectMarkerType(markers[0]) ?? 'numeric'\n const firstStart = markerToStart(markers[0])\n\n if (firstStart < 1) {\n return false\n }\n\n for (let i = 0; i < markers.length; i++) {\n const expected = startToMarker(firstType, firstStart + i)\n\n if (markers[i] !== expected) {\n return false\n }\n }\n\n return true\n}\n\nexport interface ParsedListMarker {\n type?: string\n start: number\n}\n\n/**\n * Parse a list marker into HTML ordered-list attrs (type + start).\n */\nexport function parseListMarker(marker: string): ParsedListMarker {\n return {\n type: detectMarkerType(marker),\n start: markerToStart(marker),\n }\n}\n\n/**\n * Build orderedList node attrs from the first list item marker.\n */\nexport function buildOrderedListAttrsFromMarker(marker: string): Record<string, string | number> {\n const { type, start } = parseListMarker(marker)\n const attrs: Record<string, string | number> = {}\n\n if (type) {\n attrs.type = type\n }\n\n if (start !== 1) {\n attrs.start = start\n }\n\n return attrs\n}\n\n/**\n * Returns the list marker prefix for a given item at a given index.\n *\n * @param type The list type attribute (e.g. \"a\", \"A\", \"i\", \"I\", null/undefined for default)\n * @param index The zero-based index of the list item\n * @param separator The separator to use (default: \". \")\n * @returns The marker string (e.g. \"a. \", \"I. \", \"1. \")\n */\nexport function getListMarker(\n type: string | null | undefined,\n index: number,\n separator = '. ',\n): string {\n const position = index + 1\n\n if (!type || type === '1') {\n return `${position}${separator}`\n }\n\n switch (type) {\n case 'a':\n return `${toRomanAlpha(position)}${separator}`\n case 'A':\n return `${toRomanAlpha(position).toUpperCase()}${separator}`\n case 'i':\n return `${toRoman(position)}${separator}`\n case 'I':\n return `${toRomanUpper(position)}${separator}`\n default:\n return `${position}${separator}`\n }\n}\n","import type {\n JSONContent,\n MarkdownLexerConfiguration,\n MarkdownParseHelpers,\n MarkdownToken,\n} from '@tiptap/core'\n\nimport {\n areOrderedListMarkersSequential,\n buildOrderedListAttrsFromMarker,\n detectMarkerType,\n markerToStart,\n ORDERED_LIST_MARKER_PATTERN,\n} from './roman.js'\n\nexport { ORDERED_LIST_MARKER_PATTERN }\n\n/**\n * Matches an ordered list item line with optional leading whitespace.\n * Captures: (1) indentation spaces, (2) item marker (number, letter, or roman numeral),\n * (3) separator (. or )), (4) content after marker\n *\n * Examples: \"1. Item\", \" a) Nested item\", \" I. Roman item\", \"iii. Another\", \"aa. Item 27\"\n */\nexport const ORDERED_LIST_ITEM_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.*)$`,\n)\n\n/**\n * Matches the start of an ordered list line (used by markdown tokenizer).\n */\nexport const ORDERED_LIST_LINE_START_REGEX = new RegExp(\n `^(\\\\s*)(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+`,\n)\n\n/**\n * Matches any line that starts with whitespace (indented content).\n * Used to identify continuation content that belongs to a list item.\n */\nconst INDENTED_LINE_REGEX = /^\\s/\n\n/**\n * This are blocks that can interrupt a paragraph, so a line starting with one of\n * them can never be lazy continuation text of a list item\n */\nconst PARAGRAPH_INTERRUPTERS = {\n heading: /^#{1,6}(?:\\s|$)/,\n bulletItem: /^[-+*]\\s+/,\n codeFence: /^(?:```|~~~)/,\n thematicBreak: /^(?:(?:-[ \\t]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})$/,\n}\n\n/**\n * Represents a parsed ordered list item with indentation information\n */\nexport interface OrderedListItem {\n indent: number\n number: number\n type?: string\n content: string\n contentLines: string[]\n raw: string\n}\n\nfunction isOrderedListMarkerLine(line: string): boolean {\n return ORDERED_LIST_ITEM_REGEX.test(line.trimStart())\n}\n\nfunction isBlockContentLine(line: string): boolean {\n const trimmedLine = line.trimStart()\n\n return (\n PARAGRAPH_INTERRUPTERS.bulletItem.test(trimmedLine) ||\n isOrderedListMarkerLine(trimmedLine) ||\n PARAGRAPH_INTERRUPTERS.heading.test(trimmedLine) ||\n // dash breaks are excluded: \"---\" directly below paragraph text is a\n // setext heading underline, not a thematic break\n (PARAGRAPH_INTERRUPTERS.thematicBreak.test(trimmedLine) && !trimmedLine.startsWith('-')) ||\n // oxlint-disable-next-line prefer-string-starts-ends-with\n /^>\\s?/.test(trimmedLine) ||\n PARAGRAPH_INTERRUPTERS.codeFence.test(trimmedLine)\n )\n}\n\nfunction interruptsLazyContinuation(line: string): boolean {\n return Object.values(PARAGRAPH_INTERRUPTERS).some(pattern => pattern.test(line))\n}\n\nfunction splitItemContent(contentLines: string[]): {\n paragraphLines: string[]\n blockLines: string[]\n} {\n const paragraphLines: string[] = []\n const blockLines: string[] = []\n let reachedBlockBoundary = false\n\n contentLines.forEach(line => {\n if (reachedBlockBoundary) {\n blockLines.push(line)\n return\n }\n\n if (line.trim() === '') {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n if (paragraphLines.length > 0 && isBlockContentLine(line)) {\n reachedBlockBoundary = true\n blockLines.push(line)\n return\n }\n\n paragraphLines.push(line)\n })\n\n return {\n paragraphLines,\n blockLines,\n }\n}\n\n/**\n * Collects all ordered list items from lines, parsing them into a flat array\n * with indentation information. Stops collecting continuation content when\n * encountering nested list items, allowing them to be processed separately.\n *\n * @param lines - Array of source lines to parse\n * @returns Tuple of [listItems array, number of lines consumed]\n */\nexport function collectOrderedListItems(lines: string[]): [OrderedListItem[], number] {\n const listItems: OrderedListItem[] = []\n let currentLineIndex = 0\n let consumed = 0\n\n while (currentLineIndex < lines.length) {\n const line = lines[currentLineIndex]\n const match = line.match(ORDERED_LIST_ITEM_REGEX)\n\n if (!match) {\n break\n }\n\n const [, indent, marker, _separator, content] = match\n const indentLevel = indent.length\n const number = parseInt(marker, 10)\n\n const markerType = isNaN(number) ? detectMarkerType(marker) : undefined\n const itemNumber = isNaN(number) ? markerToStart(marker) : number\n\n const itemContentLines = [content]\n let nextLineIndex = currentLineIndex + 1\n const itemLines = [line]\n let sawBlankLine = false\n\n // Collect continuation lines for this item (but NOT nested list items)\n while (nextLineIndex < lines.length) {\n const nextLine = lines[nextLineIndex]\n const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX)\n\n // If it's another list item (nested or not), stop collecting\n if (nextMatch) {\n break\n }\n\n // Check for continuation content (non-list content)\n if (nextLine.trim() === '') {\n // Empty line\n itemLines.push(nextLine)\n itemContentLines.push('')\n sawBlankLine = true\n nextLineIndex += 1\n } else if (nextLine.match(INDENTED_LINE_REGEX)) {\n // Indented content - part of this item (but not a list item).\n // Strip the indentation only up to the whitespace that is actually present,\n // so an under-indented line (e.g. a single leading space) keeps its first character.\n const leadingWhitespace = nextLine.length - nextLine.trimStart().length\n const contentIndent = indentLevel + marker.length + 1\n itemLines.push(nextLine)\n itemContentLines.push(nextLine.slice(Math.min(leadingWhitespace, contentIndent)))\n nextLineIndex += 1\n } else {\n if (sawBlankLine || interruptsLazyContinuation(nextLine)) {\n break\n }\n\n itemLines.push(nextLine)\n itemContentLines.push(nextLine)\n nextLineIndex += 1\n }\n }\n\n listItems.push({\n indent: indentLevel,\n number: itemNumber,\n type: markerType,\n content: itemContentLines.join('\\n').trim(),\n contentLines: itemContentLines,\n raw: itemLines.join('\\n'),\n })\n\n consumed = nextLineIndex\n currentLineIndex = nextLineIndex\n }\n\n return [listItems, consumed]\n}\n\nconst PLAIN_TEXT_ORDERED_LIST_LINE_REGEX = new RegExp(\n `^(${ORDERED_LIST_MARKER_PATTERN})([.)])\\\\s+(.+)$`,\n)\n\n/**\n * Parse plain-text pasted ordered list lines into JSONContent, or null if not a typed list.\n */\nexport function parsePlainTextOrderedListPaste(text: string): JSONContent | null {\n const lines = text.split('\\n').filter(l => l.trim().length > 0)\n\n if (lines.length === 0) {\n return null\n }\n\n const parsedItems: Array<{ marker: string; content: string }> = []\n\n for (const line of lines) {\n const match = line.trim().match(PLAIN_TEXT_ORDERED_LIST_LINE_REGEX)\n\n if (!match) {\n return null\n }\n\n parsedItems.push({\n marker: match[1],\n content: match[3],\n })\n }\n\n const markers = parsedItems.map(item => item.marker)\n\n if (!areOrderedListMarkersSequential(markers)) {\n return null\n }\n\n const attrs = buildOrderedListAttrsFromMarker(parsedItems[0].marker)\n\n return {\n type: 'orderedList',\n attrs,\n content: parsedItems.map(item => ({\n type: 'listItem',\n content: [\n {\n type: 'paragraph',\n content: [{ type: 'text', text: item.content }],\n },\n ],\n })),\n }\n}\n\n/**\n * Recursively builds a nested structure from a flat array of list items\n * based on their indentation levels. Creates proper markdown tokens with\n * nested lists where appropriate.\n *\n * @param items - Flat array of list items with indentation info\n * @param baseIndent - The indentation level to process at this recursion level\n * @param lexer - Markdown lexer for parsing inline and block content\n * @returns Array of list_item tokens with proper nesting\n */\nexport function buildNestedStructure(\n items: OrderedListItem[],\n baseIndent: number,\n lexer: MarkdownLexerConfiguration,\n): unknown[] {\n const result: unknown[] = []\n let currentIndex = 0\n\n while (currentIndex < items.length) {\n const item = items[currentIndex]\n\n if (item.indent === baseIndent) {\n // This item belongs at the current level\n const { paragraphLines, blockLines } = splitItemContent(item.contentLines)\n const mainText = paragraphLines.join('\\n').trim()\n\n const tokens = []\n\n // Always wrap the main text in a paragraph token\n if (mainText) {\n tokens.push({\n type: 'paragraph',\n raw: mainText,\n tokens: lexer.inlineTokens(mainText),\n })\n }\n\n const additionalContent = blockLines.join('\\n').trim()\n if (additionalContent) {\n const blockTokens = lexer.blockTokens(additionalContent)\n tokens.push(...blockTokens)\n }\n\n // Look ahead to find nested items at deeper indent levels\n let lookAheadIndex = currentIndex + 1\n const nestedItems = []\n\n while (lookAheadIndex < items.length && items[lookAheadIndex].indent > baseIndent) {\n nestedItems.push(items[lookAheadIndex])\n lookAheadIndex += 1\n }\n\n // If we have nested items, recursively build their structure\n if (nestedItems.length > 0) {\n // Find the next indent level (immediate children)\n const nextIndent = Math.min(...nestedItems.map(nestedItem => nestedItem.indent))\n\n // Build the nested list recursively with all nested items\n // The recursive call will handle further nesting\n const nestedListItems = buildNestedStructure(nestedItems, nextIndent, lexer)\n\n // Create a nested list token\n tokens.push({\n type: 'list',\n ordered: true,\n start: nestedItems[0].number,\n typeMarker: nestedItems[0].type,\n items: nestedListItems,\n raw: nestedItems.map(nestedItem => nestedItem.raw).join('\\n'),\n })\n }\n\n result.push({\n type: 'list_item',\n raw: item.raw,\n tokens,\n })\n\n // Skip the nested items we just processed\n currentIndex = lookAheadIndex\n } else {\n // This item has deeper indent than we're currently processing\n // It should be handled by a recursive call\n currentIndex += 1\n }\n }\n\n return result\n}\n\n/**\n * Parses markdown list item tokens into Tiptap JSONContent structure,\n * ensuring text content is properly wrapped in paragraph nodes.\n *\n * @param items - Array of markdown tokens representing list items\n * @param helpers - Markdown parse helpers for recursive parsing\n * @returns Array of listItem JSONContent nodes\n */\nexport function parseListItems(\n items: MarkdownToken[],\n helpers: MarkdownParseHelpers,\n): JSONContent[] {\n return items.map(item => {\n if (item.type !== 'list_item') {\n return helpers.parseChildren([item])[0]\n }\n\n // Parse the tokens within the list item\n const content: JSONContent[] = []\n\n if (item.tokens && item.tokens.length > 0) {\n item.tokens.forEach(itemToken => {\n // If it's already a proper block node (paragraph, list, etc.), parse it directly\n if (\n itemToken.type === 'paragraph' ||\n itemToken.type === 'list' ||\n itemToken.type === 'blockquote' ||\n itemToken.type === 'code'\n ) {\n content.push(...helpers.parseChildren([itemToken]))\n } else if (itemToken.type === 'text' && itemToken.tokens) {\n // If it's inline text tokens, wrap them in a paragraph\n const inlineContent = helpers.parseChildren([itemToken])\n content.push({\n type: 'paragraph',\n content: inlineContent,\n })\n } else {\n // For any other content, try to parse it\n const parsed = helpers.parseChildren([itemToken])\n if (parsed.length > 0) {\n content.push(...parsed)\n }\n }\n })\n }\n\n return {\n type: 'listItem',\n content,\n }\n })\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@tiptap/extension-list",
3
- "version": "3.27.1",
3
+ "version": "3.27.3",
4
4
  "description": "List extension for tiptap",
5
5
  "keywords": [
6
6
  "tiptap",
7
7
  "tiptap extension"
8
8
  ],
9
9
  "homepage": "https://tiptap.dev",
10
+ "bugs": {
11
+ "url": "https://github.com/ueberdosis/tiptap/issues"
12
+ },
10
13
  "license": "MIT",
11
14
  "repository": {
12
15
  "type": "git",
13
16
  "url": "https://github.com/ueberdosis/tiptap",
14
17
  "directory": "packages/extension-list"
15
18
  },
16
- "bugs": {
17
- "url": "https://github.com/ueberdosis/tiptap/issues"
18
- },
19
19
  "funding": {
20
20
  "type": "github",
21
21
  "url": "https://github.com/sponsors/ueberdosis"
@@ -95,12 +95,12 @@
95
95
  }
96
96
  },
97
97
  "devDependencies": {
98
- "@tiptap/core": "^3.27.1",
99
- "@tiptap/pm": "^3.27.1"
98
+ "@tiptap/core": "^3.27.3",
99
+ "@tiptap/pm": "^3.27.3"
100
100
  },
101
101
  "peerDependencies": {
102
- "@tiptap/core": "3.27.1",
103
- "@tiptap/pm": "3.27.1"
102
+ "@tiptap/core": "3.27.3",
103
+ "@tiptap/pm": "3.27.3"
104
104
  },
105
105
  "scripts": {
106
106
  "build": "tsup"
@@ -243,7 +243,12 @@ export const OrderedList = Node.create<OrderedListOptions>({
243
243
  return undefined
244
244
  }
245
245
 
246
- const items = buildNestedStructure(listItems, 0, lexer)
246
+ // buildNestedStructure() only includes an item when item.indent matches
247
+ // the base indent it's given, so the base must be this list's own
248
+ // indentation level (that of its first collected item, e.g. 1 for a
249
+ // line with a single leading space) rather than always 0 — a nested
250
+ // list is not necessarily flush with the start of the line.
251
+ const items = buildNestedStructure(listItems, listItems[0].indent, lexer)
247
252
 
248
253
  if (items.length === 0) {
249
254
  return undefined