diff --git a/.github/workflows/bb.yml b/.github/workflows/bb.yml index 291ab09..0198fc3 100644 --- a/.github/workflows/bb.yml +++ b/.github/workflows/bb.yml @@ -2,7 +2,7 @@ name: bb on: issues: types: [opened, reopened, edited, closed, labeled, unlabeled] - pull_request: + pull_request_target: types: [opened, reopened, edited, closed, labeled, unlabeled] jobs: main: diff --git a/lib/any.js b/lib/any.js index a1f9df0..2ceb1ff 100644 --- a/lib/any.js +++ b/lib/any.js @@ -17,19 +17,22 @@ import {pseudo} from './pseudo.js' import {test} from './test.js' import {root} from './util.js' -var type = zwitch('type', { +const type = zwitch('type', { + // @ts-expect-error: hush. unknown: unknownType, invalid: invalidType, + // @ts-expect-error: hush. handlers: {selectors, ruleSet, rule} }) /** * @param {Selectors|RuleSet|Rule} query - * @param {Node} node + * @param {Node|undefined} node * @param {SelectState} state + * @returns {Array.} */ export function any(query, node, state) { - // @ts-ignore zwitch types are off. + // @ts-expect-error: fine. return query && node ? type(query, node, state) : [] } @@ -39,8 +42,8 @@ export function any(query, node, state) { * @param {SelectState} state */ function selectors(query, node, state) { - var collect = collector(state.one) - var index = -1 + const collect = collector(state.one) + let index = -1 while (++index < query.selectors.length) { collect(ruleSet(query.selectors[index], node, state)) @@ -64,7 +67,7 @@ function ruleSet(query, node, state) { * @param {SelectState} state */ function rule(query, tree, state) { - var collect = collector(state.one) + const collect = collector(state.one) if (state.shallow && query.rule) { throw new Error('Expected selector without nesting') @@ -90,7 +93,7 @@ function rule(query, tree, state) { /** @type {SelectIterator} */ function iterator(query, node, index, parent, state) { if (test(query, node, index, parent, state)) { - if ('rule' in query) { + if (query.rule) { nest(query.rule, node, index, parent, configure(query.rule, state)) } else { collect(node) @@ -107,8 +110,8 @@ function rule(query, tree, state) { * @returns {S} */ function configure(query, state) { - var pseudos = query.pseudos || [] - var index = -1 + const pseudos = query.pseudos || [] + let index = -1 while (++index < pseudos.length) { if (pseudo.needsIndex.includes(pseudos[index].name)) { @@ -136,13 +139,13 @@ function invalidType() { } /** - * @param {boolean} one + * @param {boolean|undefined} one */ function collector(one) { /** @type {Array.} */ - var result = [] + const result = [] /** @type {boolean} */ - var found + let found collect.result = result @@ -154,7 +157,7 @@ function collector(one) { * @param {Node|Array.} node */ function collect(node) { - var index = -1 + let index = -1 if ('length' in node) { while (++index < node.length) { diff --git a/lib/attribute.js b/lib/attribute.js index 124c56b..ec9f173 100644 --- a/lib/attribute.js +++ b/lib/attribute.js @@ -6,14 +6,21 @@ import {zwitch} from 'zwitch' -var handle = zwitch('operator', { +const handle = zwitch('operator', { + // @ts-expect-error: hush. unknown: unknownOperator, + // @ts-expect-error: hush. invalid: exists, handlers: { + // @ts-expect-error: hush. '=': exact, + // @ts-expect-error: hush. '^=': begins, + // @ts-expect-error: hush. '$=': ends, + // @ts-expect-error: hush. '*=': containsString, + // @ts-expect-error: hush. '~=': containsArray } }) @@ -23,7 +30,7 @@ var handle = zwitch('operator', { * @param {Node} node */ export function attribute(query, node) { - var index = -1 + let index = -1 while (++index < query.attrs.length) { if (!handle(query.attrs[index], node)) return false @@ -39,6 +46,7 @@ export function attribute(query, node) { * @param {Node} node */ function exists(query, node) { + // @ts-expect-error: Looks like a record. return node[query.name] !== null && node[query.name] !== undefined } @@ -49,6 +57,7 @@ function exists(query, node) { * @param {Node} node */ function exact(query, node) { + // @ts-expect-error: Looks like a record. return exists(query, node) && String(node[query.name]) === query.value } @@ -59,7 +68,9 @@ function exact(query, node) { * @param {Node} node */ function containsArray(query, node) { - var value = node[query.name] + /** @type {unknown} */ + // @ts-expect-error: Looks like a record. + const value = node[query.name] if (value === null || value === undefined) return false @@ -82,9 +93,12 @@ function containsArray(query, node) { * @param {Node} node */ function begins(query, node) { - var value = node[query.name] + /** @type {unknown} */ + // @ts-expect-error: Looks like a record. + const value = node[query.name] return ( + query.value && typeof value === 'string' && value.slice(0, query.value.length) === query.value ) @@ -97,9 +111,12 @@ function begins(query, node) { * @param {Node} node */ function ends(query, node) { - var value = node[query.name] + /** @type {unknown} */ + // @ts-expect-error: Looks like a record. + const value = node[query.name] return ( + query.value && typeof value === 'string' && value.slice(-query.value.length) === query.value ) @@ -112,8 +129,10 @@ function ends(query, node) { * @param {Node} node */ function containsString(query, node) { - var value = node[query.name] - return typeof value === 'string' && value.includes(query.value) + /** @type {unknown} */ + // @ts-expect-error: Looks like a record. + const value = node[query.name] + return query.value && typeof value === 'string' && value.includes(query.value) } // Shouldn’t be invoked, Parser throws an error instead. diff --git a/lib/nest.js b/lib/nest.js index 87221e6..fb3c905 100644 --- a/lib/nest.js +++ b/lib/nest.js @@ -11,23 +11,27 @@ import {zwitch} from 'zwitch' import {parent} from './util.js' -var own = {}.hasOwnProperty +const own = {}.hasOwnProperty -var handle = zwitch('nestingOperator', { +const handle = zwitch('nestingOperator', { + // @ts-expect-error: hush. unknown: unknownNesting, + // @ts-expect-error: hush. invalid: topScan, // `undefined` is the top query selector. handlers: { + // @ts-expect-error: hush. null: descendant, // `null` is the descendant combinator. + // @ts-expect-error: hush. '>': child, + // @ts-expect-error: hush. '+': adjacentSibling, + // @ts-expect-error: hush. '~': generalSibling } }) /** @type {Handler} */ -export function nest(query, node, index, parent, state) { - return handle(query, node, index, parent, state) -} +export const nest = handle // Shouldn’t be invoked, parser gives correct data. /* c8 ignore next 6 */ @@ -41,18 +45,34 @@ function unknownNesting(query) { /** @type {Handler} */ function topScan(query, node, index, parent, state) { // Shouldn’t happen. - /* c8 ignore next 3 */ + /* c8 ignore next 7 */ if (parent) { throw new Error('topScan is supposed to be called from the root node') } + if (!state.iterator) { + throw new Error('Expected `iterator` to be defined') + } + + // Shouldn’t happen. + /* c8 ignore next 3 */ + if (typeof index !== 'number') { + throw new TypeError('Expected `index` to be defined') + } + 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) { - var previous = state.iterator + // Shouldn’t happen. + /* c8 ignore next 3 */ + if (!state.iterator) { + throw new Error('Expected `iterator` to be defined') + } + + const previous = state.iterator state.iterator = iterator child(query, node, index, parent, state) @@ -79,6 +99,12 @@ function child(query, node, _1, _2, state) { /** @type {Handler} */ function adjacentSibling(query, _, index, parent, state) { + // Shouldn’t happen. + /* c8 ignore next 3 */ + if (typeof index !== 'number') { + throw new TypeError('Expected `index` to be defined') + } + // Shouldn’t happen. /* c8 ignore next */ if (!parent) return @@ -92,6 +118,12 @@ function adjacentSibling(query, _, index, parent, state) { /** @type {Handler} */ function generalSibling(query, _, index, parent, state) { + // Shouldn’t happen. + /* c8 ignore next 3 */ + if (typeof index !== 'number') { + throw new TypeError('Expected `index` to be defined') + } + // Shouldn’t happen. /* c8 ignore next */ if (!parent) return @@ -129,7 +161,7 @@ class WalkIterator { * @returns {this} */ prefillTypeIndex(x, y) { - var [start, end] = this.defaults(x, y) + let [start, end] = this.defaults(x, y) if (this.typeIndex) { while (start < end) { @@ -147,12 +179,12 @@ class WalkIterator { * @returns {this} */ each(x, y) { - var [start, end] = this.defaults(x, y) - var child = this.parent.children[start] + const [start, end] = this.defaults(x, y) + const child = this.parent.children[start] /** @type {number} */ - var index + let index /** @type {number} */ - var nodeIndex + let nodeIndex if (start >= end) return this @@ -161,6 +193,12 @@ class WalkIterator { index = this.typeIndex.index(child) this.delayed.push(delay) } else { + // Shouldn’t happen. + /* c8 ignore next 3 */ + if (!this.state.iterator) { + throw new Error('Expected `iterator` to be defined') + } + this.state.iterator(this.query, child, start, this.parent, this.state) } @@ -173,6 +211,18 @@ class WalkIterator { * @this {WalkIterator} */ function delay() { + // Shouldn’t happen. + /* c8 ignore next 3 */ + if (!this.typeIndex) { + throw new TypeError('Expected `typeIndex` to be defined') + } + + // Shouldn’t happen. + /* c8 ignore next 3 */ + if (!this.state.iterator) { + throw new Error('Expected `iterator` to be defined') + } + this.state.typeIndex = index this.state.nodeIndex = nodeIndex this.state.typeCount = this.typeIndex.count(child) @@ -186,7 +236,7 @@ class WalkIterator { * @returns {this} */ done() { - var index = -1 + let index = -1 while (++index < this.delayed.length) { this.delayed[index].call(this) @@ -222,7 +272,7 @@ class TypeIndex { * @returns {number} */ index(node) { - var type = node.type + const type = node.type this.nodes++ diff --git a/lib/parse.js b/lib/parse.js index 2ada1d6..738e7c5 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -12,23 +12,24 @@ import fauxEsmNthCheck from 'nth-check' import {zwitch} from 'zwitch' /** @type {import('nth-check').default} */ -// @ts-ignore -var nthCheck = fauxEsmNthCheck.default +// @ts-expect-error +const nthCheck = fauxEsmNthCheck.default -var nth = new Set([ +const nth = new Set([ 'nth-child', 'nth-last-child', 'nth-of-type', 'nth-last-of-type' ]) -var parser = new CssSelectorParser() +const parser = new CssSelectorParser() parser.registerAttrEqualityMods('~', '^', '$', '*') parser.registerSelectorPseudos('any', 'matches', 'not', 'has') parser.registerNestingOperators('>', '+', '~') -var compile = zwitch('type', {handlers: {selectors, ruleSet, rule}}) +// @ts-expect-error: hush. +const compile = zwitch('type', {handlers: {selectors, ruleSet, rule}}) /** * @param {string} selector @@ -39,7 +40,7 @@ export function parse(selector) { throw new TypeError('Expected `string` as selector, not `' + selector + '`') } - // @ts-ignore types are wrong. + // @ts-expect-error types are wrong. return compile(parser.parse(selector)) } @@ -47,8 +48,8 @@ export function parse(selector) { * @param {Selectors} query */ function selectors(query) { - var selectors = query.selectors - var index = -1 + const selectors = query.selectors + let index = -1 while (++index < selectors.length) { compile(selectors[index]) @@ -68,18 +69,18 @@ function ruleSet(query) { * @param {Rule} query */ function rule(query) { - var pseudos = query.pseudos || [] - var index = -1 + const pseudos = query.pseudos || [] + let index = -1 /** @type {RulePseudo|RulePseudoNth} */ - var pseudo + let pseudo while (++index < pseudos.length) { pseudo = pseudos[index] if (nth.has(pseudo.name)) { - // @ts-ignore Patch a non-primitive type. + // @ts-expect-error Patch a non-primitive type. pseudo.value = nthCheck(pseudo.value) - // @ts-ignore Patch a non-primitive type. + // @ts-expect-error Patch a non-primitive type. pseudo.valueType = 'function' } } diff --git a/lib/pseudo.js b/lib/pseudo.js index 55f5536..134ab91 100644 --- a/lib/pseudo.js +++ b/lib/pseudo.js @@ -14,29 +14,48 @@ import {zwitch} from 'zwitch' import {convert} from 'unist-util-is' import {parent} from './util.js' -var is = convert() +const is = convert() -var handle = zwitch('name', { +const handle = zwitch('name', { + // @ts-expect-error: hush. unknown: unknownPseudo, invalid: invalidPseudo, handlers: { + // @ts-expect-error: hush. any: matches, + // @ts-expect-error: hush. blank: empty, + // @ts-expect-error: hush. empty, + // @ts-expect-error: hush. 'first-child': firstChild, + // @ts-expect-error: hush. 'first-of-type': firstOfType, + // @ts-expect-error: hush. has: hasSelector, + // @ts-expect-error: hush. 'last-child': lastChild, + // @ts-expect-error: hush. 'last-of-type': lastOfType, + // @ts-expect-error: hush. matches, + // @ts-expect-error: hush. not, + // @ts-expect-error: hush. 'nth-child': nthChild, + // @ts-expect-error: hush. 'nth-last-child': nthLastChild, + // @ts-expect-error: hush. 'nth-of-type': nthOfType, + // @ts-expect-error: hush. 'nth-last-of-type': nthLastOfType, + // @ts-expect-error: hush. 'only-child': onlyChild, + // @ts-expect-error: hush. 'only-of-type': onlyOfType, + // @ts-expect-error: hush. root, + // @ts-expect-error: hush. scope } }) @@ -63,8 +82,8 @@ pseudo.needsIndex = [ * @returns {boolean} */ export function pseudo(query, node, index, parent, state) { - var pseudos = query.pseudos - var offset = -1 + const pseudos = query.pseudos + let offset = -1 while (++offset < pseudos.length) { if (!handle(pseudos[offset], node, index, parent, state)) return false @@ -82,15 +101,13 @@ export function pseudo(query, node, index, parent, state) { * @returns {boolean} */ function matches(query, node, _1, _2, state) { - var shallow = state.shallow - var one = state.one - /** @type {boolean} */ - var result + const shallow = state.shallow + const one = state.one state.one = true state.shallow = true - result = state.any(query.value, node, state)[0] === node + const result = state.any(query.value, node, state)[0] === node state.shallow = shallow state.one = one @@ -130,7 +147,11 @@ function root(_1, node, _2, parent) { * @returns {boolean} */ function scope(_1, node, _2, _3, state) { - return is(node) && state.scopeNodes.includes(node) + return ( + is(node) && + state.scopeNodes !== undefined && + state.scopeNodes.includes(node) + ) } /** @@ -165,7 +186,10 @@ function firstChild(query, _1, _2, _3, state) { */ function lastChild(query, _1, _2, _3, state) { assertDeep(state, query) - return state.nodeIndex === state.nodeCount - 1 + return ( + typeof state.nodeCount === 'number' && + state.nodeIndex === state.nodeCount - 1 + ) } /** @@ -191,7 +215,7 @@ function onlyChild(query, _1, _2, _3, state) { */ function nthChild(query, _1, _2, _3, state) { assertDeep(state, query) - return query.value(state.nodeIndex) + return typeof state.nodeIndex === 'number' && query.value(state.nodeIndex) } /** @@ -204,7 +228,11 @@ function nthChild(query, _1, _2, _3, state) { */ function nthLastChild(query, _1, _2, _3, state) { assertDeep(state, query) - return query.value(state.nodeCount - state.nodeIndex - 1) + return ( + typeof state.nodeCount === 'number' && + typeof state.nodeIndex === 'number' && + query.value(state.nodeCount - state.nodeIndex - 1) + ) } /** @@ -217,7 +245,7 @@ function nthLastChild(query, _1, _2, _3, state) { */ function nthOfType(query, _1, _2, _3, state) { assertDeep(state, query) - return query.value(state.typeIndex) + return typeof state.typeIndex === 'number' && query.value(state.typeIndex) } /** @@ -230,7 +258,11 @@ function nthOfType(query, _1, _2, _3, state) { */ function nthLastOfType(query, _1, _2, _3, state) { assertDeep(state, query) - return query.value(state.typeCount - 1 - state.typeIndex) + return ( + typeof state.typeIndex === 'number' && + typeof state.typeCount === 'number' && + query.value(state.typeCount - 1 - state.typeIndex) + ) } /** @@ -256,7 +288,10 @@ function firstOfType(query, _1, _2, _3, state) { */ function lastOfType(query, _1, _2, _3, state) { assertDeep(state, query) - return state.typeIndex === state.typeCount - 1 + return ( + typeof state.typeCount === 'number' && + state.typeIndex === state.typeCount - 1 + ) } /** @@ -309,19 +344,17 @@ function assertDeep(state, query) { * @returns {boolean} */ function hasSelector(query, node, _1, _2, state) { - var shallow = state.shallow - var one = state.one - var scopeNodes = state.scopeNodes - var value = appendScope(query.value) - var anything = state.any - /** @type {boolean} */ - var result + const shallow = state.shallow + const one = state.one + const scopeNodes = state.scopeNodes + const value = appendScope(query.value) + const anything = state.any state.shallow = false state.one = true state.scopeNodes = [node] - result = Boolean(anything(value, node, state)[0]) + const result = Boolean(anything(value, node, state)[0]) state.shallow = shallow state.one = one @@ -335,11 +368,11 @@ function hasSelector(query, node, _1, _2, state) { */ function appendScope(value) { /** @type {Selectors} */ - var selector = + const selector = value.type === 'ruleSet' ? {type: 'selectors', selectors: [value]} : value - var index = -1 + let index = -1 /** @type {Rule} */ - var rule + let rule while (++index < selector.selectors.length) { rule = selector.selectors[index].rule @@ -358,7 +391,7 @@ function appendScope(value) { rule: { type: 'rule', rule, - // @ts-ignore pseudos are fine w/ just a name! + // @ts-expect-error pseudos are fine w/ just a name! pseudos: [{name: 'scope'}] } } diff --git a/lib/types.js b/lib/types.js index 1d5fb2f..0f92669 100644 --- a/lib/types.js +++ b/lib/types.js @@ -30,9 +30,9 @@ * @typedef {import('unist').Parent} Parent * * @typedef {Object} SelectState - * @property {(query: Query, node: Node, state: SelectState) => Node[]} any + * @property {(query: Selectors|RuleSet|Rule, node: Node|undefined, state: SelectState) => Node[]} any * @property {Array.} [scopeNodes] - * @property {SelectIterator} [iterator] + * @property {SelectIterator|null|undefined} [iterator] * @property {boolean} [one=false] * @property {boolean} [shallow=false] * @property {boolean} [index=false] diff --git a/lib/util.js b/lib/util.js index 49a92ff..4986750 100644 --- a/lib/util.js +++ b/lib/util.js @@ -29,5 +29,6 @@ export function root(node) { * @returns {node is Parent} */ export function parent(node) { + // @ts-expect-error: looks like a record. return Array.isArray(node.children) } diff --git a/package.json b/package.json index 25dd667..cb52a38 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "unist-util-select", - "version": "4.0.0", + "version": "4.0.1", "description": "unist utility to select nodes with CSS-like selectors", "license": "MIT", "keywords": [ @@ -48,6 +48,7 @@ "index.js" ], "dependencies": { + "@types/unist": "^2.0.0", "css-selector-parser": "^1.0.0", "nth-check": "^2.0.0", "unist-util-is": "^5.0.0", @@ -57,14 +58,14 @@ "@types/tape": "^4.0.0", "c8": "^7.0.0", "prettier": "^2.0.0", - "remark-cli": "^9.0.0", - "remark-preset-wooorm": "^8.0.0", + "remark-cli": "^10.0.0", + "remark-preset-wooorm": "^9.0.0", "rimraf": "^3.0.0", "tape": "^5.0.0", "type-coverage": "^2.0.0", "typescript": "^4.0.0", "unist-builder": "^3.0.0", - "xo": "^0.38.0" + "xo": "^0.46.0" }, "scripts": { "prepack": "npm run build && npm run format", @@ -85,10 +86,7 @@ "xo": { "prettier": true, "rules": { - "no-var": "off", - "prefer-arrow-callback": "off", - "max-params": "off", - "unicorn/no-array-for-each": "off" + "max-params": "off" } }, "remarkConfig": { diff --git a/test/all.js b/test/all.js index 7d6ce9c..edeb4f8 100644 --- a/test/all.js +++ b/test/all.js @@ -2,7 +2,7 @@ import test from 'tape' import {u} from 'unist-builder' import {selectAll} from '../index.js' -test('all together now', function (t) { +test('all together now', (t) => { t.deepEqual( selectAll( 'a > b[d]:nth-of-type(odd)', diff --git a/test/matches.js b/test/matches.js index 9c79128..3793b53 100644 --- a/test/matches.js +++ b/test/matches.js @@ -1,12 +1,16 @@ +/** + * @typedef {import('unist').Literal} Literal + */ + import test from 'tape' import {u} from 'unist-builder' import {matches} from '../index.js' -test('select.matches()', function (t) { - t.test('invalid selector', function (st) { +test('select.matches()', (t) => { + t.test('invalid selector', (st) => { st.throws( - function () { - // @ts-ignore runtime. + () => { + // @ts-expect-error runtime. matches() }, /Error: Expected `string` as selector, not `undefined`/, @@ -14,8 +18,8 @@ test('select.matches()', function (t) { ) st.throws( - function () { - // @ts-ignore runtime. + () => { + // @ts-expect-error runtime. matches([], u('root', [])) }, /Error: Expected `string` as selector, not ``/, @@ -23,7 +27,7 @@ test('select.matches()', function (t) { ) st.throws( - function () { + () => { matches('@supports (transform-origin: 5% 5%) {}', u('root', [])) }, /Error: Rule expected but "@" found./, @@ -31,7 +35,7 @@ test('select.matches()', function (t) { ) st.throws( - function () { + () => { matches('[foo%=bar]', u('root', [])) }, /Error: Expected "=" but "%" found./, @@ -39,7 +43,7 @@ test('select.matches()', function (t) { ) st.throws( - function () { + () => { matches(':active', u('root', [])) }, /Error: Unknown pseudo-selector `active`/, @@ -47,7 +51,7 @@ test('select.matches()', function (t) { ) st.throws( - function () { + () => { matches(':nth-foo(2n+1)', u('root', [])) }, /Error: Unknown pseudo-selector `nth-foo`/, @@ -55,7 +59,7 @@ test('select.matches()', function (t) { ) st.throws( - function () { + () => { matches('::before', u('root', [])) }, /Error: Unexpected pseudo-element or empty pseudo-class/, @@ -63,7 +67,7 @@ test('select.matches()', function (t) { ) st.throws( - function () { + () => { matches('foo bar', u('root', [])) }, /Error: Expected selector without nesting/, @@ -71,7 +75,7 @@ test('select.matches()', function (t) { ) st.throws( - function () { + () => { matches('foo > bar', u('root', [])) }, /Error: Expected selector without nesting/, @@ -81,8 +85,8 @@ test('select.matches()', function (t) { st.end() }) - t.test('parent-sensitive pseudo-selectors', function (st) { - var simplePseudos = [ + t.test('parent-sensitive pseudo-selectors', (st) => { + const simplePseudos = [ 'first-child', 'first-of-type', 'last-child', @@ -91,37 +95,45 @@ test('select.matches()', function (t) { 'only-of-type' ] - var functionalPseudos = [ + const functionalPseudos = [ 'nth-child', 'nth-last-child', 'nth-of-type', 'nth-last-of-type' ] - simplePseudos.forEach(function (pseudo) { + let index = -1 + + while (++index < simplePseudos.length) { + const pseudo = simplePseudos[index] + st.throws( - function () { + () => { matches(':' + pseudo, u('root', [])) }, new RegExp('Error: Cannot use `:' + pseudo + '` without parent'), 'should throw on `' + pseudo + '`' ) - }) + } + + index = -1 + + while (++index < functionalPseudos.length) { + const pseudo = functionalPseudos[index] - functionalPseudos.forEach(function (pseudo) { st.throws( - function () { + () => { matches(':' + pseudo + '()', u('root', [])) }, - new RegExp('Error: Cannot use `:' + pseudo + '` without parent'), + /n-th rule couldn't be parsed/, 'should throw on `' + pseudo + '()`' ) - }) + } st.end() }) - t.test('general', function (st) { + t.test('general', (st) => { st.notOk( matches('', u('root', [])), 'false for the empty string as selector' @@ -131,19 +143,22 @@ test('select.matches()', function (t) { 'false for a white-space only selector' ) st.notOk(matches('*'), 'false if not given a node') - st.ok(matches('*', {type: 'text', value: 'a'}), 'true if given an node') + st.ok( + matches('*', /** @type {Literal} */ ({type: 'text', value: 'a'})), + 'true if given an node' + ) st.end() }) - t.test('multiple selectors', function (st) { + t.test('multiple selectors', (st) => { st.ok(matches('a, b', u('a')), 'true') st.notOk(matches('b, c', u('a')), 'false') st.end() }) - t.test('tag-names: `div`, `*`', function (st) { + t.test('tag-names: `div`, `*`', (st) => { st.ok(matches('*', u('a')), 'true for `*`') st.ok(matches('b', u('b')), 'true if types matches') st.notOk(matches('b', u('a')), 'false if types don’t matches') @@ -151,9 +166,9 @@ test('select.matches()', function (t) { st.end() }) - t.test('id: `#id`', function (st) { + t.test('id: `#id`', (st) => { st.throws( - function () { + () => { matches('#one', u('a')) }, /Error: Invalid selector: id/, @@ -163,9 +178,9 @@ test('select.matches()', function (t) { st.end() }) - t.test('class: `.class`', function (st) { + t.test('class: `.class`', (st) => { st.throws( - function () { + () => { matches('.one', u('a')) }, /Error: Invalid selector: class/, @@ -175,7 +190,7 @@ test('select.matches()', function (t) { st.end() }) - t.test('attributes, existence: `[attr]`', function (st) { + t.test('attributes, existence: `[attr]`', (st) => { st.ok( matches('[foo]', u('a', {foo: 'alpha'})), 'true if attribute exists (string)' @@ -208,7 +223,7 @@ test('select.matches()', function (t) { st.end() }) - t.test('attributes, equality: `[attr=value]`', function (st) { + t.test('attributes, equality: `[attr=value]`', (st) => { st.ok( matches('[foo=alpha]', u('a', {foo: 'alpha'})), 'true if attribute matches (string)' @@ -270,7 +285,7 @@ test('select.matches()', function (t) { st.end() }) - t.test('attributes, begins: `[attr^=value]`', function (st) { + t.test('attributes, begins: `[attr^=value]`', (st) => { st.ok( matches('[foo^=al]', u('a', {foo: 'alpha'})), 'true if attribute matches (string)' @@ -300,7 +315,7 @@ test('select.matches()', function (t) { st.end() }) - t.test('attributes, ends: `[attr$=value]`', function (st) { + t.test('attributes, ends: `[attr$=value]`', (st) => { st.ok( matches('[foo$=ha]', u('a', {foo: 'alpha'})), 'true if attribute matches (string)' @@ -330,7 +345,7 @@ test('select.matches()', function (t) { st.end() }) - t.test('attributes, contains: `[attr*=value]`', function (st) { + t.test('attributes, contains: `[attr*=value]`', (st) => { st.ok( matches('[foo*=ph]', u('a', {foo: 'alpha'})), 'true if attribute matches (string)' @@ -359,7 +374,7 @@ test('select.matches()', function (t) { st.end() }) - t.test('attributes, contains in a list: `[attr~=value]`', function (st) { + t.test('attributes, contains in a list: `[attr~=value]`', (st) => { st.ok( matches('[foo~=alpha]', u('a', {foo: 'alpha'})), 'true if attribute matches (string)' @@ -437,9 +452,14 @@ test('select.matches()', function (t) { st.end() }) - t.test('pseudo-classes', function (st) { - ;[':any', ':matches'].forEach(function (pseudo) { - st.test(pseudo, function (sst) { + t.test('pseudo-classes', (st) => { + const anyMatchesPseudos = [':any', ':matches'] + let index = -1 + + while (++index < anyMatchesPseudos.length) { + const pseudo = anyMatchesPseudos[index] + + st.test(pseudo, (sst) => { sst.ok( matches(pseudo + '(a, [b])', u('a')), 'true if any matches (type)' @@ -459,9 +479,9 @@ test('select.matches()', function (t) { sst.end() }) - }) + } - st.test(':not()', function (sst) { + st.test(':not()', (sst) => { sst.notOk(matches(':not(a, [b])', u('a')), 'false if any matches (type)') sst.notOk( matches(':not(a, [b])', u('c', {b: 1})), @@ -476,12 +496,12 @@ test('select.matches()', function (t) { sst.end() }) - st.test(':has', function (sst) { - sst.doesNotThrow(function () { + st.test(':has', (sst) => { + sst.doesNotThrow(() => { matches('a:not(:has())', u('b')) }, 'should not throw on empty selectors') - sst.doesNotThrow(function () { + sst.doesNotThrow(() => { matches('a:has()', u('b')) }, 'should not throw on empty selectors') @@ -583,8 +603,15 @@ test('select.matches()', function (t) { sst.end() }) - ;[':empty', ':blank'].forEach(function (pseudo) { - st.test(pseudo, function (sst) { + + const emptyBlankPseudos = [':empty', ':blank'] + + index = -1 + + while (++index < emptyBlankPseudos.length) { + const pseudo = emptyBlankPseudos[index] + + st.test(pseudo, (sst) => { sst.ok(matches(pseudo, u('a')), 'true for void node') sst.ok(matches(pseudo, u('a', [])), 'true for parent without children') sst.notOk(matches(pseudo, u('a', '')), 'false for falsey literal') @@ -593,14 +620,14 @@ test('select.matches()', function (t) { sst.end() }) - }) + } - st.test(':root', function (sst) { + st.test(':root', (sst) => { sst.ok(matches(':root', u('a')), 'true') sst.end() }) - st.test(':scope', function (sst) { + st.test(':scope', (sst) => { sst.ok(matches(':scope', u('a')), 'true') sst.end() }) diff --git a/test/select-all.js b/test/select-all.js index 7b67e54..04d58a9 100644 --- a/test/select-all.js +++ b/test/select-all.js @@ -2,11 +2,11 @@ import test from 'tape' import {u} from 'unist-builder' import {selectAll} from '../index.js' -test('select.selectAll()', function (t) { - t.test('invalid selectors', function (st) { +test('select.selectAll()', (t) => { + t.test('invalid selectors', (st) => { st.throws( - function () { - // @ts-ignore runtime. + () => { + // @ts-expect-error runtime. selectAll() }, /Error: Expected `string` as selector, not `undefined`/, @@ -14,8 +14,8 @@ test('select.selectAll()', function (t) { ) st.throws( - function () { - // @ts-ignore runtime. + () => { + // @ts-expect-error runtime. selectAll([], u('a')) }, /Error: Expected `string` as selector, not ``/, @@ -23,7 +23,7 @@ test('select.selectAll()', function (t) { ) st.throws( - function () { + () => { selectAll('@supports (transform-origin: 5% 5%) {}', u('a')) }, /Error: Rule expected but "@" found./, @@ -31,7 +31,7 @@ test('select.selectAll()', function (t) { ) st.throws( - function () { + () => { selectAll('[foo%=bar]', u('a')) }, /Error: Expected "=" but "%" found./, @@ -39,7 +39,7 @@ test('select.selectAll()', function (t) { ) st.throws( - function () { + () => { selectAll(':active', u('a')) }, /Error: Unknown pseudo-selector `active`/, @@ -47,7 +47,7 @@ test('select.selectAll()', function (t) { ) st.throws( - function () { + () => { selectAll(':nth-foo(2n+1)', u('a')) }, /Error: Unknown pseudo-selector `nth-foo`/, @@ -55,7 +55,7 @@ test('select.selectAll()', function (t) { ) st.throws( - function () { + () => { selectAll('::before', u('a')) }, /Error: Unexpected pseudo-element or empty pseudo-class/, @@ -65,7 +65,7 @@ test('select.selectAll()', function (t) { st.end() }) - t.test('general', function (st) { + t.test('general', (st) => { st.deepEqual( selectAll('', u('a')), [], @@ -82,7 +82,7 @@ test('select.selectAll()', function (t) { st.end() }) - t.test('descendant selector', function (st) { + t.test('descendant selector', (st) => { st.deepEqual( selectAll( 'b', @@ -132,7 +132,7 @@ test('select.selectAll()', function (t) { st.end() }) - t.test('child selector', function (st) { + t.test('child selector', (st) => { st.deepEqual( selectAll( 'c > d', @@ -165,7 +165,7 @@ test('select.selectAll()', function (t) { st.end() }) - t.test('adjacent sibling selector', function (st) { + t.test('adjacent sibling selector', (st) => { st.deepEqual( selectAll( 'c + b', @@ -198,7 +198,7 @@ test('select.selectAll()', function (t) { st.end() }) - t.test('general sibling selector', function (st) { + t.test('general sibling selector', (st) => { st.deepEqual( selectAll( 'c ~ b', @@ -240,8 +240,8 @@ test('select.selectAll()', function (t) { st.end() }) - t.test('parent-sensitive pseudo-selectors', function (st) { - st.test(':first-child', function (sst) { + t.test('parent-sensitive pseudo-selectors', (st) => { + st.test(':first-child', (sst) => { sst.deepEqual( selectAll( ':first-child', @@ -278,7 +278,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':last-child', function (sst) { + st.test(':last-child', (sst) => { sst.deepEqual( selectAll( ':last-child', @@ -315,7 +315,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':only-child', function (sst) { + st.test(':only-child', (sst) => { sst.deepEqual( selectAll( ':only-child', @@ -343,7 +343,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':nth-child', function (sst) { + st.test(':nth-child', (sst) => { sst.deepEqual( selectAll( 'b:nth-child(odd)', @@ -411,7 +411,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':nth-last-child', function (sst) { + st.test(':nth-last-child', (sst) => { sst.deepEqual( selectAll( 'b:nth-last-child(odd)', @@ -479,7 +479,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':nth-of-type', function (sst) { + st.test(':nth-of-type', (sst) => { sst.deepEqual( selectAll( 'b:nth-of-type(odd)', @@ -547,7 +547,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':nth-last-of-type', function (sst) { + st.test(':nth-last-of-type', (sst) => { sst.deepEqual( selectAll( 'b:nth-last-of-type(odd)', @@ -615,7 +615,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':first-of-type', function (sst) { + st.test(':first-of-type', (sst) => { sst.deepEqual( selectAll( 'b:first-of-type', @@ -641,7 +641,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':last-of-type', function (sst) { + st.test(':last-of-type', (sst) => { sst.deepEqual( selectAll( 'b:last-of-type', @@ -667,7 +667,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':only-of-type', function (sst) { + st.test(':only-of-type', (sst) => { sst.deepEqual( selectAll( 'c:only-of-type', @@ -707,7 +707,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':root', function (sst) { + st.test(':root', (sst) => { sst.deepEqual( selectAll(':root', u('a', [u('b'), u('c', [u('d')])])), [u('a', [u('b'), u('c', [u('d')])])], @@ -717,7 +717,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':scope', function (sst) { + st.test(':scope', (sst) => { sst.deepEqual( selectAll(':scope', u('a', [u('b'), u('c', [u('d')])])), [u('a', [u('b'), u('c', [u('d')])])], @@ -727,7 +727,7 @@ test('select.selectAll()', function (t) { sst.end() }) - st.test(':has', function (sst) { + st.test(':has', (sst) => { sst.deepEqual( selectAll('c:has(:first-child)', u('a', [u('b'), u('c', [u('d')])])), [u('c', [u('d')])], diff --git a/test/select.js b/test/select.js index 0307688..306bb69 100644 --- a/test/select.js +++ b/test/select.js @@ -2,11 +2,11 @@ import test from 'tape' import {u} from 'unist-builder' import {select} from '../index.js' -test('select.select()', function (t) { - t.test('invalid selectors', function (st) { +test('select.select()', (t) => { + t.test('invalid selectors', (st) => { st.throws( - function () { - // @ts-ignore runtime. + () => { + // @ts-expect-error runtime. select() }, /Error: Expected `string` as selector, not `undefined`/, @@ -14,8 +14,8 @@ test('select.select()', function (t) { ) st.throws( - function () { - // @ts-ignore runtime. + () => { + // @ts-expect-error runtime. select([], u('a')) }, /Error: Expected `string` as selector, not ``/, @@ -23,7 +23,7 @@ test('select.select()', function (t) { ) st.throws( - function () { + () => { select('@supports (transform-origin: 5% 5%) {}', u('a')) }, /Error: Rule expected but "@" found./, @@ -31,7 +31,7 @@ test('select.select()', function (t) { ) st.throws( - function () { + () => { select('[foo%=bar]', u('a')) }, /Error: Expected "=" but "%" found./, @@ -39,7 +39,7 @@ test('select.select()', function (t) { ) st.throws( - function () { + () => { select(':active', u('a')) }, /Error: Unknown pseudo-selector `active`/, @@ -47,7 +47,7 @@ test('select.select()', function (t) { ) st.throws( - function () { + () => { select(':nth-foo(2n+1)', u('a')) }, /Error: Unknown pseudo-selector `nth-foo`/, @@ -55,7 +55,7 @@ test('select.select()', function (t) { ) st.throws( - function () { + () => { select('::before', u('a')) }, /Error: Unexpected pseudo-element or empty pseudo-class/, @@ -65,7 +65,7 @@ test('select.select()', function (t) { st.end() }) - t.test('general', function (st) { + t.test('general', (st) => { st.equal( select('', u('a')), null, @@ -83,7 +83,7 @@ test('select.select()', function (t) { st.end() }) - t.test('descendant selector', function (st) { + t.test('descendant selector', (st) => { st.deepEqual( select( 'b', @@ -122,7 +122,7 @@ test('select.select()', function (t) { st.end() }) - t.test('child selector', function (st) { + t.test('child selector', (st) => { st.deepEqual( select('c > e', u('a', [u('b'), u('c', [u('d'), u('e', [u('f')])])])), u('e', [u('f')]), @@ -149,7 +149,7 @@ test('select.select()', function (t) { st.end() }) - t.test('adjacent sibling selector', function (st) { + t.test('adjacent sibling selector', (st) => { st.deepEqual( select( 'c + b', @@ -182,7 +182,7 @@ test('select.select()', function (t) { st.end() }) - t.test('general sibling selector', function (st) { + t.test('general sibling selector', (st) => { st.deepEqual( select( 'c ~ b', @@ -224,8 +224,8 @@ test('select.select()', function (t) { st.end() }) - t.test('parent-sensitive pseudo-selectors', function (st) { - st.test(':first-child', function (sst) { + t.test('parent-sensitive pseudo-selectors', (st) => { + st.test(':first-child', (sst) => { sst.deepEqual( select( ':first-child', @@ -253,7 +253,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':last-child', function (sst) { + st.test(':last-child', (sst) => { sst.deepEqual( select( ':last-child', @@ -281,7 +281,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':only-child', function (sst) { + st.test(':only-child', (sst) => { sst.deepEqual( select( ':only-child', @@ -309,7 +309,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':nth-child', function (sst) { + st.test(':nth-child', (sst) => { sst.deepEqual( select( 'b:nth-child(odd)', @@ -377,7 +377,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':nth-last-child', function (sst) { + st.test(':nth-last-child', (sst) => { sst.deepEqual( select( 'b:nth-last-child(odd)', @@ -445,7 +445,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':nth-of-type', function (sst) { + st.test(':nth-of-type', (sst) => { sst.deepEqual( select( 'b:nth-of-type(odd)', @@ -513,7 +513,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':nth-last-of-type', function (sst) { + st.test(':nth-last-of-type', (sst) => { sst.deepEqual( select( 'b:nth-last-of-type(odd)', @@ -581,7 +581,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':first-of-type', function (sst) { + st.test(':first-of-type', (sst) => { sst.deepEqual( select( 'b:first-of-type', @@ -607,7 +607,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':last-of-type', function (sst) { + st.test(':last-of-type', (sst) => { sst.deepEqual( select( 'b:last-of-type', @@ -633,7 +633,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':only-of-type', function (sst) { + st.test(':only-of-type', (sst) => { sst.deepEqual( select( 'c:only-of-type', @@ -673,7 +673,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':root', function (sst) { + st.test(':root', (sst) => { sst.deepEqual( select(':root', u('a', [u('b'), u('c', [u('d')])])), u('a', [u('b'), u('c', [u('d')])]), @@ -683,7 +683,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':scope', function (sst) { + st.test(':scope', (sst) => { sst.deepEqual( select(':scope', u('a', [u('b'), u('c', [u('d')])])), u('a', [u('b'), u('c', [u('d')])]), @@ -693,7 +693,7 @@ test('select.select()', function (t) { sst.end() }) - st.test(':has', function (sst) { + st.test(':has', (sst) => { sst.deepEqual( select('c:has(:first-child)', u('a', [u('b'), u('c', [u('d')])])), u('c', [u('d')]), diff --git a/tsconfig.json b/tsconfig.json index 2b103bd..f437d29 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,7 @@ "declaration": true, "emitDeclarationOnly": true, "allowSyntheticDefaultImports": true, - "skipLibCheck": true + "skipLibCheck": true, + "strict": true } }