@webstudio-is/css-data 0.66.0 → 0.68.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/cjs/index.js +3 -0
- package/lib/cjs/parse-css-value.js +152 -0
- package/lib/cjs/parse-css.js +125 -0
- package/lib/cjs/property-parsers/background.js +105 -0
- package/lib/cjs/property-parsers/index.js +18 -0
- package/lib/cjs/property-parsers/parsers.js +24 -0
- package/lib/cjs/property-parsers/to-longhand.js +24 -0
- package/lib/index.js +3 -0
- package/lib/parse-css-value.js +122 -0
- package/lib/parse-css.js +95 -0
- package/lib/property-parsers/background.js +75 -0
- package/lib/property-parsers/index.js +1 -0
- package/lib/property-parsers/parsers.js +4 -0
- package/lib/property-parsers/to-longhand.js +4 -0
- package/lib/types/src/index.d.ts +3 -0
- package/lib/types/src/parse-css-value.d.ts +3 -0
- package/lib/types/src/parse-css-value.test.d.ts +1 -0
- package/lib/types/src/parse-css.d.ts +9 -0
- package/lib/types/src/parse-css.test.d.ts +1 -0
- package/lib/types/src/property-parsers/background.d.ts +11 -0
- package/lib/types/src/property-parsers/background.test.d.ts +1 -0
- package/lib/types/src/property-parsers/index.d.ts +1 -0
- package/lib/types/src/property-parsers/parsers.d.ts +1 -0
- package/lib/types/src/property-parsers/to-longhand.d.ts +1 -0
- package/package.json +12 -4
- package/src/index.ts +6 -0
- package/src/parse-css-value.test.ts +136 -0
- package/src/parse-css-value.ts +157 -0
- package/src/parse-css.test.ts +101 -0
- package/src/parse-css.ts +124 -0
- package/src/property-parsers/README.md +11 -0
- package/src/property-parsers/background.test.ts +184 -0
- package/src/property-parsers/background.ts +132 -0
- package/src/property-parsers/index.ts +1 -0
- package/src/property-parsers/parsers.ts +4 -0
- package/src/property-parsers/to-longhand.ts +4 -0
package/src/parse-css.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as csstree from "css-tree";
|
|
2
|
+
import { parseCssValue as parseCssValueLonghand } from "./parse-css-value";
|
|
3
|
+
import * as parsers from "./property-parsers/parsers";
|
|
4
|
+
import * as toLonghand from "./property-parsers/to-longhand";
|
|
5
|
+
import { StyleValue, type Style as S, type StyleProperty } from "./schema";
|
|
6
|
+
|
|
7
|
+
type Selector = string;
|
|
8
|
+
type Style = {
|
|
9
|
+
// @todo add support for states and media queries in addition to declarations
|
|
10
|
+
property: StyleProperty;
|
|
11
|
+
value: StyleValue;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type Styles = Record<Selector, Style[]>;
|
|
15
|
+
|
|
16
|
+
type Longhand = keyof typeof toLonghand;
|
|
17
|
+
|
|
18
|
+
const parseCssValue = function parseCssValue(
|
|
19
|
+
property: Longhand | StyleProperty,
|
|
20
|
+
value: string
|
|
21
|
+
): S {
|
|
22
|
+
const unwrap = toLonghand[property as Longhand];
|
|
23
|
+
|
|
24
|
+
if (typeof unwrap === "function") {
|
|
25
|
+
const longhands = unwrap(value);
|
|
26
|
+
|
|
27
|
+
return Object.fromEntries(
|
|
28
|
+
Object.entries(longhands).map(([property, value]) => {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
30
|
+
// @ts-ignore @todo remove this ignore: property is a `keyof typeof longhands` which is a key in parsers but TS can't infer the link
|
|
31
|
+
const valueParser = parsers[property];
|
|
32
|
+
|
|
33
|
+
if (typeof valueParser === "function") {
|
|
34
|
+
return [property, valueParser(value)];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
return [
|
|
39
|
+
property,
|
|
40
|
+
{
|
|
41
|
+
type: "invalid",
|
|
42
|
+
value: value.join(""),
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!value) {
|
|
48
|
+
return [property, { type: "invalid", value: "" }];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return [
|
|
52
|
+
property,
|
|
53
|
+
parseCssValueLonghand(property as StyleProperty, value),
|
|
54
|
+
];
|
|
55
|
+
})
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
[property]: parseCssValueLonghand(property as StyleProperty, value),
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const parseCss = function cssToWS(css: string) {
|
|
65
|
+
const ast = csstree.parse(css);
|
|
66
|
+
|
|
67
|
+
let selectors: Selector[] = [];
|
|
68
|
+
const styles: Styles = {};
|
|
69
|
+
|
|
70
|
+
csstree.walk(ast, (node, item) => {
|
|
71
|
+
if (node.type === "SelectorList") {
|
|
72
|
+
selectors = [];
|
|
73
|
+
}
|
|
74
|
+
if (node.type === "ClassSelector") {
|
|
75
|
+
if (!item.prev && !item.next) {
|
|
76
|
+
selectors.push(node.name);
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (node.type === "Declaration") {
|
|
82
|
+
const stringValue = csstree.generate(node.value);
|
|
83
|
+
|
|
84
|
+
const parsedCss = parseCssValue(
|
|
85
|
+
node.property as Longhand | StyleProperty,
|
|
86
|
+
stringValue
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
(Object.entries(parsedCss) as [StyleProperty, StyleValue][]).forEach(
|
|
90
|
+
([property, value]) => {
|
|
91
|
+
try {
|
|
92
|
+
StyleValue.parse(value);
|
|
93
|
+
selectors.forEach((selector) => {
|
|
94
|
+
if (Array.isArray(styles[selector])) {
|
|
95
|
+
styles[selector].push({
|
|
96
|
+
property,
|
|
97
|
+
value,
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
styles[selector] = [{ property, value }];
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (process.env.NODE_ENV !== "production") {
|
|
105
|
+
// eslint-disable-next-line no-console
|
|
106
|
+
console.warn(
|
|
107
|
+
true,
|
|
108
|
+
`Declaration parsing for \`${selectors.join(", ")}.${
|
|
109
|
+
node.property
|
|
110
|
+
}: ${stringValue}\` failed:\n\n${JSON.stringify(
|
|
111
|
+
parsedCss,
|
|
112
|
+
null,
|
|
113
|
+
2
|
|
114
|
+
)}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return styles;
|
|
124
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Properties Parsers
|
|
2
|
+
|
|
3
|
+
This folder contains:
|
|
4
|
+
|
|
5
|
+
- `parsers.ts` individual properties parses
|
|
6
|
+
- `to-longhand.ts` shorthand forms unwrappers
|
|
7
|
+
|
|
8
|
+
The idea is that these two modules export a number of utilities whose name match the property that they parse or unwrap e.g.:
|
|
9
|
+
|
|
10
|
+
- `backgroundImage` is a property parser
|
|
11
|
+
- `background` is a "to-longhand" unwrapper
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
|
|
3
|
+
import { parseBackground } from "./background";
|
|
4
|
+
|
|
5
|
+
describe("parseBackground", () => {
|
|
6
|
+
test("parse background from figma", () => {
|
|
7
|
+
expect(
|
|
8
|
+
parseBackground(
|
|
9
|
+
"linear-gradient(180deg, #11181C 0%, rgba(17, 24, 28, 0) 36.09%), none, linear-gradient(180deg, rgba(230, 60, 254, 0.33) 0%, rgba(255, 174, 60, 0) 100%), radial-gradient(54.1% 95.83% at 100% 100%, #FFFFFF 0%, rgba(255, 255, 255, 0) 100%), linear-gradient(122.33deg, rgba(74, 78, 250, 0.2) 0%, rgba(0, 0, 0, 0) 69.38%), radial-gradient(92.26% 201.29% at 98.6% 10.65%, rgba(255, 174, 60, 0.3) 0%, rgba(227, 53, 255, 0) 100%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */, radial-gradient(84.64% 267.51% at 10.07% 81.45%, rgba(53, 255, 182, 0.2) 0%, rgba(74, 78, 250, 0.2) 100%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */, #EBFFFC;"
|
|
10
|
+
)
|
|
11
|
+
).toMatchInlineSnapshot(`
|
|
12
|
+
{
|
|
13
|
+
"backgroundColor": {
|
|
14
|
+
"alpha": 1,
|
|
15
|
+
"b": 252,
|
|
16
|
+
"g": 255,
|
|
17
|
+
"r": 235,
|
|
18
|
+
"type": "rgb",
|
|
19
|
+
},
|
|
20
|
+
"backgroundImage": {
|
|
21
|
+
"type": "layers",
|
|
22
|
+
"value": [
|
|
23
|
+
{
|
|
24
|
+
"type": "unparsed",
|
|
25
|
+
"value": "linear-gradient(180deg,#11181C 0%,rgba(17,24,28,0) 36.09%)",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "unparsed",
|
|
29
|
+
"value": "linear-gradient(180deg,rgba(230,60,254,0.33) 0%,rgba(255,174,60,0) 100%)",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "unparsed",
|
|
33
|
+
"value": "radial-gradient(54.1% 95.83%at 100% 100%,#FFFFFF 0%,rgba(255,255,255,0) 100%)",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "unparsed",
|
|
37
|
+
"value": "linear-gradient(122.33deg,rgba(74,78,250,0.2) 0%,rgba(0,0,0,0) 69.38%)",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "unparsed",
|
|
41
|
+
"value": "radial-gradient(92.26% 201.29%at 98.6% 10.65%,rgba(255,174,60,0.3) 0%,rgba(227,53,255,0) 100%)",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"type": "unparsed",
|
|
45
|
+
"value": "radial-gradient(84.64% 267.51%at 10.07% 81.45%,rgba(53,255,182,0.2) 0%,rgba(74,78,250,0.2) 100%)",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("parse background from figma without backgroundColor", () => {
|
|
54
|
+
expect(
|
|
55
|
+
parseBackground(
|
|
56
|
+
"linear-gradient(180deg, #11181C 0%, rgba(17, 24, 28, 0) 36.09%), linear-gradient(180deg, rgba(230, 60, 254, 0.33) 0%, rgba(255, 174, 60, 0) 100%), radial-gradient(54.1% 95.83% at 100% 100%, #FFFFFF 0%, rgba(255, 255, 255, 0) 100%), linear-gradient(122.33deg, rgba(74, 78, 250, 0.2) 0%, rgba(0, 0, 0, 0) 69.38%), radial-gradient(92.26% 201.29% at 98.6% 10.65%, rgba(255, 174, 60, 0.3) 0%, rgba(227, 53, 255, 0) 100%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */, radial-gradient(84.64% 267.51% at 10.07% 81.45%, rgba(53, 255, 182, 0.2) 0%, rgba(74, 78, 250, 0.2) 100%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */"
|
|
57
|
+
)
|
|
58
|
+
).toMatchInlineSnapshot(`
|
|
59
|
+
{
|
|
60
|
+
"backgroundColor": undefined,
|
|
61
|
+
"backgroundImage": {
|
|
62
|
+
"type": "layers",
|
|
63
|
+
"value": [
|
|
64
|
+
{
|
|
65
|
+
"type": "unparsed",
|
|
66
|
+
"value": "linear-gradient(180deg,#11181C 0%,rgba(17,24,28,0) 36.09%)",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "unparsed",
|
|
70
|
+
"value": "linear-gradient(180deg,rgba(230,60,254,0.33) 0%,rgba(255,174,60,0) 100%)",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"type": "unparsed",
|
|
74
|
+
"value": "radial-gradient(54.1% 95.83%at 100% 100%,#FFFFFF 0%,rgba(255,255,255,0) 100%)",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "unparsed",
|
|
78
|
+
"value": "linear-gradient(122.33deg,rgba(74,78,250,0.2) 0%,rgba(0,0,0,0) 69.38%)",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "unparsed",
|
|
82
|
+
"value": "radial-gradient(92.26% 201.29%at 98.6% 10.65%,rgba(255,174,60,0.3) 0%,rgba(227,53,255,0) 100%)",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": "unparsed",
|
|
86
|
+
"value": "radial-gradient(84.64% 267.51%at 10.07% 81.45%,rgba(53,255,182,0.2) 0%,rgba(74,78,250,0.2) 100%)",
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
`);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("parse background and skips url background", () => {
|
|
95
|
+
expect(
|
|
96
|
+
parseBackground(
|
|
97
|
+
"url(https://hello.world/some-image), linear-gradient(180deg, rgba(230, 60, 254, 0.33) 0%, rgba(255, 174, 60, 0) 100%), radial-gradient(54.1% 95.83% at 100% 100%, #FFFFFF 0%, rgba(255, 255, 255, 0) 100%), linear-gradient(122.33deg, rgba(74, 78, 250, 0.2) 0%, rgba(0, 0, 0, 0) 69.38%), radial-gradient(92.26% 201.29% at 98.6% 10.65%, rgba(255, 174, 60, 0.3) 0%, rgba(227, 53, 255, 0) 100%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */, radial-gradient(84.64% 267.51% at 10.07% 81.45%, rgba(53, 255, 182, 0.2) 0%, rgba(74, 78, 250, 0.2) 100%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */"
|
|
98
|
+
)
|
|
99
|
+
).toMatchInlineSnapshot(`
|
|
100
|
+
{
|
|
101
|
+
"backgroundColor": undefined,
|
|
102
|
+
"backgroundImage": {
|
|
103
|
+
"type": "layers",
|
|
104
|
+
"value": [
|
|
105
|
+
{
|
|
106
|
+
"type": "unparsed",
|
|
107
|
+
"value": "linear-gradient(180deg,rgba(230,60,254,0.33) 0%,rgba(255,174,60,0) 100%)",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "unparsed",
|
|
111
|
+
"value": "radial-gradient(54.1% 95.83%at 100% 100%,#FFFFFF 0%,rgba(255,255,255,0) 100%)",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"type": "unparsed",
|
|
115
|
+
"value": "linear-gradient(122.33deg,rgba(74,78,250,0.2) 0%,rgba(0,0,0,0) 69.38%)",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"type": "unparsed",
|
|
119
|
+
"value": "radial-gradient(92.26% 201.29%at 98.6% 10.65%,rgba(255,174,60,0.3) 0%,rgba(227,53,255,0) 100%)",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "unparsed",
|
|
123
|
+
"value": "radial-gradient(84.64% 267.51%at 10.07% 81.45%,rgba(53,255,182,0.2) 0%,rgba(74,78,250,0.2) 100%)",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
`);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("parse background partially copied background", () => {
|
|
132
|
+
expect(
|
|
133
|
+
parseBackground(
|
|
134
|
+
"linear-gradient(180deg, #11181C 0%, rgba(17, 24, 28, 0) 36.09%), linear-gradient(180deg, "
|
|
135
|
+
)
|
|
136
|
+
).toMatchInlineSnapshot(`
|
|
137
|
+
{
|
|
138
|
+
"backgroundColor": undefined,
|
|
139
|
+
"backgroundImage": {
|
|
140
|
+
"type": "layers",
|
|
141
|
+
"value": [
|
|
142
|
+
{
|
|
143
|
+
"type": "unparsed",
|
|
144
|
+
"value": "linear-gradient(180deg,#11181C 0%,rgba(17,24,28,0) 36.09%)",
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
`);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("parse background partially commented", () => {
|
|
153
|
+
expect(
|
|
154
|
+
parseBackground(
|
|
155
|
+
"linear-gradient(180deg, rgba(230, 60, 254, 0.33) 0%, rgba(255, 174, 60, 0) 100%), /* radial-gradient(54.1% 95.83% at 100% 100%, #FFFFFF 0%, rgba(255, 255, 255, 0) 100%) */"
|
|
156
|
+
)
|
|
157
|
+
).toMatchInlineSnapshot(`
|
|
158
|
+
{
|
|
159
|
+
"backgroundColor": undefined,
|
|
160
|
+
"backgroundImage": {
|
|
161
|
+
"type": "layers",
|
|
162
|
+
"value": [
|
|
163
|
+
{
|
|
164
|
+
"type": "unparsed",
|
|
165
|
+
"value": "linear-gradient(180deg,rgba(230,60,254,0.33) 0%,rgba(255,174,60,0) 100%)",
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
`);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("parse bad background", () => {
|
|
174
|
+
expect(parseBackground("linear-gradient(180deg,")).toMatchInlineSnapshot(`
|
|
175
|
+
{
|
|
176
|
+
"backgroundColor": undefined,
|
|
177
|
+
"backgroundImage": {
|
|
178
|
+
"type": "invalid",
|
|
179
|
+
"value": "linear-gradient(180deg,)",
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
`);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as csstree from "css-tree";
|
|
2
|
+
import { parseCssValue } from "../parse-css-value";
|
|
3
|
+
import type {
|
|
4
|
+
InvalidValue,
|
|
5
|
+
LayersValue,
|
|
6
|
+
RgbValue,
|
|
7
|
+
UnparsedValue,
|
|
8
|
+
} from "../schema";
|
|
9
|
+
|
|
10
|
+
export const gradientNames = [
|
|
11
|
+
"conic-gradient",
|
|
12
|
+
"linear-gradient",
|
|
13
|
+
"radial-gradient",
|
|
14
|
+
"repeating-conic-gradient",
|
|
15
|
+
"repeating-linear-gradient",
|
|
16
|
+
"repeating-radial-gradient",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const parseBackground = (
|
|
20
|
+
background: string
|
|
21
|
+
): {
|
|
22
|
+
backgroundImage: LayersValue | InvalidValue;
|
|
23
|
+
backgroundColor: RgbValue | undefined;
|
|
24
|
+
} => {
|
|
25
|
+
const { backgroundImage, backgroundColor: backgroundColorRaw } =
|
|
26
|
+
backgroundToLonghand(background);
|
|
27
|
+
|
|
28
|
+
const backgroundColor = backgroundColorRaw
|
|
29
|
+
? (parseCssValue("backgroundColor", backgroundColorRaw) as RgbValue)
|
|
30
|
+
: undefined;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
backgroundImage: parseBackgroundImage(backgroundImage),
|
|
34
|
+
backgroundColor:
|
|
35
|
+
backgroundColor && backgroundColor.type === "rgb"
|
|
36
|
+
? backgroundColor
|
|
37
|
+
: undefined,
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const backgroundToLonghand = (
|
|
42
|
+
background: string
|
|
43
|
+
): {
|
|
44
|
+
backgroundImage: string[];
|
|
45
|
+
backgroundColor: string | undefined;
|
|
46
|
+
} => {
|
|
47
|
+
const layers: string[] = [];
|
|
48
|
+
|
|
49
|
+
let tokenStream = background.trim();
|
|
50
|
+
|
|
51
|
+
tokenStream = tokenStream.endsWith(";")
|
|
52
|
+
? tokenStream.slice(0, -1)
|
|
53
|
+
: tokenStream;
|
|
54
|
+
|
|
55
|
+
// The user can copy the whole style together with the name of the property from figma or any other tool.
|
|
56
|
+
// We need to remove the property name from the string.
|
|
57
|
+
const cleanupKeywords = ["background:", "background-image:"];
|
|
58
|
+
|
|
59
|
+
for (const cleanupKeyword of cleanupKeywords) {
|
|
60
|
+
tokenStream = tokenStream.startsWith(cleanupKeyword)
|
|
61
|
+
? tokenStream.slice(cleanupKeyword.length).trim()
|
|
62
|
+
: tokenStream;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const cssAst = csstree.parse(tokenStream, { context: "value" });
|
|
66
|
+
|
|
67
|
+
let backgroundColorRaw: string | undefined;
|
|
68
|
+
|
|
69
|
+
let nestingLevel = 0;
|
|
70
|
+
|
|
71
|
+
csstree.walk(cssAst, {
|
|
72
|
+
enter: (node, item, list) => {
|
|
73
|
+
if (node.type === "Function") {
|
|
74
|
+
if (gradientNames.includes(node.name)) {
|
|
75
|
+
layers.push(csstree.generate(node));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// If the depth is at level 0 and the next item is null, it's likely that the backgroundColor
|
|
79
|
+
// is written as rgba(x,y,z,a) or similar format.
|
|
80
|
+
// nestingLevel is used as a fast way to check existance of parent Function node
|
|
81
|
+
if (item.next === null && nestingLevel === 0) {
|
|
82
|
+
backgroundColorRaw = csstree.generate(node);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
nestingLevel++;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (node.type === "Hash" && item.next === null && nestingLevel === 0) {
|
|
89
|
+
// If the depth is at level 0 and the next item is null, it's likely that the backgroundColor
|
|
90
|
+
// is written as hex #XYZFGH
|
|
91
|
+
backgroundColorRaw = csstree.generate(node);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
leave: (node, item, list) => {
|
|
95
|
+
if (node.type === "Function") {
|
|
96
|
+
nestingLevel--;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
backgroundImage: layers,
|
|
103
|
+
backgroundColor: backgroundColorRaw,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const parseBackgroundImage = (
|
|
108
|
+
layers: string[]
|
|
109
|
+
): LayersValue | InvalidValue => {
|
|
110
|
+
const backgroundImages: UnparsedValue[] = [];
|
|
111
|
+
|
|
112
|
+
for (const layer of layers) {
|
|
113
|
+
if (
|
|
114
|
+
gradientNames.some((gradientName) => layer.startsWith(gradientName)) ===
|
|
115
|
+
false
|
|
116
|
+
) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const layerStyle = parseCssValue("backgroundImage", layer);
|
|
121
|
+
|
|
122
|
+
if (layerStyle.type !== "unparsed") {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
backgroundImages.push(layerStyle);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return backgroundImages.length > 0
|
|
130
|
+
? { type: "layers", value: backgroundImages }
|
|
131
|
+
: { type: "invalid", value: layers.join(",") };
|
|
132
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./background";
|