cssstyle 4.3.1 → 4.4.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.
Files changed (94) hide show
  1. package/lib/CSSStyleDeclaration.js +545 -206
  2. package/lib/allExtraProperties.js +42 -60
  3. package/lib/allWebkitProperties.js +107 -187
  4. package/lib/generated/allProperties.js +615 -0
  5. package/lib/{implementedProperties.js → generated/implementedProperties.js} +11 -18
  6. package/lib/generated/properties.js +2574 -0
  7. package/lib/parsers.js +382 -547
  8. package/lib/properties/background.js +40 -13
  9. package/lib/properties/backgroundAttachment.js +23 -15
  10. package/lib/properties/backgroundColor.js +21 -19
  11. package/lib/properties/backgroundImage.js +19 -14
  12. package/lib/properties/backgroundPosition.js +35 -41
  13. package/lib/properties/backgroundRepeat.js +20 -20
  14. package/lib/properties/border.js +34 -25
  15. package/lib/properties/borderBottom.js +34 -11
  16. package/lib/properties/borderBottomColor.js +27 -8
  17. package/lib/properties/borderBottomStyle.js +42 -13
  18. package/lib/properties/borderBottomWidth.js +28 -8
  19. package/lib/properties/borderCollapse.js +16 -16
  20. package/lib/properties/borderColor.js +32 -18
  21. package/lib/properties/borderLeft.js +34 -11
  22. package/lib/properties/borderLeftColor.js +27 -8
  23. package/lib/properties/borderLeftStyle.js +42 -13
  24. package/lib/properties/borderLeftWidth.js +28 -8
  25. package/lib/properties/borderRight.js +34 -11
  26. package/lib/properties/borderRightColor.js +27 -8
  27. package/lib/properties/borderRightStyle.js +42 -13
  28. package/lib/properties/borderRightWidth.js +28 -8
  29. package/lib/properties/borderSpacing.js +31 -27
  30. package/lib/properties/borderStyle.js +43 -27
  31. package/lib/properties/borderTop.js +34 -11
  32. package/lib/properties/borderTopColor.js +27 -8
  33. package/lib/properties/borderTopStyle.js +42 -13
  34. package/lib/properties/borderTopWidth.js +28 -9
  35. package/lib/properties/borderWidth.js +32 -34
  36. package/lib/properties/bottom.js +23 -7
  37. package/lib/properties/clear.js +32 -8
  38. package/lib/properties/clip.js +33 -27
  39. package/lib/properties/color.js +23 -7
  40. package/lib/properties/flex.js +59 -29
  41. package/lib/properties/flexBasis.js +21 -16
  42. package/lib/properties/flexGrow.js +19 -10
  43. package/lib/properties/flexShrink.js +19 -10
  44. package/lib/properties/float.js +21 -6
  45. package/lib/properties/floodColor.js +23 -7
  46. package/lib/properties/font.js +120 -33
  47. package/lib/properties/fontFamily.js +59 -21
  48. package/lib/properties/fontSize.js +37 -28
  49. package/lib/properties/fontStyle.js +23 -9
  50. package/lib/properties/fontVariant.js +26 -8
  51. package/lib/properties/fontWeight.js +26 -23
  52. package/lib/properties/height.js +21 -14
  53. package/lib/properties/left.js +23 -7
  54. package/lib/properties/lightingColor.js +23 -7
  55. package/lib/properties/lineHeight.js +29 -16
  56. package/lib/properties/margin.js +42 -57
  57. package/lib/properties/marginBottom.js +34 -7
  58. package/lib/properties/marginLeft.js +34 -7
  59. package/lib/properties/marginRight.js +34 -7
  60. package/lib/properties/marginTop.js +34 -7
  61. package/lib/properties/opacity.js +39 -7
  62. package/lib/properties/outlineColor.js +23 -7
  63. package/lib/properties/padding.js +43 -51
  64. package/lib/properties/paddingBottom.js +36 -7
  65. package/lib/properties/paddingLeft.js +34 -7
  66. package/lib/properties/paddingRight.js +34 -7
  67. package/lib/properties/paddingTop.js +34 -7
  68. package/lib/properties/right.js +23 -7
  69. package/lib/properties/stopColor.js +23 -7
  70. package/lib/properties/top.js +23 -7
  71. package/lib/properties/webkitBorderAfterColor.js +23 -7
  72. package/lib/properties/webkitBorderBeforeColor.js +23 -7
  73. package/lib/properties/webkitBorderEndColor.js +23 -7
  74. package/lib/properties/webkitBorderStartColor.js +23 -7
  75. package/lib/properties/webkitColumnRuleColor.js +23 -7
  76. package/lib/properties/webkitTapHighlightColor.js +23 -7
  77. package/lib/properties/webkitTextEmphasisColor.js +23 -7
  78. package/lib/properties/webkitTextFillColor.js +23 -7
  79. package/lib/properties/webkitTextStrokeColor.js +23 -7
  80. package/lib/properties/width.js +21 -14
  81. package/lib/utils/camelize.js +35 -0
  82. package/lib/utils/propertyDescriptors.js +16 -0
  83. package/package.json +5 -4
  84. package/lib/allProperties.js +0 -529
  85. package/lib/constants.js +0 -6
  86. package/lib/named_colors.json +0 -152
  87. package/lib/properties/azimuth.js +0 -64
  88. package/lib/properties/cssFloat.js +0 -12
  89. package/lib/properties/textLineThroughColor.js +0 -14
  90. package/lib/properties/textOverlineColor.js +0 -14
  91. package/lib/properties/textUnderlineColor.js +0 -14
  92. package/lib/properties/webkitMatchNearestMailBlockquoteColor.js +0 -14
  93. package/lib/properties.js +0 -1672
  94. package/lib/utils/getBasicPropertyDescriptor.js +0 -14
package/lib/parsers.js CHANGED
@@ -1,251 +1,345 @@
1
- /*********************************************************************
2
- * These are commonly used parsers for CSS Values they take a string *
3
- * to parse and return a string after it's been converted, if needed *
4
- ********************************************************************/
5
- 'use strict';
1
+ /**
2
+ * These are commonly used parsers for CSS Values they take a string to parse
3
+ * and return a string after it's been converted, if needed
4
+ */
5
+ "use strict";
6
+
7
+ const { resolve: resolveColor, utils } = require("@asamuzakjp/css-color");
6
8
 
7
- const { resolve: resolveColor, utils } = require('@asamuzakjp/css-color');
8
9
  const { cssCalc, isColor, isGradient, splitValue } = utils;
9
10
 
10
- exports.TYPES = {
11
- INTEGER: 1,
11
+ // CSS global values
12
+ // @see https://drafts.csswg.org/css-cascade-5/#defaulting-keywords
13
+ const GLOBAL_VALUE = Object.freeze(["initial", "inherit", "unset", "revert", "revert-layer"]);
14
+
15
+ // Numeric data types
16
+ const NUM_TYPE = Object.freeze({
17
+ UNDEFINED: 0,
18
+ VAR: 1,
12
19
  NUMBER: 2,
13
- LENGTH: 3,
14
20
  PERCENT: 4,
15
- URL: 5,
16
- COLOR: 6,
17
- STRING: 7,
18
- ANGLE: 8,
19
- KEYWORD: 9,
20
- NULL_OR_EMPTY_STR: 10,
21
- CALC: 11,
22
- VAR: 12,
23
- GRADIENT: 13,
24
- };
25
-
26
- // regular expressions
27
- var DIGIT = '(?:0|[1-9]\\d*)';
28
- var NUMBER = `[+-]?(?:${DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${DIGIT})?`;
29
- var integerRegEx = new RegExp(`^[+-]?${DIGIT}$`);
30
- var numberRegEx = new RegExp(`^${NUMBER}$`);
31
- var lengthRegEx = new RegExp(
32
- `^${NUMBER}(?:[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic))$`
33
- );
34
- var percentRegEx = new RegExp(`^${NUMBER}%$`);
35
- var angleRegEx = new RegExp(`^${NUMBER}(?:deg|g?rad|turn)$`);
36
- var urlRegEx = /^url\(\s*((?:[^)]|\\\))*)\s*\)$/;
37
- var stringRegEx = /^("[^"]*"|'[^']*')$/;
38
- var varRegEx = /^var\(|(?<=[*/\s(])var\(/;
39
- var calcRegEx =
21
+ LENGTH: 8,
22
+ ANGLE: 0x10,
23
+ CALC: 0x20
24
+ });
25
+
26
+ // System colors
27
+ const SYS_COLOR = Object.freeze([
28
+ "accentcolor",
29
+ "accentcolortext",
30
+ "activetext",
31
+ "buttonborder",
32
+ "buttonface",
33
+ "buttontext",
34
+ "canvas",
35
+ "canvastext",
36
+ "field",
37
+ "fieldtext",
38
+ "graytext",
39
+ "highlight",
40
+ "highlighttext",
41
+ "linktext",
42
+ "mark",
43
+ "marktext",
44
+ "visitedtext",
45
+ "activeborder",
46
+ "activecaption",
47
+ "appworkspace",
48
+ "background",
49
+ "buttonhighlight",
50
+ "buttonshadow",
51
+ "captiontext",
52
+ "inactiveborder",
53
+ "inactivecaption",
54
+ "inactivecaptiontext",
55
+ "infobackground",
56
+ "infotext",
57
+ "menu",
58
+ "menutext",
59
+ "scrollbar",
60
+ "threeddarkshadow",
61
+ "threedface",
62
+ "threedhighlight",
63
+ "threedlightshadow",
64
+ "threedshadow",
65
+ "window",
66
+ "windowframe",
67
+ "windowtext"
68
+ ]);
69
+
70
+ // Regular expressions
71
+ const DIGIT = "(?:0|[1-9]\\d*)";
72
+ const NUMBER = `[+-]?(?:${DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${DIGIT})?`;
73
+ const unitRegEx = new RegExp(`^(${NUMBER})([a-z]+|%)?$`, "i");
74
+ const urlRegEx = /^url\(\s*((?:[^)]|\\\))*)\s*\)$/;
75
+ const keywordRegEx = /^[a-z]+(?:-[a-z]+)*$/i;
76
+ const stringRegEx = /^("[^"]*"|'[^']*')$/;
77
+ const varRegEx = /^var\(/;
78
+ const varContainedRegEx = /(?<=[*/\s(])var\(/;
79
+ const calcRegEx =
40
80
  /^(?:a?(?:cos|sin|tan)|abs|atan2|calc|clamp|exp|hypot|log|max|min|mod|pow|rem|round|sign|sqrt)\(/;
41
81
 
42
- // This will return one of the above types based on the passed in string
43
- exports.valueType = function valueType(val) {
44
- if (val === '' || val === null) {
45
- return exports.TYPES.NULL_OR_EMPTY_STR;
46
- }
47
- if (typeof val === 'number') {
48
- val = val.toString();
49
- }
50
- if (typeof val !== 'string') {
51
- return undefined;
52
- }
53
- if (integerRegEx.test(val)) {
54
- return exports.TYPES.INTEGER;
55
- }
56
- if (numberRegEx.test(val)) {
57
- return exports.TYPES.NUMBER;
58
- }
59
- if (lengthRegEx.test(val)) {
60
- return exports.TYPES.LENGTH;
61
- }
62
- if (percentRegEx.test(val)) {
63
- return exports.TYPES.PERCENT;
64
- }
65
- if (urlRegEx.test(val)) {
66
- return exports.TYPES.URL;
67
- }
82
+ const getNumericType = function getNumericType(val) {
68
83
  if (varRegEx.test(val)) {
69
- return exports.TYPES.VAR;
84
+ return NUM_TYPE.VAR;
70
85
  }
71
86
  if (calcRegEx.test(val)) {
72
- return exports.TYPES.CALC;
73
- }
74
- if (stringRegEx.test(val)) {
75
- return exports.TYPES.STRING;
76
- }
77
- if (angleRegEx.test(val)) {
78
- return exports.TYPES.ANGLE;
79
- }
80
- if (isColor(val)) {
81
- return exports.TYPES.COLOR;
82
- }
83
- if (isGradient(val)) {
84
- return exports.TYPES.GRADIENT;
87
+ return NUM_TYPE.CALC;
85
88
  }
86
-
87
- switch (val.toLowerCase()) {
88
- // the following are deprecated in CSS3
89
- case 'activeborder':
90
- case 'activecaption':
91
- case 'appworkspace':
92
- case 'background':
93
- case 'buttonface':
94
- case 'buttonhighlight':
95
- case 'buttonshadow':
96
- case 'buttontext':
97
- case 'captiontext':
98
- case 'graytext':
99
- case 'highlight':
100
- case 'highlighttext':
101
- case 'inactiveborder':
102
- case 'inactivecaption':
103
- case 'inactivecaptiontext':
104
- case 'infobackground':
105
- case 'infotext':
106
- case 'menu':
107
- case 'menutext':
108
- case 'scrollbar':
109
- case 'threeddarkshadow':
110
- case 'threedface':
111
- case 'threedhighlight':
112
- case 'threedlightshadow':
113
- case 'threedshadow':
114
- case 'window':
115
- case 'windowframe':
116
- case 'windowtext':
117
- return exports.TYPES.COLOR;
118
- default:
119
- return exports.TYPES.KEYWORD;
89
+ if (unitRegEx.test(val)) {
90
+ const [, , unit] = unitRegEx.exec(val);
91
+ if (!unit) {
92
+ return NUM_TYPE.NUMBER;
93
+ }
94
+ if (unit === "%") {
95
+ return NUM_TYPE.PERCENT;
96
+ }
97
+ if (/^(?:[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic))$/i.test(unit)) {
98
+ return NUM_TYPE.LENGTH;
99
+ }
100
+ if (/^(?:deg|g?rad|turn)$/i.test(unit)) {
101
+ return NUM_TYPE.ANGLE;
102
+ }
120
103
  }
104
+ return NUM_TYPE.UNDEFINED;
121
105
  };
122
106
 
123
- exports.parseInteger = function parseInteger(val) {
124
- var type = exports.valueType(val);
125
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
126
- return val;
127
- }
128
- if (type !== exports.TYPES.INTEGER) {
129
- return undefined;
107
+ // Prepare stringified value.
108
+ exports.prepareValue = function prepareValue(value, globalObject = globalThis) {
109
+ // `null` is converted to an empty string.
110
+ // @see https://webidl.spec.whatwg.org/#LegacyNullToEmptyString
111
+ if (value === null) {
112
+ return "";
113
+ }
114
+ const type = typeof value;
115
+ switch (type) {
116
+ case "string":
117
+ return value.trim();
118
+ case "number":
119
+ return value.toString();
120
+ case "undefined":
121
+ return "undefined";
122
+ case "symbol":
123
+ throw new globalObject.TypeError("Can not convert symbol to string.");
124
+ default: {
125
+ const str = value.toString();
126
+ if (typeof str === "string") {
127
+ return str;
128
+ }
129
+ throw new globalObject.TypeError(`Can not convert ${type} to string.`);
130
+ }
130
131
  }
131
- return String(parseInt(val, 10));
132
132
  };
133
133
 
134
- exports.parseNumber = function parseNumber(val) {
135
- var type = exports.valueType(val);
136
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
137
- return val;
138
- }
139
- if (type !== exports.TYPES.NUMBER && type !== exports.TYPES.INTEGER) {
140
- return undefined;
141
- }
142
- return String(parseFloat(val));
134
+ exports.hasVarFunc = function hasVarFunc(val) {
135
+ return varRegEx.test(val) || varContainedRegEx.test(val);
143
136
  };
144
137
 
145
- exports.parseLength = function parseLength(val) {
146
- if (val === 0 || val === '0') {
147
- return '0px';
148
- }
149
- var type = exports.valueType(val);
150
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
151
- return val;
152
- }
153
- if (type !== exports.TYPES.LENGTH) {
154
- return undefined;
138
+ exports.parseNumber = function parseNumber(val, restrictToPositive = false) {
139
+ if (val === "") {
140
+ return "";
141
+ }
142
+ const type = getNumericType(val);
143
+ switch (type) {
144
+ case NUM_TYPE.VAR:
145
+ return val;
146
+ case NUM_TYPE.CALC:
147
+ return cssCalc(val, {
148
+ format: "specifiedValue"
149
+ });
150
+ case NUM_TYPE.NUMBER: {
151
+ const num = parseFloat(val);
152
+ if (restrictToPositive && num < 0) {
153
+ return;
154
+ }
155
+ return `${num}`;
156
+ }
157
+ default:
158
+ if (varContainedRegEx.test(val)) {
159
+ return val;
160
+ }
155
161
  }
156
- return val;
157
162
  };
158
163
 
159
- exports.parsePercent = function parsePercent(val) {
160
- if (val === 0 || val === '0') {
161
- return '0%';
162
- }
163
- var type = exports.valueType(val);
164
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
165
- return val;
166
- }
167
- if (type !== exports.TYPES.PERCENT) {
168
- return undefined;
164
+ exports.parseLength = function parseLength(val, restrictToPositive = false) {
165
+ if (val === "") {
166
+ return "";
167
+ }
168
+ const type = getNumericType(val);
169
+ switch (type) {
170
+ case NUM_TYPE.VAR:
171
+ return val;
172
+ case NUM_TYPE.CALC:
173
+ return cssCalc(val, {
174
+ format: "specifiedValue"
175
+ });
176
+ case NUM_TYPE.NUMBER:
177
+ if (parseFloat(val) === 0) {
178
+ return "0px";
179
+ }
180
+ return;
181
+ case NUM_TYPE.LENGTH: {
182
+ const [, numVal, unit] = unitRegEx.exec(val);
183
+ const num = parseFloat(numVal);
184
+ if (restrictToPositive && num < 0) {
185
+ return;
186
+ }
187
+ return `${num}${unit.toLowerCase()}`;
188
+ }
189
+ default:
190
+ if (varContainedRegEx.test(val)) {
191
+ return val;
192
+ }
169
193
  }
170
- return val;
171
194
  };
172
195
 
173
- // either a length or a percent
174
- exports.parseMeasurement = function parseMeasurement(val) {
175
- var type = exports.valueType(val);
176
- if (type === exports.TYPES.VAR) {
177
- return val;
178
- }
179
- if (type === exports.TYPES.CALC) {
180
- return cssCalc(val, {
181
- format: 'specifiedValue',
182
- });
196
+ exports.parsePercent = function parsePercent(val, restrictToPositive = false) {
197
+ if (val === "") {
198
+ return "";
199
+ }
200
+ const type = getNumericType(val);
201
+ switch (type) {
202
+ case NUM_TYPE.VAR:
203
+ return val;
204
+ case NUM_TYPE.CALC:
205
+ return cssCalc(val, {
206
+ format: "specifiedValue"
207
+ });
208
+ case NUM_TYPE.NUMBER:
209
+ if (parseFloat(val) === 0) {
210
+ return "0%";
211
+ }
212
+ return;
213
+ case NUM_TYPE.PERCENT: {
214
+ const [, numVal, unit] = unitRegEx.exec(val);
215
+ const num = parseFloat(numVal);
216
+ if (restrictToPositive && num < 0) {
217
+ return;
218
+ }
219
+ return `${num}${unit.toLowerCase()}`;
220
+ }
221
+ default:
222
+ if (varContainedRegEx.test(val)) {
223
+ return val;
224
+ }
183
225
  }
226
+ };
184
227
 
185
- var length = exports.parseLength(val);
186
- if (length !== undefined) {
187
- return length;
228
+ // Either a length or a percent.
229
+ exports.parseMeasurement = function parseMeasurement(val, restrictToPositive = false) {
230
+ if (val === "") {
231
+ return "";
232
+ }
233
+ const type = getNumericType(val);
234
+ switch (type) {
235
+ case NUM_TYPE.VAR:
236
+ return val;
237
+ case NUM_TYPE.CALC:
238
+ return cssCalc(val, {
239
+ format: "specifiedValue"
240
+ });
241
+ case NUM_TYPE.NUMBER:
242
+ if (parseFloat(val) === 0) {
243
+ return "0px";
244
+ }
245
+ return;
246
+ case NUM_TYPE.LENGTH:
247
+ case NUM_TYPE.PERCENT: {
248
+ const [, numVal, unit] = unitRegEx.exec(val);
249
+ const num = parseFloat(numVal);
250
+ if (restrictToPositive && num < 0) {
251
+ return;
252
+ }
253
+ return `${num}${unit.toLowerCase()}`;
254
+ }
255
+ default:
256
+ if (varContainedRegEx.test(val)) {
257
+ return val;
258
+ }
188
259
  }
189
- return exports.parsePercent(val);
190
260
  };
191
261
 
192
- exports.parseInheritingMeasurement = function parseInheritingMeasurement(v) {
193
- if (String(v).toLowerCase() === 'auto') {
194
- return 'auto';
195
- }
196
- if (String(v).toLowerCase() === 'inherit') {
197
- return 'inherit';
262
+ exports.parseAngle = function parseAngle(val, normalizeDeg = false) {
263
+ if (val === "") {
264
+ return "";
265
+ }
266
+ const type = getNumericType(val);
267
+ switch (type) {
268
+ case NUM_TYPE.VAR:
269
+ return val;
270
+ case NUM_TYPE.CALC:
271
+ return cssCalc(val, {
272
+ format: "specifiedValue"
273
+ });
274
+ case NUM_TYPE.NUMBER:
275
+ if (parseFloat(val) === 0) {
276
+ return "0deg";
277
+ }
278
+ return;
279
+ case NUM_TYPE.ANGLE: {
280
+ let [, numVal, unit] = unitRegEx.exec(val);
281
+ numVal = parseFloat(numVal);
282
+ unit = unit.toLowerCase();
283
+ if (unit === "deg") {
284
+ if (normalizeDeg && numVal < 0) {
285
+ while (numVal < 0) {
286
+ numVal += 360;
287
+ }
288
+ }
289
+ numVal %= 360;
290
+ }
291
+ return `${numVal}${unit}`;
292
+ }
293
+ default:
294
+ if (varContainedRegEx.test(val)) {
295
+ return val;
296
+ }
198
297
  }
199
- return exports.parseMeasurement(v);
200
298
  };
201
299
 
202
300
  exports.parseUrl = function parseUrl(val) {
203
- var type = exports.valueType(val);
204
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
301
+ if (val === "") {
205
302
  return val;
206
303
  }
207
- var res = urlRegEx.exec(val);
208
- // does it match the regex?
304
+ const res = urlRegEx.exec(val);
209
305
  if (!res) {
210
- return undefined;
306
+ return;
211
307
  }
212
- var str = res[1];
213
- // if it starts with single or double quotes, does it end with the same?
308
+ let str = res[1];
309
+ // If it starts with single or double quotes, does it end with the same?
214
310
  if ((str[0] === '"' || str[0] === "'") && str[0] !== str[str.length - 1]) {
215
- return undefined;
311
+ return;
216
312
  }
217
313
  if (str[0] === '"' || str[0] === "'") {
218
314
  str = str.substr(1, str.length - 2);
219
315
  }
220
-
221
- var urlstr = '';
222
- var escaped = false;
223
- var i;
224
- for (i = 0; i < str.length; i++) {
316
+ let urlstr = "";
317
+ let escaped = false;
318
+ for (let i = 0; i < str.length; i++) {
225
319
  switch (str[i]) {
226
- case '\\':
320
+ case "\\":
227
321
  if (escaped) {
228
- urlstr += '\\\\';
322
+ urlstr += "\\\\";
229
323
  escaped = false;
230
324
  } else {
231
325
  escaped = true;
232
326
  }
233
327
  break;
234
- case '(':
235
- case ')':
236
- case ' ':
237
- case '\t':
238
- case '\n':
328
+ case "(":
329
+ case ")":
330
+ case " ":
331
+ case "\t":
332
+ case "\n":
239
333
  case "'":
240
334
  if (!escaped) {
241
- return undefined;
335
+ return;
242
336
  }
243
337
  urlstr += str[i];
244
338
  escaped = false;
245
339
  break;
246
340
  case '"':
247
341
  if (!escaped) {
248
- return undefined;
342
+ return;
249
343
  }
250
344
  urlstr += '\\"';
251
345
  escaped = false;
@@ -255,119 +349,98 @@ exports.parseUrl = function parseUrl(val) {
255
349
  escaped = false;
256
350
  }
257
351
  }
258
-
259
- return 'url("' + urlstr + '")';
352
+ return `url("${urlstr}")`;
260
353
  };
261
354
 
262
355
  exports.parseString = function parseString(val) {
263
- var type = exports.valueType(val);
264
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
265
- return val;
356
+ if (val === "") {
357
+ return "";
266
358
  }
267
- if (type !== exports.TYPES.STRING) {
268
- return undefined;
359
+ if (!stringRegEx.test(val)) {
360
+ return;
269
361
  }
270
- var i;
271
- for (i = 1; i < val.length - 1; i++) {
362
+ val = val.substr(1, val.length - 2);
363
+ let str = "";
364
+ let escaped = false;
365
+ for (let i = 0; i < val.length; i++) {
272
366
  switch (val[i]) {
273
- case val[0]:
274
- return undefined;
275
- case '\\':
276
- i++;
277
- while (i < val.length - 1 && /[0-9A-Fa-f]/.test(val[i])) {
278
- i++;
367
+ case "\\":
368
+ if (escaped) {
369
+ str += "\\\\";
370
+ escaped = false;
371
+ } else {
372
+ escaped = true;
279
373
  }
280
374
  break;
375
+ case '"':
376
+ str += '\\"';
377
+ escaped = false;
378
+ break;
379
+ default:
380
+ str += val[i];
381
+ escaped = false;
281
382
  }
282
383
  }
283
- if (i >= val.length) {
284
- return undefined;
285
- }
286
- return val;
384
+ return `"${str}"`;
287
385
  };
288
386
 
289
- exports.parseColor = function parseColor(val) {
290
- var type = exports.valueType(val);
291
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
292
- return val;
387
+ exports.parseKeyword = function parseKeyword(val, validKeywords = []) {
388
+ if (val === "") {
389
+ return "";
293
390
  }
294
- if (/^[a-z]+$/i.test(val) && type === exports.TYPES.COLOR) {
391
+ if (varRegEx.test(val)) {
295
392
  return val;
296
393
  }
297
- var res = resolveColor(val, {
298
- format: 'specifiedValue',
299
- });
300
- if (res) {
301
- return res;
302
- }
303
- return undefined;
304
- };
305
-
306
- exports.parseAngle = function parseAngle(val) {
307
- var type = exports.valueType(val);
308
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
394
+ val = val.toString().toLowerCase();
395
+ if (validKeywords.includes(val) || GLOBAL_VALUE.includes(val)) {
309
396
  return val;
310
397
  }
311
- if (type !== exports.TYPES.ANGLE) {
312
- return undefined;
313
- }
314
- var res = angleRegEx.exec(val);
315
- var flt = parseFloat(res[1]);
316
- if (res[2] === 'rad') {
317
- flt *= 180 / Math.PI;
318
- } else if (res[2] === 'grad') {
319
- flt *= 360 / 400;
320
- }
321
-
322
- while (flt < 0) {
323
- flt += 360;
324
- }
325
- while (flt > 360) {
326
- flt -= 360;
327
- }
328
- return flt + 'deg';
329
398
  };
330
399
 
331
- exports.parseKeyword = function parseKeyword(val, valid_keywords) {
332
- var type = exports.valueType(val);
333
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
400
+ exports.parseColor = function parseColor(val) {
401
+ if (val === "") {
402
+ return "";
403
+ }
404
+ if (varRegEx.test(val)) {
334
405
  return val;
335
406
  }
336
- if (type !== exports.TYPES.KEYWORD) {
337
- return undefined;
407
+ if (/^[a-z]+$/i.test(val) && SYS_COLOR.includes(val.toLowerCase())) {
408
+ return val;
338
409
  }
339
- val = val.toString().toLowerCase();
340
- var i;
341
- for (i = 0; i < valid_keywords.length; i++) {
342
- if (valid_keywords[i].toLowerCase() === val) {
343
- return valid_keywords[i];
344
- }
410
+ const res = resolveColor(val, {
411
+ format: "specifiedValue"
412
+ });
413
+ if (res) {
414
+ return res;
345
415
  }
346
- return undefined;
416
+ return exports.parseKeyword(val);
347
417
  };
348
418
 
349
419
  exports.parseImage = function parseImage(val) {
350
- if (/^(?:none|inherit)$/i.test(val)) {
351
- return val;
420
+ if (val === "") {
421
+ return "";
352
422
  }
353
- var type = exports.valueType(val);
354
- if (type === exports.TYPES.NULL_OR_EMPTY_STR || type === exports.TYPES.VAR) {
423
+ if (varRegEx.test(val)) {
355
424
  return val;
356
425
  }
357
- var values = splitValue(val, ',');
358
- var isImage = !!values.length;
359
- var i;
360
- for (i = 0; i < values.length; i++) {
361
- var image = values[i];
362
- var t = exports.valueType(image);
363
- if (t === exports.TYPES.NULL_OR_EMPTY_STR) {
364
- return image;
426
+ if (keywordRegEx.test(val)) {
427
+ return exports.parseKeyword(val, ["none"]);
428
+ }
429
+ const values = splitValue(val, {
430
+ delimiter: ",",
431
+ preserveComment: varContainedRegEx.test(val)
432
+ });
433
+ let isImage = Boolean(values.length);
434
+ for (let i = 0; i < values.length; i++) {
435
+ const image = values[i];
436
+ if (image === "") {
437
+ return "";
365
438
  }
366
- if (t === exports.TYPES.GRADIENT || /^(?:none|inherit)$/i.test(image)) {
439
+ if (isGradient(image) || /^(?:none|inherit)$/i.test(image)) {
367
440
  continue;
368
441
  }
369
- var imageUrl = exports.parseUrl(image);
370
- if (exports.valueType(imageUrl) === exports.TYPES.URL) {
442
+ const imageUrl = exports.parseUrl(image);
443
+ if (imageUrl) {
371
444
  values[i] = imageUrl;
372
445
  } else {
373
446
  isImage = false;
@@ -375,293 +448,55 @@ exports.parseImage = function parseImage(val) {
375
448
  }
376
449
  }
377
450
  if (isImage) {
378
- return values.join(', ');
379
- }
380
- return undefined;
381
- };
382
-
383
- // utility to translate from border-width to borderWidth
384
- var dashedToCamelCase = function (dashed) {
385
- var i;
386
- var camel = '';
387
- var nextCap = false;
388
- for (i = 0; i < dashed.length; i++) {
389
- if (dashed[i] !== '-') {
390
- camel += nextCap ? dashed[i].toUpperCase() : dashed[i];
391
- nextCap = false;
392
- } else {
393
- nextCap = true;
394
- }
451
+ return values.join(", ");
395
452
  }
396
- return camel;
397
453
  };
398
- exports.dashedToCamelCase = dashedToCamelCase;
399
454
 
400
- var is_space = /\s/;
401
- var opening_deliminators = ['"', "'", '('];
402
- var closing_deliminators = ['"', "'", ')'];
403
- // this splits on whitespace, but keeps quoted and parened parts together
404
- var getParts = function (str) {
405
- var deliminator_stack = [];
406
- var length = str.length;
407
- var i;
408
- var parts = [];
409
- var current_part = '';
410
- var opening_index;
411
- var closing_index;
412
- for (i = 0; i < length; i++) {
413
- opening_index = opening_deliminators.indexOf(str[i]);
414
- closing_index = closing_deliminators.indexOf(str[i]);
415
- if (is_space.test(str[i])) {
416
- if (deliminator_stack.length === 0) {
417
- if (current_part !== '') {
418
- parts.push(current_part);
419
- }
420
- current_part = '';
421
- } else {
422
- current_part += str[i];
423
- }
424
- } else {
425
- if (str[i] === '\\') {
426
- i++;
427
- current_part += str[i];
428
- } else {
429
- current_part += str[i];
430
- if (
431
- closing_index !== -1 &&
432
- closing_index === deliminator_stack[deliminator_stack.length - 1]
433
- ) {
434
- deliminator_stack.pop();
435
- } else if (opening_index !== -1) {
436
- deliminator_stack.push(opening_index);
437
- }
438
- }
455
+ exports.parseShorthand = function parseShorthand(val, shorthandFor, preserve = false) {
456
+ const obj = {};
457
+ if (val === "" || exports.hasVarFunc(val)) {
458
+ for (const [property] of shorthandFor) {
459
+ obj[property] = "";
439
460
  }
440
- }
441
- if (current_part !== '') {
442
- parts.push(current_part);
443
- }
444
- return parts;
445
- };
446
-
447
- /*
448
- * this either returns undefined meaning that it isn't valid
449
- * or returns an object where the keys are dashed short
450
- * hand properties and the values are the values to set
451
- * on them
452
- */
453
- exports.shorthandParser = function parse(v, shorthand_for) {
454
- var obj = {};
455
- var type = exports.valueType(v);
456
- if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
457
- Object.keys(shorthand_for).forEach(function (property) {
458
- obj[property] = '';
459
- });
460
461
  return obj;
461
462
  }
462
-
463
- if (typeof v === 'number') {
464
- v = v.toString();
465
- }
466
-
467
- if (typeof v !== 'string') {
468
- return undefined;
469
- }
470
-
471
- if (v.toLowerCase() === 'inherit') {
472
- return {};
473
- }
474
- var parts = getParts(v);
475
- var valid = true;
476
- parts.forEach(function (part, i) {
477
- var part_valid = false;
478
- Object.keys(shorthand_for).forEach(function (property) {
479
- if (shorthand_for[property].isValid(part, i)) {
480
- part_valid = true;
481
- obj[property] = part;
482
- }
483
- });
484
- valid = valid && part_valid;
485
- });
486
- if (!valid) {
487
- return undefined;
488
- }
489
- return obj;
490
- };
491
-
492
- exports.shorthandSetter = function (property, shorthand_for) {
493
- return function (v) {
494
- var obj = exports.shorthandParser(v, shorthand_for);
495
- if (obj === undefined) {
496
- return;
463
+ const key = exports.parseKeyword(val);
464
+ if (key) {
465
+ if (key === "inherit") {
466
+ return obj;
497
467
  }
498
- //console.log('shorthandSetter for:', property, 'obj:', obj);
499
- Object.keys(obj).forEach(function (subprop) {
500
- // in case subprop is an implicit property, this will clear
501
- // *its* subpropertiesX
502
- var camel = dashedToCamelCase(subprop);
503
- this[camel] = obj[subprop];
504
- // in case it gets translated into something else (0 -> 0px)
505
- obj[subprop] = this[camel];
506
- this.removeProperty(subprop);
507
- // don't add in empty properties
508
- if (obj[subprop] !== '') {
509
- this._values[subprop] = obj[subprop];
510
- }
511
- }, this);
512
- Object.keys(shorthand_for).forEach(function (subprop) {
513
- if (!obj.hasOwnProperty(subprop)) {
514
- this.removeProperty(subprop);
515
- delete this._values[subprop];
468
+ return;
469
+ }
470
+ const parts = splitValue(val);
471
+ const shorthandArr = [...shorthandFor];
472
+ for (const part of parts) {
473
+ let partValid = false;
474
+ for (let i = 0; i < shorthandArr.length; i++) {
475
+ const [property, value] = shorthandArr[i];
476
+ if (value.isValid(part)) {
477
+ partValid = true;
478
+ obj[property] = value.parse(part);
479
+ if (!preserve) {
480
+ shorthandArr.splice(i, 1);
481
+ break;
482
+ }
516
483
  }
517
- }, this);
518
- // in case the value is something like 'none' that removes all values,
519
- // check that the generated one is not empty, first remove the property
520
- // if it already exists, then call the shorthandGetter, if it's an empty
521
- // string, don't set the property
522
- this.removeProperty(property);
523
- var calculated = exports.shorthandGetter(property, shorthand_for).call(this);
524
- if (calculated !== '') {
525
- this._setProperty(property, calculated);
526
- }
527
- };
528
- };
529
-
530
- exports.shorthandGetter = function (property, shorthand_for) {
531
- return function () {
532
- if (this._values[property] !== undefined) {
533
- return this.getPropertyValue(property);
534
- }
535
- return Object.keys(shorthand_for)
536
- .map(function (subprop) {
537
- return this.getPropertyValue(subprop);
538
- }, this)
539
- .filter(function (value) {
540
- return value !== '';
541
- })
542
- .join(' ');
543
- };
544
- };
545
-
546
- // isValid(){1,4} | inherit
547
- // if one, it applies to all
548
- // if two, the first applies to the top and bottom, and the second to left and right
549
- // if three, the first applies to the top, the second to left and right, the third bottom
550
- // if four, top, right, bottom, left
551
- exports.implicitSetter = function (property_before, property_after, isValid, parser) {
552
- property_after = property_after || '';
553
- if (property_after !== '') {
554
- property_after = '-' + property_after;
555
- }
556
- var part_names = ['top', 'right', 'bottom', 'left'];
557
-
558
- return function (v) {
559
- if (typeof v === 'number') {
560
- v = v.toString();
561
- }
562
- if (typeof v !== 'string') {
563
- return undefined;
564
- }
565
- var parts;
566
- if (v.toLowerCase() === 'inherit' || v === '') {
567
- parts = [v];
568
- } else {
569
- parts = getParts(v);
570
- }
571
- if (parts.length < 1 || parts.length > 4) {
572
- return undefined;
573
- }
574
-
575
- if (!parts.every(isValid)) {
576
- return undefined;
577
484
  }
578
-
579
- parts = parts.map(function (part) {
580
- return parser(part);
581
- });
582
- this._setProperty(property_before + property_after, parts.join(' '));
583
- if (parts.length === 1) {
584
- parts[1] = parts[0];
585
- }
586
- if (parts.length === 2) {
587
- parts[2] = parts[0];
588
- }
589
- if (parts.length === 3) {
590
- parts[3] = parts[1];
591
- }
592
-
593
- for (var i = 0; i < 4; i++) {
594
- var property = property_before + '-' + part_names[i] + property_after;
595
- this.removeProperty(property);
596
- if (parts[i] !== '') {
597
- this._values[property] = parts[i];
598
- }
485
+ if (!partValid) {
486
+ return;
599
487
  }
600
- return v;
601
- };
488
+ }
489
+ return obj;
602
490
  };
603
491
 
604
- //
605
- // Companion to implicitSetter, but for the individual parts.
606
- // This sets the individual value, and checks to see if all four
607
- // sub-parts are set. If so, it sets the shorthand version and removes
608
- // the individual parts from the cssText.
609
- //
610
- exports.subImplicitSetter = function (prefix, part, isValid, parser) {
611
- var property = prefix + '-' + part;
612
- var subparts = [prefix + '-top', prefix + '-right', prefix + '-bottom', prefix + '-left'];
613
-
614
- return function (v) {
615
- if (typeof v === 'number') {
616
- v = v.toString();
617
- }
618
- if (v === null) {
619
- v = '';
620
- }
621
- if (typeof v !== 'string') {
622
- return undefined;
623
- }
624
- if (!isValid(v)) {
625
- return undefined;
626
- }
627
- v = parser(v);
628
- this._setProperty(property, v);
629
-
630
- var combinedPriority = this.getPropertyPriority(prefix);
631
- var parts = subparts.map((subpart) => this._values[subpart]);
632
- var priorities = subparts.map((subpart) => this.getPropertyPriority(subpart));
633
- // Combine into a single property if all values are set and have the same priority
634
- if (
635
- parts.every((p) => p !== '' && p != null) &&
636
- priorities.every((p) => p === priorities[0]) &&
637
- priorities[0] === combinedPriority
638
- ) {
639
- for (var i = 0; i < subparts.length; i++) {
640
- this.removeProperty(subparts[i]);
641
- this._values[subparts[i]] = parts[i];
642
- }
643
- this._setProperty(prefix, parts.join(' '), priorities[0]);
644
- } else {
645
- this.removeProperty(prefix);
646
- for (var j = 0; j < subparts.length; j++) {
647
- // The property we're setting won't be important, the rest will either keep their priority or inherit it from the combined property
648
- var priority = subparts[j] === property ? '' : priorities[j] || combinedPriority;
649
- this._setProperty(subparts[j], parts[j], priority);
650
- }
651
- }
652
- return v;
653
- };
492
+ // Returns `false` for global values, e.g. "inherit".
493
+ exports.isValidColor = function isValidColor(val) {
494
+ if (SYS_COLOR.includes(val.toLowerCase())) {
495
+ return true;
496
+ }
497
+ return isColor(val);
654
498
  };
655
499
 
656
- var camel_to_dashed = /[A-Z]/g;
657
- var first_segment = /^\([^-]\)-/;
658
- var vendor_prefixes = ['o', 'moz', 'ms', 'webkit'];
659
- exports.camelToDashed = function (camel_case) {
660
- var match;
661
- var dashed = camel_case.replace(camel_to_dashed, '-$&').toLowerCase();
662
- match = dashed.match(first_segment);
663
- if (match && vendor_prefixes.indexOf(match[1]) !== -1) {
664
- dashed = '-' + dashed;
665
- }
666
- return dashed;
667
- };
500
+ // Splits value into an array.
501
+ // @see https://github.com/asamuzaK/cssColor/blob/main/src/js/util.ts
502
+ exports.splitValue = splitValue;