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.
@@ -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.toLowerCase();
279
+ property = asciiLowercase(property);
279
280
  if (!allProperties.has(property) && !allExtraProperties.has(property)) {
280
281
  return;
281
282
  }
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // autogenerated - 2025-06-20
2
+ // autogenerated - 2025-06-25
3
3
  // https://www.w3.org/Style/CSS/all-properties.en.html
4
4
 
5
5
  module.exports = new Set([
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
- // autogenerated - 2025-06-20
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 (v.toLowerCase() === "none" || external_dependency_parsers_0.hasVarFunc(v)) {
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 (v.toLowerCase() === "none") {
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 (v.toLowerCase() === "none") {
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 = v.toLowerCase();
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, true);
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, true);
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, true);
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, true);
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, true);
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.toLowerCase()}`;
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.toLowerCase()}`;
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.toLowerCase()}`;
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.toLowerCase();
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().toLowerCase();
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) && SYS_COLOR.includes(val.toLowerCase())) {
408
- return val;
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.toLowerCase())) {
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 (v.toLowerCase() === "none" || parsers.hasVarFunc(v)) {
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
  }
@@ -14,7 +14,7 @@ const shorthandFor = new Map([
14
14
  module.exports.definition = {
15
15
  set(v) {
16
16
  v = parsers.prepareValue(v, this._global);
17
- if (v.toLowerCase() === "none") {
17
+ if (/^none$/i.test(v)) {
18
18
  v = "";
19
19
  }
20
20
  if (parsers.hasVarFunc(v)) {
@@ -28,7 +28,7 @@ module.exports.isValid = function isValid(v) {
28
28
  module.exports.definition = {
29
29
  set(v) {
30
30
  v = parsers.prepareValue(v, this._global);
31
- if (v.toLowerCase() === "none") {
31
+ if (/^none$/i.test(v)) {
32
32
  v = "";
33
33
  }
34
34
  if (parsers.hasVarFunc(v)) {
@@ -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 = v.toLowerCase();
17
+ v = strings.asciiLowercase(v);
17
18
  const matches = v.match(/^rect\(\s*(.*)\s*\)$/);
18
19
  if (!matches) {
19
20
  return;
@@ -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.
@@ -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, true);
8
+ const val = parsers.parseMeasurement(v);
9
9
  if (val) {
10
10
  return val;
11
11
  }
@@ -3,7 +3,7 @@
3
3
  const parsers = require("../parsers");
4
4
 
5
5
  module.exports.parse = function parse(v) {
6
- const val = parsers.parseMeasurement(v, true);
6
+ const val = parsers.parseMeasurement(v);
7
7
  if (val) {
8
8
  return val;
9
9
  }
@@ -3,7 +3,7 @@
3
3
  const parsers = require("../parsers");
4
4
 
5
5
  module.exports.parse = function parse(v) {
6
- const val = parsers.parseMeasurement(v, true);
6
+ const val = parsers.parseMeasurement(v);
7
7
  if (val) {
8
8
  return val;
9
9
  }
@@ -3,7 +3,7 @@
3
3
  const parsers = require("../parsers");
4
4
 
5
5
  module.exports.parse = function parse(v) {
6
- const val = parsers.parseMeasurement(v, true);
6
+ const val = parsers.parseMeasurement(v);
7
7
  if (val) {
8
8
  return val;
9
9
  }
@@ -3,7 +3,7 @@
3
3
  const parsers = require("../parsers");
4
4
 
5
5
  module.exports.parse = function parse(v) {
6
- const val = parsers.parseMeasurement(v, true);
6
+ const val = parsers.parseMeasurement(v);
7
7
  if (val) {
8
8
  return val;
9
9
  }
@@ -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, "-$&").toLowerCase();
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
+ };
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "CSSStyleDeclaration",
7
7
  "StyleSheet"
8
8
  ],
9
- "version": "4.5.0",
9
+ "version": "4.6.0",
10
10
  "homepage": "https://github.com/jsdom/cssstyle",
11
11
  "maintainers": [
12
12
  {