|
1 | 1 | /** |
2 | 2 | * @typedef {import('./types.js').Rule} Rule |
3 | 3 | * @typedef {import('./types.js').RulePseudo} RulePseudo |
4 | | - * @typedef {import('./types.js').RulePseudoNth} RulePseudoNth |
5 | 4 | * @typedef {import('./types.js').RulePseudoSelector} RulePseudoSelector |
6 | 5 | * @typedef {import('./types.js').Parent} Parent |
7 | 6 | * @typedef {import('./types.js').Selector} Selector |
|
10 | 9 | * @typedef {import('./types.js').Node} Node |
11 | 10 | */ |
12 | 11 |
|
13 | | -import {zwitch} from 'zwitch' |
| 12 | +import fauxEsmNthCheck from 'nth-check' |
14 | 13 | import {convert} from 'unist-util-is' |
| 14 | +import {zwitch} from 'zwitch' |
15 | 15 | import {parent} from './util.js' |
16 | 16 |
|
| 17 | +/** @type {import('nth-check').default} */ |
| 18 | +// @ts-expect-error |
| 19 | +const nthCheck = fauxEsmNthCheck.default || fauxEsmNthCheck |
| 20 | + |
17 | 21 | const is = convert() |
18 | 22 |
|
19 | 23 | /** @type {(rule: Rule | RulePseudo, element: Node, index: number | undefined, parent: Parent | undefined, state: SelectState) => boolean} */ |
@@ -191,62 +195,66 @@ function onlyChild(query, _1, _2, _3, state) { |
191 | 195 | } |
192 | 196 |
|
193 | 197 | /** |
194 | | - * @param {RulePseudoNth} query |
| 198 | + * @param {RulePseudo} query |
195 | 199 | * @param {Node} _1 |
196 | 200 | * @param {number | undefined} _2 |
197 | 201 | * @param {Parent | undefined} _3 |
198 | 202 | * @param {SelectState} state |
199 | 203 | * @returns {boolean} |
200 | 204 | */ |
201 | 205 | function nthChild(query, _1, _2, _3, state) { |
| 206 | + const fn = getCachedNthCheck(query) |
202 | 207 | assertDeep(state, query) |
203 | | - return typeof state.nodeIndex === 'number' && query.value(state.nodeIndex) |
| 208 | + return typeof state.nodeIndex === 'number' && fn(state.nodeIndex) |
204 | 209 | } |
205 | 210 |
|
206 | 211 | /** |
207 | | - * @param {RulePseudoNth} query |
| 212 | + * @param {RulePseudo} query |
208 | 213 | * @param {Node} _1 |
209 | 214 | * @param {number | undefined} _2 |
210 | 215 | * @param {Parent | undefined} _3 |
211 | 216 | * @param {SelectState} state |
212 | 217 | * @returns {boolean} |
213 | 218 | */ |
214 | 219 | function nthLastChild(query, _1, _2, _3, state) { |
| 220 | + const fn = getCachedNthCheck(query) |
215 | 221 | assertDeep(state, query) |
216 | 222 | return ( |
217 | 223 | typeof state.nodeCount === 'number' && |
218 | 224 | typeof state.nodeIndex === 'number' && |
219 | | - query.value(state.nodeCount - state.nodeIndex - 1) |
| 225 | + fn(state.nodeCount - state.nodeIndex - 1) |
220 | 226 | ) |
221 | 227 | } |
222 | 228 |
|
223 | 229 | /** |
224 | | - * @param {RulePseudoNth} query |
| 230 | + * @param {RulePseudo} query |
225 | 231 | * @param {Node} _1 |
226 | 232 | * @param {number | undefined} _2 |
227 | 233 | * @param {Parent | undefined} _3 |
228 | 234 | * @param {SelectState} state |
229 | 235 | * @returns {boolean} |
230 | 236 | */ |
231 | 237 | function nthOfType(query, _1, _2, _3, state) { |
| 238 | + const fn = getCachedNthCheck(query) |
232 | 239 | assertDeep(state, query) |
233 | | - return typeof state.typeIndex === 'number' && query.value(state.typeIndex) |
| 240 | + return typeof state.typeIndex === 'number' && fn(state.typeIndex) |
234 | 241 | } |
235 | 242 |
|
236 | 243 | /** |
237 | | - * @param {RulePseudoNth} query |
| 244 | + * @param {RulePseudo} query |
238 | 245 | * @param {Node} _1 |
239 | 246 | * @param {number | undefined} _2 |
240 | 247 | * @param {Parent | undefined} _3 |
241 | 248 | * @param {SelectState} state |
242 | 249 | * @returns {boolean} |
243 | 250 | */ |
244 | 251 | function nthLastOfType(query, _1, _2, _3, state) { |
| 252 | + const fn = getCachedNthCheck(query) |
245 | 253 | assertDeep(state, query) |
246 | 254 | return ( |
247 | 255 | typeof state.typeIndex === 'number' && |
248 | 256 | typeof state.typeCount === 'number' && |
249 | | - query.value(state.typeCount - 1 - state.typeIndex) |
| 257 | + fn(state.typeCount - 1 - state.typeIndex) |
250 | 258 | ) |
251 | 259 | } |
252 | 260 |
|
@@ -314,7 +322,7 @@ function unknownPseudo(query) { |
314 | 322 |
|
315 | 323 | /** |
316 | 324 | * @param {SelectState} state |
317 | | - * @param {RulePseudo | RulePseudoNth} query |
| 325 | + * @param {RulePseudo} query |
318 | 326 | */ |
319 | 327 | function assertDeep(state, query) { |
320 | 328 | if (state.shallow) { |
@@ -387,3 +395,22 @@ function appendScope(value) { |
387 | 395 |
|
388 | 396 | return selector |
389 | 397 | } |
| 398 | + |
| 399 | +/** |
| 400 | + * @param {RulePseudo} query |
| 401 | + * @returns {(value: number) => boolean} |
| 402 | + */ |
| 403 | +function getCachedNthCheck(query) { |
| 404 | + /** @type {(value: number) => boolean} */ |
| 405 | + // @ts-expect-error: cache. |
| 406 | + let fn = query._cachedFn |
| 407 | + |
| 408 | + if (!fn) { |
| 409 | + // @ts-expect-error: always string. |
| 410 | + fn = nthCheck(query.value) |
| 411 | + // @ts-expect-error: cache. |
| 412 | + query._cachedFn = fn |
| 413 | + } |
| 414 | + |
| 415 | + return fn |
| 416 | +} |
0 commit comments