UNPKG

unist-util-select

Version:

unist utility to select nodes with CSS-like selectors

110 lines (103 loc) 2.95 kB
/** * @typedef {import('unist').Position} Position * @typedef {import('unist').Node} Node * @typedef {import('./lib/types.js').SelectState} SelectState */ /** * @typedef {Record<string, unknown> & {type: string, position?: Position | undefined}} NodeLike */ import {parse} from './lib/parse.js' import {parent} from './lib/util.js' import {walk} from './lib/walk.js' /** * Check that the given `node` matches `selector`. * * This only checks the node itself, not the surrounding tree. * Thus, nesting in selectors is not supported (`paragraph strong`, * `paragraph > strong`), neither are selectors like `:first-child`, etc. * This only checks that the given node matches the selector. * * @param {string} selector * CSS selector, such as (`heading`, `link, linkReference`). * @param {Node | NodeLike | null | undefined} [node] * Node that might match `selector`. * @returns {boolean} * Whether `node` matches `selector`. */ export function matches(selector, node) { const state = createState(selector, node) state.one = true state.shallow = true walk(state, node || undefined) return state.results.length > 0 } /** * Select the first node that matches `selector` in the given `tree`. * * Searches the tree in *preorder*. * * @param {string} selector * CSS selector, such as (`heading`, `link, linkReference`). * @param {Node | NodeLike | null | undefined} [tree] * Tree to search. * @returns {Node | undefined} * First node in `tree` that matches `selector` or `null` if nothing is * found. * * This could be `tree` itself. */ export function select(selector, tree) { const state = createState(selector, tree) state.one = true walk(state, tree || undefined) return state.results[0] } /** * Select all nodes that match `selector` in the given `tree`. * * Searches the tree in *preorder*. * * @param {string} selector * CSS selector, such as (`heading`, `link, linkReference`). * @param {Node | NodeLike | null | undefined} [tree] * Tree to search. * @returns {Array<Node>} * Nodes in `tree` that match `selector`. * * This could include `tree` itself. */ export function selectAll(selector, tree) { const state = createState(selector, tree) walk(state, tree || undefined) return state.results } /** * @param {string} selector * Selector to parse. * @param {Node | null | undefined} tree * Tree to search. * @returns {SelectState} * State. */ function createState(selector, tree) { return { // State of the query. rootQuery: parse(selector), results: [], scopeNodes: tree ? parent(tree) && // Root in nlcst. (tree.type === 'RootNode' || tree.type === 'root') ? tree.children : [tree] : [], one: false, shallow: false, found: false, // State in the tree. typeIndex: undefined, nodeIndex: undefined, typeCount: undefined, nodeCount: undefined } }