Skip to content

Commit

Permalink
Update css-selector-parser
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Nov 6, 2023
1 parent 3032a27 commit d20a835
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 89 deletions.
27 changes: 1 addition & 26 deletions lib/attribute.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/**
* @typedef {import('css-selector-parser').AstAttribute} AstAttribute
* @typedef {import('css-selector-parser').AstRule} AstRule
*
* @typedef {import('hast').Element} Element
* @typedef {import('hast').Properties} Properties
Expand All @@ -14,30 +13,6 @@ import {ok as assert} from 'devlop'
import {find} from 'property-information'
import * as spaces from 'space-separated-tokens'

/**
* @param {AstRule} query
* Query.
* @param {Element} element
* Element.
* @param {Schema} schema
* Schema of element.
* @returns {boolean}
* Whether `element` matches `query`.
*/
export function attributes(query, element, schema) {
let index = -1

if (query.attributes) {
while (++index < query.attributes.length) {
if (!attribute(query.attributes[index], element, schema)) {
return false
}
}
}

return true
}

/**
* @param {AstAttribute} query
* Query.
Expand All @@ -48,7 +23,7 @@ export function attributes(query, element, schema) {
* @returns {boolean}
* Whether `element` matches `query`.
*/
function attribute(query, element, schema) {
export function attribute(query, element, schema) {
const info = find(schema, query.name)
const propertyValue = element.properties[info.property]
let value = normalizeValue(propertyValue, info)
Expand Down
13 changes: 3 additions & 10 deletions lib/class-name.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @typedef {import('css-selector-parser').AstRule} AstRule
* @typedef {import('css-selector-parser').AstClassName} AstClassName
* @typedef {import('hast').Element} Element
*/

Expand All @@ -9,7 +9,7 @@ const emptyClassNames = []
/**
* Check whether an element has all class names.
*
* @param {AstRule} query
* @param {AstClassName} query
* AST rule (with `classNames`).
* @param {Element} element
* Element.
Expand All @@ -21,13 +21,6 @@ export function className(query, element) {
const value = /** @type {Readonly<Array<string>>} */ (
element.properties.className || emptyClassNames
)
let index = -1

if (query.classNames) {
while (++index < query.classNames.length) {
if (!value.includes(query.classNames[index])) return false
}
}

return true
return value.includes(query.name)
}
11 changes: 5 additions & 6 deletions lib/id.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
/**
* @typedef {import('css-selector-parser').AstRule} AstRule
* @typedef {import('css-selector-parser').AstId} AstId
*
* @typedef {import('hast').Element} Element
*/

import {ok as assert} from 'devlop'
// Workaround to show references to above types in VS Code.
''

/**
* Check whether an element has an ID.
*
* @param {AstRule} query
* @param {AstId} query
* AST rule (with `ids`).
* @param {Element} element
* Element.
* @returns {boolean}
* Whether `element` matches `query`.
*/
export function id(query, element) {
const ids = query.ids
assert(ids, 'expected `ids`')
return ids.length === 1 && element.properties.id === ids[0]
return element.properties.id === query.name
}
10 changes: 5 additions & 5 deletions lib/name.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
/**
* @typedef {import('css-selector-parser').AstRule} AstRule
* @typedef {import('css-selector-parser').AstTagName} AstTagName
*
* @typedef {import('hast').Element} Element
*/

import {ok as assert} from 'devlop'
// Workaround to show references to above types in VS Code.
''

/**
* Check whether an element has a tag name.
*
* @param {AstRule} query
* @param {AstTagName} query
* AST rule (with `tag`).
* @param {Element} element
* Element.
* @returns {boolean}
* Whether `element` matches `query`.
*/
export function name(query, element) {
assert(query.tag, 'expected `tag`')
return query.tag.type === 'WildcardTag' || query.tag.name === element.tagName
return query.name === element.tagName
}
33 changes: 2 additions & 31 deletions lib/pseudo.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/**
* @typedef {import('css-selector-parser').AstRule} AstRule
* @typedef {import('css-selector-parser').AstPseudoClass} AstPseudoClass
*
* @typedef {import('hast').Element} Element
Expand All @@ -22,8 +21,8 @@ import {walk} from './walk.js'
// @ts-expect-error: types are broken.
const nthCheck = fauxEsmNthCheck.default || fauxEsmNthCheck

/** @type {(rule: AstPseudoClass | AstRule, element: Element, index: number | undefined, parent: Parents | undefined, state: State) => boolean} */
const handle = zwitch('name', {
/** @type {(rule: AstPseudoClass, element: Element, index: number | undefined, parent: Parents | undefined, state: State) => boolean} */
export const pseudo = zwitch('name', {
handlers: {
'any-link': anyLink,
blank,
Expand Down Expand Up @@ -57,34 +56,6 @@ const handle = zwitch('name', {
unknown: unknownPseudo
})

/**
* Check whether an element matches pseudo selectors.
*
* @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 pseudo(query, element, index, parent, state) {
const pseudos = query.pseudoClasses
assert(pseudos, 'expected `pseudoClasses`')
let offset = -1

while (++offset < pseudos.length) {
if (!handle(pseudos[offset], element, index, parent, state)) return false
}

return true
}

/**
* Check whether an element matches an `:any-link` pseudo.
*
Expand Down
29 changes: 19 additions & 10 deletions lib/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @typedef {import('./index.js').State} State
*/

import {attributes} from './attribute.js'
import {attribute} from './attribute.js'
import {className} from './class-name.js'
import {id} from './id.js'
import {name} from './name.js'
Expand All @@ -30,15 +30,24 @@ import {pseudo} from './pseudo.js'
* Whether `element` matches `query`.
*/
export function test(query, element, index, parent, state) {
if (query.pseudoElement) {
throw new Error('Invalid selector: `::' + query.pseudoElement + '`')
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 Boolean(
(!query.tag || name(query, element)) &&
(!query.classNames || className(query, element)) &&
(!query.ids || id(query, element)) &&
(!query.attributes || attributes(query, element, state.schema)) &&
(!query.pseudoClasses || pseudo(query, element, index, parent, state))
)
return true
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"@types/unist": "^3.0.0",
"bcp-47-match": "^2.0.0",
"comma-separated-tokens": "^2.0.0",
"css-selector-parser": "^2.0.0",
"css-selector-parser": "^3.0.0",
"devlop": "^1.0.0",
"direction": "^2.0.0",
"hast-util-has-property": "^3.0.0",
Expand Down

0 comments on commit d20a835

Please sign in to comment.