cssstyle 4.5.0 → 4.6.0
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/lib/CSSStyleDeclaration.js +2 -1
- package/lib/generated/implementedProperties.js +1 -1
- package/lib/generated/properties.js +29 -17
- package/lib/parsers.js +54 -19
- package/lib/properties/background.js +7 -1
- package/lib/properties/border.js +1 -1
- package/lib/properties/borderStyle.js +1 -1
- package/lib/properties/clip.js +2 -1
- package/lib/properties/font.js +1 -7
- package/lib/properties/fontFamily.js +10 -0
- package/lib/properties/margin.js +1 -1
- package/lib/properties/marginBottom.js +1 -1
- package/lib/properties/marginLeft.js +1 -1
- package/lib/properties/marginRight.js +1 -1
- package/lib/properties/marginTop.js +1 -1
- package/lib/utils/camelize.js +3 -1
- package/lib/utils/strings.js +167 -0
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ const generatedProperties = require("./generated/properties");
|
|
|
11
11
|
const { hasVarFunc, parseKeyword, parseShorthand, prepareValue, splitValue } = require("./parsers");
|
|
12
12
|
const { dashedToCamelCase } = require("./utils/camelize");
|
|
13
13
|
const { getPropertyDescriptor } = require("./utils/propertyDescriptors");
|
|
14
|
+
const { asciiLowercase } = require("./utils/strings");
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* @see https://drafts.csswg.org/cssom/#the-cssstyledeclaration-interface
|
|
@@ -275,7 +276,7 @@ class CSSStyleDeclaration {
|
|
|
275
276
|
this._setProperty(property, value);
|
|
276
277
|
return;
|
|
277
278
|
}
|
|
278
|
-
property = property
|
|
279
|
+
property = asciiLowercase(property);
|
|
279
280
|
if (!allProperties.has(property) && !allExtraProperties.has(property)) {
|
|
280
281
|
return;
|
|
281
282
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// autogenerated - 2025-06-
|
|
2
|
+
// autogenerated - 2025-06-25
|
|
3
3
|
// https://www.w3.org/Style/CSS/all-properties.en.html
|
|
4
4
|
|
|
5
5
|
var external_dependency_parsers_0 = require("../parsers.js");
|
|
6
|
+
var external_dependency_strings_1 = require("../utils/strings.js");
|
|
6
7
|
var backgroundImage_export_parse, backgroundImage_export_isValid, backgroundImage_export_definition;
|
|
7
8
|
backgroundImage_export_parse = function parse(v) {
|
|
8
9
|
return external_dependency_parsers_0.parseImage(v);
|
|
@@ -189,7 +190,12 @@ const background_local_var_shorthandFor = new Map([["background-image", {
|
|
|
189
190
|
background_export_definition = {
|
|
190
191
|
set(v) {
|
|
191
192
|
v = external_dependency_parsers_0.prepareValue(v, this._global);
|
|
192
|
-
if (
|
|
193
|
+
if (/^none$/i.test(v)) {
|
|
194
|
+
for (const [key] of background_local_var_shorthandFor) {
|
|
195
|
+
this._setProperty(key, "");
|
|
196
|
+
}
|
|
197
|
+
this._setProperty("background", external_dependency_strings_1.asciiLowercase(v));
|
|
198
|
+
} else if (external_dependency_parsers_0.hasVarFunc(v)) {
|
|
193
199
|
for (const [key] of background_local_var_shorthandFor) {
|
|
194
200
|
this._setProperty(key, "");
|
|
195
201
|
}
|
|
@@ -258,7 +264,7 @@ borderStyle_export_isValid = function isValid(v) {
|
|
|
258
264
|
borderStyle_export_definition = {
|
|
259
265
|
set(v) {
|
|
260
266
|
v = external_dependency_parsers_0.prepareValue(v, this._global);
|
|
261
|
-
if (
|
|
267
|
+
if (/^none$/i.test(v)) {
|
|
262
268
|
v = "";
|
|
263
269
|
}
|
|
264
270
|
if (external_dependency_parsers_0.hasVarFunc(v)) {
|
|
@@ -323,7 +329,7 @@ const border_local_var_shorthandFor = new Map([["border-width", {
|
|
|
323
329
|
border_export_definition = {
|
|
324
330
|
set(v) {
|
|
325
331
|
v = external_dependency_parsers_0.prepareValue(v, this._global);
|
|
326
|
-
if (
|
|
332
|
+
if (/^none$/i.test(v)) {
|
|
327
333
|
v = "";
|
|
328
334
|
}
|
|
329
335
|
if (external_dependency_parsers_0.hasVarFunc(v)) {
|
|
@@ -1014,7 +1020,7 @@ clip_export_parse = function parse(v) {
|
|
|
1014
1020
|
return val;
|
|
1015
1021
|
}
|
|
1016
1022
|
// parse legacy <shape>
|
|
1017
|
-
v =
|
|
1023
|
+
v = external_dependency_strings_1.asciiLowercase(v);
|
|
1018
1024
|
const matches = v.match(/^rect\(\s*(.*)\s*\)$/);
|
|
1019
1025
|
if (!matches) {
|
|
1020
1026
|
return;
|
|
@@ -1428,6 +1434,7 @@ fontFamily_export_parse = function parse(v) {
|
|
|
1428
1434
|
return v;
|
|
1429
1435
|
}
|
|
1430
1436
|
const keywords = ["serif", "sans-serif", "cursive", "fantasy", "monospace", "system-ui", "math", "ui-serif", "ui-sans-serif", "ui-monospace", "ui-rounded"];
|
|
1437
|
+
const genericValues = ["fangsong", "kai", "khmer-mul", "nastaliq"];
|
|
1431
1438
|
const val = external_dependency_parsers_0.splitValue(v, {
|
|
1432
1439
|
delimiter: ","
|
|
1433
1440
|
});
|
|
@@ -1446,6 +1453,18 @@ fontFamily_export_parse = function parse(v) {
|
|
|
1446
1453
|
valid = true;
|
|
1447
1454
|
continue;
|
|
1448
1455
|
}
|
|
1456
|
+
const obj = external_dependency_parsers_0.parseFunction(i);
|
|
1457
|
+
if (obj) {
|
|
1458
|
+
const {
|
|
1459
|
+
name,
|
|
1460
|
+
value
|
|
1461
|
+
} = obj;
|
|
1462
|
+
if (name === "generic" && genericValues.includes(value)) {
|
|
1463
|
+
font.push(`${name}(${value})`);
|
|
1464
|
+
valid = true;
|
|
1465
|
+
continue;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1449
1468
|
// This implementation does not strictly follow the specification.
|
|
1450
1469
|
// The spec does not require the first letter of the font-family to be
|
|
1451
1470
|
// capitalized, and unquoted font-family names are not restricted to ASCII.
|
|
@@ -1570,13 +1589,6 @@ font_export_parse = function parse(v) {
|
|
|
1570
1589
|
case "font-style":
|
|
1571
1590
|
case "font-variant":
|
|
1572
1591
|
case "font-weight":
|
|
1573
|
-
{
|
|
1574
|
-
const value = font_local_var_shorthandFor.get(property);
|
|
1575
|
-
if (value.isValid(part)) {
|
|
1576
|
-
font[property] = value.parse(part);
|
|
1577
|
-
}
|
|
1578
|
-
break;
|
|
1579
|
-
}
|
|
1580
1592
|
case "font-size":
|
|
1581
1593
|
{
|
|
1582
1594
|
const value = font_local_var_shorthandFor.get(property);
|
|
@@ -1814,7 +1826,7 @@ lightingColor_export_definition = {
|
|
|
1814
1826
|
var margin_export_parse, margin_export_isValid, margin_export_definition;
|
|
1815
1827
|
const margin_local_var_positions = ["top", "right", "bottom", "left"];
|
|
1816
1828
|
margin_export_parse = function parse(v) {
|
|
1817
|
-
const val = external_dependency_parsers_0.parseMeasurement(v
|
|
1829
|
+
const val = external_dependency_parsers_0.parseMeasurement(v);
|
|
1818
1830
|
if (val) {
|
|
1819
1831
|
return val;
|
|
1820
1832
|
}
|
|
@@ -1851,7 +1863,7 @@ margin_export_definition = {
|
|
|
1851
1863
|
};
|
|
1852
1864
|
var marginBottom_export_parse, marginBottom_export_isValid, marginBottom_export_definition;
|
|
1853
1865
|
marginBottom_export_parse = function parse(v) {
|
|
1854
|
-
const val = external_dependency_parsers_0.parseMeasurement(v
|
|
1866
|
+
const val = external_dependency_parsers_0.parseMeasurement(v);
|
|
1855
1867
|
if (val) {
|
|
1856
1868
|
return val;
|
|
1857
1869
|
}
|
|
@@ -1881,7 +1893,7 @@ marginBottom_export_definition = {
|
|
|
1881
1893
|
};
|
|
1882
1894
|
var marginLeft_export_parse, marginLeft_export_isValid, marginLeft_export_definition;
|
|
1883
1895
|
marginLeft_export_parse = function parse(v) {
|
|
1884
|
-
const val = external_dependency_parsers_0.parseMeasurement(v
|
|
1896
|
+
const val = external_dependency_parsers_0.parseMeasurement(v);
|
|
1885
1897
|
if (val) {
|
|
1886
1898
|
return val;
|
|
1887
1899
|
}
|
|
@@ -1911,7 +1923,7 @@ marginLeft_export_definition = {
|
|
|
1911
1923
|
};
|
|
1912
1924
|
var marginRight_export_parse, marginRight_export_isValid, marginRight_export_definition;
|
|
1913
1925
|
marginRight_export_parse = function parse(v) {
|
|
1914
|
-
const val = external_dependency_parsers_0.parseMeasurement(v
|
|
1926
|
+
const val = external_dependency_parsers_0.parseMeasurement(v);
|
|
1915
1927
|
if (val) {
|
|
1916
1928
|
return val;
|
|
1917
1929
|
}
|
|
@@ -1941,7 +1953,7 @@ marginRight_export_definition = {
|
|
|
1941
1953
|
};
|
|
1942
1954
|
var marginTop_export_parse, marginTop_export_isValid, marginTop_export_definition;
|
|
1943
1955
|
marginTop_export_parse = function parse(v) {
|
|
1944
|
-
const val = external_dependency_parsers_0.parseMeasurement(v
|
|
1956
|
+
const val = external_dependency_parsers_0.parseMeasurement(v);
|
|
1945
1957
|
if (val) {
|
|
1946
1958
|
return val;
|
|
1947
1959
|
}
|
package/lib/parsers.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"use strict";
|
|
6
6
|
|
|
7
7
|
const { resolve: resolveColor, utils } = require("@asamuzakjp/css-color");
|
|
8
|
+
const { asciiLowercase } = require("./utils/strings");
|
|
8
9
|
|
|
9
10
|
const { cssCalc, isColor, isGradient, splitValue } = utils;
|
|
10
11
|
|
|
@@ -24,44 +25,48 @@ const NUM_TYPE = Object.freeze({
|
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
// System colors
|
|
28
|
+
// @see https://drafts.csswg.org/css-color/#css-system-colors
|
|
29
|
+
// @see https://drafts.csswg.org/css-color/#deprecated-system-colors
|
|
27
30
|
const SYS_COLOR = Object.freeze([
|
|
28
31
|
"accentcolor",
|
|
29
32
|
"accentcolortext",
|
|
33
|
+
"activeborder",
|
|
34
|
+
"activecaption",
|
|
30
35
|
"activetext",
|
|
36
|
+
"appworkspace",
|
|
37
|
+
"background",
|
|
31
38
|
"buttonborder",
|
|
32
39
|
"buttonface",
|
|
40
|
+
"buttonhighlight",
|
|
41
|
+
"buttonshadow",
|
|
33
42
|
"buttontext",
|
|
34
43
|
"canvas",
|
|
35
44
|
"canvastext",
|
|
45
|
+
"captiontext",
|
|
36
46
|
"field",
|
|
37
47
|
"fieldtext",
|
|
38
48
|
"graytext",
|
|
39
49
|
"highlight",
|
|
40
50
|
"highlighttext",
|
|
41
|
-
"linktext",
|
|
42
|
-
"mark",
|
|
43
|
-
"marktext",
|
|
44
|
-
"visitedtext",
|
|
45
|
-
"activeborder",
|
|
46
|
-
"activecaption",
|
|
47
|
-
"appworkspace",
|
|
48
|
-
"background",
|
|
49
|
-
"buttonhighlight",
|
|
50
|
-
"buttonshadow",
|
|
51
|
-
"captiontext",
|
|
52
51
|
"inactiveborder",
|
|
53
52
|
"inactivecaption",
|
|
54
53
|
"inactivecaptiontext",
|
|
55
54
|
"infobackground",
|
|
56
55
|
"infotext",
|
|
56
|
+
"linktext",
|
|
57
|
+
"mark",
|
|
58
|
+
"marktext",
|
|
57
59
|
"menu",
|
|
58
60
|
"menutext",
|
|
59
61
|
"scrollbar",
|
|
62
|
+
"selecteditem",
|
|
63
|
+
"selecteditemtext",
|
|
60
64
|
"threeddarkshadow",
|
|
61
65
|
"threedface",
|
|
62
66
|
"threedhighlight",
|
|
63
67
|
"threedlightshadow",
|
|
64
68
|
"threedshadow",
|
|
69
|
+
"visitedtext",
|
|
65
70
|
"window",
|
|
66
71
|
"windowframe",
|
|
67
72
|
"windowtext"
|
|
@@ -78,6 +83,7 @@ const varRegEx = /^var\(/;
|
|
|
78
83
|
const varContainedRegEx = /(?<=[*/\s(])var\(/;
|
|
79
84
|
const calcRegEx =
|
|
80
85
|
/^(?:a?(?:cos|sin|tan)|abs|atan2|calc|clamp|exp|hypot|log|max|min|mod|pow|rem|round|sign|sqrt)\(/;
|
|
86
|
+
const functionRegEx = /^([a-z][a-z\d]*(?:-[a-z\d]+)*)\(/i;
|
|
81
87
|
|
|
82
88
|
const getNumericType = function getNumericType(val) {
|
|
83
89
|
if (varRegEx.test(val)) {
|
|
@@ -184,7 +190,7 @@ exports.parseLength = function parseLength(val, restrictToPositive = false) {
|
|
|
184
190
|
if (restrictToPositive && num < 0) {
|
|
185
191
|
return;
|
|
186
192
|
}
|
|
187
|
-
return `${num}${unit
|
|
193
|
+
return `${num}${asciiLowercase(unit)}`;
|
|
188
194
|
}
|
|
189
195
|
default:
|
|
190
196
|
if (varContainedRegEx.test(val)) {
|
|
@@ -216,7 +222,7 @@ exports.parsePercent = function parsePercent(val, restrictToPositive = false) {
|
|
|
216
222
|
if (restrictToPositive && num < 0) {
|
|
217
223
|
return;
|
|
218
224
|
}
|
|
219
|
-
return `${num}${unit
|
|
225
|
+
return `${num}${asciiLowercase(unit)}`;
|
|
220
226
|
}
|
|
221
227
|
default:
|
|
222
228
|
if (varContainedRegEx.test(val)) {
|
|
@@ -250,7 +256,7 @@ exports.parseMeasurement = function parseMeasurement(val, restrictToPositive = f
|
|
|
250
256
|
if (restrictToPositive && num < 0) {
|
|
251
257
|
return;
|
|
252
258
|
}
|
|
253
|
-
return `${num}${unit
|
|
259
|
+
return `${num}${asciiLowercase(unit)}`;
|
|
254
260
|
}
|
|
255
261
|
default:
|
|
256
262
|
if (varContainedRegEx.test(val)) {
|
|
@@ -279,7 +285,7 @@ exports.parseAngle = function parseAngle(val, normalizeDeg = false) {
|
|
|
279
285
|
case NUM_TYPE.ANGLE: {
|
|
280
286
|
let [, numVal, unit] = unitRegEx.exec(val);
|
|
281
287
|
numVal = parseFloat(numVal);
|
|
282
|
-
unit = unit
|
|
288
|
+
unit = asciiLowercase(unit);
|
|
283
289
|
if (unit === "deg") {
|
|
284
290
|
if (normalizeDeg && numVal < 0) {
|
|
285
291
|
while (numVal < 0) {
|
|
@@ -391,7 +397,7 @@ exports.parseKeyword = function parseKeyword(val, validKeywords = []) {
|
|
|
391
397
|
if (varRegEx.test(val)) {
|
|
392
398
|
return val;
|
|
393
399
|
}
|
|
394
|
-
val = val.toString()
|
|
400
|
+
val = asciiLowercase(val.toString());
|
|
395
401
|
if (validKeywords.includes(val) || GLOBAL_VALUE.includes(val)) {
|
|
396
402
|
return val;
|
|
397
403
|
}
|
|
@@ -404,8 +410,11 @@ exports.parseColor = function parseColor(val) {
|
|
|
404
410
|
if (varRegEx.test(val)) {
|
|
405
411
|
return val;
|
|
406
412
|
}
|
|
407
|
-
if (/^[a-z]+$/i.test(val)
|
|
408
|
-
|
|
413
|
+
if (/^[a-z]+$/i.test(val)) {
|
|
414
|
+
const v = asciiLowercase(val);
|
|
415
|
+
if (SYS_COLOR.includes(v)) {
|
|
416
|
+
return v;
|
|
417
|
+
}
|
|
409
418
|
}
|
|
410
419
|
const res = resolveColor(val, {
|
|
411
420
|
format: "specifiedValue"
|
|
@@ -452,6 +461,32 @@ exports.parseImage = function parseImage(val) {
|
|
|
452
461
|
}
|
|
453
462
|
};
|
|
454
463
|
|
|
464
|
+
exports.parseFunction = function parseFunction(val) {
|
|
465
|
+
if (val === "") {
|
|
466
|
+
return {
|
|
467
|
+
name: null,
|
|
468
|
+
value: ""
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
if (functionRegEx.test(val) && val.endsWith(")")) {
|
|
472
|
+
if (varRegEx.test(val) || varContainedRegEx.test(val)) {
|
|
473
|
+
return {
|
|
474
|
+
name: "var",
|
|
475
|
+
value: val
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
const [, name] = functionRegEx.exec(val);
|
|
479
|
+
const value = val
|
|
480
|
+
.replace(new RegExp(`^${name}\\(`), "")
|
|
481
|
+
.replace(/\)$/, "")
|
|
482
|
+
.trim();
|
|
483
|
+
return {
|
|
484
|
+
name,
|
|
485
|
+
value
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
455
490
|
exports.parseShorthand = function parseShorthand(val, shorthandFor, preserve = false) {
|
|
456
491
|
const obj = {};
|
|
457
492
|
if (val === "" || exports.hasVarFunc(val)) {
|
|
@@ -491,7 +526,7 @@ exports.parseShorthand = function parseShorthand(val, shorthandFor, preserve = f
|
|
|
491
526
|
|
|
492
527
|
// Returns `false` for global values, e.g. "inherit".
|
|
493
528
|
exports.isValidColor = function isValidColor(val) {
|
|
494
|
-
if (SYS_COLOR.includes(val
|
|
529
|
+
if (SYS_COLOR.includes(asciiLowercase(val))) {
|
|
495
530
|
return true;
|
|
496
531
|
}
|
|
497
532
|
return isColor(val);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// * also fix longhands
|
|
5
5
|
|
|
6
6
|
const parsers = require("../parsers");
|
|
7
|
+
const strings = require("../utils/strings");
|
|
7
8
|
const backgroundImage = require("./backgroundImage");
|
|
8
9
|
const backgroundPosition = require("./backgroundPosition");
|
|
9
10
|
const backgroundRepeat = require("./backgroundRepeat");
|
|
@@ -21,7 +22,12 @@ const shorthandFor = new Map([
|
|
|
21
22
|
module.exports.definition = {
|
|
22
23
|
set(v) {
|
|
23
24
|
v = parsers.prepareValue(v, this._global);
|
|
24
|
-
if (
|
|
25
|
+
if (/^none$/i.test(v)) {
|
|
26
|
+
for (const [key] of shorthandFor) {
|
|
27
|
+
this._setProperty(key, "");
|
|
28
|
+
}
|
|
29
|
+
this._setProperty("background", strings.asciiLowercase(v));
|
|
30
|
+
} else if (parsers.hasVarFunc(v)) {
|
|
25
31
|
for (const [key] of shorthandFor) {
|
|
26
32
|
this._setProperty(key, "");
|
|
27
33
|
}
|
package/lib/properties/border.js
CHANGED
package/lib/properties/clip.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// @see https://drafts.fxtf.org/css-masking/#clip-property
|
|
4
4
|
|
|
5
5
|
const parsers = require("../parsers");
|
|
6
|
+
const strings = require("../utils/strings");
|
|
6
7
|
|
|
7
8
|
module.exports.parse = function parse(v) {
|
|
8
9
|
if (v === "") {
|
|
@@ -13,7 +14,7 @@ module.exports.parse = function parse(v) {
|
|
|
13
14
|
return val;
|
|
14
15
|
}
|
|
15
16
|
// parse legacy <shape>
|
|
16
|
-
v =
|
|
17
|
+
v = strings.asciiLowercase(v);
|
|
17
18
|
const matches = v.match(/^rect\(\s*(.*)\s*\)$/);
|
|
18
19
|
if (!matches) {
|
|
19
20
|
return;
|
package/lib/properties/font.js
CHANGED
|
@@ -57,13 +57,7 @@ module.exports.parse = function parse(v) {
|
|
|
57
57
|
switch (property) {
|
|
58
58
|
case "font-style":
|
|
59
59
|
case "font-variant":
|
|
60
|
-
case "font-weight":
|
|
61
|
-
const value = shorthandFor.get(property);
|
|
62
|
-
if (value.isValid(part)) {
|
|
63
|
-
font[property] = value.parse(part);
|
|
64
|
-
}
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
60
|
+
case "font-weight":
|
|
67
61
|
case "font-size": {
|
|
68
62
|
const value = shorthandFor.get(property);
|
|
69
63
|
if (value.isValid(part)) {
|
|
@@ -19,6 +19,7 @@ module.exports.parse = function parse(v) {
|
|
|
19
19
|
"ui-monospace",
|
|
20
20
|
"ui-rounded"
|
|
21
21
|
];
|
|
22
|
+
const genericValues = ["fangsong", "kai", "khmer-mul", "nastaliq"];
|
|
22
23
|
const val = parsers.splitValue(v, {
|
|
23
24
|
delimiter: ","
|
|
24
25
|
});
|
|
@@ -37,6 +38,15 @@ module.exports.parse = function parse(v) {
|
|
|
37
38
|
valid = true;
|
|
38
39
|
continue;
|
|
39
40
|
}
|
|
41
|
+
const obj = parsers.parseFunction(i);
|
|
42
|
+
if (obj) {
|
|
43
|
+
const { name, value } = obj;
|
|
44
|
+
if (name === "generic" && genericValues.includes(value)) {
|
|
45
|
+
font.push(`${name}(${value})`);
|
|
46
|
+
valid = true;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
40
50
|
// This implementation does not strictly follow the specification.
|
|
41
51
|
// The spec does not require the first letter of the font-family to be
|
|
42
52
|
// capitalized, and unquoted font-family names are not restricted to ASCII.
|
package/lib/properties/margin.js
CHANGED
|
@@ -5,7 +5,7 @@ const parsers = require("../parsers");
|
|
|
5
5
|
const positions = ["top", "right", "bottom", "left"];
|
|
6
6
|
|
|
7
7
|
module.exports.parse = function parse(v) {
|
|
8
|
-
const val = parsers.parseMeasurement(v
|
|
8
|
+
const val = parsers.parseMeasurement(v);
|
|
9
9
|
if (val) {
|
|
10
10
|
return val;
|
|
11
11
|
}
|
package/lib/utils/camelize.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
const { asciiLowercase } = require("./strings");
|
|
4
|
+
|
|
3
5
|
// Utility to translate from `border-width` to `borderWidth`.
|
|
4
6
|
// NOTE: For values prefixed with webkit, e.g. `-webkit-foo`, we need to provide
|
|
5
7
|
// both `webkitFoo` and `WebkitFoo`. Here we only return `webkitFoo`.
|
|
@@ -27,7 +29,7 @@ exports.camelCaseToDashed = function (camelCase) {
|
|
|
27
29
|
if (camelCase.startsWith("--")) {
|
|
28
30
|
return camelCase;
|
|
29
31
|
}
|
|
30
|
-
const dashed = camelCase.replace(/(?<=[a-z])[A-Z]/g, "-$&")
|
|
32
|
+
const dashed = asciiLowercase(camelCase.replace(/(?<=[a-z])[A-Z]/g, "-$&"));
|
|
31
33
|
if (/^webkit-/.test(dashed)) {
|
|
32
34
|
return `-${dashed}`;
|
|
33
35
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Forked from https://github.com/jsdom/jsdom/blob/main/lib/jsdom/living/helpers/strings.js
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
// https://infra.spec.whatwg.org/#ascii-whitespace
|
|
6
|
+
const asciiWhitespaceRe = /^[\t\n\f\r ]$/;
|
|
7
|
+
exports.asciiWhitespaceRe = asciiWhitespaceRe;
|
|
8
|
+
|
|
9
|
+
// https://infra.spec.whatwg.org/#ascii-lowercase
|
|
10
|
+
exports.asciiLowercase = (s) => {
|
|
11
|
+
const len = s.length;
|
|
12
|
+
const out = new Array(len);
|
|
13
|
+
for (let i = 0; i < len; i++) {
|
|
14
|
+
const code = s.charCodeAt(i);
|
|
15
|
+
// If the character is between 'A' (65) and 'Z' (90), convert using bitwise OR with 32
|
|
16
|
+
out[i] = code >= 65 && code <= 90 ? String.fromCharCode(code | 32) : s[i];
|
|
17
|
+
}
|
|
18
|
+
return out.join("");
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// https://infra.spec.whatwg.org/#ascii-uppercase
|
|
22
|
+
exports.asciiUppercase = (s) => {
|
|
23
|
+
const len = s.length;
|
|
24
|
+
const out = new Array(len);
|
|
25
|
+
for (let i = 0; i < len; i++) {
|
|
26
|
+
const code = s.charCodeAt(i);
|
|
27
|
+
// If the character is between 'a' (97) and 'z' (122), convert using bitwise AND with ~32
|
|
28
|
+
out[i] = code >= 97 && code <= 122 ? String.fromCharCode(code & ~32) : s[i];
|
|
29
|
+
}
|
|
30
|
+
return out.join("");
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// https://infra.spec.whatwg.org/#strip-newlines
|
|
34
|
+
exports.stripNewlines = (s) => {
|
|
35
|
+
return s.replace(/[\n\r]+/g, "");
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
|
|
39
|
+
exports.stripLeadingAndTrailingASCIIWhitespace = (s) => {
|
|
40
|
+
return s.replace(/^[ \t\n\f\r]+/, "").replace(/[ \t\n\f\r]+$/, "");
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
|
|
44
|
+
exports.stripAndCollapseASCIIWhitespace = (s) => {
|
|
45
|
+
return s
|
|
46
|
+
.replace(/[ \t\n\f\r]+/g, " ")
|
|
47
|
+
.replace(/^[ \t\n\f\r]+/, "")
|
|
48
|
+
.replace(/[ \t\n\f\r]+$/, "");
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-simple-colour
|
|
52
|
+
exports.isValidSimpleColor = (s) => {
|
|
53
|
+
return /^#[a-fA-F\d]{6}$/.test(s);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// https://infra.spec.whatwg.org/#ascii-case-insensitive
|
|
57
|
+
exports.asciiCaseInsensitiveMatch = (a, b) => {
|
|
58
|
+
if (a.length !== b.length) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < a.length; ++i) {
|
|
63
|
+
if ((a.charCodeAt(i) | 32) !== (b.charCodeAt(i) | 32)) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return true;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
|
|
72
|
+
// Error is represented as null.
|
|
73
|
+
const parseInteger = (exports.parseInteger = (input) => {
|
|
74
|
+
// The implementation here is slightly different from the spec's. We want to use parseInt(), but parseInt() trims
|
|
75
|
+
// Unicode whitespace in addition to just ASCII ones, so we make sure that the trimmed prefix contains only ASCII
|
|
76
|
+
// whitespace ourselves.
|
|
77
|
+
const numWhitespace = input.length - input.trimStart().length;
|
|
78
|
+
if (/[^\t\n\f\r ]/.test(input.slice(0, numWhitespace))) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
// We don't allow hexadecimal numbers here.
|
|
82
|
+
// eslint-disable-next-line radix
|
|
83
|
+
const value = parseInt(input, 10);
|
|
84
|
+
if (Number.isNaN(value)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
// parseInt() returns -0 for "-0". Normalize that here.
|
|
88
|
+
return value === 0 ? 0 : value;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-non-negative-integers
|
|
92
|
+
// Error is represented as null.
|
|
93
|
+
exports.parseNonNegativeInteger = (input) => {
|
|
94
|
+
const value = parseInteger(input);
|
|
95
|
+
if (value === null) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
if (value < 0) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-floating-point-number
|
|
105
|
+
const floatingPointNumRe = /^-?(?:\d+|\d*\.\d+)(?:[eE][-+]?\d+)?$/;
|
|
106
|
+
exports.isValidFloatingPointNumber = (str) => floatingPointNumRe.test(str);
|
|
107
|
+
|
|
108
|
+
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values
|
|
109
|
+
// Error is represented as null.
|
|
110
|
+
exports.parseFloatingPointNumber = (str) => {
|
|
111
|
+
// The implementation here is slightly different from the spec's. We need to use parseFloat() in order to retain
|
|
112
|
+
// accuracy, but parseFloat() trims Unicode whitespace in addition to just ASCII ones, so we make sure that the
|
|
113
|
+
// trimmed prefix contains only ASCII whitespace ourselves.
|
|
114
|
+
const numWhitespace = str.length - str.trimStart().length;
|
|
115
|
+
if (/[^\t\n\f\r ]/.test(str.slice(0, numWhitespace))) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const parsed = parseFloat(str);
|
|
119
|
+
return isFinite(parsed) ? parsed : null;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// https://infra.spec.whatwg.org/#split-on-ascii-whitespace
|
|
123
|
+
exports.splitOnASCIIWhitespace = (str) => {
|
|
124
|
+
let position = 0;
|
|
125
|
+
const tokens = [];
|
|
126
|
+
while (position < str.length && asciiWhitespaceRe.test(str[position])) {
|
|
127
|
+
position++;
|
|
128
|
+
}
|
|
129
|
+
if (position === str.length) {
|
|
130
|
+
return tokens;
|
|
131
|
+
}
|
|
132
|
+
while (position < str.length) {
|
|
133
|
+
const start = position;
|
|
134
|
+
while (position < str.length && !asciiWhitespaceRe.test(str[position])) {
|
|
135
|
+
position++;
|
|
136
|
+
}
|
|
137
|
+
tokens.push(str.slice(start, position));
|
|
138
|
+
while (position < str.length && asciiWhitespaceRe.test(str[position])) {
|
|
139
|
+
position++;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return tokens;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// https://infra.spec.whatwg.org/#split-on-commas
|
|
146
|
+
exports.splitOnCommas = (str) => {
|
|
147
|
+
let position = 0;
|
|
148
|
+
const tokens = [];
|
|
149
|
+
while (position < str.length) {
|
|
150
|
+
let start = position;
|
|
151
|
+
while (position < str.length && str[position] !== ",") {
|
|
152
|
+
position++;
|
|
153
|
+
}
|
|
154
|
+
let end = position;
|
|
155
|
+
while (start < str.length && asciiWhitespaceRe.test(str[start])) {
|
|
156
|
+
start++;
|
|
157
|
+
}
|
|
158
|
+
while (end > start && asciiWhitespaceRe.test(str[end - 1])) {
|
|
159
|
+
end--;
|
|
160
|
+
}
|
|
161
|
+
tokens.push(str.slice(start, end));
|
|
162
|
+
if (position < str.length) {
|
|
163
|
+
position++;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return tokens;
|
|
167
|
+
};
|