From 3592016f634ae3534fe83ab4166c5565fe80b84f Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Mon, 7 Aug 2023 18:58:08 +0200 Subject: [PATCH] Add some tests for future features --- lib/pseudo.js | 13 +++++--- readme.md | 52 ++++++++++++++++------------- test/select-all.js | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 27 deletions(-) diff --git a/lib/pseudo.js b/lib/pseudo.js index 0965d77..fd61997 100644 --- a/lib/pseudo.js +++ b/lib/pseudo.js @@ -304,7 +304,12 @@ function getCachedNthCheck(query) { if (!fn) { const value = query.argument assert(value, 'expected `argument`') - assert(value.type === 'Formula', 'expected `Formula`') + + if (value.type !== 'Formula') { + throw new Error( + 'Expected `nth` formula, such as `even` or `2n+1` (`of` is not yet supported)' + ) + } fn = nthCheck(value.a + 'n+' + value.b) // @ts-expect-error: cache. @@ -364,16 +369,16 @@ function invalidPseudo() { * Query. * @param {Element} element * Element. - * @param {number | undefined} _ + * @param {number | undefined} _1 * Index of `element` in `parent`. - * @param {Parents | undefined} parent + * @param {Parents | undefined} _2 * Parent of `element`. * @param {State} state * State. * @returns {boolean} * Whether `element` matches `query`. */ -function is(query, element, _, parent, state) { +function is(query, element, _1, _2, state) { assert(query.argument, 'expected `argument`') assert(query.argument.type === 'Selector', 'expected selector') diff --git a/readme.md b/readme.md index 59b8277..fb88c5a 100644 --- a/readme.md +++ b/readme.md @@ -308,60 +308,66 @@ type Space = 'html' | 'svg' ## Unsupported * [ ] † `||` (column combinator) -* [ ] ¶ `ns|E` (namespace type selector) -* [ ] ¶ `*|E` (any namespace type selector) -* [ ] ¶ `|E` (no namespace type selector) -* [ ] ¶ `[ns|attr]` (namespace attribute) -* [ ] ¶ `[*|attr]` (any namespace attribute) -* [ ] ¶ `[|attr]` (no namespace attribute) +* [ ] † `ns|E` (namespace type selector) +* [ ] † `*|E` (any namespace type selector) +* [ ] † `|E` (no namespace type selector) +* [ ] † `[ns|attr]` (namespace attribute) +* [ ] † `[*|attr]` (any namespace attribute) +* [ ] † `[|attr]` (no namespace attribute) * [ ] ‖ `:nth-child(n of S)` (functional pseudo-class, note: scoping to parents is not supported) * [ ] ‖ `:nth-last-child(n of S)` (functional pseudo-class, note: scoping to parents is not supported) * [ ] † `:active` (pseudo-class) +* [ ] † `:autofill` (pseudo-class) +* [ ] † `:buffering` (pseudo-class) +* [ ] § `:closed` (pseudo-class) * [ ] † `:current` (pseudo-class) * [ ] † `:current()` (functional pseudo-class) * [ ] † `:default` (pseudo-class) * [ ] † `:defined` (pseudo-class) -* [ ] † `:drop` (pseudo-class) -* [ ] † `:drop()` (functional pseudo-class) * [ ] † `:focus` (pseudo-class) * [ ] † `:focus-visible` (pseudo-class) * [ ] † `:focus-within` (pseudo-class) * [ ] † `:fullscreen` (pseudo-class) * [ ] † `:future` (pseudo-class) -* [ ] ‖ `:host()` (functional pseudo-class) -* [ ] ‖ `:host-context()` (functional pseudo-class) +* [ ] § `:host()` (functional pseudo-class) +* [ ] § `:host-context()` (functional pseudo-class) * [ ] † `:hover` (pseudo-class) -* [ ] § `:in-range` (pseudo-class) +* [ ] ‡ `:in-range` (pseudo-class) * [ ] † `:indeterminate` (pseudo-class) -* [ ] § `:invalid` (pseudo-class) +* [ ] ‡ `:invalid` (pseudo-class) * [ ] † `:link` (pseudo-class) * [ ] † `:local-link` (pseudo-class) -* [ ] † `:nth-column()` (functional pseudo-class) -* [ ] † `:nth-last-column()` (functional pseudo-class) -* [ ] § `:out-of-range` (pseudo-class) +* [ ] † `:modal` (pseudo-class) +* [ ] † `:muted` (pseudo-class) +* [ ] † `:nth-col()` (functional pseudo-class) +* [ ] † `:nth-last-col()` (functional pseudo-class) +* [ ] § `:open` (pseudo-class) +* [ ] ‡ `:out-of-range` (pseudo-class) * [ ] † `:past` (pseudo-class) * [ ] † `:paused` (pseudo-class) * [ ] † `:placeholder-shown` (pseudo-class) * [ ] † `:playing` (pseudo-class) -* [ ] ‖ `:something()` (functional pseudo-class) +* [ ] † `:seeking` (pseudo-class) +* [ ] † `:stalled` (pseudo-class) * [ ] † `:target` (pseudo-class) * [ ] † `:target-within` (pseudo-class) -* [ ] † `:user-error` (pseudo-class) * [ ] † `:user-invalid` (pseudo-class) -* [ ] § `:valid` (pseudo-class) +* [ ] ‡ `:valid` (pseudo-class) * [ ] † `:visited` (pseudo-class) +* [ ] † `:volume-locked` (pseudo-class) +* [ ] § `:where()` (functional pseudo-class) * [ ] † `::before` (pseudo-elements: none are supported) ###### Notes * \* — not supported in `matches` -* † — needs a user, browser, interactivity, or scripting to make sense -* ‡ — not supported by the underlying algorithm -* § — not very interested in writing / including the code for this -* ‖ — too new, the spec is still changing -* ¶ — requires whole CSS files, not just selectors, to make sense +* † — needs a user, browser, interactivity, scripting, or whole CSS to make + sense +* ‡ — not very interested in writing / including the code for this +* § — too new, the spec is still changing +* ‖ — pr wanted! * `:any()` and `:matches()` are renamed to `:is()` in CSS. ## Types diff --git a/test/select-all.js b/test/select-all.js index e8dca64..3987d35 100644 --- a/test/select-all.js +++ b/test/select-all.js @@ -479,6 +479,89 @@ test('select.selectAll()', async function (t) { [h('li', 'Bravo'), h('li', 'Delta'), h('li', 'Foxtrot')] ) }) + + await t.test( + 'should throw on unsupported `of` syntax', + async function () { + assert.throws(function () { + selectAll(':nth-child(odd of a)', h('span')) + }, /Expected `nth` formula, such as `even` or `2n\+1` \(`of` is not yet supported\)/) + } + ) + + // To do: add `of Selector` syntax. + // These can be deep, such as `:nth-child(even of section h1)`. + // To add this, I think we need to add support to `matches` to pass a + // list of ancestors (which is likely useful in and of itself). + // In `:nth` stuff we can than filter nodes both on the `nth`, and the + // `of` selector. + // await t.test('should support `of` syntax (reference)', async function () { + // const tree = h('section', [ + // h('p', 'Alpha'), + // h('p', 'Bravo'), + // h('h1', 'Charlie'), + // h('p', 'Delta'), + // h('p', 'Echo'), + // h('p', 'Foxtrot'), + // h('h1', 'Golf') + // ]) + + // assert.deepEqual(selectAll(':is(h1, p):nth-child(even)', tree), [ + // tree.children[1], + // tree.children[3], + // tree.children[5] + // ]) + // }) + + // await t.test('should support `of` syntax (#1)', async function () { + // const tree = h('section', [ + // h('p', 'Alpha'), + // h('p', 'Bravo'), + // h('h1', 'Charlie'), + // h('p', 'Delta'), + // h('p', 'Echo'), + // h('p', 'Foxtrot'), + // h('h1', 'Golf') + // ]) + + // assert.deepEqual(selectAll(':is(h1, p):nth-child(even of p)', tree), [ + // tree.children[1], + // tree.children[4] + // ]) + // }) + + // await t.test('should support `of` syntax (#2)', async function () { + // const tree = h('section', [ + // h('p', 'Alpha'), + // h('p', 'Bravo'), + // h('h1', 'Charlie'), + // h('p', 'Delta'), + // h('p', 'Echo'), + // h('p', 'Foxtrot'), + // h('h1', 'Golf') + // ]) + + // assert.deepEqual(selectAll(':is(h1, p):nth-child(even of h1)', tree), [ + // tree.children[6] + // ]) + // }) + + // await t.test('should support `of` syntax (#3)', async function () { + // const tree = h('section', [ + // h('p', 'Alpha'), + // h('p', 'Bravo'), + // h('h1', 'Charlie'), + // h('p', 'Delta'), + // h('p', 'Echo'), + // h('p', 'Foxtrot'), + // h('h1', 'Golf') + // ]) + + // assert.deepEqual( + // selectAll(':is(h1, p):nth-child(even of section h1)', tree), + // [tree.children[6]] + // ) + // }) }) await t.test(':nth-last-child', async function (t) {