unist-util-select
Advanced tools
Comparing version 3.0.4 to 4.0.0
41
index.js
@@ -1,22 +0,33 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('unist').Node} Node | ||
*/ | ||
exports.matches = matches | ||
exports.selectAll = selectAll | ||
exports.select = select | ||
import {any} from './lib/any.js' | ||
import {parse} from './lib/parse.js' | ||
var any = require('./lib/any') | ||
var parse = require('./lib/parse') | ||
function matches(selector, node) { | ||
return Boolean( | ||
any(parse(selector), node, {one: true, shallow: true, any: any})[0] | ||
) | ||
/** | ||
* @param {string} selector | ||
* @param {Node} [node] | ||
* @returns {boolean} | ||
*/ | ||
export function matches(selector, node) { | ||
return Boolean(any(parse(selector), node, {one: true, shallow: true, any})[0]) | ||
} | ||
function select(selector, node) { | ||
return any(parse(selector), node, {one: true, any: any})[0] || null | ||
/** | ||
* @param {string} selector | ||
* @param {Node} [node] | ||
* @returns {Node|null} | ||
*/ | ||
export function select(selector, node) { | ||
return any(parse(selector), node, {one: true, any})[0] || null | ||
} | ||
function selectAll(selector, node) { | ||
return any(parse(selector), node, {any: any}) | ||
/** | ||
* @param {string} selector | ||
* @param {Node} [node] | ||
* @returns {Array.<Node>} | ||
*/ | ||
export function selectAll(selector, node) { | ||
return any(parse(selector), node, {any}) | ||
} |
@@ -1,24 +0,41 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('./types.js').Selector} Selector | ||
* @typedef {import('./types.js').Selectors} Selectors | ||
* @typedef {import('./types.js').Rule} Rule | ||
* @typedef {import('./types.js').RuleSet} RuleSet | ||
* @typedef {import('./types.js').RulePseudo} RulePseudo | ||
* @typedef {import('./types.js').Query} Query | ||
* @typedef {import('./types.js').Node} Node | ||
* @typedef {import('./types.js').Parent} Parent | ||
* @typedef {import('./types.js').SelectIterator} SelectIterator | ||
* @typedef {import('./types.js').SelectState} SelectState | ||
*/ | ||
module.exports = match | ||
import {zwitch} from 'zwitch' | ||
import {nest} from './nest.js' | ||
import {pseudo} from './pseudo.js' | ||
import {test} from './test.js' | ||
import {root} from './util.js' | ||
var zwitch = require('zwitch') | ||
var pseudo = require('./pseudo') | ||
var test = require('./test') | ||
var nest = require('./nest') | ||
var type = zwitch('type', { | ||
unknown: unknownType, | ||
invalid: invalidType, | ||
handlers: { | ||
selectors: selectors, | ||
ruleSet: ruleSet, | ||
rule: rule | ||
} | ||
handlers: {selectors, ruleSet, rule} | ||
}) | ||
function match(query, node, state) { | ||
/** | ||
* @param {Selectors|RuleSet|Rule} query | ||
* @param {Node} node | ||
* @param {SelectState} state | ||
*/ | ||
export function any(query, node, state) { | ||
// @ts-ignore zwitch types are off. | ||
return query && node ? type(query, node, state) : [] | ||
} | ||
/** | ||
* @param {Selectors} query | ||
* @param {Node} node | ||
* @param {SelectState} state | ||
*/ | ||
function selectors(query, node, state) { | ||
@@ -35,2 +52,7 @@ var collect = collector(state.one) | ||
/** | ||
* @param {RuleSet} query | ||
* @param {Node} node | ||
* @param {SelectState} state | ||
*/ | ||
function ruleSet(query, node, state) { | ||
@@ -40,2 +62,7 @@ return rule(query.rule, node, state) | ||
/** | ||
* @param {Rule} query | ||
* @param {Node} tree | ||
* @param {SelectState} state | ||
*/ | ||
function rule(query, tree, state) { | ||
@@ -54,4 +81,5 @@ var collect = collector(state.one) | ||
configure(query, { | ||
scopeNodes: tree.type === 'root' ? tree.children : [tree], | ||
iterator: iterator, | ||
scopeNodes: root(tree) ? tree.children : [tree], | ||
index: false, | ||
iterator, | ||
one: state.one, | ||
@@ -65,5 +93,6 @@ shallow: state.shallow, | ||
/** @type {SelectIterator} */ | ||
function iterator(query, node, index, parent, state) { | ||
if (test(query, node, index, parent, state)) { | ||
if (query.rule) { | ||
if ('rule' in query) { | ||
nest(query.rule, node, index, parent, configure(query.rule, state)) | ||
@@ -78,2 +107,8 @@ } else { | ||
/** | ||
* @template {SelectState} S | ||
* @param {Rule} query | ||
* @param {S} state | ||
* @returns {S} | ||
*/ | ||
function configure(query, state) { | ||
@@ -84,3 +119,3 @@ var pseudos = query.pseudos || [] | ||
while (++index < pseudos.length) { | ||
if (pseudo.needsIndex.indexOf(pseudos[index].name) > -1) { | ||
if (pseudo.needsIndex.includes(pseudos[index].name)) { | ||
state.index = true | ||
@@ -94,3 +129,7 @@ break | ||
/* istanbul ignore next - Shouldn’t be invoked, all data is handled. */ | ||
// Shouldn’t be invoked, all data is handled. | ||
/* c8 ignore next 6 */ | ||
/** | ||
* @param {{[x: string]: unknown, type: string}} query | ||
*/ | ||
function unknownType(query) { | ||
@@ -100,3 +139,4 @@ throw new Error('Unknown type `' + query.type + '`') | ||
/* istanbul ignore next - Shouldn’t be invoked, parser gives correct data. */ | ||
// Shouldn’t be invoked, parser gives correct data. | ||
/* c8 ignore next 3 */ | ||
function invalidType() { | ||
@@ -106,4 +146,9 @@ throw new Error('Invalid type') | ||
/** | ||
* @param {boolean} one | ||
*/ | ||
function collector(one) { | ||
/** @type {Array.<Node>} */ | ||
var result = [] | ||
/** @type {boolean} */ | ||
var found | ||
@@ -115,3 +160,7 @@ | ||
/* Append nodes to array, filtering out duplicates. */ | ||
/** | ||
* Append nodes to array, filtering out duplicates. | ||
* | ||
* @param {Node|Array.<Node>} node | ||
*/ | ||
function collect(node) { | ||
@@ -129,5 +178,9 @@ var index = -1 | ||
/** | ||
* @param {Node} node | ||
*/ | ||
function collectOne(node) { | ||
if (one) { | ||
/* istanbul ignore if - shouldn’t happen, safeguards performance problems. */ | ||
/* Shouldn’t happen, safeguards performance problems. */ | ||
/* c8 ignore next */ | ||
if (found) throw new Error('Cannot collect multiple nodes') | ||
@@ -138,4 +191,4 @@ | ||
if (result.indexOf(node) < 0) result.push(node) | ||
if (!result.includes(node)) result.push(node) | ||
} | ||
} |
@@ -1,7 +0,9 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('./types.js').Rule} Rule | ||
* @typedef {import('./types.js').RuleAttr} RuleAttr | ||
* @typedef {import('./types.js').Node} Node | ||
*/ | ||
module.exports = match | ||
import {zwitch} from 'zwitch' | ||
var zwitch = require('zwitch') | ||
var handle = zwitch('operator', { | ||
@@ -19,8 +21,11 @@ unknown: unknownOperator, | ||
function match(query, node) { | ||
var attrs = query.attrs | ||
/** | ||
* @param {Rule} query | ||
* @param {Node} node | ||
*/ | ||
export function attribute(query, node) { | ||
var index = -1 | ||
while (++index < attrs.length) { | ||
if (!handle(attrs[index], node)) return false | ||
while (++index < query.attrs.length) { | ||
if (!handle(query.attrs[index], node)) return false | ||
} | ||
@@ -31,24 +36,38 @@ | ||
// [attr] | ||
/** | ||
* `[attr]` | ||
* | ||
* @param {RuleAttr} query | ||
* @param {Node} node | ||
*/ | ||
function exists(query, node) { | ||
return node[query.name] != null | ||
return node[query.name] !== null && node[query.name] !== undefined | ||
} | ||
// [attr=value] | ||
/** | ||
* `[attr=value]` | ||
* | ||
* @param {RuleAttr} query | ||
* @param {Node} node | ||
*/ | ||
function exact(query, node) { | ||
return node[query.name] != null && String(node[query.name]) === query.value | ||
return exists(query, node) && String(node[query.name]) === query.value | ||
} | ||
// [attr~=value] | ||
/** | ||
* `[attr~=value]` | ||
* | ||
* @param {RuleAttr} query | ||
* @param {Node} node | ||
*/ | ||
function containsArray(query, node) { | ||
var value = node[query.name] | ||
if (value == null) return false | ||
if (value === null || value === undefined) return false | ||
// If this is an array, and the query is contained in it, return true. | ||
if ( | ||
typeof value === 'object' && | ||
'length' in value && | ||
value.indexOf(query.value) > -1 | ||
) { | ||
// Coverage comment in place because TS turns `Array.isArray(unknown)` | ||
// into `Array.<any>` instead of `Array.<unknown>`. | ||
// type-coverage:ignore-next-line | ||
if (Array.isArray(value) && value.includes(query.value)) { | ||
return true | ||
@@ -61,3 +80,8 @@ } | ||
// [attr^=value] | ||
/** | ||
* `[attr^=value]` | ||
* | ||
* @param {RuleAttr} query | ||
* @param {Node} node | ||
*/ | ||
function begins(query, node) { | ||
@@ -72,3 +96,8 @@ var value = node[query.name] | ||
// [attr$=value] | ||
/** | ||
* `[attr$=value]` | ||
* | ||
* @param {RuleAttr} query | ||
* @param {Node} node | ||
*/ | ||
function ends(query, node) { | ||
@@ -83,11 +112,20 @@ var value = node[query.name] | ||
// [attr*=value] | ||
/** | ||
* `[attr*=value]` | ||
* | ||
* @param {RuleAttr} query | ||
* @param {Node} node | ||
*/ | ||
function containsString(query, node) { | ||
var value = node[query.name] | ||
return typeof value === 'string' && value.indexOf(query.value) > -1 | ||
return typeof value === 'string' && value.includes(query.value) | ||
} | ||
/* istanbul ignore next - Shouldn’t be invoked, Parser throws an error instead. */ | ||
// Shouldn’t be invoked, Parser throws an error instead. | ||
/* c8 ignore next 6 */ | ||
/** | ||
* @param {{[x: string]: unknown, type: string}} query | ||
*/ | ||
function unknownOperator(query) { | ||
throw new Error('Unknown operator `' + query.operator + '`') | ||
} |
@@ -1,7 +0,12 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('./types.js').Rule} Rule | ||
* @typedef {import('./types.js').Node} Node | ||
*/ | ||
module.exports = match | ||
function match(query, node) { | ||
/** | ||
* @param {Rule} query | ||
* @param {Node} node | ||
*/ | ||
export function name(query, node) { | ||
return query.tagName === '*' || query.tagName === node.type | ||
} |
221
lib/nest.js
@@ -1,7 +0,14 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('./types.js').Rule} Rule | ||
* @typedef {import('./types.js').Query} Query | ||
* @typedef {import('./types.js').Node} Node | ||
* @typedef {import('./types.js').Parent} Parent | ||
* @typedef {import('./types.js').SelectState} SelectState | ||
* @typedef {import('./types.js').SelectIterator} SelectIterator | ||
* @typedef {import('./types.js').Handler} Handler | ||
*/ | ||
module.exports = match | ||
import {zwitch} from 'zwitch' | ||
import {parent} from './util.js' | ||
var zwitch = require('zwitch') | ||
var own = {}.hasOwnProperty | ||
@@ -20,7 +27,12 @@ | ||
function match(query, node, index, parent, state) { | ||
/** @type {Handler} */ | ||
export function nest(query, node, index, parent, state) { | ||
return handle(query, node, index, parent, state) | ||
} | ||
/* istanbul ignore next - Shouldn’t be invoked, parser gives correct data. */ | ||
// Shouldn’t be invoked, parser gives correct data. | ||
/* c8 ignore next 6 */ | ||
/** | ||
* @param {{[x: string]: unknown, type: string}} query | ||
*/ | ||
function unknownNesting(query) { | ||
@@ -30,4 +42,6 @@ throw new Error('Unexpected nesting `' + query.nestingOperator + '`') | ||
/** @type {Handler} */ | ||
function topScan(query, node, index, parent, state) { | ||
/* istanbul ignore if - Shouldn’t happen. */ | ||
// Shouldn’t happen. | ||
/* c8 ignore next 3 */ | ||
if (parent) { | ||
@@ -37,7 +51,7 @@ throw new Error('topScan is supposed to be called from the root node') | ||
state.iterator.apply(null, arguments) | ||
if (!state.shallow) descendant.apply(this, arguments) | ||
state.iterator(query, node, index, parent, state) | ||
if (!state.shallow) descendant(query, node, index, parent, state) | ||
} | ||
/** @type {Handler} */ | ||
function descendant(query, node, index, parent, state) { | ||
@@ -47,8 +61,8 @@ var previous = state.iterator | ||
state.iterator = iterator | ||
child(query, node, index, parent, state) | ||
child.apply(this, arguments) | ||
function iterator(_, node, index, parent, state) { | ||
/** @type {SelectIterator} */ | ||
function iterator(query, node, index, parent, state) { | ||
state.iterator = previous | ||
previous.apply(this, arguments) | ||
previous(query, node, index, parent, state) | ||
state.iterator = iterator | ||
@@ -58,17 +72,21 @@ | ||
child.call(this, query, node, index, parent, state) | ||
child(query, node, index, parent, state) | ||
} | ||
} | ||
function child(query, node, index, parent, state) { | ||
if (!node.children || !node.children.length) return | ||
/** @type {Handler} */ | ||
function child(query, node, _1, _2, state) { | ||
if (!parent(node)) return | ||
if (node.children.length === 0) return | ||
walkIterator(query, node, state).each().done() | ||
new WalkIterator(query, node, state).each().done() | ||
} | ||
function adjacentSibling(query, node, index, parent, state) { | ||
/* istanbul ignore if - Shouldn’t happen. */ | ||
/** @type {Handler} */ | ||
function adjacentSibling(query, _, index, parent, state) { | ||
// Shouldn’t happen. | ||
/* c8 ignore next */ | ||
if (!parent) return | ||
walkIterator(query, parent, state) | ||
new WalkIterator(query, parent, state) | ||
.prefillTypeIndex(0, ++index) | ||
@@ -80,7 +98,9 @@ .each(index, ++index) | ||
function generalSibling(query, node, index, parent, state) { | ||
/* istanbul ignore if - Shouldn’t happen. */ | ||
/** @type {Handler} */ | ||
function generalSibling(query, _, index, parent, state) { | ||
// Shouldn’t happen. | ||
/* c8 ignore next */ | ||
if (!parent) return | ||
walkIterator(query, parent, state) | ||
new WalkIterator(query, parent, state) | ||
.prefillTypeIndex(0, ++index) | ||
@@ -91,29 +111,34 @@ .each(index) | ||
// Handles typeIndex and typeCount properties for every walker. | ||
function walkIterator(query, parent, state) { | ||
var typeIndex = state.index && createTypeIndex() | ||
var siblings = parent.children | ||
var delayed = [] | ||
return { | ||
prefillTypeIndex: rangeDefaults(prefillTypeIndex), | ||
each: rangeDefaults(each), | ||
done: done | ||
class WalkIterator { | ||
/** | ||
* Handles typeIndex and typeCount properties for every walker. | ||
* | ||
* @param {Rule} query | ||
* @param {Parent} parent | ||
* @param {SelectState} state | ||
*/ | ||
constructor(query, parent, state) { | ||
/** @type {Rule} */ | ||
this.query = query | ||
/** @type {Parent} */ | ||
this.parent = parent | ||
/** @type {SelectState} */ | ||
this.state = state | ||
/** @type {TypeIndex|undefined} */ | ||
this.typeIndex = state.index ? new TypeIndex() : undefined | ||
/** @type {Array.<Function>} */ | ||
this.delayed = [] | ||
} | ||
function done() { | ||
var index = -1 | ||
/** | ||
* @param {number|null|undefined} [x] | ||
* @param {number|null|undefined} [y] | ||
* @returns {this} | ||
*/ | ||
prefillTypeIndex(x, y) { | ||
var [start, end] = this.defaults(x, y) | ||
while (++index < delayed.length) { | ||
delayed[index]() | ||
if (state.one && state.found) break | ||
} | ||
return this | ||
} | ||
function prefillTypeIndex(start, end) { | ||
if (typeIndex) { | ||
if (this.typeIndex) { | ||
while (start < end) { | ||
typeIndex(siblings[start]) | ||
this.typeIndex.index(this.parent.children[start]) | ||
start++ | ||
@@ -126,5 +151,13 @@ } | ||
function each(start, end) { | ||
var child = siblings[start] | ||
/** | ||
* @param {number|null|undefined} [x] | ||
* @param {number|null|undefined} [y] | ||
* @returns {this} | ||
*/ | ||
each(x, y) { | ||
var [start, end] = this.defaults(x, y) | ||
var child = this.parent.children[start] | ||
/** @type {number} */ | ||
var index | ||
/** @type {number} */ | ||
var nodeIndex | ||
@@ -134,57 +167,85 @@ | ||
if (typeIndex) { | ||
nodeIndex = typeIndex.nodes | ||
index = typeIndex(child) | ||
delayed.push(delay) | ||
if (this.typeIndex) { | ||
nodeIndex = this.typeIndex.nodes | ||
index = this.typeIndex.index(child) | ||
this.delayed.push(delay) | ||
} else { | ||
state.iterator(query, child, start, parent, state) | ||
this.state.iterator(this.query, child, start, this.parent, this.state) | ||
} | ||
// Stop if we’re looking for one node and it’s already found. | ||
if (state.one && state.found) return this | ||
if (this.state.one && this.state.found) return this | ||
return each.call(this, start + 1, end) | ||
return this.each(start + 1, end) | ||
/** | ||
* @this {WalkIterator} | ||
*/ | ||
function delay() { | ||
state.typeIndex = index | ||
state.nodeIndex = nodeIndex | ||
state.typeCount = typeIndex.count(child) | ||
state.nodeCount = typeIndex.nodes | ||
state.iterator(query, child, start, parent, state) | ||
this.state.typeIndex = index | ||
this.state.nodeIndex = nodeIndex | ||
this.state.typeCount = this.typeIndex.count(child) | ||
this.state.nodeCount = this.typeIndex.nodes | ||
this.state.iterator(this.query, child, start, this.parent, this.state) | ||
} | ||
} | ||
function rangeDefaults(iterator) { | ||
return rangeDefault | ||
/** | ||
* Done! | ||
* @returns {this} | ||
*/ | ||
done() { | ||
var index = -1 | ||
function rangeDefault(start, end) { | ||
if (start == null || start < 0) start = 0 | ||
if (end == null || end > siblings.length) end = siblings.length | ||
return iterator.call(this, start, end) | ||
while (++index < this.delayed.length) { | ||
this.delayed[index].call(this) | ||
if (this.state.one && this.state.found) break | ||
} | ||
return this | ||
} | ||
/** | ||
* @param {number|null|undefined} [start] | ||
* @param {number|null|undefined} [end] | ||
* @returns {[number, number]} | ||
*/ | ||
defaults(start, end) { | ||
if (start === null || start === undefined || start < 0) start = 0 | ||
if (end === null || end === undefined || end > this.parent.children.length) | ||
end = this.parent.children.length | ||
return [start, end] | ||
} | ||
} | ||
function createTypeIndex() { | ||
var counts = {} | ||
class TypeIndex { | ||
constructor() { | ||
/** @type {Object.<string, number>} */ | ||
this.counts = {} | ||
/** @type {number} */ | ||
this.nodes = 0 | ||
} | ||
index.count = count | ||
index.nodes = 0 | ||
return index | ||
function index(node) { | ||
/** | ||
* @param {Node} node | ||
* @returns {number} | ||
*/ | ||
index(node) { | ||
var type = node.type | ||
index.nodes++ | ||
this.nodes++ | ||
if (!own.call(counts, type)) counts[type] = 0 | ||
if (!own.call(this.counts, type)) this.counts[type] = 0 | ||
// Note: `++` is intended to be postfixed! | ||
return counts[type]++ | ||
return this.counts[type]++ | ||
} | ||
function count(node) { | ||
return counts[node.type] | ||
/** | ||
* @param {Node} node | ||
* @returns {number|undefined} | ||
*/ | ||
count(node) { | ||
return this.counts[node.type] | ||
} | ||
} |
@@ -1,21 +0,27 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('./types.js').Selector} Selector | ||
* @typedef {import('./types.js').Selectors} Selectors | ||
* @typedef {import('./types.js').RuleSet} RuleSet | ||
* @typedef {import('./types.js').Rule} Rule | ||
* @typedef {import('./types.js').RulePseudo} RulePseudo | ||
* @typedef {import('./types.js').RulePseudoNth} RulePseudoNth | ||
*/ | ||
module.exports = parse | ||
import {CssSelectorParser} from 'css-selector-parser' | ||
import fauxEsmNthCheck from 'nth-check' | ||
import {zwitch} from 'zwitch' | ||
var Parser = require('css-selector-parser').CssSelectorParser | ||
var zwitch = require('zwitch') | ||
var nthCheck = require('nth-check').default | ||
/** @type {import('nth-check').default} */ | ||
// @ts-ignore | ||
var nthCheck = fauxEsmNthCheck.default | ||
var nth = ['nth-child', 'nth-last-child', 'nth-of-type', 'nth-last-of-type'] | ||
var nth = new Set([ | ||
'nth-child', | ||
'nth-last-child', | ||
'nth-of-type', | ||
'nth-last-of-type' | ||
]) | ||
var parser = new Parser() | ||
var parser = new CssSelectorParser() | ||
var compile = zwitch('type', { | ||
handlers: { | ||
selectors: selectors, | ||
ruleSet: ruleSet, | ||
rule: rule | ||
} | ||
}) | ||
parser.registerAttrEqualityMods('~', '^', '$', '*') | ||
@@ -25,3 +31,9 @@ parser.registerSelectorPseudos('any', 'matches', 'not', 'has') | ||
function parse(selector) { | ||
var compile = zwitch('type', {handlers: {selectors, ruleSet, rule}}) | ||
/** | ||
* @param {string} selector | ||
* @returns {Selector} | ||
*/ | ||
export function parse(selector) { | ||
if (typeof selector !== 'string') { | ||
@@ -31,5 +43,9 @@ throw new TypeError('Expected `string` as selector, not `' + selector + '`') | ||
// @ts-ignore types are wrong. | ||
return compile(parser.parse(selector)) | ||
} | ||
/** | ||
* @param {Selectors} query | ||
*/ | ||
function selectors(query) { | ||
@@ -46,2 +62,5 @@ var selectors = query.selectors | ||
/** | ||
* @param {RuleSet} query | ||
*/ | ||
function ruleSet(query) { | ||
@@ -51,5 +70,9 @@ return rule(query.rule) | ||
/** | ||
* @param {Rule} query | ||
*/ | ||
function rule(query) { | ||
var pseudos = query.pseudos || [] | ||
var index = -1 | ||
/** @type {RulePseudo|RulePseudoNth} */ | ||
var pseudo | ||
@@ -60,4 +83,6 @@ | ||
if (nth.indexOf(pseudo.name) > -1) { | ||
if (nth.has(pseudo.name)) { | ||
// @ts-ignore Patch a non-primitive type. | ||
pseudo.value = nthCheck(pseudo.value) | ||
// @ts-ignore Patch a non-primitive type. | ||
pseudo.valueType = 'function' | ||
@@ -64,0 +89,0 @@ } |
@@ -1,24 +0,19 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('./types.js').Rule} Rule | ||
* @typedef {import('./types.js').RulePseudo} RulePseudo | ||
* @typedef {import('./types.js').RulePseudoNth} RulePseudoNth | ||
* @typedef {import('./types.js').RulePseudoSelector} RulePseudoSelector | ||
* @typedef {import('./types.js').Parent} Parent | ||
* @typedef {import('./types.js').Selector} Selector | ||
* @typedef {import('./types.js').Selectors} Selectors | ||
* @typedef {import('./types.js').SelectState} SelectState | ||
* @typedef {import('./types.js').Node} Node | ||
*/ | ||
module.exports = match | ||
import {zwitch} from 'zwitch' | ||
import {convert} from 'unist-util-is' | ||
import {parent} from './util.js' | ||
var zwitch = require('zwitch') | ||
var not = require('not') | ||
var convert = require('unist-util-is/convert') | ||
var is = convert() | ||
match.needsIndex = [ | ||
'first-child', | ||
'first-of-type', | ||
'last-child', | ||
'last-of-type', | ||
'nth-child', | ||
'nth-last-child', | ||
'nth-of-type', | ||
'nth-last-of-type', | ||
'only-child', | ||
'only-of-type' | ||
] | ||
var handle = zwitch('name', { | ||
@@ -30,3 +25,3 @@ unknown: unknownPseudo, | ||
blank: empty, | ||
empty: empty, | ||
empty, | ||
'first-child': firstChild, | ||
@@ -37,4 +32,4 @@ 'first-of-type': firstOfType, | ||
'last-of-type': lastOfType, | ||
matches: matches, | ||
not: not(matches), | ||
matches, | ||
not, | ||
'nth-child': nthChild, | ||
@@ -46,8 +41,29 @@ 'nth-last-child': nthLastChild, | ||
'only-of-type': onlyOfType, | ||
root: root, | ||
scope: scope | ||
root, | ||
scope | ||
} | ||
}) | ||
function match(query, node, index, parent, state) { | ||
pseudo.needsIndex = [ | ||
'first-child', | ||
'first-of-type', | ||
'last-child', | ||
'last-of-type', | ||
'nth-child', | ||
'nth-last-child', | ||
'nth-of-type', | ||
'nth-last-of-type', | ||
'only-child', | ||
'only-of-type' | ||
] | ||
/** | ||
* @param {Rule} query | ||
* @param {Node} node | ||
* @param {number|null} index | ||
* @param {Parent|null} parent | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
export function pseudo(query, node, index, parent, state) { | ||
var pseudos = query.pseudos | ||
@@ -63,6 +79,14 @@ var offset = -1 | ||
function matches(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudoSelector} query | ||
* @param {Node} node | ||
* @param {number|null} _1 | ||
* @param {Parent|null} _2 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function matches(query, node, _1, _2, state) { | ||
var shallow = state.shallow | ||
var one = state.one | ||
var anything = state.any | ||
/** @type {boolean} */ | ||
var result | ||
@@ -73,3 +97,3 @@ | ||
result = anything(query.value, node, state)[0] === node | ||
result = state.any(query.value, node, state)[0] === node | ||
@@ -82,15 +106,55 @@ state.shallow = shallow | ||
function root(query, node, index, parent) { | ||
/** | ||
* @param {RulePseudoSelector} query | ||
* @param {Node} node | ||
* @param {number|null} index | ||
* @param {Parent|null} parent | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function not(query, node, index, parent, state) { | ||
return !matches(query, node, index, parent, state) | ||
} | ||
/** | ||
* @param {RulePseudo} _1 | ||
* @param {Node} node | ||
* @param {number|null} _2 | ||
* @param {Parent|null} parent | ||
* @returns {boolean} | ||
*/ | ||
function root(_1, node, _2, parent) { | ||
return is(node) && !parent | ||
} | ||
function scope(query, node, index, parent, state) { | ||
return is(node) && state.scopeNodes.indexOf(node) > -1 | ||
/** | ||
* @param {RulePseudo} _1 | ||
* @param {Node} node | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function scope(_1, node, _2, _3, state) { | ||
return is(node) && state.scopeNodes.includes(node) | ||
} | ||
function empty(query, node) { | ||
return node.children ? !node.children.length : !('value' in node) | ||
/** | ||
* @param {RulePseudo} _1 | ||
* @param {Node} node | ||
* @returns {boolean} | ||
*/ | ||
function empty(_1, node) { | ||
return parent(node) ? node.children.length === 0 : !('value' in node) | ||
} | ||
function firstChild(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudo} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function firstChild(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -100,3 +164,11 @@ return state.nodeIndex === 0 // Specifically `0`, not falsey. | ||
function lastChild(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudo} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function lastChild(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -106,3 +178,11 @@ return state.nodeIndex === state.nodeCount - 1 | ||
function onlyChild(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudo} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function onlyChild(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -112,3 +192,11 @@ return state.nodeCount === 1 | ||
function nthChild(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudoNth} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function nthChild(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -118,3 +206,11 @@ return query.value(state.nodeIndex) | ||
function nthLastChild(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudoNth} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function nthLastChild(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -124,3 +220,11 @@ return query.value(state.nodeCount - state.nodeIndex - 1) | ||
function nthOfType(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudoNth} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function nthOfType(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -130,3 +234,11 @@ return query.value(state.typeIndex) | ||
function nthLastOfType(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudoNth} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function nthLastOfType(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -136,3 +248,11 @@ return query.value(state.typeCount - 1 - state.typeIndex) | ||
function firstOfType(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudo} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function firstOfType(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -142,3 +262,11 @@ return state.typeIndex === 0 | ||
function lastOfType(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudo} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function lastOfType(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -148,3 +276,11 @@ return state.typeIndex === state.typeCount - 1 | ||
function onlyOfType(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudo} query | ||
* @param {Node} _1 | ||
* @param {number|null} _2 | ||
* @param {Parent|null} _3 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function onlyOfType(query, _1, _2, _3, state) { | ||
assertDeep(state, query) | ||
@@ -154,3 +290,4 @@ return state.typeCount === 1 | ||
/* istanbul ignore next - Shouldn’t be invoked, parser gives correct data. */ | ||
// Shouldn’t be invoked, parser gives correct data. | ||
/* c8 ignore next 3 */ | ||
function invalidPseudo() { | ||
@@ -160,2 +297,6 @@ throw new Error('Invalid pseudo-selector') | ||
/** | ||
* @param {RulePseudo} query | ||
* @returns {boolean} | ||
*/ | ||
function unknownPseudo(query) { | ||
@@ -169,2 +310,6 @@ if (query.name) { | ||
/** | ||
* @param {SelectState} state | ||
* @param {RulePseudo|RulePseudoNth} query | ||
*/ | ||
function assertDeep(state, query) { | ||
@@ -176,3 +321,11 @@ if (state.shallow) { | ||
function hasSelector(query, node, index, parent, state) { | ||
/** | ||
* @param {RulePseudoSelector} query | ||
* @param {Node} node | ||
* @param {number|null} _1 | ||
* @param {Parent|null} _2 | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
function hasSelector(query, node, _1, _2, state) { | ||
var shallow = state.shallow | ||
@@ -183,2 +336,3 @@ var one = state.one | ||
var anything = state.any | ||
/** @type {boolean} */ | ||
var result | ||
@@ -190,3 +344,3 @@ | ||
result = anything(value, node, state)[0] | ||
result = Boolean(anything(value, node, state)[0]) | ||
@@ -200,6 +354,11 @@ state.shallow = shallow | ||
/** | ||
* @param {Selector} value | ||
*/ | ||
function appendScope(value) { | ||
/** @type {Selectors} */ | ||
var selector = | ||
value.type === 'ruleSet' ? {type: 'selectors', selectors: [value]} : value | ||
var index = -1 | ||
/** @type {Rule} */ | ||
var rule | ||
@@ -211,3 +370,5 @@ | ||
/* istanbul ignore else - needed if new pseudo’s are added that accepts commas (such as, `:lang(en, nl)`) */ | ||
// Needed if new pseudo’s are added that accepts commas (such as | ||
// `:lang(en, nl)`) | ||
/* c8 ignore else */ | ||
if ( | ||
@@ -219,5 +380,9 @@ !rule.pseudos || | ||
selector.selectors[index] = { | ||
type: 'rule', | ||
rule: rule, | ||
pseudos: [{name: 'scope'}] | ||
type: 'ruleSet', | ||
rule: { | ||
type: 'rule', | ||
rule, | ||
// @ts-ignore pseudos are fine w/ just a name! | ||
pseudos: [{name: 'scope'}] | ||
} | ||
} | ||
@@ -224,0 +389,0 @@ } |
@@ -1,24 +0,30 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('./types.js').Rule} Rule | ||
* @typedef {import('./types.js').Node} Node | ||
* @typedef {import('./types.js').Parent} Parent | ||
* @typedef {import('./types.js').SelectState} SelectState | ||
*/ | ||
module.exports = test | ||
import {attribute} from './attribute.js' | ||
import {name} from './name.js' | ||
import {pseudo} from './pseudo.js' | ||
var name = require('./name') | ||
var attributes = require('./attribute') | ||
var pseudos = require('./pseudo') | ||
/** | ||
* @param {Rule} query | ||
* @param {Node} node | ||
* @param {number|null} index | ||
* @param {Parent|null} parent | ||
* @param {SelectState} state | ||
* @returns {boolean} | ||
*/ | ||
export function test(query, node, index, parent, state) { | ||
if (query.id) throw new Error('Invalid selector: id') | ||
if (query.classNames) throw new Error('Invalid selector: class') | ||
function test(query, node, index, parent, state) { | ||
if (query.id) { | ||
throw new Error('Invalid selector: id') | ||
} | ||
if (query.classNames) { | ||
throw new Error('Invalid selector: class') | ||
} | ||
return Boolean( | ||
node && | ||
(!query.tagName || name(query, node)) && | ||
(!query.attrs || attributes(query, node)) && | ||
(!query.pseudos || pseudos(query, node, index, parent, state)) | ||
(!query.attrs || attribute(query, node)) && | ||
(!query.pseudos || pseudo(query, node, index, parent, state)) | ||
) | ||
} |
{ | ||
"name": "unist-util-select", | ||
"version": "3.0.4", | ||
"version": "4.0.0", | ||
"description": "unist utility to select nodes with CSS-like selectors", | ||
@@ -41,38 +41,38 @@ "license": "MIT", | ||
], | ||
"sideEffects": false, | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"files": [ | ||
"index.js", | ||
"lib/", | ||
"types/index.d.ts" | ||
"index.d.ts", | ||
"index.js" | ||
], | ||
"types": "types/index.d.ts", | ||
"dependencies": { | ||
"css-selector-parser": "^1.0.0", | ||
"not": "^0.1.0", | ||
"nth-check": "^2.0.0", | ||
"unist-util-is": "^4.0.0", | ||
"zwitch": "^1.0.0" | ||
"unist-util-is": "^5.0.0", | ||
"zwitch": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"dtslint": "^4.0.0", | ||
"nyc": "^15.0.0", | ||
"@types/tape": "^4.0.0", | ||
"c8": "^7.0.0", | ||
"prettier": "^2.0.0", | ||
"remark-cli": "^9.0.0", | ||
"remark-preset-wooorm": "^8.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"unist-builder": "^2.0.0", | ||
"xo": "^0.36.0" | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"unist-builder": "^3.0.0", | ||
"xo": "^0.38.0" | ||
}, | ||
"scripts": { | ||
"prepack": "npm run build && npm run format", | ||
"build": "rimraf \"{lib/**,test/**,}*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"test-api": "node test", | ||
"test-coverage": "nyc --reporter lcov tape test/index.js", | ||
"test-types": "dtslint types", | ||
"test": "npm run format && npm run test-coverage && npm run test-types" | ||
"test-api": "node test/index.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test/index.js", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
}, | ||
"nyc": { | ||
"check-coverage": true, | ||
"lines": 100, | ||
"functions": 100, | ||
"branches": 100 | ||
}, | ||
"prettier": { | ||
@@ -88,19 +88,7 @@ "tabWidth": 2, | ||
"prettier": true, | ||
"esnext": false, | ||
"ignore": [ | ||
"types" | ||
], | ||
"rules": { | ||
"eqeqeq": [ | ||
"error", | ||
"always", | ||
{ | ||
"null": "ignore" | ||
} | ||
], | ||
"no-eq-null": "off", | ||
"no-var": "off", | ||
"prefer-arrow-callback": "off", | ||
"max-params": "off", | ||
"unicorn/explicit-length-check": "off", | ||
"unicorn/prefer-includes": "off", | ||
"unicorn/prefer-reflect-apply": "off" | ||
"unicorn/no-array-for-each": "off" | ||
} | ||
@@ -112,3 +100,8 @@ }, | ||
] | ||
}, | ||
"typeCoverage": { | ||
"atLeast": 100, | ||
"detail": true, | ||
"strict": true | ||
} | ||
} |
@@ -22,2 +22,5 @@ # unist-util-select | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
[npm][]: | ||
@@ -31,4 +34,7 @@ | ||
### `select.matches(selector, node)` | ||
This package exports the following identifiers: `matches`, `select`, `selectAll`. | ||
There is no default export. | ||
### `matches(selector, node)` | ||
Check that the given [node][] matches `selector`. | ||
@@ -43,4 +49,4 @@ Returns `boolean`, whether the node matches or not. | ||
```js | ||
var u = require('unist-builder') | ||
var matches = require('unist-util-select').matches | ||
import {u} from 'unist-builder' | ||
import {matches} from 'unist-util-select' | ||
@@ -51,3 +57,3 @@ matches('strong, em', u('strong', [u('text', 'important')])) // => true | ||
### `select.select(selector, tree)` | ||
### `select(selector, tree)` | ||
@@ -59,4 +65,4 @@ Select the first node matching `selector` in the given `tree` (could be the | ||
```js | ||
var u = require('unist-builder') | ||
var select = require('unist-util-select').select | ||
import {u} from 'unist-builder' | ||
import {select} from 'unist-util-select' | ||
@@ -83,3 +89,3 @@ console.log( | ||
### `select.selectAll(selector, tree)` | ||
### `selectAll(selector, tree)` | ||
@@ -91,4 +97,4 @@ Select all nodes matching `selector` in the given `tree` (could include the | ||
```js | ||
var u = require('unist-builder') | ||
var selectAll = require('unist-util-select').selectAll | ||
import {u} from 'unist-builder' | ||
import {selectAll} from 'unist-util-select' | ||
@@ -95,0 +101,0 @@ console.log( |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45741
4
23
1264
240
Yes
11
1
+ Added@types/unist@2.0.11(transitive)
+ Addedunist-util-is@5.2.1(transitive)
+ Addedzwitch@2.0.4(transitive)
- Removednot@^0.1.0
- Removednot@0.1.0(transitive)
- Removedunist-util-is@4.1.0(transitive)
- Removedzwitch@1.0.5(transitive)
Updatedunist-util-is@^5.0.0
Updatedzwitch@^2.0.0