@asamuzakjp/dom-selector 7.0.9 → 7.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -24,6 +24,7 @@
24
24
  "./package.json": "./package.json"
25
25
  },
26
26
  "dependencies": {
27
+ "@asamuzakjp/generational-cache": "^1.0.1",
27
28
  "@asamuzakjp/nwsapi": "^2.3.9",
28
29
  "bidi-js": "^1.0.3",
29
30
  "css-tree": "^3.2.1",
@@ -31,7 +32,7 @@
31
32
  },
32
33
  "devDependencies": {
33
34
  "@types/css-tree": "^2.3.11",
34
- "@types/node": "^25.5.2",
35
+ "@types/node": "^25.6.0",
35
36
  "benchmark": "^2.1.4",
36
37
  "c8": "^11.0.0",
37
38
  "chai": "^6.2.2",
@@ -42,12 +43,13 @@
42
43
  "eslint-plugin-prettier": "^5.5.5",
43
44
  "eslint-plugin-regexp": "^3.1.0",
44
45
  "eslint-plugin-unicorn": "^64.0.0",
45
- "globals": "^17.4.0",
46
+ "globals": "^17.5.0",
46
47
  "jsdom": "^29.0.2",
48
+ "mitata": "^1.0.34",
47
49
  "mocha": "^11.7.5",
48
50
  "neostandard": "^0.13.0",
49
- "prettier": "^3.8.1",
50
- "sinon": "^21.0.3",
51
+ "prettier": "^3.8.3",
52
+ "sinon": "^21.1.2",
51
53
  "typescript": "^6.0.2",
52
54
  "wpt-runner": "^7.0.0"
53
55
  },
@@ -60,6 +62,8 @@
60
62
  },
61
63
  "scripts": {
62
64
  "bench": "node benchmark/bench.js",
65
+ "bench:cache": "node benchmark/bench-cache.js",
66
+ "bench:cacheMonster": "node benchmark/bench-cache-monster.js",
63
67
  "bench:sizzle": "node benchmark/bench-sizzle.js",
64
68
  "build": "npm run tsc && npm run lint && npm test",
65
69
  "lint": "eslint --fix .",
@@ -71,5 +75,5 @@
71
75
  "engines": {
72
76
  "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
73
77
  },
74
- "version": "7.0.9"
78
+ "version": "7.0.10"
75
79
  }
package/src/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  /* import */
9
- import { GenerationalCache } from './js/cache.js';
9
+ import { GenerationalCache } from '@asamuzakjp/generational-cache';
10
10
  import { Finder } from './js/finder.js';
11
11
  import { filterSelector, getType, initNwsapi } from './js/utility.js';
12
12
 
@@ -20,7 +20,7 @@ import {
20
20
  TARGET_LINEAL,
21
21
  TARGET_SELF
22
22
  } from './js/constant.js';
23
- const MAX_CACHE = 1024;
23
+ const CACHE_SIZE = 1024;
24
24
 
25
25
  /**
26
26
  * @typedef {object} CheckResult
@@ -46,13 +46,13 @@ export class DOMSelector {
46
46
  * @param {object} [opt] - Options.
47
47
  */
48
48
  constructor(window, document, opt = {}) {
49
- const { idlUtils } = opt;
49
+ const { cacheSize, idlUtils } = opt;
50
50
  this.#window = window;
51
51
  this.#document = document ?? window.document;
52
52
  this.#finder = new Finder(window);
53
53
  this.#idlUtils = idlUtils;
54
54
  this.#nwsapi = initNwsapi(window, document);
55
- this.#cache = new GenerationalCache(MAX_CACHE);
55
+ this.#cache = new GenerationalCache(cacheSize ?? CACHE_SIZE);
56
56
  }
57
57
 
58
58
  /**
package/src/js/matcher.js CHANGED
@@ -443,16 +443,19 @@ export const matchAttributeSelector = (ast, node, opt = {}) => {
443
443
  const { name: astIdentValue, value: astStringValue } = astValue ?? {};
444
444
  let attrValue;
445
445
  if (astIdentValue) {
446
+ // Ident values are not unescaped by css-tree, so we must unescape them
447
+ // (e.g. `\5c` hex escapes, `\n` character escapes).
446
448
  if (caseInsensitive) {
447
- attrValue = astIdentValue.toLowerCase().replace(/\\(?!\\)/g, '');
449
+ attrValue = unescapeSelector(astIdentValue).toLowerCase();
448
450
  } else {
449
- attrValue = astIdentValue.replace(/\\(?!\\)/g, '');
451
+ attrValue = unescapeSelector(astIdentValue);
450
452
  }
451
453
  } else if (astStringValue) {
454
+ // String values (quoted) are already unescaped by css-tree, so use as-is.
452
455
  if (caseInsensitive) {
453
- attrValue = astStringValue.toLowerCase().replace(/\\(?!\\)/g, '');
456
+ attrValue = astStringValue.toLowerCase();
454
457
  } else {
455
- attrValue = astStringValue.replace(/\\(?!\\)/g, '');
458
+ attrValue = astStringValue;
456
459
  }
457
460
  } else if (astStringValue === '') {
458
461
  attrValue = astStringValue;
package/src/js/parser.js CHANGED
@@ -72,6 +72,13 @@ export const unescapeSelector = (selector = '') => {
72
72
  const item = arr[i];
73
73
  if (item === '' && i === l - 1) {
74
74
  selectorItems.push(U_FFFD);
75
+ } else if (item === '') {
76
+ // Empty segment at non-last position means \\ (escaped backslash)
77
+ selectorItems.push('\\');
78
+ i++; // skip the next segment which is the remainder after \\
79
+ if (i < l) {
80
+ selectorItems.push(arr[i]);
81
+ }
75
82
  } else {
76
83
  const hexExists = /^([\da-f]{1,6}\s?)/i.exec(item);
77
84
  if (hexExists) {
package/src/js/cache.js DELETED
@@ -1,77 +0,0 @@
1
- /**
2
- * cache.js
3
- */
4
-
5
- /* Generational Cache */
6
- export class GenerationalCache {
7
- #max;
8
- #boundary;
9
- #current;
10
- #old;
11
-
12
- /**
13
- * constructor
14
- * @param {number} max - max cache size
15
- */
16
- constructor(max) {
17
- this.#current = new Map();
18
- this.#old = new Map();
19
- this.max = max;
20
- }
21
-
22
- get size() {
23
- return this.#current.size + this.#old.size;
24
- }
25
-
26
- /**
27
- * @returns {number} max cache size
28
- */
29
- get max() {
30
- return this.#max;
31
- }
32
-
33
- set max(value) {
34
- if (Number.isFinite(value) && value > 4) {
35
- this.#max = value;
36
- this.#boundary = Math.ceil(value / 2);
37
- } else {
38
- this.#max = 4;
39
- this.#boundary = 2;
40
- }
41
- this.clear();
42
- }
43
-
44
- get(key) {
45
- if (this.#current.has(key)) {
46
- return this.#current.get(key);
47
- }
48
- const value = this.#old.get(key);
49
- if (value !== undefined) {
50
- this.set(key, value);
51
- return value;
52
- }
53
- return undefined;
54
- }
55
-
56
- set(key, value) {
57
- this.#current.set(key, value);
58
- if (this.#current.size >= this.#boundary) {
59
- this.#old = this.#current;
60
- this.#current = new Map();
61
- }
62
- }
63
-
64
- has(key) {
65
- return this.#current.has(key) || this.#old.has(key);
66
- }
67
-
68
- delete(key) {
69
- this.#current.delete(key);
70
- this.#old.delete(key);
71
- }
72
-
73
- clear() {
74
- this.#current.clear();
75
- this.#old.clear();
76
- }
77
- }
@@ -1,12 +0,0 @@
1
- export class GenerationalCache {
2
- constructor(max: number);
3
- set max(value: number);
4
- get max(): number;
5
- get size(): number;
6
- get(key: any): any;
7
- set(key: any, value: any): void;
8
- has(key: any): boolean;
9
- delete(key: any): void;
10
- clear(): void;
11
- #private;
12
- }