@node-projects/web-component-designer 0.1.331 → 0.1.334
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/.claude/settings.local.json +9 -0
- package/dist/elements/documentContainer.js +0 -4
- package/dist/elements/documentContainer.js.map +1 -1
- package/dist/elements/helper/SwitchContainerHelper.js +1 -2
- package/dist/elements/helper/SwitchContainerHelper.js.map +1 -1
- package/dist/elements/services/stylesheetService/AbstractStylesheetService.js +2 -2
- package/dist/elements/services/stylesheetService/AbstractStylesheetService.js.map +1 -1
- package/dist/elements/services/stylesheetService/SpecificityCalculator.d.ts +5 -1
- package/dist/elements/services/stylesheetService/SpecificityCalculator.js +437 -153
- package/dist/elements/services/stylesheetService/SpecificityCalculator.js.map +1 -1
- package/dist/elements/widgets/designerView/IDesignerCanvas.d.ts +4 -0
- package/dist/elements/widgets/designerView/designerCanvas.d.ts +4 -0
- package/dist/elements/widgets/designerView/designerCanvas.js +3 -0
- package/dist/elements/widgets/designerView/designerCanvas.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/ResizeExtension.js +3 -0
- package/dist/elements/widgets/designerView/extensions/ResizeExtension.js.map +1 -1
- package/dist/elements/widgets/designerView/extensions/contextMenu/ItemsBelowContextMenu.js.map +1 -1
- package/dist/index-min.js +161 -160
- package/dist/index-min.js.map +7 -0
- package/jest.config.js +2 -2
- package/package.json +2 -2
- package/tests/SpecificityCalculator.test.ts +554 -1
|
@@ -1,168 +1,452 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
// Char codes used throughout
|
|
2
|
+
const CH_HASH = 35; // #
|
|
3
|
+
const CH_DOT = 46; // .
|
|
4
|
+
const CH_COLON = 58; // :
|
|
5
|
+
const CH_LBRACKET = 91; // [
|
|
6
|
+
const CH_RBRACKET = 93; // ]
|
|
7
|
+
const CH_LPAREN = 40; // (
|
|
8
|
+
const CH_RPAREN = 41; // )
|
|
9
|
+
const CH_COMMA = 44; // ,
|
|
10
|
+
const CH_BACKSLASH = 92; // \
|
|
11
|
+
const CH_STAR = 42; // *
|
|
12
|
+
const CH_PIPE = 124; // |
|
|
13
|
+
const CH_SPACE = 32; // ' '
|
|
14
|
+
const CH_GT = 62; // >
|
|
15
|
+
const CH_PLUS = 43; // +
|
|
16
|
+
const CH_TILDE = 126; // ~
|
|
17
|
+
const CH_SQUOTE = 39; // '
|
|
18
|
+
const CH_DQUOTE = 34; // "
|
|
19
|
+
const CH_UNDERSCORE = 95; // _
|
|
20
|
+
const CH_DASH = 45; // -
|
|
9
21
|
export function calculateSpecificity(selector) {
|
|
10
|
-
|
|
22
|
+
const spec = { A: 0, B: 0, C: 0 };
|
|
23
|
+
// Fast path: simple selectors without pseudo-classes, attributes, functions, commas, or escapes
|
|
24
|
+
if (!needsFullParse(selector)) {
|
|
25
|
+
calcSimple(selector, spec);
|
|
26
|
+
return spec;
|
|
27
|
+
}
|
|
28
|
+
parseSelectorList(selector, 0, spec);
|
|
29
|
+
return spec;
|
|
30
|
+
}
|
|
31
|
+
function needsFullParse(selector) {
|
|
32
|
+
for (let i = 0; i < selector.length; i++) {
|
|
33
|
+
const c = selector.charCodeAt(i);
|
|
34
|
+
if (c === CH_COLON || c === CH_LBRACKET || c === CH_LPAREN || c === CH_COMMA || c === CH_BACKSLASH)
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
11
38
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
let
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
39
|
+
function calcSimple(selector, spec) {
|
|
40
|
+
const len = selector.length;
|
|
41
|
+
let i = 0;
|
|
42
|
+
while (i < len) {
|
|
43
|
+
const c = selector.charCodeAt(i);
|
|
44
|
+
// Column combinator ||
|
|
45
|
+
if (c === CH_PIPE && i + 1 < len && selector.charCodeAt(i + 1) === CH_PIPE) {
|
|
46
|
+
i += 2;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (c === CH_SPACE || c === CH_GT || c === CH_PLUS || c === CH_TILDE) {
|
|
50
|
+
i++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (c === CH_HASH) {
|
|
54
|
+
spec.A++;
|
|
55
|
+
i++;
|
|
56
|
+
while (i < len && isIdentCC(selector.charCodeAt(i)))
|
|
57
|
+
i++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (c === CH_DOT) {
|
|
61
|
+
spec.B++;
|
|
62
|
+
i++;
|
|
63
|
+
while (i < len && isIdentCC(selector.charCodeAt(i)))
|
|
64
|
+
i++;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (c === CH_STAR) {
|
|
68
|
+
i++;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (isIdentStartCC(c) || c === CH_PIPE) {
|
|
72
|
+
while (i < len) {
|
|
73
|
+
const cc = selector.charCodeAt(i);
|
|
74
|
+
if (isIdentCC(cc) || cc === CH_PIPE)
|
|
75
|
+
i++;
|
|
76
|
+
else
|
|
77
|
+
break;
|
|
20
78
|
}
|
|
79
|
+
spec.C++;
|
|
80
|
+
continue;
|
|
21
81
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
82
|
+
i++;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/* ---- Full parser (used when selector contains :, [, (, \, or ,) ---- */
|
|
86
|
+
function parseSelectorList(input, start, spec) {
|
|
87
|
+
let i = start;
|
|
88
|
+
let tA = 0, tB = 0, tC = 0;
|
|
89
|
+
while (i < input.length) {
|
|
90
|
+
tA = tB = tC = 0;
|
|
91
|
+
i = parseSelector(input, i, spec, true);
|
|
92
|
+
// parseSelector wrote into spec; grab those values as temp then reset
|
|
93
|
+
tA = spec.A;
|
|
94
|
+
tB = spec.B;
|
|
95
|
+
tC = spec.C;
|
|
96
|
+
// On the very first iteration we just keep the values.
|
|
97
|
+
// On subsequent iterations we pick the most specific (lexicographic).
|
|
98
|
+
// To avoid extra bookkeeping we always overwrite spec and compare below.
|
|
99
|
+
if (input.charCodeAt(i) === CH_COMMA) {
|
|
100
|
+
i++;
|
|
101
|
+
// Need to parse more selectors — save best so far
|
|
102
|
+
let bestA = tA, bestB = tB, bestC = tC;
|
|
103
|
+
while (i < input.length) {
|
|
104
|
+
spec.A = spec.B = spec.C = 0;
|
|
105
|
+
i = parseSelector(input, i, spec, true);
|
|
106
|
+
if (spec.A > bestA || (spec.A === bestA && (spec.B > bestB || (spec.B === bestB && spec.C > bestC)))) {
|
|
107
|
+
bestA = spec.A;
|
|
108
|
+
bestB = spec.B;
|
|
109
|
+
bestC = spec.C;
|
|
110
|
+
}
|
|
111
|
+
if (input.charCodeAt(i) === CH_COMMA) {
|
|
112
|
+
i++;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
25
116
|
}
|
|
117
|
+
spec.A = bestA;
|
|
118
|
+
spec.B = bestB;
|
|
119
|
+
spec.C = bestC;
|
|
26
120
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
else if (selector.substring(n + 1, n + 9) === 'slotted(') {
|
|
115
|
-
s.B++;
|
|
116
|
-
n += 9;
|
|
117
|
-
const res = calculateSpecificityInternal(selector, n);
|
|
118
|
-
n = res[1];
|
|
119
|
-
s.A += res[0].A;
|
|
120
|
-
s.B += res[0].B;
|
|
121
|
-
s.C += res[0].C;
|
|
122
|
-
}
|
|
123
|
-
else if (selector.substring(n + 1, n + 7) === 'where(') { //where does not add specificity
|
|
124
|
-
parseState = ParseState.parseInFunc;
|
|
125
|
-
n += 7;
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
s.B++;
|
|
129
|
-
parseState = ParseState.parseName;
|
|
130
|
-
n++;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
return i;
|
|
124
|
+
}
|
|
125
|
+
// When called from parseSelectorList with direct=true, writes directly into spec (avoids temp object).
|
|
126
|
+
// When called recursively (direct=false), the caller manages its own temp.
|
|
127
|
+
function parseSelector(input, start, spec, direct) {
|
|
128
|
+
let i = start;
|
|
129
|
+
if (direct) {
|
|
130
|
+
spec.A = spec.B = spec.C = 0;
|
|
131
|
+
}
|
|
132
|
+
while (i < input.length) {
|
|
133
|
+
const c = input.charCodeAt(i);
|
|
134
|
+
if (c === CH_COMMA || c === CH_RPAREN)
|
|
135
|
+
break;
|
|
136
|
+
// Column combinator ||
|
|
137
|
+
if (c === CH_PIPE && input.charCodeAt(i + 1) === CH_PIPE) {
|
|
138
|
+
i += 2;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (c === CH_SPACE || c === CH_GT || c === CH_PLUS || c === CH_TILDE) {
|
|
142
|
+
i++;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (c === CH_HASH) {
|
|
146
|
+
i = readIdent(input, i + 1);
|
|
147
|
+
spec.A++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (c === CH_DOT) {
|
|
151
|
+
i = readIdent(input, i + 1);
|
|
152
|
+
spec.B++;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (c === CH_LBRACKET) {
|
|
156
|
+
i = readBalanced(input, i, CH_LBRACKET, CH_RBRACKET);
|
|
157
|
+
spec.B++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (c === CH_COLON) {
|
|
161
|
+
if (input.charCodeAt(i + 1) === CH_COLON) {
|
|
162
|
+
i += 2;
|
|
163
|
+
i = readIdent(input, i);
|
|
164
|
+
if (input.charCodeAt(i) === CH_LPAREN)
|
|
165
|
+
i = readBalanced(input, i, CH_LPAREN, CH_RPAREN);
|
|
166
|
+
spec.C++;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const nameStart = i + 1;
|
|
170
|
+
const nameEnd = readIdent(input, nameStart);
|
|
171
|
+
i = nameEnd;
|
|
172
|
+
// Legacy single-colon pseudo-elements — count as C (pseudo-element), not B
|
|
173
|
+
if (isLegacyPseudoElement(input, nameStart, nameEnd - nameStart)) {
|
|
174
|
+
spec.C++;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (input.charCodeAt(i) === CH_LPAREN) {
|
|
178
|
+
const innerStart = i + 1;
|
|
179
|
+
const innerEnd = readBalanced(input, i, CH_LPAREN, CH_RPAREN);
|
|
180
|
+
// Identify the pseudo-class by comparing chars directly (avoids substring allocation)
|
|
181
|
+
const nameLen = nameEnd - nameStart;
|
|
182
|
+
const pcKind = classifyPseudo(input, nameStart, nameLen);
|
|
183
|
+
switch (pcKind) {
|
|
184
|
+
case PC_WHERE:
|
|
185
|
+
i = innerEnd;
|
|
186
|
+
continue;
|
|
187
|
+
case PC_IS:
|
|
188
|
+
case PC_NOT:
|
|
189
|
+
case PC_HAS:
|
|
190
|
+
case PC_MATCHES:
|
|
191
|
+
case PC_WEBKIT_ANY:
|
|
192
|
+
case PC_MOZ_ANY: {
|
|
193
|
+
let bestA = 0, bestB = 0, bestC = 0;
|
|
194
|
+
let j = innerStart;
|
|
195
|
+
const limit = innerEnd - 1;
|
|
196
|
+
while (j < limit) {
|
|
197
|
+
const saved = { A: 0, B: 0, C: 0 };
|
|
198
|
+
j = parseSelectorInner(input, j, saved);
|
|
199
|
+
if (saved.A > bestA || (saved.A === bestA && (saved.B > bestB || (saved.B === bestB && saved.C > bestC)))) {
|
|
200
|
+
bestA = saved.A;
|
|
201
|
+
bestB = saved.B;
|
|
202
|
+
bestC = saved.C;
|
|
203
|
+
}
|
|
204
|
+
if (input.charCodeAt(j) === CH_COMMA)
|
|
205
|
+
j++;
|
|
206
|
+
else
|
|
207
|
+
break;
|
|
131
208
|
}
|
|
209
|
+
spec.A += bestA;
|
|
210
|
+
spec.B += bestB;
|
|
211
|
+
spec.C += bestC;
|
|
212
|
+
i = innerEnd;
|
|
213
|
+
continue;
|
|
132
214
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
215
|
+
case PC_SLOTTED: {
|
|
216
|
+
const inner = { A: 0, B: 0, C: 0 };
|
|
217
|
+
parseSelector(input, innerStart, inner, false);
|
|
218
|
+
spec.A += inner.A;
|
|
219
|
+
spec.B += inner.B;
|
|
220
|
+
spec.C += inner.C;
|
|
221
|
+
i = innerEnd;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
case PC_HOST:
|
|
225
|
+
case PC_HOST_CTX: {
|
|
226
|
+
spec.B++;
|
|
227
|
+
const inner = { A: 0, B: 0, C: 0 };
|
|
228
|
+
parseSelector(input, innerStart, inner, false);
|
|
229
|
+
spec.A += inner.A;
|
|
230
|
+
spec.B += inner.B;
|
|
231
|
+
spec.C += inner.C;
|
|
232
|
+
i = innerEnd;
|
|
233
|
+
continue;
|
|
146
234
|
}
|
|
235
|
+
case PC_NTH_CHILD:
|
|
236
|
+
case PC_NTH_LAST: {
|
|
237
|
+
spec.B++;
|
|
238
|
+
const limit = innerEnd - 1;
|
|
239
|
+
const ofIndex = findOfKeyword(input, innerStart, limit);
|
|
240
|
+
if (ofIndex !== -1) {
|
|
241
|
+
let afterOf = ofIndex + 2;
|
|
242
|
+
while (afterOf < limit && isWhitespaceCC(input.charCodeAt(afterOf)))
|
|
243
|
+
afterOf++;
|
|
244
|
+
let bestA = 0, bestB = 0, bestC = 0;
|
|
245
|
+
let j = afterOf;
|
|
246
|
+
while (j < limit) {
|
|
247
|
+
const ts = { A: 0, B: 0, C: 0 };
|
|
248
|
+
j = parseSelector(input, j, ts, false);
|
|
249
|
+
if (ts.A > bestA || (ts.A === bestA && (ts.B > bestB || (ts.B === bestB && ts.C > bestC)))) {
|
|
250
|
+
bestA = ts.A;
|
|
251
|
+
bestB = ts.B;
|
|
252
|
+
bestC = ts.C;
|
|
253
|
+
}
|
|
254
|
+
if (input.charCodeAt(j) === CH_COMMA)
|
|
255
|
+
j++;
|
|
256
|
+
else
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
spec.A += bestA;
|
|
260
|
+
spec.B += bestB;
|
|
261
|
+
spec.C += bestC;
|
|
262
|
+
}
|
|
263
|
+
i = innerEnd;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
default:
|
|
267
|
+
spec.B++;
|
|
268
|
+
i = innerEnd;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
spec.B++;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (c === CH_STAR) {
|
|
278
|
+
i++;
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (isIdentStartCC(c) || c === CH_PIPE) {
|
|
282
|
+
while (i < input.length && (isIdentCC(input.charCodeAt(i)) || input.charCodeAt(i) === CH_PIPE))
|
|
283
|
+
i++;
|
|
284
|
+
spec.C++;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
i++;
|
|
288
|
+
}
|
|
289
|
+
return i;
|
|
290
|
+
}
|
|
291
|
+
// Parse a single selector within a functional pseudo-class argument (handles commas at the caller level)
|
|
292
|
+
function parseSelectorInner(input, start, spec) {
|
|
293
|
+
return parseSelector(input, start, spec, false);
|
|
294
|
+
}
|
|
295
|
+
/* ---- Pseudo-class classification (avoids substring + switch on string) ---- */
|
|
296
|
+
const PC_OTHER = 0;
|
|
297
|
+
const PC_WHERE = 1;
|
|
298
|
+
const PC_IS = 2;
|
|
299
|
+
const PC_NOT = 3;
|
|
300
|
+
const PC_HAS = 4;
|
|
301
|
+
const PC_SLOTTED = 5;
|
|
302
|
+
const PC_HOST = 6;
|
|
303
|
+
const PC_HOST_CTX = 7;
|
|
304
|
+
const PC_NTH_CHILD = 8;
|
|
305
|
+
const PC_NTH_LAST = 9;
|
|
306
|
+
const PC_MATCHES = 10;
|
|
307
|
+
const PC_WEBKIT_ANY = 11;
|
|
308
|
+
const PC_MOZ_ANY = 12;
|
|
309
|
+
function classifyPseudo(input, start, len) {
|
|
310
|
+
// Most common first
|
|
311
|
+
if (len === 5 && input.charCodeAt(start) === 119) { // 'w'here
|
|
312
|
+
if (input.charCodeAt(start + 1) === 104 && input.charCodeAt(start + 2) === 101 &&
|
|
313
|
+
input.charCodeAt(start + 3) === 114 && input.charCodeAt(start + 4) === 101)
|
|
314
|
+
return PC_WHERE;
|
|
315
|
+
}
|
|
316
|
+
if (len === 3 && input.charCodeAt(start) === 110) { // 'n'ot
|
|
317
|
+
if (input.charCodeAt(start + 1) === 111 && input.charCodeAt(start + 2) === 116)
|
|
318
|
+
return PC_NOT;
|
|
319
|
+
}
|
|
320
|
+
if (len === 2 && input.charCodeAt(start) === 105) { // 'i's
|
|
321
|
+
if (input.charCodeAt(start + 1) === 115)
|
|
322
|
+
return PC_IS;
|
|
323
|
+
}
|
|
324
|
+
if (len === 3 && input.charCodeAt(start) === 104) { // 'h'as / 'h'ost
|
|
325
|
+
if (input.charCodeAt(start + 1) === 97 && input.charCodeAt(start + 2) === 115)
|
|
326
|
+
return PC_HAS;
|
|
327
|
+
}
|
|
328
|
+
if (len === 4 && input.charCodeAt(start) === 104) { // 'h'ost
|
|
329
|
+
if (input.charCodeAt(start + 1) === 111 && input.charCodeAt(start + 2) === 115 &&
|
|
330
|
+
input.charCodeAt(start + 3) === 116)
|
|
331
|
+
return PC_HOST;
|
|
332
|
+
}
|
|
333
|
+
if (len === 12 && input.charCodeAt(start) === 104) { // host-context
|
|
334
|
+
if (input.charCodeAt(start + 4) === CH_DASH && input.charCodeAt(start + 5) === 99) {
|
|
335
|
+
// Quick check first+last chars, then full
|
|
336
|
+
if (input.substring(start, start + len) === 'host-context')
|
|
337
|
+
return PC_HOST_CTX;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (len === 7 && input.charCodeAt(start) === 115) { // slotted
|
|
341
|
+
if (input.substring(start, start + 7) === 'slotted')
|
|
342
|
+
return PC_SLOTTED;
|
|
343
|
+
}
|
|
344
|
+
if (len === 9 && input.charCodeAt(start) === 110) { // nth-child
|
|
345
|
+
if (input.substring(start, start + 9) === 'nth-child')
|
|
346
|
+
return PC_NTH_CHILD;
|
|
347
|
+
}
|
|
348
|
+
if (len === 14 && input.charCodeAt(start) === 110) { // nth-last-child
|
|
349
|
+
if (input.substring(start, start + 14) === 'nth-last-child')
|
|
350
|
+
return PC_NTH_LAST;
|
|
351
|
+
}
|
|
352
|
+
if (len === 7 && input.charCodeAt(start) === 109) { // matches
|
|
353
|
+
if (input.substring(start, start + 7) === 'matches')
|
|
354
|
+
return PC_MATCHES;
|
|
355
|
+
}
|
|
356
|
+
if (len === 11 && input.charCodeAt(start) === CH_DASH) { // -webkit-any
|
|
357
|
+
if (input.substring(start, start + 11) === '-webkit-any')
|
|
358
|
+
return PC_WEBKIT_ANY;
|
|
359
|
+
}
|
|
360
|
+
if (len === 8 && input.charCodeAt(start) === CH_DASH) { // -moz-any
|
|
361
|
+
if (input.substring(start, start + 8) === '-moz-any')
|
|
362
|
+
return PC_MOZ_ANY;
|
|
363
|
+
}
|
|
364
|
+
return PC_OTHER;
|
|
365
|
+
}
|
|
366
|
+
// Legacy single-colon pseudo-elements that should count as C, not B
|
|
367
|
+
function isLegacyPseudoElement(input, start, len) {
|
|
368
|
+
if (len === 6) { // before / after
|
|
369
|
+
const c0 = input.charCodeAt(start);
|
|
370
|
+
if (c0 === 98)
|
|
371
|
+
return input.substring(start, start + 6) === 'before'; // 'b'efore
|
|
372
|
+
if (c0 === 97)
|
|
373
|
+
return input.substring(start, start + 6) === 'after'; // 'a'fter (5 chars, won't match — handled below)
|
|
374
|
+
}
|
|
375
|
+
if (len === 5 && input.charCodeAt(start) === 97) { // after
|
|
376
|
+
return input.substring(start, start + 5) === 'after';
|
|
377
|
+
}
|
|
378
|
+
if (len === 10 && input.charCodeAt(start) === 102) { // first-line
|
|
379
|
+
return input.substring(start, start + 10) === 'first-line';
|
|
380
|
+
}
|
|
381
|
+
if (len === 12 && input.charCodeAt(start) === 102) { // first-letter
|
|
382
|
+
return input.substring(start, start + 12) === 'first-letter';
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
/* ---- Character classification (charCode-based, no string allocation) ---- */
|
|
387
|
+
function isIdentStartCC(code) {
|
|
388
|
+
return (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === CH_UNDERSCORE || code === CH_DASH || code === CH_BACKSLASH;
|
|
389
|
+
}
|
|
390
|
+
function isIdentCC(code) {
|
|
391
|
+
return (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || (code >= 48 && code <= 57) || code === CH_UNDERSCORE || code === CH_DASH || code === CH_BACKSLASH;
|
|
392
|
+
}
|
|
393
|
+
function isWhitespaceCC(code) {
|
|
394
|
+
return code === 32 || code === 9 || code === 10 || code === 13 || code === 12;
|
|
395
|
+
}
|
|
396
|
+
function readIdent(input, start) {
|
|
397
|
+
let i = start;
|
|
398
|
+
while (i < input.length) {
|
|
399
|
+
const cc = input.charCodeAt(i);
|
|
400
|
+
if (cc === CH_BACKSLASH) {
|
|
401
|
+
i += 2;
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (!isIdentCC(cc))
|
|
405
|
+
break;
|
|
406
|
+
i++;
|
|
407
|
+
}
|
|
408
|
+
return i;
|
|
409
|
+
}
|
|
410
|
+
function readBalanced(input, start, open, close) {
|
|
411
|
+
let depth = 0, inQuote = 0, i = start;
|
|
412
|
+
while (i < input.length) {
|
|
413
|
+
const c = input.charCodeAt(i);
|
|
414
|
+
if (inQuote) {
|
|
415
|
+
if (c === CH_BACKSLASH) {
|
|
416
|
+
i += 2;
|
|
417
|
+
continue;
|
|
147
418
|
}
|
|
419
|
+
if (c === inQuote)
|
|
420
|
+
inQuote = 0;
|
|
421
|
+
i++;
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (c === CH_DQUOTE || c === CH_SQUOTE) {
|
|
425
|
+
inQuote = c;
|
|
426
|
+
i++;
|
|
427
|
+
continue;
|
|
148
428
|
}
|
|
429
|
+
if (c === open)
|
|
430
|
+
depth++;
|
|
431
|
+
else if (c === close) {
|
|
432
|
+
depth--;
|
|
433
|
+
if (depth === 0)
|
|
434
|
+
return i + 1;
|
|
435
|
+
}
|
|
436
|
+
i++;
|
|
149
437
|
}
|
|
150
|
-
return
|
|
438
|
+
return i;
|
|
151
439
|
}
|
|
152
|
-
function
|
|
153
|
-
let
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (s == null || res[0].A > s.A || (res[0].A === s.A && res[0].B > s.B) || (res[0].A === s.A && res[0].B === s.B && res[0].C > s.C))
|
|
164
|
-
s = res[0];
|
|
165
|
-
}
|
|
166
|
-
return [s, idx];
|
|
440
|
+
function findOfKeyword(input, start, end) {
|
|
441
|
+
let i = start;
|
|
442
|
+
while (i <= end - 1) {
|
|
443
|
+
while (i <= end - 1 && isWhitespaceCC(input.charCodeAt(i)))
|
|
444
|
+
i++;
|
|
445
|
+
if (input.charCodeAt(i) === 111 && input.charCodeAt(i + 1) === 102 && // 'o','f'
|
|
446
|
+
(i + 2 > end - 1 || isWhitespaceCC(input.charCodeAt(i + 2)) || input.charCodeAt(i + 2) === CH_LPAREN))
|
|
447
|
+
return i;
|
|
448
|
+
i++;
|
|
449
|
+
}
|
|
450
|
+
return -1;
|
|
167
451
|
}
|
|
168
452
|
//# sourceMappingURL=SpecificityCalculator.js.map
|