103 lines
3 KiB
JavaScript
103 lines
3 KiB
JavaScript
|
/**
|
|||
|
* @typedef {import('mdast').List} List
|
|||
|
* @typedef {import('mdast').Parents} Parents
|
|||
|
* @typedef {import('../types.js').Info} Info
|
|||
|
* @typedef {import('../types.js').State} State
|
|||
|
*/
|
|||
|
|
|||
|
import {checkBullet} from '../util/check-bullet.js'
|
|||
|
import {checkBulletOther} from '../util/check-bullet-other.js'
|
|||
|
import {checkBulletOrdered} from '../util/check-bullet-ordered.js'
|
|||
|
import {checkRule} from '../util/check-rule.js'
|
|||
|
|
|||
|
/**
|
|||
|
* @param {List} node
|
|||
|
* @param {Parents | undefined} parent
|
|||
|
* @param {State} state
|
|||
|
* @param {Info} info
|
|||
|
* @returns {string}
|
|||
|
*/
|
|||
|
export function list(node, parent, state, info) {
|
|||
|
const exit = state.enter('list')
|
|||
|
const bulletCurrent = state.bulletCurrent
|
|||
|
/** @type {string} */
|
|||
|
let bullet = node.ordered ? checkBulletOrdered(state) : checkBullet(state)
|
|||
|
/** @type {string} */
|
|||
|
const bulletOther = node.ordered
|
|||
|
? bullet === '.'
|
|||
|
? ')'
|
|||
|
: '.'
|
|||
|
: checkBulletOther(state)
|
|||
|
let useDifferentMarker =
|
|||
|
parent && state.bulletLastUsed ? bullet === state.bulletLastUsed : false
|
|||
|
|
|||
|
if (!node.ordered) {
|
|||
|
const firstListItem = node.children ? node.children[0] : undefined
|
|||
|
|
|||
|
// If there’s an empty first list item directly in two list items,
|
|||
|
// we have to use a different bullet:
|
|||
|
//
|
|||
|
// ```markdown
|
|||
|
// * - *
|
|||
|
// ```
|
|||
|
//
|
|||
|
// …because otherwise it would become one big thematic break.
|
|||
|
if (
|
|||
|
// Bullet could be used as a thematic break marker:
|
|||
|
(bullet === '*' || bullet === '-') &&
|
|||
|
// Empty first list item:
|
|||
|
firstListItem &&
|
|||
|
(!firstListItem.children || !firstListItem.children[0]) &&
|
|||
|
// Directly in two other list items:
|
|||
|
state.stack[state.stack.length - 1] === 'list' &&
|
|||
|
state.stack[state.stack.length - 2] === 'listItem' &&
|
|||
|
state.stack[state.stack.length - 3] === 'list' &&
|
|||
|
state.stack[state.stack.length - 4] === 'listItem' &&
|
|||
|
// That are each the first child.
|
|||
|
state.indexStack[state.indexStack.length - 1] === 0 &&
|
|||
|
state.indexStack[state.indexStack.length - 2] === 0 &&
|
|||
|
state.indexStack[state.indexStack.length - 3] === 0
|
|||
|
) {
|
|||
|
useDifferentMarker = true
|
|||
|
}
|
|||
|
|
|||
|
// If there’s a thematic break at the start of the first list item,
|
|||
|
// we have to use a different bullet:
|
|||
|
//
|
|||
|
// ```markdown
|
|||
|
// * ---
|
|||
|
// ```
|
|||
|
//
|
|||
|
// …because otherwise it would become one big thematic break.
|
|||
|
if (checkRule(state) === bullet && firstListItem) {
|
|||
|
let index = -1
|
|||
|
|
|||
|
while (++index < node.children.length) {
|
|||
|
const item = node.children[index]
|
|||
|
|
|||
|
if (
|
|||
|
item &&
|
|||
|
item.type === 'listItem' &&
|
|||
|
item.children &&
|
|||
|
item.children[0] &&
|
|||
|
item.children[0].type === 'thematicBreak'
|
|||
|
) {
|
|||
|
useDifferentMarker = true
|
|||
|
break
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (useDifferentMarker) {
|
|||
|
bullet = bulletOther
|
|||
|
}
|
|||
|
|
|||
|
state.bulletCurrent = bullet
|
|||
|
const value = state.containerFlow(node, info)
|
|||
|
state.bulletLastUsed = bullet
|
|||
|
state.bulletCurrent = bulletCurrent
|
|||
|
exit()
|
|||
|
return value
|
|||
|
}
|