mirror of
https://github.com/sern-handler/website
synced 2026-06-28 02:32:23 +00:00
feat: migrate to starlight
This commit is contained in:
2
node_modules/hast-util-select/index.d.ts
generated
vendored
Normal file
2
node_modules/hast-util-select/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export type Space = import('./lib/index.js').Space;
|
||||
export { matches, select, selectAll } from "./lib/index.js";
|
||||
5
node_modules/hast-util-select/index.js
generated
vendored
Normal file
5
node_modules/hast-util-select/index.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @typedef {import('./lib/index.js').Space} Space
|
||||
*/
|
||||
|
||||
export {matches, select, selectAll} from './lib/index.js'
|
||||
16
node_modules/hast-util-select/lib/attribute.d.ts
generated
vendored
Normal file
16
node_modules/hast-util-select/lib/attribute.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @param {AstAttribute} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {Schema} schema
|
||||
* Schema of element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function attribute(query: AstAttribute, element: Element, schema: Schema): boolean;
|
||||
export type AstAttribute = import('css-selector-parser').AstAttribute;
|
||||
export type Element = import('hast').Element;
|
||||
export type Properties = import('hast').Properties;
|
||||
export type Info = import('property-information').Info;
|
||||
export type Schema = import('property-information').Schema;
|
||||
118
node_modules/hast-util-select/lib/attribute.js
generated
vendored
Normal file
118
node_modules/hast-util-select/lib/attribute.js
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstAttribute} AstAttribute
|
||||
*
|
||||
* @typedef {import('hast').Element} Element
|
||||
* @typedef {import('hast').Properties} Properties
|
||||
*
|
||||
* @typedef {import('property-information').Info} Info
|
||||
* @typedef {import('property-information').Schema} Schema
|
||||
*/
|
||||
|
||||
import {stringify as commas} from 'comma-separated-tokens'
|
||||
import {ok as assert} from 'devlop'
|
||||
import {find} from 'property-information'
|
||||
import * as spaces from 'space-separated-tokens'
|
||||
|
||||
/**
|
||||
* @param {AstAttribute} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {Schema} schema
|
||||
* Schema of element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function attribute(query, element, schema) {
|
||||
const info = find(schema, query.name)
|
||||
const propertyValue = element.properties[info.property]
|
||||
let value = normalizeValue(propertyValue, info)
|
||||
|
||||
// Exists.
|
||||
if (!query.value) {
|
||||
return value !== undefined
|
||||
}
|
||||
|
||||
assert(query.value.type === 'String', 'expected plain string')
|
||||
let key = query.value.value
|
||||
|
||||
// Case-sensitivity.
|
||||
if (query.caseSensitivityModifier === 'i') {
|
||||
key = key.toLowerCase()
|
||||
|
||||
if (value) {
|
||||
value = value.toLowerCase()
|
||||
}
|
||||
}
|
||||
|
||||
if (value !== undefined) {
|
||||
switch (query.operator) {
|
||||
// Exact.
|
||||
case '=': {
|
||||
return key === value
|
||||
}
|
||||
|
||||
// Ends.
|
||||
case '$=': {
|
||||
return key === value.slice(-key.length)
|
||||
}
|
||||
|
||||
// Contains.
|
||||
case '*=': {
|
||||
return value.includes(key)
|
||||
}
|
||||
|
||||
// Begins.
|
||||
case '^=': {
|
||||
return key === value.slice(0, key.length)
|
||||
}
|
||||
|
||||
// Exact or prefix.
|
||||
case '|=': {
|
||||
return (
|
||||
key === value ||
|
||||
(key === value.slice(0, key.length) &&
|
||||
value.charAt(key.length) === '-')
|
||||
)
|
||||
}
|
||||
|
||||
// Space-separated list.
|
||||
case '~=': {
|
||||
return (
|
||||
// For all other values (including comma-separated lists), return whether this
|
||||
// is an exact match.
|
||||
key === value ||
|
||||
// If this is a space-separated list, and the query is contained in it, return
|
||||
// true.
|
||||
spaces.parse(value).includes(key)
|
||||
)
|
||||
}
|
||||
// Other values are not yet supported by CSS.
|
||||
// No default
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Properties[keyof Properties]} value
|
||||
* @param {Info} info
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
function normalizeValue(value, info) {
|
||||
if (value === null || value === undefined) {
|
||||
// Empty.
|
||||
} else if (typeof value === 'boolean') {
|
||||
if (value) {
|
||||
return info.attribute
|
||||
}
|
||||
} else if (Array.isArray(value)) {
|
||||
if (value.length > 0) {
|
||||
return (info.commaSeparated ? commas : spaces.stringify)(value)
|
||||
}
|
||||
} else {
|
||||
return String(value)
|
||||
}
|
||||
}
|
||||
13
node_modules/hast-util-select/lib/class-name.d.ts
generated
vendored
Normal file
13
node_modules/hast-util-select/lib/class-name.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Check whether an element has all class names.
|
||||
*
|
||||
* @param {AstClassName} query
|
||||
* AST rule (with `classNames`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function className(query: AstClassName, element: Element): boolean;
|
||||
export type AstClassName = import('css-selector-parser').AstClassName;
|
||||
export type Element = import('hast').Element;
|
||||
26
node_modules/hast-util-select/lib/class-name.js
generated
vendored
Normal file
26
node_modules/hast-util-select/lib/class-name.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstClassName} AstClassName
|
||||
* @typedef {import('hast').Element} Element
|
||||
*/
|
||||
|
||||
/** @type {Array<never>} */
|
||||
const emptyClassNames = []
|
||||
|
||||
/**
|
||||
* Check whether an element has all class names.
|
||||
*
|
||||
* @param {AstClassName} query
|
||||
* AST rule (with `classNames`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function className(query, element) {
|
||||
// Assume array.
|
||||
const value = /** @type {Readonly<Array<string>>} */ (
|
||||
element.properties.className || emptyClassNames
|
||||
)
|
||||
|
||||
return value.includes(query.name)
|
||||
}
|
||||
20
node_modules/hast-util-select/lib/enter-state.d.ts
generated
vendored
Normal file
20
node_modules/hast-util-select/lib/enter-state.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Enter a node.
|
||||
*
|
||||
* The caller is responsible for calling the return value `exit`.
|
||||
*
|
||||
* @param {State} state
|
||||
* Current state.
|
||||
*
|
||||
* Will be mutated: `exit` undos the changes.
|
||||
* @param {Nodes} node
|
||||
* Node to enter.
|
||||
* @returns {() => undefined}
|
||||
* Call to exit.
|
||||
*/
|
||||
export function enterState(state: State, node: Nodes): () => undefined;
|
||||
export type ElementContent = import('hast').ElementContent;
|
||||
export type Nodes = import('hast').Nodes;
|
||||
export type Visitor = import('unist-util-visit').Visitor<ElementContent>;
|
||||
export type Direction = import('./index.js').Direction;
|
||||
export type State = import('./index.js').State;
|
||||
164
node_modules/hast-util-select/lib/enter-state.js
generated
vendored
Normal file
164
node_modules/hast-util-select/lib/enter-state.js
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @typedef {import('hast').ElementContent} ElementContent
|
||||
* @typedef {import('hast').Nodes} Nodes
|
||||
*
|
||||
* @typedef {import('unist-util-visit').Visitor<ElementContent>} Visitor
|
||||
*
|
||||
* @typedef {import('./index.js').Direction} Direction
|
||||
* @typedef {import('./index.js').State} State
|
||||
*/
|
||||
|
||||
import {direction} from 'direction'
|
||||
import {toString} from 'hast-util-to-string'
|
||||
import {svg} from 'property-information'
|
||||
import {EXIT, SKIP, visit} from 'unist-util-visit'
|
||||
|
||||
/**
|
||||
* Enter a node.
|
||||
*
|
||||
* The caller is responsible for calling the return value `exit`.
|
||||
*
|
||||
* @param {State} state
|
||||
* Current state.
|
||||
*
|
||||
* Will be mutated: `exit` undos the changes.
|
||||
* @param {Nodes} node
|
||||
* Node to enter.
|
||||
* @returns {() => undefined}
|
||||
* Call to exit.
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
export function enterState(state, node) {
|
||||
const schema = state.schema
|
||||
const language = state.language
|
||||
const currentDirection = state.direction
|
||||
const editableOrEditingHost = state.editableOrEditingHost
|
||||
/** @type {Direction | undefined} */
|
||||
let dirInferred
|
||||
|
||||
if (node.type === 'element') {
|
||||
const lang = node.properties.xmlLang || node.properties.lang
|
||||
const type = node.properties.type || 'text'
|
||||
const dir = dirProperty(node)
|
||||
|
||||
if (lang !== null && lang !== undefined) {
|
||||
state.language = String(lang)
|
||||
}
|
||||
|
||||
if (schema && schema.space === 'html') {
|
||||
if (node.properties.contentEditable === 'true') {
|
||||
state.editableOrEditingHost = true
|
||||
}
|
||||
|
||||
if (node.tagName === 'svg') {
|
||||
state.schema = svg
|
||||
}
|
||||
|
||||
// See: <https://html.spec.whatwg.org/#the-directionality>.
|
||||
// Explicit `[dir=rtl]`.
|
||||
if (dir === 'rtl') {
|
||||
dirInferred = dir
|
||||
} else if (
|
||||
// Explicit `[dir=ltr]`.
|
||||
dir === 'ltr' ||
|
||||
// HTML with an invalid or no `[dir]`.
|
||||
(dir !== 'auto' && node.tagName === 'html') ||
|
||||
// `input[type=tel]` with an invalid or no `[dir]`.
|
||||
(dir !== 'auto' && node.tagName === 'input' && type === 'tel')
|
||||
) {
|
||||
dirInferred = 'ltr'
|
||||
// `[dir=auto]` or `bdi` with an invalid or no `[dir]`.
|
||||
} else if (dir === 'auto' || node.tagName === 'bdi') {
|
||||
if (node.tagName === 'textarea') {
|
||||
// Check contents of `<textarea>`.
|
||||
dirInferred = dirBidi(toString(node))
|
||||
} else if (
|
||||
node.tagName === 'input' &&
|
||||
(type === 'email' ||
|
||||
type === 'search' ||
|
||||
type === 'tel' ||
|
||||
type === 'text')
|
||||
) {
|
||||
// Check value of `<input>`.
|
||||
dirInferred = node.properties.value
|
||||
? dirBidi(String(node.properties.value))
|
||||
: 'ltr'
|
||||
} else {
|
||||
// Check text nodes in `node`.
|
||||
visit(node, inferDirectionality)
|
||||
}
|
||||
}
|
||||
|
||||
if (dirInferred) {
|
||||
state.direction = dirInferred
|
||||
}
|
||||
}
|
||||
// Turn off editing mode in non-HTML spaces.
|
||||
else if (state.editableOrEditingHost) {
|
||||
state.editableOrEditingHost = false
|
||||
}
|
||||
}
|
||||
|
||||
return reset
|
||||
|
||||
/**
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
function reset() {
|
||||
state.schema = schema
|
||||
state.language = language
|
||||
state.direction = currentDirection
|
||||
state.editableOrEditingHost = editableOrEditingHost
|
||||
}
|
||||
|
||||
/** @type {Visitor} */
|
||||
function inferDirectionality(child) {
|
||||
if (child.type === 'text') {
|
||||
dirInferred = dirBidi(child.value)
|
||||
return dirInferred ? EXIT : undefined
|
||||
}
|
||||
|
||||
if (
|
||||
child !== node &&
|
||||
child.type === 'element' &&
|
||||
(child.tagName === 'bdi' ||
|
||||
child.tagName === 'script' ||
|
||||
child.tagName === 'style' ||
|
||||
child.tagName === 'textare' ||
|
||||
dirProperty(child))
|
||||
) {
|
||||
return SKIP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See `wooorm/direction`.
|
||||
*
|
||||
* @param {string} value
|
||||
* Value to check.
|
||||
* @returns {Exclude<Direction, 'auto'> | undefined}
|
||||
* Directionality.
|
||||
*/
|
||||
function dirBidi(value) {
|
||||
const result = direction(value)
|
||||
return result === 'neutral' ? undefined : result
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ElementContent} node
|
||||
* Node to check.
|
||||
* @returns {Direction | undefined}
|
||||
* Directionality.
|
||||
*/
|
||||
function dirProperty(node) {
|
||||
const value =
|
||||
node.type === 'element' && typeof node.properties.dir === 'string'
|
||||
? node.properties.dir.toLowerCase()
|
||||
: undefined
|
||||
|
||||
return value === 'auto' || value === 'ltr' || value === 'rtl'
|
||||
? value
|
||||
: undefined
|
||||
}
|
||||
13
node_modules/hast-util-select/lib/id.d.ts
generated
vendored
Normal file
13
node_modules/hast-util-select/lib/id.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Check whether an element has an ID.
|
||||
*
|
||||
* @param {AstId} query
|
||||
* AST rule (with `ids`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function id(query: AstId, element: Element): boolean;
|
||||
export type AstId = import('css-selector-parser').AstId;
|
||||
export type Element = import('hast').Element;
|
||||
22
node_modules/hast-util-select/lib/id.js
generated
vendored
Normal file
22
node_modules/hast-util-select/lib/id.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstId} AstId
|
||||
*
|
||||
* @typedef {import('hast').Element} Element
|
||||
*/
|
||||
|
||||
// Workaround to show references to above types in VS Code.
|
||||
''
|
||||
|
||||
/**
|
||||
* Check whether an element has an ID.
|
||||
*
|
||||
* @param {AstId} query
|
||||
* AST rule (with `ids`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function id(query, element) {
|
||||
return element.properties.id === query.name
|
||||
}
|
||||
123
node_modules/hast-util-select/lib/index.d.ts
generated
vendored
Normal file
123
node_modules/hast-util-select/lib/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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: string, node?: Nodes | null | undefined, space?: Space | null | undefined): boolean;
|
||||
/**
|
||||
* 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: string, tree?: Nodes | null | undefined, space?: Space | null | undefined): Element | undefined;
|
||||
/**
|
||||
* 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: string, tree?: Nodes | null | undefined, space?: Space | null | undefined): Array<Element>;
|
||||
export type AstSelector = import('css-selector-parser').AstSelector;
|
||||
export type Element = import('hast').Element;
|
||||
export type Nodes = import('hast').Nodes;
|
||||
export type RootContent = import('hast').RootContent;
|
||||
export type Schema = import('property-information').Schema;
|
||||
/**
|
||||
* Name of namespace.
|
||||
*/
|
||||
export type Space = 'html' | 'svg';
|
||||
/**
|
||||
* Direction.
|
||||
*/
|
||||
export type Direction = 'auto' | 'ltr' | 'rtl';
|
||||
/**
|
||||
* Current state.
|
||||
*/
|
||||
export type State = {
|
||||
/**
|
||||
* Current direction.
|
||||
*/
|
||||
direction: Direction;
|
||||
/**
|
||||
* Whether we’re in `contentEditable`.
|
||||
*/
|
||||
editableOrEditingHost: boolean;
|
||||
/**
|
||||
* Track siblings: there are `n` siblings.
|
||||
*/
|
||||
elementCount: number | undefined;
|
||||
/**
|
||||
* Track siblings: this current element has `n` elements before it.
|
||||
*/
|
||||
elementIndex: number | undefined;
|
||||
/**
|
||||
* Whether we found at least one match.
|
||||
*/
|
||||
found: boolean;
|
||||
/**
|
||||
* Current language.
|
||||
*/
|
||||
language: string | undefined;
|
||||
/**
|
||||
* Whether we can stop looking after we found one element.
|
||||
*/
|
||||
one: boolean;
|
||||
/**
|
||||
* Matches.
|
||||
*/
|
||||
results: Array<Element>;
|
||||
/**
|
||||
* Original root selectors.
|
||||
*/
|
||||
rootQuery: AstSelector;
|
||||
/**
|
||||
* Current schema.
|
||||
*/
|
||||
schema: Schema;
|
||||
/**
|
||||
* Elements in scope.
|
||||
*/
|
||||
scopeElements: Array<RootContent>;
|
||||
/**
|
||||
* Whether we only allow selectors without nesting.
|
||||
*/
|
||||
shallow: boolean;
|
||||
/**
|
||||
* Track siblings: there are `n` siblings with this element’s tag name.
|
||||
*/
|
||||
typeCount: number | undefined;
|
||||
/**
|
||||
* Track siblings: this current element has `n` elements with its tag name
|
||||
* before it.
|
||||
*/
|
||||
typeIndex: number | undefined;
|
||||
};
|
||||
149
node_modules/hast-util-select/lib/index.js
generated
vendored
Normal file
149
node_modules/hast-util-select/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @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 we’re 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 element’s 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
|
||||
}
|
||||
}
|
||||
13
node_modules/hast-util-select/lib/name.d.ts
generated
vendored
Normal file
13
node_modules/hast-util-select/lib/name.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Check whether an element has a tag name.
|
||||
*
|
||||
* @param {AstTagName} query
|
||||
* AST rule (with `tag`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function name(query: AstTagName, element: Element): boolean;
|
||||
export type AstTagName = import('css-selector-parser').AstTagName;
|
||||
export type Element = import('hast').Element;
|
||||
22
node_modules/hast-util-select/lib/name.js
generated
vendored
Normal file
22
node_modules/hast-util-select/lib/name.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstTagName} AstTagName
|
||||
*
|
||||
* @typedef {import('hast').Element} Element
|
||||
*/
|
||||
|
||||
// Workaround to show references to above types in VS Code.
|
||||
''
|
||||
|
||||
/**
|
||||
* Check whether an element has a tag name.
|
||||
*
|
||||
* @param {AstTagName} query
|
||||
* AST rule (with `tag`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function name(query, element) {
|
||||
return query.name === element.tagName
|
||||
}
|
||||
8
node_modules/hast-util-select/lib/parse.d.ts
generated
vendored
Normal file
8
node_modules/hast-util-select/lib/parse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @param {string} selector
|
||||
* Selector to parse.
|
||||
* @returns {AstSelector}
|
||||
* Parsed selector.
|
||||
*/
|
||||
export function parse(selector: string): AstSelector;
|
||||
export type AstSelector = import('css-selector-parser').AstSelector;
|
||||
21
node_modules/hast-util-select/lib/parse.js
generated
vendored
Normal file
21
node_modules/hast-util-select/lib/parse.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstSelector} AstSelector
|
||||
*/
|
||||
|
||||
import {createParser} from 'css-selector-parser'
|
||||
|
||||
const cssSelectorParse = createParser({syntax: 'selectors-4'})
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* Selector to parse.
|
||||
* @returns {AstSelector}
|
||||
* Parsed selector.
|
||||
*/
|
||||
export function parse(selector) {
|
||||
if (typeof selector !== 'string') {
|
||||
throw new TypeError('Expected `string` as selector, not `' + selector + '`')
|
||||
}
|
||||
|
||||
return cssSelectorParse(selector)
|
||||
}
|
||||
7
node_modules/hast-util-select/lib/pseudo.d.ts
generated
vendored
Normal file
7
node_modules/hast-util-select/lib/pseudo.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/** @type {(rule: AstPseudoClass, element: Element, index: number | undefined, parent: Parents | undefined, state: State) => boolean} */
|
||||
export const pseudo: (rule: AstPseudoClass, element: Element, index: number | undefined, parent: Parents | undefined, state: State) => boolean;
|
||||
export type AstPseudoClass = import('css-selector-parser').AstPseudoClass;
|
||||
export type Element = import('hast').Element;
|
||||
export type ElementContent = import('hast').ElementContent;
|
||||
export type Parents = import('hast').Parents;
|
||||
export type State = import('./index.js').State;
|
||||
761
node_modules/hast-util-select/lib/pseudo.js
generated
vendored
Normal file
761
node_modules/hast-util-select/lib/pseudo.js
generated
vendored
Normal file
@@ -0,0 +1,761 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstPseudoClass} AstPseudoClass
|
||||
*
|
||||
* @typedef {import('hast').Element} Element
|
||||
* @typedef {import('hast').ElementContent} ElementContent
|
||||
* @typedef {import('hast').Parents} Parents
|
||||
*
|
||||
* @typedef {import('./index.js').State} State
|
||||
*/
|
||||
|
||||
import {extendedFilter} from 'bcp-47-match'
|
||||
import {parse as commas} from 'comma-separated-tokens'
|
||||
import {ok as assert, unreachable} from 'devlop'
|
||||
import {hasProperty} from 'hast-util-has-property'
|
||||
import {whitespace} from 'hast-util-whitespace'
|
||||
import fauxEsmNthCheck from 'nth-check'
|
||||
import {zwitch} from 'zwitch'
|
||||
import {walk} from './walk.js'
|
||||
|
||||
/** @type {import('nth-check').default} */
|
||||
// @ts-expect-error: types are broken.
|
||||
const nthCheck = fauxEsmNthCheck.default || fauxEsmNthCheck
|
||||
|
||||
/** @type {(rule: AstPseudoClass, element: Element, index: number | undefined, parent: Parents | undefined, state: State) => boolean} */
|
||||
export const pseudo = zwitch('name', {
|
||||
handlers: {
|
||||
'any-link': anyLink,
|
||||
blank,
|
||||
checked,
|
||||
dir,
|
||||
disabled,
|
||||
empty,
|
||||
enabled,
|
||||
'first-child': firstChild,
|
||||
'first-of-type': firstOfType,
|
||||
has,
|
||||
is,
|
||||
lang,
|
||||
'last-child': lastChild,
|
||||
'last-of-type': lastOfType,
|
||||
not,
|
||||
'nth-child': nthChild,
|
||||
'nth-last-child': nthLastChild,
|
||||
'nth-last-of-type': nthLastOfType,
|
||||
'nth-of-type': nthOfType,
|
||||
'only-child': onlyChild,
|
||||
'only-of-type': onlyOfType,
|
||||
optional,
|
||||
'read-only': readOnly,
|
||||
'read-write': readWrite,
|
||||
required,
|
||||
root,
|
||||
scope
|
||||
},
|
||||
invalid: invalidPseudo,
|
||||
unknown: unknownPseudo
|
||||
})
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:any-link` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function anyLink(_, element) {
|
||||
return (
|
||||
(element.tagName === 'a' ||
|
||||
element.tagName === 'area' ||
|
||||
element.tagName === 'link') &&
|
||||
hasProperty(element, 'href')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
*/
|
||||
function assertDeep(state, query) {
|
||||
if (state.shallow) {
|
||||
throw new Error('Cannot use `:' + query.name + '` without parent')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:blank` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function blank(_, element) {
|
||||
return !someChildren(element, check)
|
||||
|
||||
/**
|
||||
* @param {ElementContent} child
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function check(child) {
|
||||
return (
|
||||
child.type === 'element' || (child.type === 'text' && !whitespace(child))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:checked` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function checked(_, element) {
|
||||
if (element.tagName === 'input' || element.tagName === 'menuitem') {
|
||||
return Boolean(
|
||||
(element.properties.type === 'checkbox' ||
|
||||
element.properties.type === 'radio') &&
|
||||
hasProperty(element, 'checked')
|
||||
)
|
||||
}
|
||||
|
||||
if (element.tagName === 'option') {
|
||||
return hasProperty(element, 'selected')
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:dir()` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function dir(query, _1, _2, _3, state) {
|
||||
assert(query.argument, 'expected `argument`')
|
||||
assert(query.argument.type === 'String', 'expected plain text')
|
||||
return state.direction === query.argument.value
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:disabled` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function disabled(_, element) {
|
||||
return (
|
||||
(element.tagName === 'button' ||
|
||||
element.tagName === 'input' ||
|
||||
element.tagName === 'select' ||
|
||||
element.tagName === 'textarea' ||
|
||||
element.tagName === 'optgroup' ||
|
||||
element.tagName === 'option' ||
|
||||
element.tagName === 'menuitem' ||
|
||||
element.tagName === 'fieldset') &&
|
||||
hasProperty(element, 'disabled')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:empty` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function empty(_, element) {
|
||||
return !someChildren(element, check)
|
||||
|
||||
/**
|
||||
* @param {ElementContent} child
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function check(child) {
|
||||
return child.type === 'element' || child.type === 'text'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:enabled` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function enabled(query, element) {
|
||||
return !disabled(query, element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:first-child` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function firstChild(query, _1, _2, _3, state) {
|
||||
assertDeep(state, query)
|
||||
return state.elementIndex === 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:first-of-type` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function firstOfType(query, _1, _2, _3, state) {
|
||||
assertDeep(state, query)
|
||||
return state.typeIndex === 0
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @returns {(value: number) => boolean}
|
||||
* N.
|
||||
*/
|
||||
function getCachedNthCheck(query) {
|
||||
/** @type {(value: number) => boolean} */
|
||||
// @ts-expect-error: cache.
|
||||
let fn = query._cachedFn
|
||||
|
||||
if (!fn) {
|
||||
const value = query.argument
|
||||
assert(value, 'expected `argument`')
|
||||
|
||||
if (value.type !== 'Formula') {
|
||||
throw new Error(
|
||||
'Expected `nth` formula, such as `even` or `2n+1` (`of` is not yet supported)'
|
||||
)
|
||||
}
|
||||
|
||||
fn = nthCheck(value.a + 'n+' + value.b)
|
||||
// @ts-expect-error: cache.
|
||||
query._cachedFn = fn
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} _1
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _2
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function has(query, element, _1, _2, state) {
|
||||
assert(query.argument, 'expected `argument`')
|
||||
assert(query.argument.type === 'Selector', 'expected selector')
|
||||
|
||||
/** @type {State} */
|
||||
const childState = {
|
||||
...state,
|
||||
// Not found yet.
|
||||
found: false,
|
||||
// One result is enough.
|
||||
one: true,
|
||||
results: [],
|
||||
rootQuery: query.argument,
|
||||
scopeElements: [element],
|
||||
// Do walk deep.
|
||||
shallow: false
|
||||
}
|
||||
|
||||
walk(childState, {type: 'root', children: element.children})
|
||||
|
||||
return childState.results.length > 0
|
||||
}
|
||||
|
||||
// Shouldn’t be called, parser gives correct data.
|
||||
/* c8 ignore next 3 */
|
||||
function invalidPseudo() {
|
||||
unreachable('Invalid pseudo-selector')
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element `:is` further selectors.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} _1
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _2
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function is(query, element, _1, _2, state) {
|
||||
assert(query.argument, 'expected `argument`')
|
||||
assert(query.argument.type === 'Selector', 'expected selector')
|
||||
|
||||
/** @type {State} */
|
||||
const childState = {
|
||||
...state,
|
||||
// Not found yet.
|
||||
found: false,
|
||||
// One result is enough.
|
||||
one: true,
|
||||
results: [],
|
||||
rootQuery: query.argument,
|
||||
scopeElements: [element],
|
||||
// Do walk deep.
|
||||
shallow: false
|
||||
}
|
||||
|
||||
walk(childState, element)
|
||||
|
||||
return childState.results[0] === element
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:lang()` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function lang(query, _1, _2, _3, state) {
|
||||
assert(query.argument, 'expected `argument`')
|
||||
assert(query.argument.type === 'String', 'expected string')
|
||||
|
||||
return (
|
||||
state.language !== '' &&
|
||||
state.language !== undefined &&
|
||||
extendedFilter(state.language, commas(query.argument.value)).length > 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:last-child` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function lastChild(query, _1, _2, _3, state) {
|
||||
assertDeep(state, query)
|
||||
return Boolean(
|
||||
state.elementCount && state.elementIndex === state.elementCount - 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:last-of-type` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function lastOfType(query, _1, _2, _3, state) {
|
||||
assertDeep(state, query)
|
||||
return (
|
||||
typeof state.typeIndex === 'number' &&
|
||||
typeof state.typeCount === 'number' &&
|
||||
state.typeIndex === state.typeCount - 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element does `:not` match further selectors.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} index
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} parent
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function not(query, element, index, parent, state) {
|
||||
return !is(query, element, index, parent, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:nth-child` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function nthChild(query, _1, _2, _3, state) {
|
||||
const fn = getCachedNthCheck(query)
|
||||
assertDeep(state, query)
|
||||
return typeof state.elementIndex === 'number' && fn(state.elementIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:nth-last-child` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function nthLastChild(query, _1, _2, _3, state) {
|
||||
const fn = getCachedNthCheck(query)
|
||||
assertDeep(state, query)
|
||||
return Boolean(
|
||||
typeof state.elementCount === 'number' &&
|
||||
typeof state.elementIndex === 'number' &&
|
||||
fn(state.elementCount - state.elementIndex - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:nth-last-of-type` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function nthLastOfType(query, _1, _2, _3, state) {
|
||||
const fn = getCachedNthCheck(query)
|
||||
assertDeep(state, query)
|
||||
return (
|
||||
typeof state.typeCount === 'number' &&
|
||||
typeof state.typeIndex === 'number' &&
|
||||
fn(state.typeCount - 1 - state.typeIndex)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:nth-of-type` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function nthOfType(query, _1, _2, _3, state) {
|
||||
const fn = getCachedNthCheck(query)
|
||||
assertDeep(state, query)
|
||||
return typeof state.typeIndex === 'number' && fn(state.typeIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:only-child` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function onlyChild(query, _1, _2, _3, state) {
|
||||
assertDeep(state, query)
|
||||
return state.elementCount === 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:only-of-type` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} _1
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function onlyOfType(query, _1, _2, _3, state) {
|
||||
assertDeep(state, query)
|
||||
return state.typeCount === 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches an `:optional` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function optional(query, element) {
|
||||
return !required(query, element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:read-only` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} query
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} index
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} parent
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function readOnly(query, element, index, parent, state) {
|
||||
return !readWrite(query, element, index, parent, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:read-write` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} _1
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _2
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function readWrite(_, element, _1, _2, state) {
|
||||
return element.tagName === 'input' || element.tagName === 'textarea'
|
||||
? !hasProperty(element, 'readOnly') && !hasProperty(element, 'disabled')
|
||||
: Boolean(state.editableOrEditingHost)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:required` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function required(_, element) {
|
||||
return (
|
||||
(element.tagName === 'input' ||
|
||||
element.tagName === 'textarea' ||
|
||||
element.tagName === 'select') &&
|
||||
hasProperty(element, 'required')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:root` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _1
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} parent
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function root(_1, element, _2, parent, state) {
|
||||
return Boolean(
|
||||
(!parent || parent.type === 'root') &&
|
||||
state.schema &&
|
||||
(state.schema.space === 'html' || state.schema.space === 'svg') &&
|
||||
(element.tagName === 'html' || element.tagName === 'svg')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element matches a `:scope` pseudo.
|
||||
*
|
||||
* @param {AstPseudoClass} _1
|
||||
* Query.
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} _2
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} _3
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
function scope(_1, element, _2, _3, state) {
|
||||
return state.scopeElements.includes(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check children.
|
||||
*
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {(child: ElementContent) => boolean} check
|
||||
* Check.
|
||||
* @returns {boolean}
|
||||
* Whether a child of `element` matches `check`.
|
||||
*/
|
||||
function someChildren(element, check) {
|
||||
const children = element.children
|
||||
let index = -1
|
||||
|
||||
while (++index < children.length) {
|
||||
if (check(children[index])) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} query_
|
||||
* Query-like value.
|
||||
* @returns {never}
|
||||
* Nothing.
|
||||
* @throws
|
||||
* Exception.
|
||||
*/
|
||||
function unknownPseudo(query_) {
|
||||
// Runtime JS guarantees it has a `name`.
|
||||
const query = /** @type {AstPseudoClass} */ (query_)
|
||||
throw new Error('Unknown pseudo-selector `' + query.name + '`')
|
||||
}
|
||||
21
node_modules/hast-util-select/lib/test.d.ts
generated
vendored
Normal file
21
node_modules/hast-util-select/lib/test.d.ts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Test a rule.
|
||||
*
|
||||
* @param {AstRule} query
|
||||
* AST rule (with `pseudoClasses`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} index
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} parent
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function test(query: AstRule, element: Element, index: number | undefined, parent: Parents | undefined, state: State): boolean;
|
||||
export type AstRule = import('css-selector-parser').AstRule;
|
||||
export type Element = import('hast').Element;
|
||||
export type Parents = import('hast').Parents;
|
||||
export type State = import('./index.js').State;
|
||||
53
node_modules/hast-util-select/lib/test.js
generated
vendored
Normal file
53
node_modules/hast-util-select/lib/test.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstRule} AstRule
|
||||
*
|
||||
* @typedef {import('hast').Element} Element
|
||||
* @typedef {import('hast').Parents} Parents
|
||||
*
|
||||
* @typedef {import('./index.js').State} State
|
||||
*/
|
||||
|
||||
import {attribute} from './attribute.js'
|
||||
import {className} from './class-name.js'
|
||||
import {id} from './id.js'
|
||||
import {name} from './name.js'
|
||||
import {pseudo} from './pseudo.js'
|
||||
|
||||
/**
|
||||
* Test a rule.
|
||||
*
|
||||
* @param {AstRule} query
|
||||
* AST rule (with `pseudoClasses`).
|
||||
* @param {Element} element
|
||||
* Element.
|
||||
* @param {number | undefined} index
|
||||
* Index of `element` in `parent`.
|
||||
* @param {Parents | undefined} parent
|
||||
* Parent of `element`.
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @returns {boolean}
|
||||
* Whether `element` matches `query`.
|
||||
*/
|
||||
export function test(query, element, index, parent, state) {
|
||||
for (const item of query.items) {
|
||||
// eslint-disable-next-line unicorn/prefer-switch
|
||||
if (item.type === 'Attribute') {
|
||||
if (!attribute(item, element, state.schema)) return false
|
||||
} else if (item.type === 'Id') {
|
||||
if (!id(item, element)) return false
|
||||
} else if (item.type === 'ClassName') {
|
||||
if (!className(item, element)) return false
|
||||
} else if (item.type === 'PseudoClass') {
|
||||
if (!pseudo(item, element, index, parent, state)) return false
|
||||
} else if (item.type === 'PseudoElement') {
|
||||
throw new Error('Invalid selector: `::' + item.name + '`')
|
||||
} else if (item.type === 'TagName') {
|
||||
if (!name(item, element)) return false
|
||||
} else {
|
||||
// Otherwise `item.type` is `WildcardTag`, which matches.
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
48
node_modules/hast-util-select/lib/walk.d.ts
generated
vendored
Normal file
48
node_modules/hast-util-select/lib/walk.d.ts
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Walk a tree.
|
||||
*
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @param {Nodes | undefined} tree
|
||||
* Tree.
|
||||
*/
|
||||
export function walk(state: State, tree: Nodes | undefined): void;
|
||||
export type AstRule = import('css-selector-parser').AstRule;
|
||||
export type Element = import('hast').Element;
|
||||
export type Nodes = import('hast').Nodes;
|
||||
export type Parents = import('hast').Parents;
|
||||
export type State = import('./index.js').State;
|
||||
/**
|
||||
* Info on elements in a parent.
|
||||
*/
|
||||
export type Counts = {
|
||||
/**
|
||||
* Number of elements.
|
||||
*/
|
||||
count: number;
|
||||
/**
|
||||
* Number of elements by tag name.
|
||||
*/
|
||||
types: Map<string, number>;
|
||||
};
|
||||
/**
|
||||
* Rule sets by nesting.
|
||||
*/
|
||||
export type Nest = {
|
||||
/**
|
||||
* `a + b`
|
||||
*/
|
||||
adjacentSibling: Array<AstRule> | undefined;
|
||||
/**
|
||||
* `a b`
|
||||
*/
|
||||
descendant: Array<AstRule> | undefined;
|
||||
/**
|
||||
* `a > b`
|
||||
*/
|
||||
directChild: Array<AstRule> | undefined;
|
||||
/**
|
||||
* `a ~ b`
|
||||
*/
|
||||
generalSibling: Array<AstRule> | undefined;
|
||||
};
|
||||
329
node_modules/hast-util-select/lib/walk.js
generated
vendored
Normal file
329
node_modules/hast-util-select/lib/walk.js
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
/**
|
||||
* @typedef {import('css-selector-parser').AstRule} AstRule
|
||||
*
|
||||
* @typedef {import('hast').Element} Element
|
||||
* @typedef {import('hast').Nodes} Nodes
|
||||
* @typedef {import('hast').Parents} Parents
|
||||
*
|
||||
* @typedef {import('./index.js').State} State
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Counts
|
||||
* Info on elements in a parent.
|
||||
* @property {number} count
|
||||
* Number of elements.
|
||||
* @property {Map<string, number>} types
|
||||
* Number of elements by tag name.
|
||||
*
|
||||
* @typedef Nest
|
||||
* Rule sets by nesting.
|
||||
* @property {Array<AstRule> | undefined} adjacentSibling
|
||||
* `a + b`
|
||||
* @property {Array<AstRule> | undefined} descendant
|
||||
* `a b`
|
||||
* @property {Array<AstRule> | undefined} directChild
|
||||
* `a > b`
|
||||
* @property {Array<AstRule> | undefined} generalSibling
|
||||
* `a ~ b`
|
||||
*/
|
||||
|
||||
import {enterState} from './enter-state.js'
|
||||
import {test} from './test.js'
|
||||
|
||||
/** @type {Array<never>} */
|
||||
const empty = []
|
||||
|
||||
/**
|
||||
* Walk a tree.
|
||||
*
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @param {Nodes | undefined} tree
|
||||
* Tree.
|
||||
*/
|
||||
export function walk(state, tree) {
|
||||
if (tree) {
|
||||
one(state, [], tree, undefined, undefined, tree)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a rule to a nesting map.
|
||||
*
|
||||
* @param {Nest} nest
|
||||
* Nesting.
|
||||
* @param {keyof Nest} field
|
||||
* Field.
|
||||
* @param {AstRule} rule
|
||||
* Rule.
|
||||
*/
|
||||
function add(nest, field, rule) {
|
||||
const list = nest[field]
|
||||
if (list) {
|
||||
list.push(rule)
|
||||
} else {
|
||||
nest[field] = [rule]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check in a parent.
|
||||
*
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @param {Nest} nest
|
||||
* Nesting.
|
||||
* @param {Parents} node
|
||||
* Parent.
|
||||
* @param {Nodes} tree
|
||||
* Tree.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
function all(state, nest, node, tree) {
|
||||
const fromParent = combine(nest.descendant, nest.directChild)
|
||||
/** @type {Array<AstRule> | undefined} */
|
||||
let fromSibling
|
||||
let index = -1
|
||||
/**
|
||||
* Total counts.
|
||||
* @type {Counts}
|
||||
*/
|
||||
const total = {count: 0, types: new Map()}
|
||||
/**
|
||||
* Counts of previous siblings.
|
||||
* @type {Counts}
|
||||
*/
|
||||
const before = {count: 0, types: new Map()}
|
||||
|
||||
while (++index < node.children.length) {
|
||||
count(total, node.children[index])
|
||||
}
|
||||
|
||||
index = -1
|
||||
|
||||
while (++index < node.children.length) {
|
||||
const child = node.children[index]
|
||||
// Uppercase to prevent prototype polution, injecting `constructor` or so.
|
||||
// Normalize because HTML is insensitive.
|
||||
const name =
|
||||
child.type === 'element' ? child.tagName.toUpperCase() : undefined
|
||||
// Before counting further elements:
|
||||
state.elementIndex = before.count
|
||||
state.typeIndex = name ? before.types.get(name) || 0 : 0
|
||||
// After counting all elements.
|
||||
state.elementCount = total.count
|
||||
state.typeCount = name ? total.types.get(name) : 0
|
||||
|
||||
// Only apply if this is a parent, this should be an element, but we check
|
||||
// for parents so that we delve into custom nodes too.
|
||||
if ('children' in child) {
|
||||
const forSibling = combine(fromParent, fromSibling)
|
||||
const nest = one(
|
||||
state,
|
||||
forSibling,
|
||||
node.children[index],
|
||||
index,
|
||||
node,
|
||||
tree
|
||||
)
|
||||
fromSibling = combine(nest.generalSibling, nest.adjacentSibling)
|
||||
}
|
||||
|
||||
// We found one thing, and one is enough.
|
||||
if (state.one && state.found) {
|
||||
break
|
||||
}
|
||||
|
||||
count(before, node.children[index])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply selectors to an element.
|
||||
*
|
||||
* @param {State} state
|
||||
* Current state.
|
||||
* @param {Array<AstRule>} rules
|
||||
* Rules to apply.
|
||||
* @param {Element} node
|
||||
* Element to apply rules to.
|
||||
* @param {number | undefined} index
|
||||
* Index of `node` in `parent`.
|
||||
* @param {Parents | undefined} parent
|
||||
* Parent of `node`.
|
||||
* @returns {Nest}
|
||||
* Further rules.
|
||||
*/
|
||||
function applySelectors(state, rules, node, index, parent) {
|
||||
/** @type {Nest} */
|
||||
const nestResult = {
|
||||
adjacentSibling: undefined,
|
||||
descendant: undefined,
|
||||
directChild: undefined,
|
||||
generalSibling: undefined
|
||||
}
|
||||
let selectorIndex = -1
|
||||
|
||||
while (++selectorIndex < rules.length) {
|
||||
const rule = rules[selectorIndex]
|
||||
|
||||
// We found one thing, and one is enough.
|
||||
if (state.one && state.found) {
|
||||
break
|
||||
}
|
||||
|
||||
// When shallow, we don’t allow nested rules.
|
||||
// Idea: we could allow a stack of parents?
|
||||
// Might get quite complex though.
|
||||
if (state.shallow && rule.nestedRule) {
|
||||
throw new Error('Expected selector without nesting')
|
||||
}
|
||||
|
||||
// If this rule matches:
|
||||
if (test(rule, node, index, parent, state)) {
|
||||
const nest = rule.nestedRule
|
||||
|
||||
// Are there more?
|
||||
if (nest) {
|
||||
/** @type {keyof Nest} */
|
||||
const label =
|
||||
nest.combinator === '+'
|
||||
? 'adjacentSibling'
|
||||
: nest.combinator === '~'
|
||||
? 'generalSibling'
|
||||
: nest.combinator === '>'
|
||||
? 'directChild'
|
||||
: 'descendant'
|
||||
add(nestResult, label, nest)
|
||||
} else {
|
||||
// We have a match!
|
||||
state.found = true
|
||||
|
||||
if (!state.results.includes(node)) {
|
||||
state.results.push(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Descendant.
|
||||
if (rule.combinator === undefined) {
|
||||
add(nestResult, 'descendant', rule)
|
||||
}
|
||||
// Adjacent.
|
||||
else if (rule.combinator === '~') {
|
||||
add(nestResult, 'generalSibling', rule)
|
||||
}
|
||||
// Drop direct child (`>`), adjacent sibling (`+`).
|
||||
}
|
||||
|
||||
return nestResult
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine two lists, if needed.
|
||||
*
|
||||
* This is optimized to create as few lists as possible.
|
||||
*
|
||||
* @param {Array<AstRule> | undefined} left
|
||||
* Rules.
|
||||
* @param {Array<AstRule> | undefined} right
|
||||
* Rules.
|
||||
* @returns {Array<AstRule>}
|
||||
* Rules.
|
||||
*/
|
||||
function combine(left, right) {
|
||||
return left && right && left.length > 0 && right.length > 0
|
||||
? [...left, ...right]
|
||||
: left && left.length > 0
|
||||
? left
|
||||
: right && right.length > 0
|
||||
? right
|
||||
: empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Count a node.
|
||||
*
|
||||
* @param {Counts} counts
|
||||
* Counts.
|
||||
* @param {Nodes} node
|
||||
* Node (we’re looking for elements).
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
function count(counts, node) {
|
||||
if (node.type === 'element') {
|
||||
// Uppercase to prevent prototype polution, injecting `constructor` or so.
|
||||
// Normalize because HTML is insensitive.
|
||||
const name = node.tagName.toUpperCase()
|
||||
const count = (counts.types.get(name) || 0) + 1
|
||||
counts.count++
|
||||
counts.types.set(name, count)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a node.
|
||||
*
|
||||
* @param {State} state
|
||||
* State.
|
||||
* @param {Array<AstRule>} currentRules
|
||||
* Rules.
|
||||
* @param {Nodes} node
|
||||
* Node.
|
||||
* @param {number | undefined} index
|
||||
* Index of `node` in `parent`.
|
||||
* @param {Parents | undefined} parent
|
||||
* Parent of `node`.
|
||||
* @param {Nodes} tree
|
||||
* Tree.
|
||||
* @returns {Nest}
|
||||
* Nesting.
|
||||
*/
|
||||
function one(state, currentRules, node, index, parent, tree) {
|
||||
/** @type {Nest} */
|
||||
let nestResult = {
|
||||
adjacentSibling: undefined,
|
||||
descendant: undefined,
|
||||
directChild: undefined,
|
||||
generalSibling: undefined
|
||||
}
|
||||
|
||||
const exit = enterState(state, node)
|
||||
|
||||
if (node.type === 'element') {
|
||||
let rootRules = state.rootQuery.rules
|
||||
|
||||
// Remove direct child rules if this is the root.
|
||||
// This only happens for a `:has()` rule, which can be like
|
||||
// `a:has(> b)`.
|
||||
if (parent && parent !== tree) {
|
||||
rootRules = state.rootQuery.rules.filter(
|
||||
(d) =>
|
||||
d.combinator === undefined ||
|
||||
(d.combinator === '>' && parent === tree)
|
||||
)
|
||||
}
|
||||
|
||||
nestResult = applySelectors(
|
||||
state,
|
||||
// Try the root rules for this element too.
|
||||
combine(currentRules, rootRules),
|
||||
node,
|
||||
index,
|
||||
parent
|
||||
)
|
||||
}
|
||||
|
||||
// If this is a parent, and we want to delve into them, and we haven’t found
|
||||
// our single result yet.
|
||||
if ('children' in node && !state.shallow && !(state.one && state.found)) {
|
||||
all(state, nestResult, node, tree)
|
||||
}
|
||||
|
||||
exit()
|
||||
|
||||
return nestResult
|
||||
}
|
||||
22
node_modules/hast-util-select/license
generated
vendored
Normal file
22
node_modules/hast-util-select/license
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017 Titus Wormer <tituswormer@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
115
node_modules/hast-util-select/package.json
generated
vendored
Normal file
115
node_modules/hast-util-select/package.json
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"name": "hast-util-select",
|
||||
"version": "6.0.2",
|
||||
"description": "hast utility for `querySelector`, `querySelectorAll`, and `matches`",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"unist",
|
||||
"hast",
|
||||
"hast-util",
|
||||
"util",
|
||||
"utility",
|
||||
"html",
|
||||
"css",
|
||||
"select",
|
||||
"selectall",
|
||||
"selector",
|
||||
"query",
|
||||
"match",
|
||||
"matches"
|
||||
],
|
||||
"repository": "syntax-tree/hast-util-select",
|
||||
"bugs": "https://github.com/syntax-tree/hast-util-select/issues",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
},
|
||||
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
|
||||
"contributors": [
|
||||
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"exports": "./index.js",
|
||||
"files": [
|
||||
"lib/",
|
||||
"index.d.ts",
|
||||
"index.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/unist": "^3.0.0",
|
||||
"bcp-47-match": "^2.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"css-selector-parser": "^3.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"direction": "^2.0.0",
|
||||
"hast-util-has-property": "^3.0.0",
|
||||
"hast-util-to-string": "^3.0.0",
|
||||
"hast-util-whitespace": "^3.0.0",
|
||||
"not": "^0.1.0",
|
||||
"nth-check": "^2.0.0",
|
||||
"property-information": "^6.0.0",
|
||||
"space-separated-tokens": "^2.0.0",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"zwitch": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"c8": "^8.0.0",
|
||||
"hastscript": "^8.0.0",
|
||||
"prettier": "^3.0.0",
|
||||
"remark-cli": "^11.0.0",
|
||||
"remark-preset-wooorm": "^9.0.0",
|
||||
"type-coverage": "^2.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"unist-builder": "^4.0.0",
|
||||
"xo": "^0.56.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepack": "npm run build && npm run format",
|
||||
"build": "tsc --build --clean && tsc --build && type-coverage",
|
||||
"format": "remark . -qfo && prettier . -w --log-level warn && xo --fix",
|
||||
"test-api": "node --conditions development test/index.js",
|
||||
"test-coverage": "c8 --100 --reporter lcov npm run test-api",
|
||||
"test": "npm run build && npm run format && npm run test-coverage"
|
||||
},
|
||||
"prettier": {
|
||||
"bracketSpacing": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "none",
|
||||
"useTabs": false
|
||||
},
|
||||
"remarkConfig": {
|
||||
"plugins": [
|
||||
"remark-preset-wooorm"
|
||||
]
|
||||
},
|
||||
"typeCoverage": {
|
||||
"atLeast": 100,
|
||||
"detail": true,
|
||||
"ignoreCatch": true,
|
||||
"strict": true
|
||||
},
|
||||
"xo": {
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"test/**/*.js"
|
||||
],
|
||||
"rules": {
|
||||
"import/no-unassigned-import": "off",
|
||||
"max-nested-callbacks": "off",
|
||||
"no-await-in-loop": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
"max-params": "off",
|
||||
"unicorn/prefer-at": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
484
node_modules/hast-util-select/readme.md
generated
vendored
Normal file
484
node_modules/hast-util-select/readme.md
generated
vendored
Normal file
@@ -0,0 +1,484 @@
|
||||
# hast-util-select
|
||||
|
||||
[![Build][build-badge]][build]
|
||||
[![Coverage][coverage-badge]][coverage]
|
||||
[![Downloads][downloads-badge]][downloads]
|
||||
[![Size][size-badge]][size]
|
||||
[![Sponsors][sponsors-badge]][collective]
|
||||
[![Backers][backers-badge]][collective]
|
||||
[![Chat][chat-badge]][chat]
|
||||
|
||||
[hast][] utility with equivalents for `matches`, `querySelector`,
|
||||
and `querySelectorAll`.
|
||||
|
||||
## Contents
|
||||
|
||||
* [What is this?](#what-is-this)
|
||||
* [When should I use this?](#when-should-i-use-this)
|
||||
* [Install](#install)
|
||||
* [Use](#use)
|
||||
* [API](#api)
|
||||
* [`matches(selector, node[, space])`](#matchesselector-node-space)
|
||||
* [`select(selector, tree[, space])`](#selectselector-tree-space)
|
||||
* [`selectAll(selector, tree[, space])`](#selectallselector-tree-space)
|
||||
* [`Space`](#space)
|
||||
* [Support](#support)
|
||||
* [Unsupported](#unsupported)
|
||||
* [Types](#types)
|
||||
* [Compatibility](#compatibility)
|
||||
* [Security](#security)
|
||||
* [Related](#related)
|
||||
* [Contribute](#contribute)
|
||||
* [License](#license)
|
||||
|
||||
## What is this?
|
||||
|
||||
This package lets you find nodes in a tree, similar to how `matches`,
|
||||
`querySelector`, and `querySelectorAll` work with the DOM.
|
||||
|
||||
One notable difference between DOM and hast is that DOM nodes have references
|
||||
to their parents, meaning that `document.body.matches(':last-child')` can
|
||||
be evaluated to check whether the body is the last child of its parent.
|
||||
This information is not stored in hast, so selectors like that don’t work.
|
||||
|
||||
## When should I use this?
|
||||
|
||||
This is a small utility that is quite useful, but is rather slow if you use it a
|
||||
lot.
|
||||
For each call, it has to walk the entire tree.
|
||||
In some cases, walking the tree once with [`unist-util-visit`][unist-util-visit]
|
||||
is smarter, such as when you want to change certain nodes.
|
||||
On the other hand, this is quite powerful and fast enough for many other cases.
|
||||
|
||||
This utility is similar to [`unist-util-select`][unist-util-select], which can
|
||||
find and match any unist node.
|
||||
|
||||
## Install
|
||||
|
||||
This package is [ESM only][esm].
|
||||
In Node.js (version 16+), install with [npm][]:
|
||||
|
||||
```sh
|
||||
npm install hast-util-select
|
||||
```
|
||||
|
||||
In Deno with [`esm.sh`][esmsh]:
|
||||
|
||||
```js
|
||||
import {matches, select, selectAll} from "https://esm.sh/hast-util-select@6"
|
||||
```
|
||||
|
||||
In browsers with [`esm.sh`][esmsh]:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import {matches, select, selectAll} from "https://esm.sh/hast-util-select@6?bundle"
|
||||
</script>
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
```js
|
||||
import {h} from 'hastscript'
|
||||
import {matches, select, selectAll} from 'hast-util-select'
|
||||
|
||||
const tree = h('section', [
|
||||
h('p', 'Alpha'),
|
||||
h('p', 'Bravo'),
|
||||
h('h1', 'Charlie'),
|
||||
h('p', 'Delta'),
|
||||
h('p', 'Echo'),
|
||||
h('p', 'Foxtrot'),
|
||||
h('p', 'Golf')
|
||||
])
|
||||
|
||||
console.log(matches('section', tree)) // `true`
|
||||
|
||||
console.log(select('h1 ~ :nth-child(even)', tree))
|
||||
// The paragraph with `Delta`
|
||||
|
||||
console.log(selectAll('h1 ~ :nth-child(even)', tree))
|
||||
// The paragraphs with `Delta` and `Foxtrot`
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
This package exports the identifiers [`matches`][api-matches],
|
||||
[`select`][api-select], and [`selectAll`][api-select-all].
|
||||
There is no default export.
|
||||
|
||||
### `matches(selector, node[, space])`
|
||||
|
||||
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.
|
||||
|
||||
###### Parameters
|
||||
|
||||
* `selector` (`string`)
|
||||
— CSS selector, such as (`h1`, `a, b`)
|
||||
* `node` ([`Node`][node], optional)
|
||||
— node that might match `selector`, should be an element
|
||||
* `space` ([`Space`][api-space], default: `'html'`)
|
||||
— name of namespace
|
||||
|
||||
###### Returns
|
||||
|
||||
Whether `node` matches `selector` (`boolean`).
|
||||
|
||||
###### Example
|
||||
|
||||
```js
|
||||
import {h} from 'hastscript'
|
||||
import {matches} from 'hast-util-select'
|
||||
|
||||
matches('b, i', h('b')) // => true
|
||||
matches(':any-link', h('a')) // => false
|
||||
matches(':any-link', h('a', {href: '#'})) // => true
|
||||
matches('.classy', h('a', {className: ['classy']})) // => true
|
||||
matches('#id', h('a', {id: 'id'})) // => true
|
||||
matches('[lang|=en]', h('a', {lang: 'en'})) // => true
|
||||
matches('[lang|=en]', h('a', {lang: 'en-GB'})) // => true
|
||||
```
|
||||
|
||||
### `select(selector, tree[, space])`
|
||||
|
||||
Select the first element that matches `selector` in the given `tree`.
|
||||
Searches the tree in *[preorder][]*.
|
||||
|
||||
###### Parameters
|
||||
|
||||
* `selector` (`string`)
|
||||
— CSS selector, such as (`h1`, `a, b`)
|
||||
* `tree` ([`Node`][node], optional)
|
||||
— tree to search
|
||||
* `space` ([`Space`][api-space], default: `'html'`)
|
||||
— name of namespace
|
||||
|
||||
###### Returns
|
||||
|
||||
First element in `tree` that matches `selector` or `undefined` if nothing is
|
||||
found.
|
||||
This could be `tree` itself.
|
||||
|
||||
###### Example
|
||||
|
||||
```js
|
||||
import {h} from 'hastscript'
|
||||
import {select} from 'hast-util-select'
|
||||
|
||||
console.log(
|
||||
select(
|
||||
'h1 ~ :nth-child(even)',
|
||||
h('section', [
|
||||
h('p', 'Alpha'),
|
||||
h('p', 'Bravo'),
|
||||
h('h1', 'Charlie'),
|
||||
h('p', 'Delta'),
|
||||
h('p', 'Echo')
|
||||
])
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
Yields:
|
||||
|
||||
```js
|
||||
{ type: 'element',
|
||||
tagName: 'p',
|
||||
properties: {},
|
||||
children: [ { type: 'text', value: 'Delta' } ] }
|
||||
```
|
||||
|
||||
### `selectAll(selector, tree[, space])`
|
||||
|
||||
Select all elements that match `selector` in the given `tree`.
|
||||
Searches the tree in *[preorder][]*.
|
||||
|
||||
###### Parameters
|
||||
|
||||
* `selector` (`string`)
|
||||
— CSS selector, such as (`h1`, `a, b`)
|
||||
* `tree` ([`Node`][node], optional)
|
||||
— tree to search
|
||||
* `space` ([`Space`][api-space], default: `'html'`)
|
||||
— name of namespace
|
||||
|
||||
###### Returns
|
||||
|
||||
Elements in `tree` that match `selector`.
|
||||
This could include `tree` itself.
|
||||
|
||||
###### Example
|
||||
|
||||
```js
|
||||
import {h} from 'hastscript'
|
||||
import {selectAll} from 'hast-util-select'
|
||||
|
||||
console.log(
|
||||
selectAll(
|
||||
'h1 ~ :nth-child(even)',
|
||||
h('section', [
|
||||
h('p', 'Alpha'),
|
||||
h('p', 'Bravo'),
|
||||
h('h1', 'Charlie'),
|
||||
h('p', 'Delta'),
|
||||
h('p', 'Echo'),
|
||||
h('p', 'Foxtrot'),
|
||||
h('p', 'Golf')
|
||||
])
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
Yields:
|
||||
|
||||
```js
|
||||
[ { type: 'element',
|
||||
tagName: 'p',
|
||||
properties: {},
|
||||
children: [ { type: 'text', value: 'Delta' } ] },
|
||||
{ type: 'element',
|
||||
tagName: 'p',
|
||||
properties: {},
|
||||
children: [ { type: 'text', value: 'Foxtrot' } ] } ]
|
||||
```
|
||||
|
||||
### `Space`
|
||||
|
||||
Namespace (TypeScript type).
|
||||
|
||||
###### Type
|
||||
|
||||
```ts
|
||||
type Space = 'html' | 'svg'
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
* [x] `*` (universal selector)
|
||||
* [x] `,` (multiple selector)
|
||||
* [x] `p` (type selector)
|
||||
* [x] `.class` (class selector)
|
||||
* [x] `#id` (id selector)
|
||||
* [x] `article p` (combinator: descendant selector)
|
||||
* [x] `article > p` (combinator: child selector)
|
||||
* [x] `h1 + p` (combinator: next-sibling selector)
|
||||
* [x] `h1 ~ p` (combinator: subsequent sibling selector)
|
||||
* [x] `[attr]` (attribute existence)
|
||||
* [x] `[attr… i]` (attribute case-insensitive)
|
||||
* [x] `[attr… s]` (attribute case-sensitive) (useless, default)
|
||||
* [x] `[attr=value]` (attribute equality)
|
||||
* [x] `[attr~=value]` (attribute contains in space-separated list)
|
||||
* [x] `[attr|=value]` (attribute equality or prefix)
|
||||
* [x] `[attr^=value]` (attribute begins with)
|
||||
* [x] `[attr$=value]` (attribute ends with)
|
||||
* [x] `[attr*=value]` (attribute contains)
|
||||
* [x] `:dir()` (functional pseudo-class)
|
||||
* [x] `:has()` (functional pseudo-class; also supports `a:has(> b)`)
|
||||
* [x] `:is()` (functional pseudo-class)
|
||||
* [x] `:lang()` (functional pseudo-class)
|
||||
* [x] `:not()` (functional pseudo-class)
|
||||
* [x] `:any-link` (pseudo-class)
|
||||
* [x] `:blank` (pseudo-class)
|
||||
* [x] `:checked` (pseudo-class)
|
||||
* [x] `:disabled` (pseudo-class)
|
||||
* [x] `:empty` (pseudo-class)
|
||||
* [x] `:enabled` (pseudo-class)
|
||||
* [x] `:optional` (pseudo-class)
|
||||
* [x] `:read-only` (pseudo-class)
|
||||
* [x] `:read-write` (pseudo-class)
|
||||
* [x] `:required` (pseudo-class)
|
||||
* [x] `:root` (pseudo-class)
|
||||
* [x] `:scope` (pseudo-class):
|
||||
* [x] \* `:first-child` (pseudo-class)
|
||||
* [x] \* `:first-of-type` (pseudo-class)
|
||||
* [x] \* `:last-child` (pseudo-class)
|
||||
* [x] \* `:last-of-type` (pseudo-class)
|
||||
* [x] \* `:only-child` (pseudo-class)
|
||||
* [x] \* `:only-of-type` (pseudo-class)
|
||||
* [x] \* `:nth-child()` (functional pseudo-class)
|
||||
* [x] \* `:nth-last-child()` (functional pseudo-class)
|
||||
* [x] \* `:nth-last-of-type()` (functional pseudo-class)
|
||||
* [x] \* `:nth-of-type()` (functional pseudo-class)
|
||||
|
||||
## Unsupported
|
||||
|
||||
* [ ] † `||` (column combinator)
|
||||
* [ ] † `ns|E` (namespace type selector)
|
||||
* [ ] † `*|E` (any namespace type selector)
|
||||
* [ ] † `|E` (no namespace type selector)
|
||||
* [ ] † `[ns|attr]` (namespace attribute)
|
||||
* [ ] † `[*|attr]` (any namespace attribute)
|
||||
* [ ] † `[|attr]` (no namespace attribute)
|
||||
* [ ] ‖ `:nth-child(n of S)` (functional pseudo-class, note: scoping to
|
||||
parents is not supported)
|
||||
* [ ] ‖ `:nth-last-child(n of S)` (functional pseudo-class, note: scoping to
|
||||
parents is not supported)
|
||||
* [ ] † `:active` (pseudo-class)
|
||||
* [ ] † `:autofill` (pseudo-class)
|
||||
* [ ] † `:buffering` (pseudo-class)
|
||||
* [ ] § `:closed` (pseudo-class)
|
||||
* [ ] † `:current` (pseudo-class)
|
||||
* [ ] † `:current()` (functional pseudo-class)
|
||||
* [ ] † `:default` (pseudo-class)
|
||||
* [ ] † `:defined` (pseudo-class)
|
||||
* [ ] † `:focus` (pseudo-class)
|
||||
* [ ] † `:focus-visible` (pseudo-class)
|
||||
* [ ] † `:focus-within` (pseudo-class)
|
||||
* [ ] † `:fullscreen` (pseudo-class)
|
||||
* [ ] † `:future` (pseudo-class)
|
||||
* [ ] § `:host()` (functional pseudo-class)
|
||||
* [ ] § `:host-context()` (functional pseudo-class)
|
||||
* [ ] † `:hover` (pseudo-class)
|
||||
* [ ] ‡ `:in-range` (pseudo-class)
|
||||
* [ ] † `:indeterminate` (pseudo-class)
|
||||
* [ ] ‡ `:invalid` (pseudo-class)
|
||||
* [ ] † `:link` (pseudo-class)
|
||||
* [ ] † `:local-link` (pseudo-class)
|
||||
* [ ] † `:modal` (pseudo-class)
|
||||
* [ ] † `:muted` (pseudo-class)
|
||||
* [ ] † `:nth-col()` (functional pseudo-class)
|
||||
* [ ] † `:nth-last-col()` (functional pseudo-class)
|
||||
* [ ] § `:open` (pseudo-class)
|
||||
* [ ] ‡ `:out-of-range` (pseudo-class)
|
||||
* [ ] † `:past` (pseudo-class)
|
||||
* [ ] † `:paused` (pseudo-class)
|
||||
* [ ] † `:placeholder-shown` (pseudo-class)
|
||||
* [ ] † `:playing` (pseudo-class)
|
||||
* [ ] † `:seeking` (pseudo-class)
|
||||
* [ ] † `:stalled` (pseudo-class)
|
||||
* [ ] † `:target` (pseudo-class)
|
||||
* [ ] † `:target-within` (pseudo-class)
|
||||
* [ ] † `:user-invalid` (pseudo-class)
|
||||
* [ ] ‡ `:valid` (pseudo-class)
|
||||
* [ ] † `:visited` (pseudo-class)
|
||||
* [ ] † `:volume-locked` (pseudo-class)
|
||||
* [ ] § `:where()` (functional pseudo-class)
|
||||
* [ ] † `::before` (pseudo-elements: none are supported)
|
||||
|
||||
###### Notes
|
||||
|
||||
* \* — not supported in `matches`
|
||||
* † — needs a user, browser, interactivity, scripting, or whole CSS to make
|
||||
sense
|
||||
* ‡ — not very interested in writing / including the code for this
|
||||
* § — too new, the spec is still changing
|
||||
* ‖ — pr wanted!
|
||||
* `:any()` and `:matches()` are renamed to `:is()` in CSS.
|
||||
|
||||
## Types
|
||||
|
||||
This package is fully typed with [TypeScript][].
|
||||
It exports the additional type [`Space`][api-space].
|
||||
|
||||
## Compatibility
|
||||
|
||||
Projects maintained by the unified collective are compatible with maintained
|
||||
versions of Node.js.
|
||||
|
||||
When we cut a new major release, we drop support for unmaintained versions of
|
||||
Node.
|
||||
This means we try to keep the current release line, `hast-util-select@^6`,
|
||||
compatible with Node.js 16.
|
||||
|
||||
## Security
|
||||
|
||||
This package does not change the syntax tree so there are no openings for
|
||||
[cross-site scripting (XSS)][xss] attacks.
|
||||
|
||||
## Related
|
||||
|
||||
* [`unist-util-select`](https://github.com/syntax-tree/unist-util-select)
|
||||
— select unist nodes with CSS-like selectors
|
||||
* [`hast-util-find-and-replace`](https://github.com/syntax-tree/hast-util-find-and-replace)
|
||||
— find and replace text in a hast tree
|
||||
* [`hast-util-parse-selector`](https://github.com/syntax-tree/hast-util-parse-selector)
|
||||
— create an element from a simple CSS selector
|
||||
* [`hast-util-from-selector`](https://github.com/syntax-tree/hast-util-from-selector)
|
||||
— create an element from a complex CSS selector
|
||||
|
||||
## Contribute
|
||||
|
||||
See [`contributing.md`][contributing] in [`syntax-tree/.github`][health] for
|
||||
ways to get started.
|
||||
See [`support.md`][help] for ways to get help.
|
||||
|
||||
This project has a [code of conduct][coc].
|
||||
By interacting with this repository, organization, or community you agree to
|
||||
abide by its terms.
|
||||
|
||||
## License
|
||||
|
||||
[MIT][license] © [Titus Wormer][author]
|
||||
|
||||
<!-- Definitions -->
|
||||
|
||||
[build-badge]: https://github.com/syntax-tree/hast-util-select/workflows/main/badge.svg
|
||||
|
||||
[build]: https://github.com/syntax-tree/hast-util-select/actions
|
||||
|
||||
[coverage-badge]: https://img.shields.io/codecov/c/github/syntax-tree/hast-util-select.svg
|
||||
|
||||
[coverage]: https://codecov.io/github/syntax-tree/hast-util-select
|
||||
|
||||
[downloads-badge]: https://img.shields.io/npm/dm/hast-util-select.svg
|
||||
|
||||
[downloads]: https://www.npmjs.com/package/hast-util-select
|
||||
|
||||
[size-badge]: https://img.shields.io/badge/dynamic/json?label=minzipped%20size&query=$.size.compressedSize&url=https://deno.bundlejs.com/?q=hast-util-select
|
||||
|
||||
[size]: https://bundlejs.com/?q=hast-util-select
|
||||
|
||||
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
|
||||
|
||||
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
|
||||
|
||||
[collective]: https://opencollective.com/unified
|
||||
|
||||
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
|
||||
|
||||
[chat]: https://github.com/syntax-tree/unist/discussions
|
||||
|
||||
[npm]: https://docs.npmjs.com/cli/install
|
||||
|
||||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
|
||||
|
||||
[esmsh]: https://esm.sh
|
||||
|
||||
[typescript]: https://www.typescriptlang.org
|
||||
|
||||
[license]: license
|
||||
|
||||
[author]: https://wooorm.com
|
||||
|
||||
[health]: https://github.com/syntax-tree/.github
|
||||
|
||||
[contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md
|
||||
|
||||
[help]: https://github.com/syntax-tree/.github/blob/main/support.md
|
||||
|
||||
[coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md
|
||||
|
||||
[preorder]: https://github.com/syntax-tree/unist#preorder
|
||||
|
||||
[hast]: https://github.com/syntax-tree/hast
|
||||
|
||||
[node]: https://github.com/syntax-tree/hast#nodes
|
||||
|
||||
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
|
||||
|
||||
[unist-util-visit]: https://github.com/syntax-tree/unist-util-visit
|
||||
|
||||
[unist-util-select]: https://github.com/syntax-tree/unist-util-select
|
||||
|
||||
[api-matches]: #matchesselector-node-space
|
||||
|
||||
[api-select]: #selectselector-tree-space
|
||||
|
||||
[api-select-all]: #selectallselector-tree-space
|
||||
|
||||
[api-space]: #space
|
||||
Reference in New Issue
Block a user