@asamuzakjp/dom-selector 0.12.1 → 0.12.3
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 +1 -1
- package/src/js/matcher.js +38 -24
- package/src/js/parser.js +14 -10
package/package.json
CHANGED
package/src/js/matcher.js
CHANGED
|
@@ -25,9 +25,9 @@ const HEX_CAPTURE = /^([\da-f]{1,6}\s?)/i;
|
|
|
25
25
|
const HTML_FORM_INPUT = /^(?:(?:inpu|selec)t|textarea)$/;
|
|
26
26
|
const HTML_FORM_PARTS = /^(?:button|fieldset|opt(?:group|ion))$/;
|
|
27
27
|
const HTML_INTERACT = /^d(?:etails|ialog)$/;
|
|
28
|
+
const INPUT_TYPE_BARRED = /^(?:(?:butto|hidde)n|reset)$/;
|
|
28
29
|
const PSEUDO_FUNC = /^(?:(?:ha|i)s|not|where)$/;
|
|
29
30
|
const PSEUDO_NTH = /^nth-(?:last-)?(?:child|of-type)$/;
|
|
30
|
-
const REPLACE_CHAR = /[\0\uD800-\uDFFF]/g;
|
|
31
31
|
const WHITESPACE = /^[\n\r\f]/;
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -94,7 +94,7 @@ const unescapeSelector = (selector = '') => {
|
|
|
94
94
|
selector.indexOf(String.fromCharCode(0x5c), 0) >= 0) {
|
|
95
95
|
const arr = selector.split('\\');
|
|
96
96
|
const l = arr.length;
|
|
97
|
-
for (let i =
|
|
97
|
+
for (let i = 1; i < l; i++) {
|
|
98
98
|
let item = arr[i];
|
|
99
99
|
if (i === l - 1 && item === '') {
|
|
100
100
|
item = '\uFFFD';
|
|
@@ -104,12 +104,22 @@ const unescapeSelector = (selector = '') => {
|
|
|
104
104
|
const [, hex] = hexExists;
|
|
105
105
|
let str;
|
|
106
106
|
try {
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
const low = parseInt('D800', 16);
|
|
108
|
+
const high = parseInt('DFFF', 16);
|
|
109
|
+
const deci = parseInt(hex, 16);
|
|
110
|
+
if (deci === 0 || (deci >= low && deci <= high)) {
|
|
111
|
+
str = '\uFFFD';
|
|
112
|
+
} else {
|
|
113
|
+
str = String.fromCodePoint(deci);
|
|
114
|
+
}
|
|
109
115
|
} catch (e) {
|
|
110
116
|
str = '\uFFFD';
|
|
111
117
|
}
|
|
112
|
-
|
|
118
|
+
let postStr = '';
|
|
119
|
+
if (item.length > hex.length) {
|
|
120
|
+
postStr = item.substring(hex.length);
|
|
121
|
+
}
|
|
122
|
+
item = `${str}${postStr}`;
|
|
113
123
|
} else if (WHITESPACE.test(item)) {
|
|
114
124
|
item = '\\' + item;
|
|
115
125
|
}
|
|
@@ -150,7 +160,7 @@ const collectNthChild = (anb = {}, node = {}) => {
|
|
|
150
160
|
}
|
|
151
161
|
// :first-child, :last-child, :nth-child(0 of S)
|
|
152
162
|
if (a === 0) {
|
|
153
|
-
if (b
|
|
163
|
+
if (b > 0 && b <= l) {
|
|
154
164
|
if (items.length) {
|
|
155
165
|
let i = 0;
|
|
156
166
|
while (i < l) {
|
|
@@ -162,7 +172,7 @@ const collectNthChild = (anb = {}, node = {}) => {
|
|
|
162
172
|
i++;
|
|
163
173
|
}
|
|
164
174
|
} else {
|
|
165
|
-
const current = arr[b];
|
|
175
|
+
const current = arr[b - 1];
|
|
166
176
|
matched.push(current);
|
|
167
177
|
}
|
|
168
178
|
}
|
|
@@ -225,14 +235,14 @@ const collectNthOfType = (anb = {}, node = {}) => {
|
|
|
225
235
|
const l = arr.length;
|
|
226
236
|
// :first-of-type, :last-of-type
|
|
227
237
|
if (a === 0) {
|
|
228
|
-
if (b
|
|
238
|
+
if (b > 0 && b <= l) {
|
|
229
239
|
let i = 0;
|
|
230
240
|
let j = 0;
|
|
231
241
|
while (i < l) {
|
|
232
242
|
const current = arr[i];
|
|
233
243
|
const { localName: itemLocalName, prefix: itemPrefix } = current;
|
|
234
244
|
if (itemLocalName === localName && itemPrefix === prefix) {
|
|
235
|
-
if (j === b) {
|
|
245
|
+
if (j === b - 1) {
|
|
236
246
|
matched.push(current);
|
|
237
247
|
break;
|
|
238
248
|
}
|
|
@@ -457,6 +467,9 @@ const matchAttributeSelector = (ast = {}, node = {}) => {
|
|
|
457
467
|
const l = attributes.length;
|
|
458
468
|
let { name: astAttrName } = astName;
|
|
459
469
|
astAttrName = unescapeSelector(astAttrName);
|
|
470
|
+
if (caseInsensitive) {
|
|
471
|
+
astAttrName = astAttrName.toLowerCase();
|
|
472
|
+
}
|
|
460
473
|
// namespaced
|
|
461
474
|
if (/\|/.test(astAttrName)) {
|
|
462
475
|
const [astAttrPrefix, astAttrLocalName] = astAttrName.split('|');
|
|
@@ -957,20 +970,21 @@ const matchPseudoClassSelector = (
|
|
|
957
970
|
}
|
|
958
971
|
break;
|
|
959
972
|
case 'in-range':
|
|
960
|
-
if (localName === 'input' &&
|
|
961
|
-
node.hasAttribute('
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
973
|
+
if (localName === 'input' && !node.readonly &&
|
|
974
|
+
!(node.hasAttribute('type') &&
|
|
975
|
+
INPUT_TYPE_BARRED.test(node.getAttribute('type'))) &&
|
|
976
|
+
node.hasAttribute('min') && node.hasAttribute('max') &&
|
|
977
|
+
!(node.validity.rangeUnderflow || node.validity.rangeOverflow)) {
|
|
978
|
+
matched.push(node);
|
|
966
979
|
}
|
|
967
980
|
break;
|
|
968
981
|
case 'out-of-range':
|
|
969
|
-
if (localName === 'input' &&
|
|
970
|
-
node.hasAttribute('
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
982
|
+
if (localName === 'input' && !node.readonly &&
|
|
983
|
+
!(node.hasAttribute('type') &&
|
|
984
|
+
INPUT_TYPE_BARRED.test(node.getAttribute('type'))) &&
|
|
985
|
+
node.hasAttribute('min') && node.hasAttribute('max') &&
|
|
986
|
+
(node.validity.rangeUnderflow || node.validity.rangeOverflow)) {
|
|
987
|
+
matched.push(node);
|
|
974
988
|
}
|
|
975
989
|
break;
|
|
976
990
|
case 'required':
|
|
@@ -1018,7 +1032,7 @@ const matchPseudoClassSelector = (
|
|
|
1018
1032
|
case 'first-of-type': {
|
|
1019
1033
|
const [node1] = collectNthOfType({
|
|
1020
1034
|
a: 0,
|
|
1021
|
-
b:
|
|
1035
|
+
b: 1
|
|
1022
1036
|
}, node);
|
|
1023
1037
|
if (node1) {
|
|
1024
1038
|
matched.push(node1);
|
|
@@ -1028,7 +1042,7 @@ const matchPseudoClassSelector = (
|
|
|
1028
1042
|
case 'last-of-type': {
|
|
1029
1043
|
const [node1] = collectNthOfType({
|
|
1030
1044
|
a: 0,
|
|
1031
|
-
b:
|
|
1045
|
+
b: 1,
|
|
1032
1046
|
reverse: true
|
|
1033
1047
|
}, node);
|
|
1034
1048
|
if (node1) {
|
|
@@ -1039,11 +1053,11 @@ const matchPseudoClassSelector = (
|
|
|
1039
1053
|
case 'only-of-type': {
|
|
1040
1054
|
const [node1] = collectNthOfType({
|
|
1041
1055
|
a: 0,
|
|
1042
|
-
b:
|
|
1056
|
+
b: 1
|
|
1043
1057
|
}, node);
|
|
1044
1058
|
const [node2] = collectNthOfType({
|
|
1045
1059
|
a: 0,
|
|
1046
|
-
b:
|
|
1060
|
+
b: 1,
|
|
1047
1061
|
reverse: true
|
|
1048
1062
|
}, node);
|
|
1049
1063
|
if (node1 === node && node2 === node) {
|
package/src/js/parser.js
CHANGED
|
@@ -23,16 +23,16 @@ const preprocess = (...args) => {
|
|
|
23
23
|
throw new TypeError('1 argument required, but only 0 present');
|
|
24
24
|
}
|
|
25
25
|
let [selector] = args;
|
|
26
|
-
if (typeof selector
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
if (typeof selector === 'string') {
|
|
27
|
+
selector = selector.replace(/\f|\r\n?/g, '\n')
|
|
28
|
+
.replace(/[\0\uD800-\uDFFF]|\\$/g, '\uFFFD').trim();
|
|
29
|
+
} else if (selector === undefined || selector === null) {
|
|
30
|
+
selector = Object.prototype.toString.call(selector)
|
|
31
|
+
.slice(TYPE_FROM, TYPE_TO).toLowerCase();
|
|
32
|
+
} else {
|
|
33
|
+
throw new DOMException(`invalid selector ${selector}`, 'SyntaxError');
|
|
33
34
|
}
|
|
34
|
-
return selector
|
|
35
|
-
.replace(/[\0\uD800-\uDFFF]/g, '\uFFFD').trim();
|
|
35
|
+
return selector;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -54,7 +54,11 @@ const parseSelector = selector => {
|
|
|
54
54
|
});
|
|
55
55
|
res = toPlainObject(ast);
|
|
56
56
|
} catch (e) {
|
|
57
|
-
|
|
57
|
+
if (e.message === '"]" is expected' && !selector.endsWith(']')) {
|
|
58
|
+
res = parseSelector(`${selector}]`);
|
|
59
|
+
} else {
|
|
60
|
+
throw new DOMException(e.message, 'SyntaxError');
|
|
61
|
+
}
|
|
58
62
|
}
|
|
59
63
|
return res;
|
|
60
64
|
};
|