OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * @constructor | |
7 */ | |
8 WebInspector.SCSSParser = function() | |
9 { | |
10 } | |
11 | |
12 /** | |
13 * @constructor | |
14 */ | |
15 WebInspector.SCSSParser.Result = function() | |
16 { | |
17 this.properties = []; | |
18 this.variables = []; | |
19 this.mixins = []; | |
20 } | |
21 | |
22 WebInspector.SCSSParser.prototype = { | |
23 /** | |
24 * @param {string} content | |
25 * @return {!Promise<!WebInspector.SCSSParser.Result>} | |
26 */ | |
27 parse: function(content) | |
28 { | |
29 this._content = content; | |
dgozman
2016/04/29 01:16:17
Stateless!
lushnikov
2016/04/29 01:55:41
Done.
| |
30 return self.runtime.loadModulePromise("gonzales") | |
dgozman
2016/04/29 01:16:17
Let's put this file into gonzales module and have
lushnikov
2016/04/29 01:55:42
Done.
| |
31 .then(this._innerParse.bind(this, content)) | |
32 .catch(onError) | |
33 | |
34 /** | |
35 * @param {*} error | |
36 */ | |
37 function onError(error) | |
38 { | |
39 console.error(error); | |
40 return new WebInspector.SCSSParser.Result(); | |
41 } | |
42 }, | |
43 | |
44 /** | |
45 * @param {string} content | |
46 * @return {!WebInspector.SCSSParser.Result} | |
47 */ | |
48 _innerParse: function(content) | |
49 { | |
50 var result = new WebInspector.SCSSParser.Result(); | |
51 var ast = null; | |
52 try { | |
53 ast = gonzales.parse(content, {syntax: "scss"}); | |
54 } catch (e) { | |
55 return result; | |
56 } | |
57 | |
58 var extractedNodes = []; | |
59 WebInspector.SCSSParser.extractNodes(ast, extractedNodes); | |
60 | |
61 for (var node of extractedNodes) { | |
62 if (node.type === "declaration") | |
63 this._handleDeclaration(node, result); | |
64 else if (node.type === "include") | |
65 this._handleInclude(node, result); | |
66 else if (node.type === "multilineComment" && node.start.line === nod e.end.line) | |
67 this._handleComment(node, result); | |
68 } | |
69 return result; | |
70 }, | |
71 | |
72 /** | |
73 * @param {!Gonzales.Node} node | |
74 * @param {!WebInspector.SCSSParser.Result} result | |
75 */ | |
76 _handleDeclaration: function(node, result) | |
77 { | |
78 var propertyNode = node.content.find(node => node.type === "property"); | |
79 var delimeterNode = node.content.find(node => node.type === "propertyDel imiter"); | |
80 var valueNode = node.content.find(node => node.type === "value"); | |
81 if (!propertyNode || !delimeterNode || !valueNode) | |
82 return; | |
83 | |
84 var nameRange = new WebInspector.TextRange(propertyNode.start.line - 1, propertyNode.start.column - 1, delimeterNode.start.line - 1, delimeterNode.start .column - 1); | |
85 var valueRange = new WebInspector.TextRange(delimeterNode.end.line - 1, delimeterNode.end.column, valueNode.end.line - 1, valueNode.end.column); | |
86 var range = /** @type {!WebInspector.TextRange} */(node.declarationRange ); | |
87 | |
88 var property = new WebInspector.SCSSParser.Property(range, nameRange, va lueRange, false); | |
89 var isVariable = !!propertyNode.content.find(node => node.type === "vari able"); | |
90 if (isVariable) | |
91 result.variables.push(property); | |
92 else | |
93 result.properties.push(property); | |
94 }, | |
95 | |
96 /** | |
97 * @param {!Gonzales.Node} node | |
98 * @param {!WebInspector.SCSSParser.Result} result | |
99 */ | |
100 _handleInclude: function(node, result) | |
101 { | |
102 var mixinName = node.content.find(node => node.type === "ident"); | |
103 if (!mixinName) | |
104 return; | |
105 var nameRange = WebInspector.SCSSParser.rangeFromNode(mixinName); | |
106 var mixinArguments = node.content.find(node => node.type === "arguments" ); | |
107 if (!mixinArguments) | |
108 return; | |
109 var parameters = mixinArguments.content.filter(node => node.type !== "de limiter" && node.type !== "space"); | |
dgozman
2016/04/29 01:16:17
Can we whitelist them?
lushnikov
2016/04/29 01:55:41
There are multiple different nodes: "15px" would b
| |
110 for (var parameter of parameters) { | |
111 var range = WebInspector.SCSSParser.rangeFromNode(node); | |
112 var valueRange = WebInspector.SCSSParser.rangeFromNode(parameter); | |
113 var property = new WebInspector.SCSSParser.Property(range, nameRange , valueRange, false); | |
114 result.mixins.push(property); | |
115 } | |
116 }, | |
117 | |
118 /** | |
119 * @param {!Gonzales.Node} node | |
120 * @param {!WebInspector.SCSSParser.Result} result | |
121 */ | |
122 _handleComment: function(node, result) | |
123 { | |
124 if (node.start.line !== node.end.line) | |
125 return; | |
126 var innerText = /** @type {string} */(node.content); | |
127 var innerResult = this._innerParse(innerText); | |
128 if (innerResult.properties.length !== 1 || innerResult.variables.length !== 0 || innerResult.mixins.length !== 0) | |
129 return; | |
130 var property = innerResult.properties[0]; | |
131 var disabledProperty = property.rebaseInsideOneLineComment(node); | |
132 result.properties.push(disabledProperty); | |
133 }, | |
134 } | |
135 | |
136 /** | |
137 * @param {!Gonzales.Node} node | |
138 * @return {!WebInspector.TextRange} | |
139 */ | |
140 WebInspector.SCSSParser.rangeFromNode = function(node) | |
141 { | |
142 return new WebInspector.TextRange(node.start.line - 1, node.start.column - 1 , node.end.line - 1, node.end.column); | |
143 } | |
144 | |
145 /** | |
146 * @constructor | |
147 * @param {!WebInspector.TextRange} range | |
148 * @param {!WebInspector.TextRange} nameRange | |
149 * @param {!WebInspector.TextRange} valueRange | |
150 * @param {boolean} disabled | |
151 */ | |
152 WebInspector.SCSSParser.Property = function(range, nameRange, valueRange, disabl ed) | |
153 { | |
154 this.range = range; | |
155 this.name = nameRange; | |
156 this.value = valueRange; | |
157 this.disabled = disabled; | |
158 } | |
159 | |
160 WebInspector.SCSSParser.Property.prototype = { | |
161 /** | |
162 * @param {!Gonzales.Node} commentNode | |
163 * @return {!WebInspector.SCSSParser.Property} | |
164 */ | |
165 rebaseInsideOneLineComment: function(commentNode) | |
166 { | |
167 var lineOffset = commentNode.start.line - 1; | |
168 var columnOffset = commentNode.start.column - 1 + 2; | |
dgozman
2016/04/29 01:16:17
// account 2 for "/*"
lushnikov
2016/04/29 01:55:41
Done.
| |
169 var range = WebInspector.SCSSParser.rangeFromNode(commentNode); | |
170 var name = rebaseRange(this.name, lineOffset, columnOffset); | |
171 var value = rebaseRange(this.value, lineOffset, columnOffset); | |
172 return new WebInspector.SCSSParser.Property(range, name, value, true); | |
173 | |
174 /** | |
175 * @param {!WebInspector.TextRange} range | |
176 * @param {number} lineOffset | |
177 * @param {number} columnOffset | |
178 * @return {!WebInspector.TextRange} | |
179 */ | |
180 function rebaseRange(range, lineOffset, columnOffset) | |
181 { | |
182 return new WebInspector.TextRange(range.startLine + lineOffset, rang e.startColumn + columnOffset, range.endLine + lineOffset, range.endColumn + colu mnOffset); | |
183 } | |
184 } | |
185 } | |
186 | |
187 /** | |
188 * @param {!Gonzales.Node} node | |
189 * @param {!Array<!Gonzales.Node>} output | |
190 */ | |
191 WebInspector.SCSSParser.extractNodes = function(node, output) | |
192 { | |
193 if (!Array.isArray(node.content)) | |
194 return; | |
195 var lastDeclaration = null; | |
196 for (var i = 0; i < node.content.length; ++i) { | |
197 var child = node.content[i]; | |
198 if (child.type === "declarationDelimiter" && lastDeclaration) { | |
199 lastDeclaration.declarationRange.endLine = child.end.line - 1; | |
200 lastDeclaration.declarationRange.endColumn = child.end.column; | |
201 lastDeclaration = null; | |
202 } | |
203 if (child.type === "include" || child.type === "declaration" || child.ty pe === "multilineComment") | |
204 output.push(child); | |
205 if (child.type === "declaration") { | |
206 lastDeclaration = child; | |
207 lastDeclaration.declarationRange = WebInspector.TextRange.createFrom Location(child.start.line - 1, child.start.column - 1); | |
208 } | |
209 WebInspector.SCSSParser.extractNodes(child, output); | |
210 } | |
211 if (lastDeclaration) { | |
212 lastDeclaration.declarationRange.endLine = node.end.line - 1; | |
213 lastDeclaration.declarationRange.endColumn = node.end.column - 1; | |
214 } | |
215 } | |
216 | |
217 /** | |
218 * @param {string} text | |
219 */ | |
220 WebInspector.SCSSParser.parse = function(text) | |
221 { | |
222 var parser = new WebInspector.SCSSParser(); | |
223 parser.parse(text).then(postMessage); | |
224 } | |
225 | |
OLD | NEW |