Skip to content

Commit 680b6b6

Browse files
committed
feat(css): Added optional css-tree parser
1 parent d0d4d81 commit 680b6b6

File tree

4 files changed

+137
-4
lines changed

4 files changed

+137
-4
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import {
2+
parse
3+
} from "css-tree";
4+
5+
function mapSelectors(selector: string): string[] {
6+
if (!selector) {
7+
return [];
8+
}
9+
10+
return selector.split(/\s*(?![^(]*\)),\s*/).map(s => s.replace(/\u200C/g, ","));
11+
}
12+
13+
function mapPosition(node) {
14+
return {
15+
start: {
16+
line: node.loc.start.line,
17+
column: node.loc.start.column
18+
},
19+
end: {
20+
line: node.loc.end.line,
21+
column: node.loc.end.column
22+
}
23+
};
24+
}
25+
26+
function transformAst(node) {
27+
if (!node) {
28+
return;
29+
}
30+
31+
if (node.type === "StyleSheet") {
32+
return {
33+
type: "stylesheet",
34+
stylesheet: {
35+
source: node.loc.source,
36+
rules: node.children.toArray().map(child => transformAst(child)),
37+
parsingErrors: []
38+
}
39+
};
40+
}
41+
42+
if (node.type === "Atrule") {
43+
let atrule: any = {
44+
type: node.name,
45+
};
46+
47+
if (node.name === "supports" || node.name === "media") {
48+
atrule[node.name] = node.prelude.value;
49+
atrule.rules = transformAst(node.block);
50+
} else if (node.name === "page") {
51+
atrule.selectors = node.prelude ? mapSelectors(node.prelude.value) : [];
52+
atrule.declarations = transformAst(node.block);
53+
} else if (node.name === "document") {
54+
atrule.document = node.prelude ? node.prelude.value : "";
55+
atrule.vendor = "";
56+
atrule.rules = transformAst(node.block);
57+
} else if (node.name === "font-face") {
58+
atrule.declarations = transformAst(node.block);
59+
} else if (node.name === "import" || node.name === "charset" || node.name === "namespace") {
60+
atrule[node.name] = node.prelude ? node.prelude.value : "";
61+
} else {
62+
atrule.rules = transformAst(node.block);
63+
}
64+
65+
return atrule;
66+
}
67+
68+
if (node.type === "Block") {
69+
return node.children.toArray().map(child => transformAst(child));
70+
}
71+
72+
if (node.type === "Rule") {
73+
let value = node.prelude.value;
74+
75+
return {
76+
type: "rule",
77+
selectors: mapSelectors(value),
78+
declarations: transformAst(node.block),
79+
position: mapPosition(node)
80+
};
81+
}
82+
83+
if (node.type === "Comment") {
84+
return {
85+
type: "comment",
86+
comment: node.value,
87+
position: mapPosition(node)
88+
};
89+
}
90+
91+
if (node.type === "Declaration") {
92+
return {
93+
type: "declaration",
94+
property: node.property,
95+
value: node.value.value,
96+
position: mapPosition(node)
97+
};
98+
}
99+
100+
throw Error(`Unknown node type ${node.type}`);
101+
}
102+
103+
export function cssTreeParse(css, source): any {
104+
let errors = [];
105+
let ast = parse(css, {
106+
parseValue: false,
107+
parseAtrulePrelude: false,
108+
parseRulePrelude: false,
109+
positions: true,
110+
filename: source,
111+
onParseError: error => {
112+
errors.push(`${source}:${error.line}:${error.column}: ${error.formattedMessage}`);
113+
}
114+
});
115+
116+
if (errors.length > 0) {
117+
throw new Error(errors[0]);
118+
}
119+
120+
return transformAst(ast);
121+
}

nativescript-core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"dependencies": {
2121
"nativescript-hook": "0.2.5",
2222
"reduce-css-calc": "^2.1.6",
23+
"css-tree": "^1.0.0-alpha.37",
2324
"semver": "6.3.0",
2425
"tns-core-modules-widgets": "next",
2526
"tslib": "1.10.0"

nativescript-core/ui/styling/style-scope.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import {
1212
CSS3Parser,
1313
CSSNativeScript
1414
} from "../../css/parser";
15+
import {
16+
cssTreeParse
17+
} from "../../css/css-tree-parser";
1518

1619
import {
1720
RuleSet,
@@ -50,11 +53,15 @@ function ensureCssAnimationParserModule() {
5053
}
5154
}
5255

53-
let parser: "rework" | "nativescript" = "rework";
56+
let parser: "rework" | "nativescript" | "css-tree" = "rework";
5457
try {
5558
const appConfig = require("~/package.json");
56-
if (appConfig && appConfig.cssParser === "nativescript") {
57-
parser = "nativescript";
59+
if (appConfig) {
60+
if (appConfig.cssParser === "css-tree") {
61+
parser = "css-tree";
62+
} else if (appConfig.cssParser === "nativescript") {
63+
parser = "nativescript";
64+
}
5865
}
5966
} catch (e) {
6067
//
@@ -220,6 +227,10 @@ class CSSSource {
220227
private parseCSSAst() {
221228
if (this._source) {
222229
switch (parser) {
230+
case "css-tree":
231+
this._ast = cssTreeParse(this._source, this._file);
232+
233+
return;
223234
case "nativescript":
224235
const cssparser = new CSS3Parser(this._source);
225236
const stylesheet = cssparser.parseAStylesheet();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@types/node": "~10.12.18",
1616
"chai": "^4.1.2",
1717
"css": "^2.2.1",
18-
"css-tree": "^1.0.0-alpha24",
18+
"css-tree": "^1.0.0-alpha.37",
1919
"gonzales": "^1.0.7",
2020
"madge": "^2.2.0",
2121
"markdown-snippet-injector": "0.2.2",

0 commit comments

Comments
 (0)