cssstyle 5.2.1 → 5.3.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 +250 -254
- package/lib/generated/allProperties.js +39 -1
- package/lib/generated/implementedProperties.js +2219 -80
- package/lib/generated/properties.js +5253 -1904
- package/lib/normalize.js +1417 -0
- package/lib/parsers.js +372 -389
- package/lib/properties/background.js +76 -63
- package/lib/properties/backgroundAttachment.js +37 -22
- package/lib/properties/backgroundClip.js +37 -22
- package/lib/properties/backgroundColor.js +35 -15
- package/lib/properties/backgroundImage.js +49 -19
- package/lib/properties/backgroundOrigin.js +37 -22
- package/lib/properties/backgroundPosition.js +145 -128
- package/lib/properties/backgroundRepeat.js +55 -48
- package/lib/properties/backgroundSize.js +86 -46
- package/lib/properties/border.js +139 -22
- package/lib/properties/borderBottom.js +137 -21
- package/lib/properties/borderBottomColor.js +41 -16
- package/lib/properties/borderBottomStyle.js +39 -30
- package/lib/properties/borderBottomWidth.js +49 -16
- package/lib/properties/borderCollapse.js +32 -8
- package/lib/properties/borderColor.js +96 -23
- package/lib/properties/borderLeft.js +137 -21
- package/lib/properties/borderLeftColor.js +41 -16
- package/lib/properties/borderLeftStyle.js +39 -30
- package/lib/properties/borderLeftWidth.js +49 -16
- package/lib/properties/borderRight.js +137 -21
- package/lib/properties/borderRightColor.js +41 -16
- package/lib/properties/borderRightStyle.js +39 -30
- package/lib/properties/borderRightWidth.js +49 -16
- package/lib/properties/borderSpacing.js +42 -25
- package/lib/properties/borderStyle.js +96 -34
- package/lib/properties/borderTop.js +131 -15
- package/lib/properties/borderTopColor.js +41 -16
- package/lib/properties/borderTopStyle.js +39 -30
- package/lib/properties/borderTopWidth.js +49 -16
- package/lib/properties/borderWidth.js +108 -23
- package/lib/properties/bottom.js +40 -12
- package/lib/properties/clear.js +32 -22
- package/lib/properties/clip.js +46 -32
- package/lib/properties/color.js +34 -13
- package/lib/properties/display.js +169 -179
- package/lib/properties/flex.js +137 -38
- package/lib/properties/flexBasis.js +43 -14
- package/lib/properties/flexGrow.js +42 -9
- package/lib/properties/flexShrink.js +42 -9
- package/lib/properties/float.js +32 -9
- package/lib/properties/floodColor.js +34 -13
- package/lib/properties/font.js +145 -44
- package/lib/properties/fontFamily.js +66 -67
- package/lib/properties/fontSize.js +43 -26
- package/lib/properties/fontStyle.js +42 -11
- package/lib/properties/fontVariant.js +52 -15
- package/lib/properties/fontWeight.js +47 -15
- package/lib/properties/height.js +40 -13
- package/lib/properties/left.js +40 -12
- package/lib/properties/lightingColor.js +34 -13
- package/lib/properties/lineHeight.js +45 -18
- package/lib/properties/margin.js +73 -36
- package/lib/properties/marginBottom.js +43 -19
- package/lib/properties/marginLeft.js +43 -19
- package/lib/properties/marginRight.js +43 -19
- package/lib/properties/marginTop.js +43 -19
- package/lib/properties/opacity.js +41 -28
- package/lib/properties/outlineColor.js +34 -13
- package/lib/properties/padding.js +71 -36
- package/lib/properties/paddingBottom.js +44 -21
- package/lib/properties/paddingLeft.js +44 -19
- package/lib/properties/paddingRight.js +44 -19
- package/lib/properties/paddingTop.js +44 -19
- package/lib/properties/right.js +40 -12
- package/lib/properties/stopColor.js +34 -13
- package/lib/properties/top.js +40 -12
- package/lib/properties/webkitBorderAfterColor.js +34 -13
- package/lib/properties/webkitBorderBeforeColor.js +34 -13
- package/lib/properties/webkitBorderEndColor.js +34 -13
- package/lib/properties/webkitBorderStartColor.js +34 -13
- package/lib/properties/webkitColumnRuleColor.js +34 -13
- package/lib/properties/webkitTapHighlightColor.js +34 -13
- package/lib/properties/webkitTextEmphasisColor.js +34 -13
- package/lib/properties/webkitTextFillColor.js +34 -13
- package/lib/properties/webkitTextStrokeColor.js +34 -13
- package/lib/properties/width.js +40 -13
- package/lib/{allWebkitProperties.js → utils/allExtraProperties.js} +42 -1
- package/lib/utils/propertyDescriptors.js +6 -3
- package/package.json +11 -10
- package/lib/allExtraProperties.js +0 -49
- package/lib/shorthandProperties.js +0 -21
package/lib/parsers.js
CHANGED
|
@@ -1,31 +1,16 @@
|
|
|
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
1
|
"use strict";
|
|
6
2
|
|
|
7
3
|
const {
|
|
8
4
|
resolve: resolveColor,
|
|
9
|
-
utils: { cssCalc,
|
|
5
|
+
utils: { cssCalc, resolveGradient, splitValue }
|
|
10
6
|
} = require("@asamuzakjp/css-color");
|
|
11
7
|
const { next: syntaxes } = require("@csstools/css-syntax-patches-for-csstree");
|
|
12
8
|
const csstree = require("css-tree");
|
|
13
9
|
const { asciiLowercase } = require("./utils/strings");
|
|
14
10
|
|
|
15
|
-
// CSS global
|
|
11
|
+
// CSS global keywords
|
|
16
12
|
// @see https://drafts.csswg.org/css-cascade-5/#defaulting-keywords
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
// Numeric data types
|
|
20
|
-
const NUM_TYPE = Object.freeze({
|
|
21
|
-
UNDEFINED: 0,
|
|
22
|
-
VAR: 1,
|
|
23
|
-
NUMBER: 2,
|
|
24
|
-
PERCENT: 4,
|
|
25
|
-
LENGTH: 8,
|
|
26
|
-
ANGLE: 0x10,
|
|
27
|
-
CALC: 0x20
|
|
28
|
-
});
|
|
13
|
+
const GLOBAL_KEY = Object.freeze(["initial", "inherit", "unset", "revert", "revert-layer"]);
|
|
29
14
|
|
|
30
15
|
// System colors
|
|
31
16
|
// @see https://drafts.csswg.org/css-color/#css-system-colors
|
|
@@ -76,49 +61,19 @@ const SYS_COLOR = Object.freeze([
|
|
|
76
61
|
]);
|
|
77
62
|
|
|
78
63
|
// Regular expressions
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const stringRegEx = /^("[^"]*"|'[^']*')$/;
|
|
64
|
+
const CALC_FUNC_NAMES =
|
|
65
|
+
"(?:a?(?:cos|sin|tan)|abs|atan2|calc|clamp|exp|hypot|log|max|min|mod|pow|rem|round|sign|sqrt)";
|
|
66
|
+
const calcRegEx = new RegExp(`^${CALC_FUNC_NAMES}\\(`);
|
|
67
|
+
const calcContainedRegEx = new RegExp(`(?<=[*/\\s(])${CALC_FUNC_NAMES}\\(`);
|
|
68
|
+
const calcNameRegEx = new RegExp(`^${CALC_FUNC_NAMES}$`);
|
|
85
69
|
const varRegEx = /^var\(/;
|
|
86
70
|
const varContainedRegEx = /(?<=[*/\s(])var\(/;
|
|
87
|
-
const calcRegEx =
|
|
88
|
-
/^(?:a?(?:cos|sin|tan)|abs|atan2|calc|clamp|exp|hypot|log|max|min|mod|pow|rem|round|sign|sqrt)\(/;
|
|
89
|
-
const gradientRegEx = /^(?:repeating-)?(?:conic|linear|radial)-gradient\(/;
|
|
90
|
-
const functionRegEx = /^([a-z][a-z\d]*(?:-[a-z\d]+)*)\(/i;
|
|
91
71
|
|
|
92
|
-
|
|
93
|
-
if (varRegEx.test(val)) {
|
|
94
|
-
return NUM_TYPE.VAR;
|
|
95
|
-
}
|
|
96
|
-
if (calcRegEx.test(val)) {
|
|
97
|
-
return NUM_TYPE.CALC;
|
|
98
|
-
}
|
|
99
|
-
if (unitRegEx.test(val)) {
|
|
100
|
-
const [, , unit] = unitRegEx.exec(val);
|
|
101
|
-
if (!unit) {
|
|
102
|
-
return NUM_TYPE.NUMBER;
|
|
103
|
-
}
|
|
104
|
-
if (unit === "%") {
|
|
105
|
-
return NUM_TYPE.PERCENT;
|
|
106
|
-
}
|
|
107
|
-
if (/^(?:[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic))$/i.test(unit)) {
|
|
108
|
-
return NUM_TYPE.LENGTH;
|
|
109
|
-
}
|
|
110
|
-
if (/^(?:deg|g?rad|turn)$/i.test(unit)) {
|
|
111
|
-
return NUM_TYPE.ANGLE;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return NUM_TYPE.UNDEFINED;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
// Patch css-tree
|
|
72
|
+
// Patched css-tree
|
|
118
73
|
const cssTree = csstree.fork(syntaxes);
|
|
119
74
|
|
|
120
75
|
// Prepare stringified value.
|
|
121
|
-
exports.prepareValue =
|
|
76
|
+
exports.prepareValue = (value, globalObject = globalThis) => {
|
|
122
77
|
// `null` is converted to an empty string.
|
|
123
78
|
// @see https://webidl.spec.whatwg.org/#LegacyNullToEmptyString
|
|
124
79
|
if (value === null) {
|
|
@@ -137,416 +92,444 @@ exports.prepareValue = function prepareValue(value, globalObject = globalThis) {
|
|
|
137
92
|
default: {
|
|
138
93
|
const str = value.toString();
|
|
139
94
|
if (typeof str === "string") {
|
|
140
|
-
return str;
|
|
95
|
+
return str.trim();
|
|
141
96
|
}
|
|
142
97
|
throw new globalObject.TypeError(`Can not convert ${type} to string.`);
|
|
143
98
|
}
|
|
144
99
|
}
|
|
145
100
|
};
|
|
146
101
|
|
|
147
|
-
|
|
102
|
+
// Value is a global keyword.
|
|
103
|
+
exports.isGlobalKeyword = (val) => {
|
|
104
|
+
return GLOBAL_KEY.includes(asciiLowercase(val));
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Value starts with and/or contains CSS var() function.
|
|
108
|
+
exports.hasVarFunc = (val) => {
|
|
148
109
|
return varRegEx.test(val) || varContainedRegEx.test(val);
|
|
149
110
|
};
|
|
150
111
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
112
|
+
// Value starts with and/or contains CSS calc() related functions.
|
|
113
|
+
exports.hasCalcFunc = (val) => {
|
|
114
|
+
return calcRegEx.test(val) || calcContainedRegEx.test(val);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Splits value into an array.
|
|
118
|
+
// @see https://github.com/asamuzaK/cssColor/blob/main/src/js/util.ts
|
|
119
|
+
exports.splitValue = splitValue;
|
|
120
|
+
|
|
121
|
+
// Parse CSS to AST.
|
|
122
|
+
exports.parseCSS = (val, opt, toObject = false) => {
|
|
123
|
+
if (typeof val !== "string") {
|
|
124
|
+
val = exports.prepareValue(val);
|
|
154
125
|
}
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return val;
|
|
159
|
-
case NUM_TYPE.CALC:
|
|
160
|
-
return cssCalc(val, {
|
|
161
|
-
format: "specifiedValue"
|
|
162
|
-
});
|
|
163
|
-
case NUM_TYPE.NUMBER: {
|
|
164
|
-
const num = parseFloat(val);
|
|
165
|
-
if (restrictToPositive && num < 0) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
return `${num}`;
|
|
169
|
-
}
|
|
170
|
-
default:
|
|
171
|
-
if (varContainedRegEx.test(val)) {
|
|
172
|
-
return val;
|
|
173
|
-
}
|
|
126
|
+
const ast = cssTree.parse(val, opt);
|
|
127
|
+
if (toObject) {
|
|
128
|
+
return cssTree.toPlainObject(ast);
|
|
174
129
|
}
|
|
130
|
+
return ast;
|
|
175
131
|
};
|
|
176
132
|
|
|
177
|
-
|
|
133
|
+
// Value is a valid property value.
|
|
134
|
+
// Returns `false` for custom property and/or var().
|
|
135
|
+
exports.isValidPropertyValue = (prop, val) => {
|
|
136
|
+
if (typeof val !== "string") {
|
|
137
|
+
val = exports.prepareValue(val);
|
|
138
|
+
}
|
|
178
139
|
if (val === "") {
|
|
179
|
-
return
|
|
140
|
+
return true;
|
|
180
141
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return
|
|
187
|
-
format: "specifiedValue"
|
|
188
|
-
});
|
|
189
|
-
case NUM_TYPE.NUMBER:
|
|
190
|
-
if (parseFloat(val) === 0) {
|
|
191
|
-
return "0px";
|
|
192
|
-
}
|
|
193
|
-
return;
|
|
194
|
-
case NUM_TYPE.LENGTH: {
|
|
195
|
-
const [, numVal, unit] = unitRegEx.exec(val);
|
|
196
|
-
const num = parseFloat(numVal);
|
|
197
|
-
if (restrictToPositive && num < 0) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
return `${num}${asciiLowercase(unit)}`;
|
|
142
|
+
// cssTree.lexer does not support deprecated system colors
|
|
143
|
+
// @see https://github.com/w3c/webref/issues/1519#issuecomment-3120290261
|
|
144
|
+
// @see https://github.com/w3c/webref/issues/1647
|
|
145
|
+
if (SYS_COLOR.includes(asciiLowercase(val))) {
|
|
146
|
+
if (/^(?:-webkit-)?(?:[a-z][a-z\d]*-)*color$/i.test(prop)) {
|
|
147
|
+
return true;
|
|
201
148
|
}
|
|
202
|
-
|
|
203
|
-
if (varContainedRegEx.test(val)) {
|
|
204
|
-
return val;
|
|
205
|
-
}
|
|
149
|
+
return false;
|
|
206
150
|
}
|
|
151
|
+
let ast;
|
|
152
|
+
try {
|
|
153
|
+
ast = exports.parseCSS(val, {
|
|
154
|
+
context: "value"
|
|
155
|
+
});
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
const { error, matched } = cssTree.lexer.matchProperty(prop, ast);
|
|
160
|
+
return error === null && matched !== null;
|
|
207
161
|
};
|
|
208
162
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
163
|
+
// Simplify / resolve math functions.
|
|
164
|
+
exports.resolveCalc = (val, opt = { format: "specifiedValue" }) => {
|
|
165
|
+
if (typeof val !== "string") {
|
|
166
|
+
val = exports.prepareValue(val);
|
|
212
167
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
|
|
168
|
+
if (val === "" || exports.hasVarFunc(val) || !exports.hasCalcFunc(val)) {
|
|
169
|
+
return val;
|
|
170
|
+
}
|
|
171
|
+
const obj = exports.parseCSS(val, { context: "value" }, true);
|
|
172
|
+
if (!obj?.children) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const { children: items } = obj;
|
|
176
|
+
const values = [];
|
|
177
|
+
for (const item of items) {
|
|
178
|
+
const { type: itemType, name: itemName, value: itemValue } = item;
|
|
179
|
+
if (itemType === "Function") {
|
|
180
|
+
const value = cssTree
|
|
181
|
+
.generate(item)
|
|
182
|
+
.replace(/\)(?!\)|\s|,)/g, ") ")
|
|
183
|
+
.trim();
|
|
184
|
+
if (calcNameRegEx.test(itemName)) {
|
|
185
|
+
const newValue = cssCalc(value, opt);
|
|
186
|
+
values.push(newValue);
|
|
187
|
+
} else {
|
|
188
|
+
values.push(value);
|
|
231
189
|
}
|
|
232
|
-
|
|
190
|
+
} else if (itemType === "String") {
|
|
191
|
+
values.push(`"${itemValue}"`);
|
|
192
|
+
} else {
|
|
193
|
+
values.push(itemName ?? itemValue);
|
|
233
194
|
}
|
|
234
|
-
default:
|
|
235
|
-
if (varContainedRegEx.test(val)) {
|
|
236
|
-
return val;
|
|
237
|
-
}
|
|
238
195
|
}
|
|
196
|
+
return values.join(" ");
|
|
239
197
|
};
|
|
240
198
|
|
|
241
|
-
//
|
|
242
|
-
exports.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
format: "specifiedValue"
|
|
253
|
-
});
|
|
254
|
-
case NUM_TYPE.NUMBER:
|
|
255
|
-
if (parseFloat(val) === 0) {
|
|
256
|
-
return "0px";
|
|
257
|
-
}
|
|
199
|
+
// Parse property value. Returns string or array of parsed object.
|
|
200
|
+
exports.parsePropertyValue = (prop, val, opt = {}) => {
|
|
201
|
+
const { caseSensitive, globalObject, inArray } = opt;
|
|
202
|
+
val = exports.prepareValue(val, globalObject);
|
|
203
|
+
if (val === "" || exports.hasVarFunc(val)) {
|
|
204
|
+
return val;
|
|
205
|
+
} else if (exports.hasCalcFunc(val)) {
|
|
206
|
+
const calculatedValue = exports.resolveCalc(val, {
|
|
207
|
+
format: "specifiedValue"
|
|
208
|
+
});
|
|
209
|
+
if (typeof calculatedValue !== "string") {
|
|
258
210
|
return;
|
|
259
|
-
case NUM_TYPE.LENGTH:
|
|
260
|
-
case NUM_TYPE.PERCENT: {
|
|
261
|
-
const [, numVal, unit] = unitRegEx.exec(val);
|
|
262
|
-
const num = parseFloat(numVal);
|
|
263
|
-
if (restrictToPositive && num < 0) {
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
return `${num}${asciiLowercase(unit)}`;
|
|
267
211
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
212
|
+
val = calculatedValue;
|
|
213
|
+
}
|
|
214
|
+
const lowerCasedValue = asciiLowercase(val);
|
|
215
|
+
if (GLOBAL_KEY.includes(lowerCasedValue)) {
|
|
216
|
+
if (inArray) {
|
|
217
|
+
return [
|
|
218
|
+
{
|
|
219
|
+
type: "GlobalKeyword",
|
|
220
|
+
name: lowerCasedValue
|
|
221
|
+
}
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
return lowerCasedValue;
|
|
225
|
+
} else if (SYS_COLOR.includes(lowerCasedValue)) {
|
|
226
|
+
if (/^(?:(?:-webkit-)?(?:[a-z][a-z\d]*-)*color|border)$/i.test(prop)) {
|
|
227
|
+
if (inArray) {
|
|
228
|
+
return [
|
|
229
|
+
{
|
|
230
|
+
type: "Identifier",
|
|
231
|
+
name: lowerCasedValue
|
|
232
|
+
}
|
|
233
|
+
];
|
|
271
234
|
}
|
|
235
|
+
return lowerCasedValue;
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
272
238
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const type = getNumericType(val);
|
|
280
|
-
switch (type) {
|
|
281
|
-
case NUM_TYPE.VAR:
|
|
282
|
-
return val;
|
|
283
|
-
case NUM_TYPE.CALC:
|
|
284
|
-
return cssCalc(val, {
|
|
285
|
-
format: "specifiedValue"
|
|
286
|
-
});
|
|
287
|
-
case NUM_TYPE.NUMBER:
|
|
288
|
-
if (parseFloat(val) === 0) {
|
|
289
|
-
return "0deg";
|
|
290
|
-
}
|
|
239
|
+
try {
|
|
240
|
+
const ast = exports.parseCSS(val, {
|
|
241
|
+
context: "value"
|
|
242
|
+
});
|
|
243
|
+
const { error, matched } = cssTree.lexer.matchProperty(prop, ast);
|
|
244
|
+
if (error || !matched) {
|
|
291
245
|
return;
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
246
|
+
}
|
|
247
|
+
if (inArray) {
|
|
248
|
+
const obj = cssTree.toPlainObject(ast);
|
|
249
|
+
const items = obj.children;
|
|
250
|
+
const parsedValues = [];
|
|
251
|
+
for (const item of items) {
|
|
252
|
+
const { children, name, type, value, unit } = item;
|
|
253
|
+
switch (type) {
|
|
254
|
+
case "Dimension": {
|
|
255
|
+
parsedValues.push({
|
|
256
|
+
type,
|
|
257
|
+
value,
|
|
258
|
+
unit: asciiLowercase(unit)
|
|
259
|
+
});
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
case "Function": {
|
|
263
|
+
const css = cssTree
|
|
264
|
+
.generate(item)
|
|
265
|
+
.replace(/\)(?!\)|\s|,)/g, ") ")
|
|
266
|
+
.trim();
|
|
267
|
+
const raw = items.length === 1 ? val : css;
|
|
268
|
+
const itemValue = raw
|
|
269
|
+
.replace(new RegExp(`^${name}\\(`), "")
|
|
270
|
+
.replace(/\)$/, "")
|
|
271
|
+
.trim();
|
|
272
|
+
if (name === "calc") {
|
|
273
|
+
if (children.length === 1) {
|
|
274
|
+
const [child] = children;
|
|
275
|
+
if (child.type === "Number") {
|
|
276
|
+
parsedValues.push({
|
|
277
|
+
type: "Calc",
|
|
278
|
+
name: "calc",
|
|
279
|
+
isNumber: true,
|
|
280
|
+
value: `${parseFloat(child.value)}`,
|
|
281
|
+
raw
|
|
282
|
+
});
|
|
283
|
+
} else {
|
|
284
|
+
parsedValues.push({
|
|
285
|
+
type: "Calc",
|
|
286
|
+
name: "calc",
|
|
287
|
+
isNumber: false,
|
|
288
|
+
value: `${asciiLowercase(itemValue)}`,
|
|
289
|
+
raw
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
parsedValues.push({
|
|
294
|
+
type: "Calc",
|
|
295
|
+
name: "calc",
|
|
296
|
+
isNumber: false,
|
|
297
|
+
value: asciiLowercase(itemValue),
|
|
298
|
+
raw
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
parsedValues.push({
|
|
303
|
+
type,
|
|
304
|
+
name,
|
|
305
|
+
value: asciiLowercase(itemValue),
|
|
306
|
+
raw
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
case "Identifier": {
|
|
312
|
+
if (caseSensitive) {
|
|
313
|
+
parsedValues.push(item);
|
|
314
|
+
} else {
|
|
315
|
+
parsedValues.push({
|
|
316
|
+
type,
|
|
317
|
+
name: asciiLowercase(name)
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
default: {
|
|
323
|
+
parsedValues.push(item);
|
|
300
324
|
}
|
|
301
325
|
}
|
|
302
|
-
numVal %= 360;
|
|
303
326
|
}
|
|
304
|
-
return
|
|
327
|
+
return parsedValues;
|
|
305
328
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return val;
|
|
309
|
-
}
|
|
329
|
+
} catch {
|
|
330
|
+
return;
|
|
310
331
|
}
|
|
332
|
+
return val;
|
|
311
333
|
};
|
|
312
334
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (!res) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
let str = res[1];
|
|
322
|
-
// If it starts with single or double quotes, does it end with the same?
|
|
323
|
-
if ((str[0] === '"' || str[0] === "'") && str[0] !== str[str.length - 1]) {
|
|
335
|
+
// Parse <number>.
|
|
336
|
+
exports.parseNumber = (val, opt = {}) => {
|
|
337
|
+
const [item] = val;
|
|
338
|
+
const { type, value } = item ?? {};
|
|
339
|
+
if (type !== "Number") {
|
|
324
340
|
return;
|
|
325
341
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
let
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
urlstr += "\\\\";
|
|
336
|
-
escaped = false;
|
|
337
|
-
} else {
|
|
338
|
-
escaped = true;
|
|
339
|
-
}
|
|
340
|
-
break;
|
|
341
|
-
case "(":
|
|
342
|
-
case ")":
|
|
343
|
-
case " ":
|
|
344
|
-
case "\t":
|
|
345
|
-
case "\n":
|
|
346
|
-
case "'":
|
|
347
|
-
if (!escaped) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
urlstr += str[i];
|
|
351
|
-
escaped = false;
|
|
352
|
-
break;
|
|
353
|
-
case '"':
|
|
354
|
-
if (!escaped) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
urlstr += '\\"';
|
|
358
|
-
escaped = false;
|
|
359
|
-
break;
|
|
360
|
-
default:
|
|
361
|
-
urlstr += str[i];
|
|
362
|
-
escaped = false;
|
|
342
|
+
const { clamp } = opt;
|
|
343
|
+
const max = opt.max ?? Number.INFINITY;
|
|
344
|
+
const min = opt.min ?? Number.NEGATIVE_INFINITY;
|
|
345
|
+
let num = parseFloat(value);
|
|
346
|
+
if (clamp) {
|
|
347
|
+
if (num > max) {
|
|
348
|
+
num = max;
|
|
349
|
+
} else if (num < min) {
|
|
350
|
+
num = min;
|
|
363
351
|
}
|
|
352
|
+
} else if (num > max || num < min) {
|
|
353
|
+
return;
|
|
364
354
|
}
|
|
365
|
-
return
|
|
355
|
+
return `${num}`;
|
|
366
356
|
};
|
|
367
357
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
if (!
|
|
358
|
+
// Parse <length>.
|
|
359
|
+
exports.parseLength = (val, opt = {}) => {
|
|
360
|
+
const [item] = val;
|
|
361
|
+
const { type, value, unit } = item ?? {};
|
|
362
|
+
if (type !== "Dimension" && !(type === "Number" && value === "0")) {
|
|
373
363
|
return;
|
|
374
364
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
} else {
|
|
385
|
-
escaped = true;
|
|
386
|
-
}
|
|
387
|
-
break;
|
|
388
|
-
case '"':
|
|
389
|
-
str += '\\"';
|
|
390
|
-
escaped = false;
|
|
391
|
-
break;
|
|
392
|
-
default:
|
|
393
|
-
str += val[i];
|
|
394
|
-
escaped = false;
|
|
365
|
+
const { clamp } = opt;
|
|
366
|
+
const max = opt.max ?? Number.INFINITY;
|
|
367
|
+
const min = opt.min ?? Number.NEGATIVE_INFINITY;
|
|
368
|
+
let num = parseFloat(value);
|
|
369
|
+
if (clamp) {
|
|
370
|
+
if (num > max) {
|
|
371
|
+
num = max;
|
|
372
|
+
} else if (num < min) {
|
|
373
|
+
num = min;
|
|
395
374
|
}
|
|
375
|
+
} else if (num > max || num < min) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (num === 0 && !unit) {
|
|
379
|
+
return `${num}px`;
|
|
380
|
+
} else if (unit) {
|
|
381
|
+
return `${num}${asciiLowercase(unit)}`;
|
|
396
382
|
}
|
|
397
|
-
return `"${str}"`;
|
|
398
383
|
};
|
|
399
384
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
385
|
+
// Parse <percentage>.
|
|
386
|
+
exports.parsePercentage = (val, opt = {}) => {
|
|
387
|
+
const [item] = val;
|
|
388
|
+
const { type, value } = item ?? {};
|
|
389
|
+
if (type !== "Percentage" && !(type === "Number" && value === "0")) {
|
|
390
|
+
return;
|
|
403
391
|
}
|
|
404
|
-
|
|
405
|
-
|
|
392
|
+
const { clamp } = opt;
|
|
393
|
+
const max = opt.max ?? Number.INFINITY;
|
|
394
|
+
const min = opt.min ?? Number.NEGATIVE_INFINITY;
|
|
395
|
+
let num = parseFloat(value);
|
|
396
|
+
if (clamp) {
|
|
397
|
+
if (num > max) {
|
|
398
|
+
num = max;
|
|
399
|
+
} else if (num < min) {
|
|
400
|
+
num = min;
|
|
401
|
+
}
|
|
402
|
+
} else if (num > max || num < min) {
|
|
403
|
+
return;
|
|
406
404
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
return val;
|
|
405
|
+
if (num === 0) {
|
|
406
|
+
return `${num}%`;
|
|
410
407
|
}
|
|
408
|
+
return `${num}%`;
|
|
411
409
|
};
|
|
412
410
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
if (
|
|
418
|
-
return
|
|
411
|
+
// Parse <length-percentage>.
|
|
412
|
+
exports.parseLengthPercentage = (val, opt = {}) => {
|
|
413
|
+
const [item] = val;
|
|
414
|
+
const { type, value, unit } = item ?? {};
|
|
415
|
+
if (type !== "Dimension" && type !== "Percentage" && !(type === "Number" && value === "0")) {
|
|
416
|
+
return;
|
|
419
417
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
418
|
+
const { clamp } = opt;
|
|
419
|
+
const max = opt.max ?? Number.INFINITY;
|
|
420
|
+
const min = opt.min ?? Number.NEGATIVE_INFINITY;
|
|
421
|
+
let num = parseFloat(value);
|
|
422
|
+
if (clamp) {
|
|
423
|
+
if (num > max) {
|
|
424
|
+
num = max;
|
|
425
|
+
} else if (num < min) {
|
|
426
|
+
num = min;
|
|
424
427
|
}
|
|
428
|
+
} else if (num > max || num < min) {
|
|
429
|
+
return;
|
|
425
430
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
return
|
|
431
|
+
if (unit) {
|
|
432
|
+
if (/deg|g?rad|turn/i.test(unit)) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
return `${num}${asciiLowercase(unit)}`;
|
|
436
|
+
} else if (type === "Percentage") {
|
|
437
|
+
return `${num}%`;
|
|
438
|
+
} else if (num === 0) {
|
|
439
|
+
return `${num}px`;
|
|
431
440
|
}
|
|
432
|
-
return exports.parseKeyword(val);
|
|
433
441
|
};
|
|
434
442
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
if (
|
|
440
|
-
return
|
|
441
|
-
}
|
|
442
|
-
if (keywordRegEx.test(val)) {
|
|
443
|
-
return exports.parseKeyword(val, ["none"]);
|
|
443
|
+
// Parse <angle>.
|
|
444
|
+
exports.parseAngle = (val) => {
|
|
445
|
+
const [item] = val;
|
|
446
|
+
const { type, value, unit } = item ?? {};
|
|
447
|
+
if (type !== "Dimension" && !(type === "Number" && value === "0")) {
|
|
448
|
+
return;
|
|
444
449
|
}
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
+
const num = parseFloat(value);
|
|
451
|
+
if (unit) {
|
|
452
|
+
if (!/^(?:deg|g?rad|turn)$/i.test(unit)) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
return `${num}${asciiLowercase(unit)}`;
|
|
456
|
+
} else if (num === 0) {
|
|
457
|
+
return `${num}deg`;
|
|
450
458
|
}
|
|
451
|
-
return exports.parseUrl(val);
|
|
452
459
|
};
|
|
453
460
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
461
|
-
if (functionRegEx.test(val) && val.endsWith(")")) {
|
|
462
|
-
if (varRegEx.test(val) || varContainedRegEx.test(val)) {
|
|
463
|
-
return {
|
|
464
|
-
name: "var",
|
|
465
|
-
value: val
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
const [, name] = functionRegEx.exec(val);
|
|
469
|
-
const value = val
|
|
470
|
-
.replace(new RegExp(`^${name}\\(`), "")
|
|
471
|
-
.replace(/\)$/, "")
|
|
472
|
-
.trim();
|
|
473
|
-
return {
|
|
474
|
-
name,
|
|
475
|
-
value
|
|
476
|
-
};
|
|
461
|
+
// Parse <url>.
|
|
462
|
+
exports.parseUrl = (val) => {
|
|
463
|
+
const [item] = val;
|
|
464
|
+
const { type, value } = item ?? {};
|
|
465
|
+
if (type !== "Url") {
|
|
466
|
+
return;
|
|
477
467
|
}
|
|
468
|
+
const str = value.replace(/\\\\/g, "\\").replaceAll('"', '\\"');
|
|
469
|
+
return `url("${str}")`;
|
|
478
470
|
};
|
|
479
471
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
return obj;
|
|
487
|
-
}
|
|
488
|
-
const key = exports.parseKeyword(val);
|
|
489
|
-
if (key) {
|
|
490
|
-
if (key === "inherit") {
|
|
491
|
-
return obj;
|
|
492
|
-
}
|
|
472
|
+
// Parse <string>.
|
|
473
|
+
exports.parseString = (val) => {
|
|
474
|
+
const [item] = val;
|
|
475
|
+
const { type, value } = item ?? {};
|
|
476
|
+
if (type !== "String") {
|
|
493
477
|
return;
|
|
494
478
|
}
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
479
|
+
const str = value.replace(/\\\\/g, "\\").replaceAll('"', '\\"');
|
|
480
|
+
return `"${str}"`;
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// Parse <color>.
|
|
484
|
+
exports.parseColor = (val) => {
|
|
485
|
+
const [item] = val;
|
|
486
|
+
const { name, type, value } = item ?? {};
|
|
487
|
+
switch (type) {
|
|
488
|
+
case "Function": {
|
|
489
|
+
const res = resolveColor(`${name}(${value})`, {
|
|
490
|
+
format: "specifiedValue"
|
|
491
|
+
});
|
|
492
|
+
if (res) {
|
|
493
|
+
return res;
|
|
508
494
|
}
|
|
495
|
+
break;
|
|
509
496
|
}
|
|
510
|
-
|
|
511
|
-
|
|
497
|
+
case "Hash": {
|
|
498
|
+
const res = resolveColor(`#${value}`, {
|
|
499
|
+
format: "specifiedValue"
|
|
500
|
+
});
|
|
501
|
+
if (res) {
|
|
502
|
+
return res;
|
|
503
|
+
}
|
|
504
|
+
break;
|
|
512
505
|
}
|
|
506
|
+
case "Identifier": {
|
|
507
|
+
if (SYS_COLOR.includes(name)) {
|
|
508
|
+
return name;
|
|
509
|
+
}
|
|
510
|
+
const res = resolveColor(name, {
|
|
511
|
+
format: "specifiedValue"
|
|
512
|
+
});
|
|
513
|
+
if (res) {
|
|
514
|
+
return res;
|
|
515
|
+
}
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
default:
|
|
513
519
|
}
|
|
514
|
-
return obj;
|
|
515
|
-
};
|
|
516
|
-
|
|
517
|
-
exports.parseCSS = function parseCSS(val, opt, toObject = false) {
|
|
518
|
-
const ast = cssTree.parse(val, opt);
|
|
519
|
-
if (toObject) {
|
|
520
|
-
return cssTree.toPlainObject(ast);
|
|
521
|
-
}
|
|
522
|
-
return ast;
|
|
523
520
|
};
|
|
524
521
|
|
|
525
|
-
//
|
|
526
|
-
exports.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
if (
|
|
530
|
-
|
|
531
|
-
return true;
|
|
532
|
-
}
|
|
533
|
-
return false;
|
|
522
|
+
// Parse <gradient>.
|
|
523
|
+
exports.parseGradient = (val) => {
|
|
524
|
+
const [item] = val;
|
|
525
|
+
const { name, type, value } = item ?? {};
|
|
526
|
+
if (type !== "Function") {
|
|
527
|
+
return;
|
|
534
528
|
}
|
|
535
|
-
const
|
|
536
|
-
|
|
529
|
+
const res = resolveGradient(`${name}(${value})`, {
|
|
530
|
+
format: "specifiedValue"
|
|
537
531
|
});
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
// Returns `false` for global values, e.g. "inherit".
|
|
543
|
-
exports.isValidColor = function isValidColor(val) {
|
|
544
|
-
if (SYS_COLOR.includes(asciiLowercase(val))) {
|
|
545
|
-
return true;
|
|
532
|
+
if (res) {
|
|
533
|
+
return res;
|
|
546
534
|
}
|
|
547
|
-
return isColor(val);
|
|
548
535
|
};
|
|
549
|
-
|
|
550
|
-
// Splits value into an array.
|
|
551
|
-
// @see https://github.com/asamuzaK/cssColor/blob/main/src/js/util.ts
|
|
552
|
-
exports.splitValue = splitValue;
|