-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Accept "of selector" syntax in
:nth-[last]-child
pseudo-classes (#1524
) * Add (empty) selector to :nth-child * Accept of selector syntax (with no effect) * Improve nth * Make selector optional in JSON * Fix specificity of :nth-child * Add of selector syntax for :nth-last-child * Fix matching
- Loading branch information
Showing
10 changed files
with
293 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@siteimprove/alfa-selector": minor | ||
--- | ||
|
||
**Added:** The `:nth-child` and `:nth-last-child` pseudo-classes now accept the "of selector" syntax. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 38 additions & 18 deletions
56
packages/alfa-selector/src/selector/simple/pseudo-class/nth-child.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,79 @@ | ||
import type { Parser as CSSParser } from "@siteimprove/alfa-css"; | ||
import type { Nth } from "@siteimprove/alfa-css"; | ||
import { Element } from "@siteimprove/alfa-dom"; | ||
import { Maybe, None, Option } from "@siteimprove/alfa-option"; | ||
import type { Thunk } from "@siteimprove/alfa-thunk"; | ||
|
||
import { WithIndex } from "./pseudo-class"; | ||
import type { Context } from "../../../context"; | ||
import { Universal } from "../../index"; | ||
|
||
import type { Absolute } from "../../index"; | ||
|
||
import { WithIndexAndSelector } from "./pseudo-class"; | ||
|
||
const { isElement } = Element; | ||
|
||
/** | ||
* {@link https://drafts.csswg.org/selectors/#nth-child-pseudo} | ||
*/ | ||
export class NthChild extends WithIndex<"nth-child"> { | ||
public static of(index: Nth): NthChild { | ||
return new NthChild(index); | ||
export class NthChild extends WithIndexAndSelector<"nth-child"> { | ||
public static of(index: Nth, selector: Maybe<Absolute> = None): NthChild { | ||
return new NthChild(index, Maybe.toOption(selector)); | ||
} | ||
|
||
private constructor(index: Nth) { | ||
super("nth-child", index); | ||
private readonly _indices = new WeakMap<Element, number>(); | ||
|
||
private constructor(index: Nth, selector: Option<Absolute>) { | ||
super("nth-child", index, selector); | ||
} | ||
|
||
/** @public (knip) */ | ||
public *[Symbol.iterator](): Iterator<NthChild> { | ||
yield this; | ||
} | ||
|
||
public matches(element: Element): boolean { | ||
const indices = NthChild._indices; | ||
|
||
if (!indices.has(element)) { | ||
public matches(element: Element, context?: Context): boolean { | ||
if (!this._indices.has(element)) { | ||
element | ||
.inclusiveSiblings() | ||
.filter(isElement) | ||
.filter((element) => | ||
this._selector | ||
.getOr(Universal.of(Option.of("*"))) | ||
.matches(element, context), | ||
) | ||
.forEach((element, i) => { | ||
indices.set(element, i + 1); | ||
this._indices.set(element, i + 1); | ||
}); | ||
} | ||
|
||
return this._index.matches(indices.get(element)!); | ||
if (!this._indices.has(element)) { | ||
return false; | ||
} | ||
|
||
return this._index.matches(this._indices.get(element)!); | ||
} | ||
|
||
public equals(value: NthChild): boolean; | ||
|
||
public equals(value: unknown): value is this; | ||
|
||
public equals(value: unknown): boolean { | ||
return value instanceof NthChild && value._index.equals(this._index); | ||
return value instanceof NthChild && super.equals(value); | ||
} | ||
|
||
public toJSON(): NthChild.JSON { | ||
return { | ||
...super.toJSON(), | ||
}; | ||
return super.toJSON(); | ||
} | ||
} | ||
|
||
export namespace NthChild { | ||
export interface JSON extends WithIndex.JSON<"nth-child"> {} | ||
export interface JSON extends WithIndexAndSelector.JSON<"nth-child"> {} | ||
|
||
export const parse = WithIndex.parseWithIndex("nth-child", NthChild.of); | ||
export const parse = (parseSelector: Thunk<CSSParser<Absolute>>) => | ||
WithIndexAndSelector.parseWithIndexAndSelector( | ||
"nth-child", | ||
parseSelector, | ||
NthChild.of, | ||
); | ||
} |
59 changes: 38 additions & 21 deletions
59
packages/alfa-selector/src/selector/simple/pseudo-class/nth-last-child.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,80 @@ | ||
import type { Parser as CSSParser } from "@siteimprove/alfa-css"; | ||
import type { Nth } from "@siteimprove/alfa-css"; | ||
import { Element } from "@siteimprove/alfa-dom"; | ||
import { Maybe, None, Option } from "@siteimprove/alfa-option"; | ||
import type { Thunk } from "@siteimprove/alfa-thunk"; | ||
|
||
import { WithIndex } from "./pseudo-class"; | ||
import type { Context } from "../../../context"; | ||
import { Universal } from "../../index"; | ||
|
||
import type { Absolute } from "../../index"; | ||
|
||
import { WithIndexAndSelector } from "./pseudo-class"; | ||
|
||
const { isElement } = Element; | ||
|
||
/** | ||
* {@link https://drafts.csswg.org/selectors/#nth-last-child-pseudo} | ||
*/ | ||
export class NthLastChild extends WithIndex<"nth-last-child"> { | ||
public static of(index: Nth): NthLastChild { | ||
return new NthLastChild(index); | ||
export class NthLastChild extends WithIndexAndSelector<"nth-last-child"> { | ||
public static of(index: Nth, selector: Maybe<Absolute> = None): NthLastChild { | ||
return new NthLastChild(index, Maybe.toOption(selector)); | ||
} | ||
|
||
private constructor(nth: Nth) { | ||
super("nth-last-child", nth); | ||
private readonly _indices = new WeakMap<Element, number>(); | ||
|
||
private constructor(nth: Nth, selector: Option<Absolute>) { | ||
super("nth-last-child", nth, selector); | ||
} | ||
|
||
/** @public (knip) */ | ||
public *[Symbol.iterator](): Iterator<NthLastChild> { | ||
yield this; | ||
} | ||
|
||
public matches(element: Element): boolean { | ||
const indices = NthLastChild._indices; | ||
|
||
if (!indices.has(element)) { | ||
public matches(element: Element, context?: Context): boolean { | ||
if (!this._indices.has(element)) { | ||
element | ||
.inclusiveSiblings() | ||
.filter(isElement) | ||
.filter((element) => | ||
this._selector | ||
.getOr(Universal.of(Option.of("*"))) | ||
.matches(element, context), | ||
) | ||
.reverse() | ||
.forEach((element, i) => { | ||
indices.set(element, i + 1); | ||
this._indices.set(element, i + 1); | ||
}); | ||
} | ||
|
||
return this._index.matches(indices.get(element)!); | ||
if (!this._indices.has(element)) { | ||
return false; | ||
} | ||
|
||
return this._index.matches(this._indices.get(element)!); | ||
} | ||
|
||
public equals(value: NthLastChild): boolean; | ||
|
||
public equals(value: unknown): value is this; | ||
|
||
public equals(value: unknown): boolean { | ||
return value instanceof NthLastChild && value._index.equals(this._index); | ||
return value instanceof NthLastChild && super.equals(value); | ||
} | ||
|
||
public toJSON(): NthLastChild.JSON { | ||
return { | ||
...super.toJSON(), | ||
}; | ||
return super.toJSON(); | ||
} | ||
} | ||
|
||
export namespace NthLastChild { | ||
export interface JSON extends WithIndex.JSON<"nth-last-child"> {} | ||
export interface JSON extends WithIndexAndSelector.JSON<"nth-last-child"> {} | ||
|
||
export const parse = WithIndex.parseWithIndex( | ||
"nth-last-child", | ||
NthLastChild.of, | ||
); | ||
export const parse = (parseSelector: Thunk<CSSParser<Absolute>>) => | ||
WithIndexAndSelector.parseWithIndexAndSelector( | ||
"nth-last-child", | ||
parseSelector, | ||
NthLastChild.of, | ||
); | ||
} |
Oops, something went wrong.