11/**
2- * @typedef {import('./types.js ').Rule } Rule
3- * @typedef {import('./types.js ').RuleAttr } RuleAttr
4- * @typedef {import('./types.js ').Element } Element
5- * @typedef {import('./types.js ').Schema } Schema
6- * @typedef {import('./types.js ').Info } Info
7- * @typedef {import('./types.js ').PropertyValue } PropertyValue
2+ * @typedef {import('css-selector-parser ').AstRule } AstRule
3+ * @typedef {import('css-selector-parser ').AstAttribute } AstAttribute
4+ * @typedef {import('hast ').Element } Element
5+ * @typedef {import('hast ').Properties } Properties
6+ * @typedef {import('property-information ').Schema } Schema
7+ * @typedef {import('property-information ').Info } Info
88 */
99
1010import { stringify as commas } from 'comma-separated-tokens'
11+ import { ok as assert } from 'devlop'
1112import { hasProperty } from 'hast-util-has-property'
1213import { find } from 'property-information'
1314import { stringify as spaces } from 'space-separated-tokens'
1415import { zwitch } from 'zwitch'
1516
16- /** @type {(query: RuleAttr , element: Element, info: Info) => boolean } */
17+ /** @type {(query: AstAttribute , element: Element, info: Info) => boolean } */
1718const handle = zwitch ( 'operator' , {
1819 unknown : unknownOperator ,
1920 // @ts -expect-error: hush.
@@ -29,18 +30,21 @@ const handle = zwitch('operator', {
2930} )
3031
3132/**
32- * @param {Rule } query
33+ * @param {AstRule } query
3334 * @param {Element } element
3435 * @param {Schema } schema
3536 * @returns {boolean }
3637 */
3738export function attribute ( query , element , schema ) {
38- const attrs = query . attrs
3939 let index = - 1
4040
41- while ( ++ index < attrs . length ) {
42- if ( ! handle ( attrs [ index ] , element , find ( schema , attrs [ index ] . name ) ) ) {
43- return false
41+ if ( query . attributes ) {
42+ while ( ++ index < query . attributes . length ) {
43+ const attribute = query . attributes [ index ]
44+
45+ if ( ! handle ( attribute , element , find ( schema , attribute . name ) ) ) {
46+ return false
47+ }
4448 }
4549 }
4650
@@ -52,7 +56,7 @@ export function attribute(query, element, schema) {
5256 *
5357 * `[attr]`
5458 *
55- * @param {RuleAttr } _
59+ * @param {AstAttribute } _
5660 * @param {Element } element
5761 * @param {Info } info
5862 * @returns {boolean }
@@ -66,16 +70,20 @@ function exists(_, element, info) {
6670 *
6771 * `[attr=value]`
6872 *
69- * @param {RuleAttr } query
73+ * @param {AstAttribute } query
7074 * @param {Element } element
7175 * @param {Info } info
7276 * @returns {boolean }
7377 */
7478function exact ( query , element , info ) {
79+ assert ( query . value , 'expected `value`' )
80+ assert ( query . value . type === 'String' , 'expected plain string' )
81+
7582 return Boolean (
7683 hasProperty ( element , info . property ) &&
7784 element . properties &&
78- normalizeValue ( element . properties [ info . property ] , info ) === query . value
85+ normalizeValue ( element . properties [ info . property ] , info ) ===
86+ query . value . value
7987 )
8088}
8189
@@ -85,12 +93,15 @@ function exact(query, element, info) {
8593 *
8694 * `[attr~=value]`
8795 *
88- * @param {RuleAttr } query
96+ * @param {AstAttribute } query
8997 * @param {Element } element
9098 * @param {Info } info
9199 * @returns {boolean }
92100 */
93101function spaceSeparatedList ( query , element , info ) {
102+ assert ( query . value , 'expected `value`' )
103+ assert ( query . value . type === 'String' , 'expected plain string' )
104+
94105 const value = element . properties && element . properties [ info . property ]
95106
96107 return (
@@ -99,12 +110,11 @@ function spaceSeparatedList(query, element, info) {
99110 ( ! info . commaSeparated &&
100111 value &&
101112 typeof value === 'object' &&
102- query . value &&
103- value . includes ( query . value ) ) ||
113+ value . includes ( query . value . value ) ) ||
104114 // For all other values (including comma-separated lists), return whether this
105115 // is an exact match.
106116 ( hasProperty ( element , info . property ) &&
107- normalizeValue ( value , info ) === query . value )
117+ normalizeValue ( value , info ) === query . value . value )
108118 )
109119}
110120
@@ -114,23 +124,25 @@ function spaceSeparatedList(query, element, info) {
114124 *
115125 * `[attr|=value]`
116126 *
117- * @param {RuleAttr } query
127+ * @param {AstAttribute } query
118128 * @param {Element } element
119129 * @param {Info } info
120130 * @returns {boolean }
121131 */
122132function exactOrPrefix ( query , element , info ) {
133+ assert ( query . value , 'expected `value`' )
134+ assert ( query . value . type === 'String' , 'expected plain string' )
135+
123136 const value = normalizeValue (
124137 element . properties && element . properties [ info . property ] ,
125138 info
126139 )
127140
128141 return Boolean (
129142 hasProperty ( element , info . property ) &&
130- query . value &&
131- ( value === query . value ||
132- ( value . slice ( 0 , query . value . length ) === query . value &&
133- value . charAt ( query . value . length ) === '-' ) )
143+ ( value === query . value . value ||
144+ ( value . slice ( 0 , query . value . value . length ) === query . value . value &&
145+ value . charAt ( query . value . value . length ) === '-' ) )
134146 )
135147}
136148
@@ -139,20 +151,22 @@ function exactOrPrefix(query, element, info) {
139151 *
140152 * `[attr^=value]`
141153 *
142- * @param {RuleAttr } query
154+ * @param {AstAttribute } query
143155 * @param {Element } element
144156 * @param {Info } info
145157 * @returns {boolean }
146158 */
147159function begins ( query , element , info ) {
160+ assert ( query . value , 'expected `value`' )
161+ assert ( query . value . type === 'String' , 'expected plain string' )
162+
148163 return Boolean (
149164 hasProperty ( element , info . property ) &&
150165 element . properties &&
151- query . value &&
152166 normalizeValue ( element . properties [ info . property ] , info ) . slice (
153167 0 ,
154- query . value . length
155- ) === query . value
168+ query . value . value . length
169+ ) === query . value . value
156170 )
157171}
158172
@@ -161,19 +175,21 @@ function begins(query, element, info) {
161175 *
162176 * `[attr$=value]`
163177 *
164- * @param {RuleAttr } query
178+ * @param {AstAttribute } query
165179 * @param {Element } element
166180 * @param {Info } info
167181 * @returns {boolean }
168182 */
169183function ends ( query , element , info ) {
184+ assert ( query . value , 'expected `value`' )
185+ assert ( query . value . type === 'String' , 'expected plain string' )
186+
170187 return Boolean (
171188 hasProperty ( element , info . property ) &&
172189 element . properties &&
173- query . value &&
174190 normalizeValue ( element . properties [ info . property ] , info ) . slice (
175- - query . value . length
176- ) === query . value
191+ - query . value . value . length
192+ ) === query . value . value
177193 )
178194}
179195
@@ -182,18 +198,20 @@ function ends(query, element, info) {
182198 *
183199 * `[attr*=value]`
184200 *
185- * @param {RuleAttr } query
201+ * @param {AstAttribute } query
186202 * @param {Element } element
187203 * @param {Info } info
188204 * @returns {boolean }
189205 */
190206function contains ( query , element , info ) {
207+ assert ( query . value , 'expected `value`' )
208+ assert ( query . value . type === 'String' , 'expected plain string' )
209+
191210 return Boolean (
192211 hasProperty ( element , info . property ) &&
193212 element . properties &&
194- query . value &&
195213 normalizeValue ( element . properties [ info . property ] , info ) . includes (
196- query . value
214+ query . value . value
197215 )
198216 )
199217}
@@ -212,7 +230,7 @@ function unknownOperator(query) {
212230/**
213231 * Stringify a hast value back to its HTML form.
214232 *
215- * @param {PropertyValue } value
233+ * @param {Properties[keyof Properties] } value
216234 * @param {Info } info
217235 * @returns {string }
218236 */
0 commit comments