Files
website/node_modules/hast-util-select/lib/index.js
2024-05-06 17:15:30 -04:00

150 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @typedef {import('css-selector-parser').AstSelector} AstSelector
*
* @typedef {import('hast').Element} Element
* @typedef {import('hast').Nodes} Nodes
* @typedef {import('hast').RootContent} RootContent
*
* @typedef {import('property-information').Schema} Schema
*/
/**
* @typedef {'html' | 'svg'} Space
* Name of namespace.
*
* @typedef {'auto' | 'ltr' | 'rtl'} Direction
* Direction.
*
* @typedef State
* Current state.
* @property {Direction} direction
* Current direction.
* @property {boolean} editableOrEditingHost
* Whether were in `contentEditable`.
* @property {number | undefined} elementCount
* Track siblings: there are `n` siblings.
* @property {number | undefined} elementIndex
* Track siblings: this current element has `n` elements before it.
* @property {boolean} found
* Whether we found at least one match.
* @property {string | undefined} language
* Current language.
* @property {boolean} one
* Whether we can stop looking after we found one element.
* @property {Array<Element>} results
* Matches.
* @property {AstSelector} rootQuery
* Original root selectors.
* @property {Schema} schema
* Current schema.
* @property {Array<RootContent>} scopeElements
* Elements in scope.
* @property {boolean} shallow
* Whether we only allow selectors without nesting.
* @property {number | undefined} typeCount
* Track siblings: there are `n` siblings with this elements tag name.
* @property {number | undefined} typeIndex
* Track siblings: this current element has `n` elements with its tag name
* before it.
*/
import {html, svg} from 'property-information'
import {parse} from './parse.js'
import {walk} from './walk.js'
/**
* Check that the given `node` matches `selector`.
*
* This only checks the element itself, not the surrounding tree.
* Thus, nesting in selectors is not supported (`p b`, `p > b`), neither are
* selectors like `:first-child`, etc.
* This only checks that the given element matches the selector.
*
* @param {string} selector
* CSS selector, such as (`h1`, `a, b`).
* @param {Nodes | null | undefined} [node]
* Node that might match `selector`, should be an element (optional).
* @param {Space | null | undefined} [space='html']
* Name of namespace (default: `'html'`).
* @returns {boolean}
* Whether `node` matches `selector`.
*/
export function matches(selector, node, space) {
const state = createState(selector, node, space)
state.one = true
state.shallow = true
walk(state, node || undefined)
return state.results.length > 0
}
/**
* Select the first element that matches `selector` in the given `tree`.
* Searches the tree in *preorder*.
*
* @param {string} selector
* CSS selector, such as (`h1`, `a, b`).
* @param {Nodes | null | undefined} [tree]
* Tree to search (optional).
* @param {Space | null | undefined} [space='html']
* Name of namespace (default: `'html'`).
* @returns {Element | undefined}
* First element in `tree` that matches `selector` or `undefined` if nothing
* is found; this could be `tree` itself.
*/
export function select(selector, tree, space) {
const state = createState(selector, tree, space)
state.one = true
walk(state, tree || undefined)
return state.results[0]
}
/**
* Select all elements that match `selector` in the given `tree`.
* Searches the tree in *preorder*.
*
* @param {string} selector
* CSS selector, such as (`h1`, `a, b`).
* @param {Nodes | null | undefined} [tree]
* Tree to search (optional).
* @param {Space | null | undefined} [space='html']
* Name of namespace (default: `'html'`).
* @returns {Array<Element>}
* Elements in `tree` that match `selector`.
* This could include `tree` itself.
*/
export function selectAll(selector, tree, space) {
const state = createState(selector, tree, space)
walk(state, tree || undefined)
return state.results
}
/**
* @param {string} selector
* CSS selector, such as (`h1`, `a, b`).
* @param {Nodes | null | undefined} [tree]
* Tree to search (optional).
* @param {Space | null | undefined} [space='html']
* Name of namespace (default: `'html'`).
* @returns {State} State
* State.
*/
function createState(selector, tree, space) {
return {
direction: 'ltr',
editableOrEditingHost: false,
elementCount: undefined,
elementIndex: undefined,
found: false,
language: undefined,
one: false,
// State of the query.
results: [],
rootQuery: parse(selector),
schema: space === 'svg' ? svg : html,
scopeElements: tree ? (tree.type === 'root' ? tree.children : [tree]) : [],
shallow: false,
typeIndex: undefined,
typeCount: undefined
}
}