site/node_modules/hast-util-to-html/lib/omission/closing.js

360 lines
8.6 KiB
JavaScript
Raw Normal View History

2024-10-14 06:09:33 +00:00
/**
* @typedef {import('hast').Element} Element
* @typedef {import('hast').Parents} Parents
*/
import {whitespace} from 'hast-util-whitespace'
import {siblingAfter} from './util/siblings.js'
import {omission} from './omission.js'
export const closing = omission({
body,
caption: headOrColgroupOrCaption,
colgroup: headOrColgroupOrCaption,
dd,
dt,
head: headOrColgroupOrCaption,
html,
li,
optgroup,
option,
p,
rp: rubyElement,
rt: rubyElement,
tbody,
td: cells,
tfoot,
th: cells,
thead,
tr
})
/**
* Macro for `</head>`, `</colgroup>`, and `</caption>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function headOrColgroupOrCaption(_, index, parent) {
const next = siblingAfter(parent, index, true)
return (
!next ||
(next.type !== 'comment' &&
!(next.type === 'text' && whitespace(next.value.charAt(0))))
)
}
/**
* Whether to omit `</html>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function html(_, index, parent) {
const next = siblingAfter(parent, index)
return !next || next.type !== 'comment'
}
/**
* Whether to omit `</body>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function body(_, index, parent) {
const next = siblingAfter(parent, index)
return !next || next.type !== 'comment'
}
/**
* Whether to omit `</p>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function p(_, index, parent) {
const next = siblingAfter(parent, index)
return next
? next.type === 'element' &&
(next.tagName === 'address' ||
next.tagName === 'article' ||
next.tagName === 'aside' ||
next.tagName === 'blockquote' ||
next.tagName === 'details' ||
next.tagName === 'div' ||
next.tagName === 'dl' ||
next.tagName === 'fieldset' ||
next.tagName === 'figcaption' ||
next.tagName === 'figure' ||
next.tagName === 'footer' ||
next.tagName === 'form' ||
next.tagName === 'h1' ||
next.tagName === 'h2' ||
next.tagName === 'h3' ||
next.tagName === 'h4' ||
next.tagName === 'h5' ||
next.tagName === 'h6' ||
next.tagName === 'header' ||
next.tagName === 'hgroup' ||
next.tagName === 'hr' ||
next.tagName === 'main' ||
next.tagName === 'menu' ||
next.tagName === 'nav' ||
next.tagName === 'ol' ||
next.tagName === 'p' ||
next.tagName === 'pre' ||
next.tagName === 'section' ||
next.tagName === 'table' ||
next.tagName === 'ul')
: !parent ||
// Confusing parent.
!(
parent.type === 'element' &&
(parent.tagName === 'a' ||
parent.tagName === 'audio' ||
parent.tagName === 'del' ||
parent.tagName === 'ins' ||
parent.tagName === 'map' ||
parent.tagName === 'noscript' ||
parent.tagName === 'video')
)
}
/**
* Whether to omit `</li>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function li(_, index, parent) {
const next = siblingAfter(parent, index)
return !next || (next.type === 'element' && next.tagName === 'li')
}
/**
* Whether to omit `</dt>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function dt(_, index, parent) {
const next = siblingAfter(parent, index)
return Boolean(
next &&
next.type === 'element' &&
(next.tagName === 'dt' || next.tagName === 'dd')
)
}
/**
* Whether to omit `</dd>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function dd(_, index, parent) {
const next = siblingAfter(parent, index)
return (
!next ||
(next.type === 'element' &&
(next.tagName === 'dt' || next.tagName === 'dd'))
)
}
/**
* Whether to omit `</rt>` or `</rp>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function rubyElement(_, index, parent) {
const next = siblingAfter(parent, index)
return (
!next ||
(next.type === 'element' &&
(next.tagName === 'rp' || next.tagName === 'rt'))
)
}
/**
* Whether to omit `</optgroup>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function optgroup(_, index, parent) {
const next = siblingAfter(parent, index)
return !next || (next.type === 'element' && next.tagName === 'optgroup')
}
/**
* Whether to omit `</option>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function option(_, index, parent) {
const next = siblingAfter(parent, index)
return (
!next ||
(next.type === 'element' &&
(next.tagName === 'option' || next.tagName === 'optgroup'))
)
}
/**
* Whether to omit `</thead>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function thead(_, index, parent) {
const next = siblingAfter(parent, index)
return Boolean(
next &&
next.type === 'element' &&
(next.tagName === 'tbody' || next.tagName === 'tfoot')
)
}
/**
* Whether to omit `</tbody>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function tbody(_, index, parent) {
const next = siblingAfter(parent, index)
return (
!next ||
(next.type === 'element' &&
(next.tagName === 'tbody' || next.tagName === 'tfoot'))
)
}
/**
* Whether to omit `</tfoot>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function tfoot(_, index, parent) {
return !siblingAfter(parent, index)
}
/**
* Whether to omit `</tr>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function tr(_, index, parent) {
const next = siblingAfter(parent, index)
return !next || (next.type === 'element' && next.tagName === 'tr')
}
/**
* Whether to omit `</td>` or `</th>`.
*
* @param {Element} _
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the closing tag can be omitted.
*/
function cells(_, index, parent) {
const next = siblingAfter(parent, index)
return (
!next ||
(next.type === 'element' &&
(next.tagName === 'td' || next.tagName === 'th'))
)
}