Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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 WebInspector.SASSSupport = {} | |
| 6 | |
| 7 /** | |
| 8 * @constructor | |
| 9 * @param {string} url | |
| 10 * @param {string} text | |
| 11 */ | |
| 12 WebInspector.SASSSupport.ASTDocument = function(url, text) | |
| 13 { | |
| 14 this.url = url; | |
| 15 this.text = text; | |
| 16 } | |
| 17 | |
| 18 /** | |
| 19 * @param {string} url | |
| 20 * @param {string} text | |
| 21 * @param {!WebInspector.TokenizerFactory} tokenizerFactory | |
| 22 * @return {!WebInspector.SASSSupport.AST} | |
| 23 */ | |
| 24 WebInspector.SASSSupport.parseSCSS = function(url, text, tokenizerFactory) | |
| 25 { | |
| 26 var document = new WebInspector.SASSSupport.ASTDocument(url, text); | |
| 27 var result = WebInspector.SASSSupport._innerParseSCSS(document, tokenizerFac tory); | |
| 28 | |
| 29 var rules = [ | |
| 30 new WebInspector.SASSSupport.Rule(document, "variables", result.variable s), | |
| 31 new WebInspector.SASSSupport.Rule(document, "properties", result.propert ies), | |
| 32 new WebInspector.SASSSupport.Rule(document, "mixins", result.mixins) | |
| 33 ]; | |
| 34 | |
| 35 return new WebInspector.SASSSupport.AST(document, rules); | |
| 36 } | |
| 37 | |
| 38 /** @enum {string} */ | |
| 39 WebInspector.SASSSupport.SCSSParserStates = { | |
| 40 Initial: "Initial", | |
| 41 PropertyName: "PropertyName", | |
| 42 PropertyValue: "PropertyValue", | |
| 43 VariableName: "VariableName", | |
| 44 VariableValue: "VariableValue", | |
| 45 MixinName: "MixinName", | |
| 46 MixinValue: "MixinValue", | |
| 47 Media: "Media", | |
| 48 } | |
| 49 | |
| 50 /** | |
| 51 * @param {!WebInspector.SASSSupport.ASTDocument} document | |
| 52 * @param {!WebInspector.TokenizerFactory} tokenizerFactory | |
| 53 * @return {!{variables: !Array<!WebInspector.SASSSupport.Property>, properties: !Array<!WebInspector.SASSSupport.Property>, mixins: !Array<!WebInspector.SASSSu pport.Property>}} | |
| 54 */ | |
| 55 WebInspector.SASSSupport._innerParseSCSS = function(document, tokenizerFactory) | |
| 56 { | |
| 57 var lines = document.text.split("\n"); | |
| 58 var properties = []; | |
| 59 var variables = []; | |
| 60 var mixins = []; | |
| 61 | |
| 62 var States = WebInspector.SASSSupport.SCSSParserStates; | |
| 63 var state = States.Initial; | |
| 64 var propertyName, propertyValue; | |
| 65 var variableName, variableValue; | |
| 66 var mixinName, mixinValue; | |
| 67 var UndefTokenType = {}; | |
| 68 | |
| 69 /** | |
| 70 * @param {string} tokenValue | |
| 71 * @param {?string} tokenTypes | |
| 72 * @param {number} column | |
| 73 * @param {number} newColumn | |
| 74 */ | |
| 75 function processToken(tokenValue, tokenTypes, column, newColumn) | |
| 76 { | |
| 77 var tokenType = tokenTypes ? tokenTypes.split(" ").keySet() : UndefToken Type; | |
| 78 switch (state) { | |
| 79 case States.Initial: | |
| 80 if (tokenType["css-variable-2"]) { | |
| 81 variableName = new WebInspector.SASSSupport.TextNode(document, t okenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn) ); | |
| 82 state = States.VariableName; | |
| 83 } else if (tokenType["css-property"] || tokenType["css-meta"]) { | |
| 84 propertyName = new WebInspector.SASSSupport.TextNode(document, t okenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn) ); | |
| 85 state = States.PropertyName; | |
| 86 } else if (tokenType["css-def"] && tokenValue === "@include") { | |
| 87 mixinName = new WebInspector.SASSSupport.TextNode(document, toke nValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn)); | |
| 88 state = States.MixinName; | |
| 89 } else if (tokenType["css-comment"]) { | |
| 90 // Support only a one-line comments. | |
| 91 if (tokenValue.substring(0, 2) !== "/*" || tokenValue.substring( tokenValue.length - 2) !== "*/") | |
| 92 break; | |
| 93 var uncommentedText = tokenValue.substring(2, tokenValue.length - 2); | |
| 94 var fakeRuleText = "a{\n" + uncommentedText + "}"; | |
| 95 var fakeDocument = new WebInspector.SASSSupport.ASTDocument("", fakeRuleText); | |
| 96 var result = WebInspector.SASSSupport._innerParseSCSS(fakeDocume nt, tokenizerFactory); | |
| 97 if (result.properties.length === 1 && result.variables.length == = 0 && result.mixins.length === 0) { | |
| 98 var disabledProperty = result.properties[0]; | |
| 99 // We should offset property to current coordinates. | |
| 100 var offset = column + 2; | |
| 101 var nameRange = new WebInspector.TextRange(lineNumber, disab ledProperty.name.range.startColumn + offset, | |
| 102 lineNumber, disabledProperty.name.range.endColumn + offset); | |
| 103 var valueRange = new WebInspector.TextRange(lineNumber, disa bledProperty.value.range.startColumn + offset, | |
| 104 lineNumber, disabledProperty.value.range.endColumn + offset); | |
| 105 var name = new WebInspector.SASSSupport.TextNode(document, d isabledProperty.name.text, nameRange); | |
| 106 var value = new WebInspector.SASSSupport.TextNode(document, disabledProperty.value.text, valueRange); | |
| 107 var range = new WebInspector.TextRange(lineNumber, column, l ineNumber, newColumn); | |
| 108 var property = new WebInspector.SASSSupport.Property(documen t, name, value, range, true); | |
| 109 properties.push(property); | |
| 110 } | |
| 111 } else if (tokenType["css-def"] && tokenValue === "@media") { | |
| 112 state = States.Media; | |
| 113 } | |
| 114 break; | |
| 115 case States.VariableName: | |
| 116 if (tokenValue === ")" && tokenType === UndefTokenType) { | |
| 117 state = States.Initial; | |
| 118 } else if (tokenValue === ":" && tokenType === UndefTokenType) { | |
| 119 state = States.VariableValue; | |
| 120 variableValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn)); | |
| 121 } else if (tokenType !== UndefTokenType) { | |
| 122 state = States.Initial; | |
| 123 } | |
| 124 break; | |
| 125 case States.VariableValue: | |
| 126 if (tokenValue === ";" && tokenType === UndefTokenType) { | |
| 127 variableValue.range.endLine = lineNumber; | |
| 128 variableValue.range.endColumn = column; | |
| 129 var variable = new WebInspector.SASSSupport.Property(document, v ariableName, variableValue, variableName.range.clone(), false); | |
| 130 variable.range.endLine = lineNumber; | |
| 131 variable.range.endColumn = newColumn; | |
| 132 variables.push(variable); | |
| 133 state = States.Initial; | |
| 134 } else { | |
| 135 variableValue.text += tokenValue; | |
| 136 } | |
| 137 break; | |
| 138 case States.PropertyName: | |
| 139 if (tokenValue === ":" && tokenType === UndefTokenType) { | |
| 140 state = States.PropertyValue; | |
| 141 propertyName.range.endLine = lineNumber; | |
| 142 propertyName.range.endColumn = column; | |
| 143 propertyValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn)); | |
| 144 } else if (tokenType["css-property"]) { | |
| 145 propertyName.text += tokenValue; | |
| 146 } | |
| 147 break; | |
| 148 case States.PropertyValue: | |
| 149 if ((tokenValue === "}" || tokenValue === ";") && tokenType === Unde fTokenType) { | |
| 150 propertyValue.range.endLine = lineNumber; | |
| 151 propertyValue.range.endColumn = column; | |
| 152 var property = new WebInspector.SASSSupport.Property(document, p ropertyName, propertyValue, propertyName.range.clone(), false); | |
| 153 property.range.endLine = lineNumber; | |
| 154 property.range.endColumn = newColumn; | |
| 155 properties.push(property); | |
| 156 state = States.Initial; | |
| 157 } else { | |
| 158 propertyValue.text += tokenValue; | |
| 159 } | |
| 160 break; | |
| 161 case States.MixinName: | |
| 162 if (tokenValue === "(" && tokenType === UndefTokenType) { | |
| 163 state = States.MixinValue; | |
| 164 mixinName.range.endLine = lineNumber; | |
| 165 mixinName.range.endColumn = column; | |
| 166 mixinValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn)); | |
| 167 } else if (tokenValue === ";" && tokenType === UndefTokenType) { | |
| 168 state = States.Initial; | |
| 169 mixinValue = null; | |
| 170 } else { | |
| 171 mixinName.text += tokenValue; | |
| 172 } | |
| 173 break; | |
| 174 case States.MixinValue: | |
| 175 if (tokenValue === ")" && tokenType === UndefTokenType) { | |
| 176 mixinValue.range.endLine = lineNumber; | |
| 177 mixinValue.range.endColumn = column; | |
| 178 var mixin = new WebInspector.SASSSupport.Property(document, mixi nName, /** @type {!WebInspector.SASSSupport.TextNode} */(mixinValue), mixinName. range.clone(), false); | |
| 179 mixin.range.endLine = lineNumber; | |
| 180 mixin.range.endColumn = newColumn; | |
| 181 mixins.push(mixin); | |
| 182 state = States.Initial; | |
| 183 } else { | |
| 184 mixinValue.text += tokenValue; | |
| 185 } | |
| 186 break; | |
| 187 case States.Media: | |
| 188 if (tokenValue === "{" && tokenType === UndefTokenType) | |
| 189 state = States.Initial; | |
| 190 break; | |
| 191 default: | |
| 192 console.assert(false, "Unknown SASS parser state."); | |
| 193 } | |
| 194 } | |
| 195 var tokenizer = tokenizerFactory.createTokenizer("text/x-scss"); | |
| 196 var lineNumber; | |
| 197 for (lineNumber = 0; lineNumber < lines.length; ++lineNumber) { | |
| 198 var line = lines[lineNumber]; | |
| 199 tokenizer(line, processToken); | |
| 200 processToken("\n", null, line.length, line.length + 1); | |
| 201 } | |
| 202 return { | |
| 203 variables: variables, | |
| 204 properties: properties, | |
| 205 mixins: mixins | |
| 206 }; | |
| 207 } | |
| 208 | |
| 209 /** | |
| 210 * @constructor | |
| 211 * @param {!WebInspector.SASSSupport.ASTDocument} document | |
| 212 */ | |
| 213 WebInspector.SASSSupport.Node = function(document) | |
| 214 { | |
| 215 this.document = document; | |
| 216 } | |
| 217 | |
| 218 /** | |
| 219 * @constructor | |
| 220 * @extends {WebInspector.SASSSupport.Node} | |
| 221 * @param {!WebInspector.SASSSupport.ASTDocument} document | |
| 222 * @param {string} text | |
| 223 * @param {!WebInspector.TextRange} range | |
| 224 */ | |
| 225 WebInspector.SASSSupport.TextNode = function(document, text, range) | |
| 226 { | |
| 227 WebInspector.SASSSupport.Node.call(this, document); | |
| 228 this.text = text; | |
|
pfeldman
2015/12/09 20:13:43
Why is text necessary? You can fetch it at any mom
lushnikov
2015/12/09 21:41:54
I want to modify AST tree later, adding properties
| |
| 229 this.range = range; | |
| 230 } | |
| 231 | |
| 232 WebInspector.SASSSupport.TextNode.prototype = { | |
| 233 /** | |
| 234 * @return {!WebInspector.SASSSupport.TextNode} | |
| 235 */ | |
| 236 clone: function() | |
| 237 { | |
| 238 return new WebInspector.SASSSupport.TextNode(this.document, this.text, t his.range.clone()); | |
| 239 }, | |
| 240 | |
| 241 __proto__: WebInspector.SASSSupport.Node.prototype | |
| 242 } | |
| 243 | |
| 244 /** | |
| 245 * @constructor | |
| 246 * @extends {WebInspector.SASSSupport.Node} | |
| 247 * @param {!WebInspector.SASSSupport.ASTDocument} document | |
| 248 * @param {!WebInspector.SASSSupport.TextNode} name | |
| 249 * @param {!WebInspector.SASSSupport.TextNode} value | |
| 250 * @param {!WebInspector.TextRange} range | |
| 251 * @param {boolean} disabled | |
| 252 */ | |
| 253 WebInspector.SASSSupport.Property = function(document, name, value, range, disab led) | |
| 254 { | |
| 255 WebInspector.SASSSupport.Node.call(this, document); | |
| 256 this.name = name; | |
| 257 this.value = value; | |
| 258 this.range = range; | |
| 259 this.name.parent = this; | |
| 260 this.value.parent = this; | |
| 261 this.disabled = disabled; | |
| 262 } | |
| 263 | |
| 264 WebInspector.SASSSupport.Property.prototype = { | |
| 265 /** | |
| 266 * @return {!WebInspector.SASSSupport.Property} | |
| 267 */ | |
| 268 clone: function() | |
| 269 { | |
| 270 return new WebInspector.SASSSupport.Property(this.document, this.name.cl one(), this.value.clone(), this.range.clone(), this.disabled); | |
| 271 }, | |
| 272 | |
| 273 __proto__: WebInspector.SASSSupport.Node.prototype | |
| 274 } | |
| 275 | |
| 276 /** | |
| 277 * @constructor | |
| 278 * @extends {WebInspector.SASSSupport.Node} | |
| 279 * @param {!WebInspector.SASSSupport.ASTDocument} document | |
| 280 * @param {string} selector | |
| 281 * @param {!Array<!WebInspector.SASSSupport.Property>} properties | |
| 282 */ | |
| 283 WebInspector.SASSSupport.Rule = function(document, selector, properties) | |
| 284 { | |
| 285 WebInspector.SASSSupport.Node.call(this, document); | |
| 286 this.selector = selector; | |
| 287 this.properties = properties; | |
| 288 for (var i = 0; i < this.properties.length; ++i) | |
| 289 this.properties[i].parent = this; | |
| 290 } | |
| 291 | |
| 292 WebInspector.SASSSupport.Rule.prototype = { | |
| 293 /** | |
| 294 * @return {!WebInspector.SASSSupport.Rule} | |
| 295 */ | |
| 296 clone: function() | |
| 297 { | |
| 298 var properties = []; | |
| 299 for (var i = 0; i < this.properties.length; ++i) | |
| 300 properties.push(this.properties[i].clone()); | |
| 301 return new WebInspector.SASSSupport.Rule(this.document, this.selector, p roperties); | |
| 302 }, | |
| 303 | |
| 304 __proto__: WebInspector.SASSSupport.Node.prototype | |
| 305 } | |
| 306 | |
| 307 /** | |
| 308 * @constructor | |
| 309 * @extends {WebInspector.SASSSupport.Node} | |
| 310 * @param {!WebInspector.SASSSupport.ASTDocument} document | |
| 311 * @param {!Array<!WebInspector.SASSSupport.Rule>} rules | |
| 312 */ | |
| 313 WebInspector.SASSSupport.AST = function(document, rules) | |
| 314 { | |
| 315 WebInspector.SASSSupport.Node.call(this, document); | |
| 316 this.rules = rules; | |
| 317 for (var i = 0; i < rules.length; ++i) | |
| 318 rules[i].parent = this; | |
| 319 } | |
| 320 | |
| 321 WebInspector.SASSSupport.AST.prototype = { | |
| 322 /** | |
| 323 * @return {!WebInspector.SASSSupport.AST} | |
| 324 */ | |
| 325 clone: function() | |
| 326 { | |
| 327 var rules = []; | |
| 328 for (var i = 0; i < this.rules.length; ++i) | |
| 329 rules.push(this.rules[i].clone()); | |
| 330 return new WebInspector.SASSSupport.AST(this.document, rules); | |
| 331 }, | |
| 332 | |
| 333 __proto__: WebInspector.SASSSupport.Node.prototype | |
| 334 } | |
| 335 | |
| OLD | NEW |