Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/gonzales/SCSSParser.js

Issue 1938313002: DevTools: [SASS] parse SCSS rules and their selectors. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @constructor 6 * @constructor
7 * @implements {WebInspector.FormatterWorkerContentParser} 7 * @implements {WebInspector.FormatterWorkerContentParser}
8 */ 8 */
9 WebInspector.SCSSParser = function() 9 WebInspector.SCSSParser = function()
10 { 10 {
11 } 11 }
12 12
13 /**
14 * @constructor
15 */
16 WebInspector.SCSSParser.Result = function()
17 {
18 this.properties = [];
19 this.variables = [];
20 this.mixins = [];
21 }
22
23 WebInspector.SCSSParser.prototype = { 13 WebInspector.SCSSParser.prototype = {
24 /** 14 /**
25 * @override 15 * @override
26 * @param {string} content 16 * @param {string} content
27 * @return {!WebInspector.SCSSParser.Result} 17 * @return {!Array<!WebInspector.SCSSParser.Rule>}
28 */ 18 */
29 parse: function(content) 19 parse: function(content)
30 { 20 {
31 var result = new WebInspector.SCSSParser.Result();
32 var ast = null; 21 var ast = null;
33 try { 22 try {
34 ast = gonzales.parse(content, {syntax: "scss"}); 23 ast = gonzales.parse(content, {syntax: "scss"});
35 } catch (e) { 24 } catch (e) {
36 return result; 25 return [];
37 } 26 }
38 27
39 var extractedNodes = []; 28 var rootBlock = {
pfeldman 2016/05/03 17:55:46 Please annotate.
lushnikov 2016/05/03 20:51:23 Done.
40 WebInspector.SCSSParser.extractNodes(ast, extractedNodes); 29 properties: [],
30 node: ast
31 };
32 var blocks = [rootBlock];
pfeldman 2016/05/03 17:55:46 ditto
lushnikov 2016/05/03 20:51:23 Done.
33 ast.selectors = [];
34 WebInspector.SCSSParser.extractNodes(ast, blocks, rootBlock);
41 35
42 for (var node of extractedNodes) { 36 var rules = [];
37 for (var block of blocks)
38 this._handleBlock(block, rules);
39 return rules;
40 },
41
42 /**
43 * @param {!{node: !Gonzales.Node, properties: !Array<!Gonzales.Node>}} bloc k
44 * @param {!Array<!WebInspector.SCSSParser.Rule>} output
45 */
46 _handleBlock: function(block, output)
47 {
48 var selectors = block.node.selectors.map(WebInspector.SCSSParser.rangeFr omNode);
49 var properties = [];
50 var styleRange = WebInspector.SCSSParser.rangeFromNode(block.node);
51 styleRange.startColumn += 1;
52 styleRange.endColumn -= 1;
53 for (var node of block.properties) {
43 if (node.type === "declaration") 54 if (node.type === "declaration")
44 this._handleDeclaration(node, result); 55 this._handleDeclaration(node, properties);
45 else if (node.type === "include") 56 else if (node.type === "include")
46 this._handleInclude(node, result); 57 this._handleInclude(node, properties);
47 else if (node.type === "multilineComment" && node.start.line === nod e.end.line) 58 else if (node.type === "multilineComment" && node.start.line === nod e.end.line)
48 this._handleComment(node, result); 59 this._handleComment(node, properties);
49 } 60 }
50 return result; 61 if (!selectors.length && !properties.length)
62 return;
63 var rule = new WebInspector.SCSSParser.Rule(selectors, properties, style Range);
64 output.push(rule);
51 }, 65 },
52 66
53 /** 67 /**
54 * @param {!Gonzales.Node} node 68 * @param {!Gonzales.Node} node
55 * @param {!WebInspector.SCSSParser.Result} result 69 * @param {!Array<!WebInspector.SCSSParser.Property>} output
56 */ 70 */
57 _handleDeclaration: function(node, result) 71 _handleDeclaration: function(node, output)
58 { 72 {
59 var propertyNode = node.content.find(node => node.type === "property"); 73 var propertyNode = node.content.find(node => node.type === "property");
60 var delimeterNode = node.content.find(node => node.type === "propertyDel imiter"); 74 var delimeterNode = node.content.find(node => node.type === "propertyDel imiter");
61 var valueNode = node.content.find(node => node.type === "value"); 75 var valueNode = node.content.find(node => node.type === "value");
62 if (!propertyNode || !delimeterNode || !valueNode) 76 if (!propertyNode || !delimeterNode || !valueNode)
63 return; 77 return;
64 78
65 var nameRange = new WebInspector.TextRange(propertyNode.start.line - 1, propertyNode.start.column - 1, delimeterNode.start.line - 1, delimeterNode.start .column - 1); 79 var nameRange = new WebInspector.TextRange(propertyNode.start.line - 1, propertyNode.start.column - 1, delimeterNode.start.line - 1, delimeterNode.start .column - 1);
66 var valueRange = new WebInspector.TextRange(delimeterNode.end.line - 1, delimeterNode.end.column, valueNode.end.line - 1, valueNode.end.column); 80 var valueRange = new WebInspector.TextRange(delimeterNode.end.line - 1, delimeterNode.end.column, valueNode.end.line - 1, valueNode.end.column);
67 var range = /** @type {!WebInspector.TextRange} */(node.declarationRange ); 81 var range = /** @type {!WebInspector.TextRange} */(node.declarationRange );
68 82
69 var property = new WebInspector.SCSSParser.Property(range, nameRange, va lueRange, false); 83 var property = new WebInspector.SCSSParser.Property(range, nameRange, va lueRange, false);
70 var isVariable = !!propertyNode.content.find(node => node.type === "vari able"); 84 output.push(property);
71 if (isVariable)
72 result.variables.push(property);
73 else
74 result.properties.push(property);
75 }, 85 },
76 86
77 /** 87 /**
78 * @param {!Gonzales.Node} node 88 * @param {!Gonzales.Node} node
79 * @param {!WebInspector.SCSSParser.Result} result 89 * @param {!Array<!WebInspector.SCSSParser.Property>} output
80 */ 90 */
81 _handleInclude: function(node, result) 91 _handleInclude: function(node, output)
82 { 92 {
83 var mixinName = node.content.find(node => node.type === "ident"); 93 var mixinName = node.content.find(node => node.type === "ident");
84 if (!mixinName) 94 if (!mixinName)
85 return; 95 return;
86 var nameRange = WebInspector.SCSSParser.rangeFromNode(mixinName); 96 var nameRange = WebInspector.SCSSParser.rangeFromNode(mixinName);
87 var mixinArguments = node.content.find(node => node.type === "arguments" ); 97 var mixinArguments = node.content.find(node => node.type === "arguments" );
88 if (!mixinArguments) 98 if (!mixinArguments)
89 return; 99 return;
90 var parameters = mixinArguments.content.filter(node => node.type !== "de limiter" && node.type !== "space"); 100 var parameters = mixinArguments.content.filter(node => node.type !== "de limiter" && node.type !== "space");
91 for (var parameter of parameters) { 101 for (var parameter of parameters) {
92 var range = WebInspector.SCSSParser.rangeFromNode(node); 102 var range = WebInspector.SCSSParser.rangeFromNode(node);
93 var valueRange = WebInspector.SCSSParser.rangeFromNode(parameter); 103 var valueRange = WebInspector.SCSSParser.rangeFromNode(parameter);
94 var property = new WebInspector.SCSSParser.Property(range, nameRange , valueRange, false); 104 var property = new WebInspector.SCSSParser.Property(range, nameRange , valueRange, false);
95 result.mixins.push(property); 105 output.push(property);
96 } 106 }
97 }, 107 },
98 108
99 /** 109 /**
100 * @param {!Gonzales.Node} node 110 * @param {!Gonzales.Node} node
101 * @param {!WebInspector.SCSSParser.Result} result 111 * @param {!Array<!WebInspector.SCSSParser.Property>} output
102 */ 112 */
103 _handleComment: function(node, result) 113 _handleComment: function(node, output)
104 { 114 {
105 if (node.start.line !== node.end.line) 115 if (node.start.line !== node.end.line)
106 return; 116 return;
107 var innerText = /** @type {string} */(node.content); 117 var innerText = /** @type {string} */(node.content);
108 var innerResult = this.parse(innerText); 118 var innerResult = this.parse(innerText);
109 if (innerResult.properties.length !== 1 || innerResult.variables.length !== 0 || innerResult.mixins.length !== 0) 119 if (innerResult.length !== 1 || innerResult[0].properties.length !== 1)
110 return; 120 return;
111 var property = innerResult.properties[0]; 121 var property = innerResult[0].properties[0];
112 var disabledProperty = property.rebaseInsideOneLineComment(node); 122 var disabledProperty = property.rebaseInsideOneLineComment(node);
113 result.properties.push(disabledProperty); 123 output.push(disabledProperty);
114 }, 124 },
115 } 125 }
116 126
117 /** 127 /**
118 * @param {!Gonzales.Node} node 128 * @param {!Gonzales.Node} node
119 * @return {!WebInspector.TextRange} 129 * @return {!WebInspector.TextRange}
120 */ 130 */
121 WebInspector.SCSSParser.rangeFromNode = function(node) 131 WebInspector.SCSSParser.rangeFromNode = function(node)
122 { 132 {
123 return new WebInspector.TextRange(node.start.line - 1, node.start.column - 1 , node.end.line - 1, node.end.column); 133 return new WebInspector.TextRange(node.start.line - 1, node.start.column - 1 , node.end.line - 1, node.end.column);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 * @return {!WebInspector.TextRange} 170 * @return {!WebInspector.TextRange}
161 */ 171 */
162 function rebaseRange(range, lineOffset, columnOffset) 172 function rebaseRange(range, lineOffset, columnOffset)
163 { 173 {
164 return new WebInspector.TextRange(range.startLine + lineOffset, rang e.startColumn + columnOffset, range.endLine + lineOffset, range.endColumn + colu mnOffset); 174 return new WebInspector.TextRange(range.startLine + lineOffset, rang e.startColumn + columnOffset, range.endLine + lineOffset, range.endColumn + colu mnOffset);
165 } 175 }
166 } 176 }
167 } 177 }
168 178
169 /** 179 /**
180 * @constructor
181 * @param {!Array<!WebInspector.TextRange>} selectors
182 * @param {!Array<!WebInspector.SCSSParser.Property>} properties
183 * @param {!WebInspector.TextRange} styleRange
184 */
185 WebInspector.SCSSParser.Rule = function(selectors, properties, styleRange)
186 {
187 this.selectors = selectors;
188 this.properties = properties;
189 this.styleRange = styleRange;
190 }
191
192 /**
170 * @param {!Gonzales.Node} node 193 * @param {!Gonzales.Node} node
171 * @param {!Array<!Gonzales.Node>} output 194 * @param {!Array<{node: !Gonzales.Node, properties: !Array<!Gonzales.Node>}>} b locks
195 * @param {!{node: !Gonzales.Node, properties: !Array<!Gonzales.Node>}} lastBloc k
172 */ 196 */
173 WebInspector.SCSSParser.extractNodes = function(node, output) 197 WebInspector.SCSSParser.extractNodes = function(node, blocks, lastBlock)
174 { 198 {
175 if (!Array.isArray(node.content)) 199 if (!Array.isArray(node.content))
176 return; 200 return;
201 if (node.type === "block") {
202 lastBlock = {
203 node: node,
204 properties: []
205 };
206 blocks.push(lastBlock);
207 }
177 var lastDeclaration = null; 208 var lastDeclaration = null;
209 var selectors = [];
178 for (var i = 0; i < node.content.length; ++i) { 210 for (var i = 0; i < node.content.length; ++i) {
179 var child = node.content[i]; 211 var child = node.content[i];
180 if (child.type === "declarationDelimiter" && lastDeclaration) { 212 if (child.type === "declarationDelimiter" && lastDeclaration) {
181 lastDeclaration.declarationRange.endLine = child.end.line - 1; 213 lastDeclaration.declarationRange.endLine = child.end.line - 1;
182 lastDeclaration.declarationRange.endColumn = child.end.column; 214 lastDeclaration.declarationRange.endColumn = child.end.column;
183 lastDeclaration = null; 215 lastDeclaration = null;
216 } else if (child.type === "selector") {
217 selectors.push(child);
218 } else if (child.type === "block") {
219 child.selectors = selectors;
220 selectors = [];
184 } 221 }
185 if (child.type === "include" || child.type === "declaration" || child.ty pe === "multilineComment") 222 if (child.type === "include" || child.type === "declaration" || child.ty pe === "multilineComment")
186 output.push(child); 223 lastBlock.properties.push(child);
187 if (child.type === "declaration") { 224 if (child.type === "declaration") {
188 lastDeclaration = child; 225 lastDeclaration = child;
189 lastDeclaration.declarationRange = WebInspector.TextRange.createFrom Location(child.start.line - 1, child.start.column - 1); 226 lastDeclaration.declarationRange = WebInspector.TextRange.createFrom Location(child.start.line - 1, child.start.column - 1);
190 } 227 }
191 WebInspector.SCSSParser.extractNodes(child, output); 228 WebInspector.SCSSParser.extractNodes(child, blocks, lastBlock);
192 } 229 }
193 if (lastDeclaration) { 230 if (lastDeclaration) {
194 lastDeclaration.declarationRange.endLine = node.end.line - 1; 231 lastDeclaration.declarationRange.endLine = node.end.line - 1;
195 lastDeclaration.declarationRange.endColumn = node.end.column - 1; 232 lastDeclaration.declarationRange.endColumn = node.end.column - 1;
196 } 233 }
197 } 234 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698