Skip to content

Commit 78db794

Browse files
committed
improve
1 parent bd9ae4e commit 78db794

2 files changed

Lines changed: 44 additions & 88 deletions

File tree

src/pseudo-selectors/filters.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,16 @@ export const filters: Record<string, Filter> = {
201201
},
202202

203203
lang(next, code, { adapter }) {
204-
const ranges = code.split(",").map((r) =>
205-
r
206-
.trim()
207-
.replace(/^['"]|['"]$/g, "")
208-
.toLowerCase()
209-
.split("-"),
210-
);
204+
const ranges = code
205+
.split(",")
206+
.map((r) => r.trim())
207+
.filter((r) => r.length > 0)
208+
.map((r) =>
209+
r
210+
.replace(/^['"]|['"]$/g, "")
211+
.toLowerCase()
212+
.split("-"),
213+
);
211214

212215
return function lang(element) {
213216
let node: typeof element | null = element;

test/pseudo-classes.ts

Lines changed: 34 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -207,107 +207,60 @@ describe(":has", () => {
207207
});
208208

209209
describe(":lang", () => {
210-
it("should match exact language", () => {
211-
const dom = parseDocument('<div lang="en"><p>hello</p></div>');
212-
const matches = CSSselect.selectAll<AnyNode, Element>(":lang(en)", dom);
213-
expect(matches).toHaveLength(2);
214-
});
215-
216-
it("should match language prefix", () => {
217-
const dom = parseDocument('<div lang="en-US"><p>hello</p></div>');
218-
const matches = CSSselect.selectAll<AnyNode, Element>(":lang(en)", dom);
219-
expect(matches).toHaveLength(2);
220-
});
221-
222-
it("should be case-insensitive", () => {
223-
const dom = parseDocument('<div lang="en"><p>hello</p></div>');
224-
expect(
225-
CSSselect.selectAll<AnyNode, Element>(":lang(EN)", dom),
226-
).toHaveLength(2);
227-
228-
const dom2 = parseDocument('<div lang="EN-US"><p>hello</p></div>');
229-
expect(
230-
CSSselect.selectAll<AnyNode, Element>(":lang(en)", dom2),
231-
).toHaveLength(2);
232-
});
233-
234-
it("should inherit from ancestors", () => {
235-
const dom = parseDocument(
236-
'<div lang="fr"><section><p>bonjour</p></section></div>',
237-
);
210+
// Single fixture covering inheritance, override, and untagged elements.
211+
const langFixture = parseDocument(
212+
'<div lang="en"><p id="a">A</p><div lang="fr-BE"><p id="b">B</p></div></div><p id="c">C</p>',
213+
);
214+
215+
it.each([
216+
// [selector, expected ids]
217+
[":lang(en)", ["a"]],
218+
[":lang(EN)", ["a"]],
219+
[":lang(fr)", ["b"]],
220+
[":lang(fr-BE)", ["b"]],
221+
[":lang(en, fr)", ["a", "b"]],
222+
[":lang(de)", []],
223+
])("%s matches %j", (selector, expectedIds) => {
238224
const matches = CSSselect.selectAll<AnyNode, Element>(
239-
"p:lang(fr)",
240-
dom,
225+
`p${selector}`,
226+
langFixture,
241227
);
242-
expect(matches).toHaveLength(1);
243-
});
244-
245-
it("should not match different languages", () => {
246-
const dom = parseDocument(
247-
'<div lang="fr"><p>bonjour</p></div><div lang="en"><p>hello</p></div>',
228+
expect(matches.map((element) => element.attribs["id"])).toStrictEqual(
229+
expectedIds,
248230
);
249-
const matches = CSSselect.selectAll<AnyNode, Element>(":lang(en)", dom);
250-
expect(matches).toHaveLength(2);
251-
});
252-
253-
it("should not match partial non-prefix", () => {
254-
const dom = parseDocument('<div lang="enx"><p>hello</p></div>');
255-
const matches = CSSselect.selectAll<AnyNode, Element>(":lang(en)", dom);
256-
expect(matches).toHaveLength(0);
257231
});
258232

259-
it("should allow closer ancestor to override", () => {
260-
const dom = parseDocument(
261-
'<div lang="en"><div lang="fr"><p>bonjour</p></div></div>',
262-
);
233+
it("should not match untagged elements", () => {
263234
expect(
264-
CSSselect.selectAll<AnyNode, Element>("p:lang(fr)", dom),
235+
CSSselect.selectAll<AnyNode, Element>("p:lang(en)", langFixture),
265236
).toHaveLength(1);
266-
expect(
267-
CSSselect.selectAll<AnyNode, Element>("p:lang(en)", dom),
268-
).toHaveLength(0);
269-
});
270-
271-
it("should support comma-separated language ranges", () => {
272-
const dom = parseDocument(
273-
'<div lang="en"><p>hello</p></div><div lang="fr"><p>bonjour</p></div><div lang="de"><p>hallo</p></div>',
274-
);
275-
const matches = CSSselect.selectAll<AnyNode, Element>(
276-
":lang(en, fr)",
277-
dom,
278-
);
279-
expect(matches).toHaveLength(4);
280237
});
281238

282-
it("should use extended filtering (RFC 4647)", () => {
283-
// :lang(de-DE) should match de-Latn-DE (skipping single-char subtags)
239+
it("should use extended filtering", () => {
284240
const dom = parseDocument(
285-
'<p lang="de-DE">a</p><p lang="de-DE-1996">b</p><p lang="de-Latn-DE">c</p><p lang="de-Latf-DE">d</p><p lang="de-Latn-DE-1996">e</p>',
241+
'<p lang="de-DE">a</p><p lang="de-Latn-DE">b</p><p lang="de-Latn-DE-1996">c</p>',
286242
);
287-
const matches = CSSselect.selectAll<AnyNode, Element>(
288-
":lang(de-DE)",
289-
dom,
290-
);
291-
expect(matches).toHaveLength(5);
243+
expect(
244+
CSSselect.selectAll<AnyNode, Element>(":lang(de-DE)", dom),
245+
).toHaveLength(3);
292246
});
293247

294248
it("should support wildcard primary subtag", () => {
295249
const dom = parseDocument(
296-
'<p lang="de-CH">a</p><p lang="it-CH">b</p><p lang="fr-CH">c</p><p lang="fr-FR">d</p>',
297-
);
298-
const matches = CSSselect.selectAll<AnyNode, Element>(
299-
":lang(\\*-CH)",
300-
dom,
250+
'<p lang="de-CH">a</p><p lang="fr-CH">b</p><p lang="fr-FR">c</p>',
301251
);
302-
expect(matches).toHaveLength(3);
252+
expect(
253+
CSSselect.selectAll<AnyNode, Element>(":lang(\\*-CH)", dom),
254+
).toHaveLength(2);
303255
});
304256

305-
it("should support xml:lang attribute", () => {
306-
const dom = parseDocument('<div xml:lang="ja"><p>hello</p></div>', {
257+
it("should support xml:lang", () => {
258+
const dom = parseDocument('<div xml:lang="ja"><p>x</p></div>', {
307259
xmlMode: true,
308260
});
309-
const matches = CSSselect.selectAll<AnyNode, Element>(":lang(ja)", dom);
310-
expect(matches).toHaveLength(2);
261+
expect(
262+
CSSselect.selectAll<AnyNode, Element>(":lang(ja)", dom),
263+
).toHaveLength(2);
311264
});
312265
});
313266

0 commit comments

Comments
 (0)