Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 } |
| OLD | NEW |