@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 +9 -5
- package/src/index.js +4 -4
- package/src/js/matcher.js +7 -4
- package/src/js/parser.js +7 -0
- package/src/js/cache.js +0 -77
- package/types/js/cache.d.ts +0 -12
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.
|
|
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.
|
|
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.
|
|
50
|
-
"sinon": "^21.
|
|
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.
|
|
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 '
|
|
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
|
|
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(
|
|
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()
|
|
449
|
+
attrValue = unescapeSelector(astIdentValue).toLowerCase();
|
|
448
450
|
} else {
|
|
449
|
-
attrValue = astIdentValue
|
|
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()
|
|
456
|
+
attrValue = astStringValue.toLowerCase();
|
|
454
457
|
} else {
|
|
455
|
-
attrValue = astStringValue
|
|
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
|
-
}
|
package/types/js/cache.d.ts
DELETED
|
@@ -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
|
-
}
|