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 /** |
| 6 * @constructor |
| 7 * @param {!Map<string, string>} sassSources |
| 8 */ |
| 9 WebInspector.SASSStructureMapping = function(cssStruct, sassSources) |
| 10 { |
| 11 this._sources = sassSources; |
| 12 this._cssStruct = cssStruct; |
| 13 this._sassStructs = new Map(); |
| 14 } |
| 15 |
| 16 WebInspector.SASSStructureMapping.prototype = { |
| 17 cssPropertyValueToSASS: function(cssValueRange, sourceMap) |
| 18 { |
| 19 var entry = sourceMap.findEntry(cssValueRange.endLine, cssValueRange.end
Column); |
| 20 var url = entry.sourceURL; |
| 21 var struct = this._structForURL(url); |
| 22 if (!struct) { |
| 23 console.error("Failed to get structure of " + url); |
| 24 return null; |
| 25 } |
| 26 var sassValue = this._sassValue(struct, entry); |
| 27 if (!sassValue) |
| 28 return null; |
| 29 return { |
| 30 url: url, |
| 31 range: sassValue.range |
| 32 }; |
| 33 }, |
| 34 |
| 35 cssPropertyToSASS: function(cssPropertyRange, sourceMap) |
| 36 { |
| 37 var entry = sourceMap.findEntry(cssPropertyRange.startLine, cssPropertyR
ange.startColumn); |
| 38 var struct = this._structForURL(entry.sourceURL); |
| 39 if (!struct) { |
| 40 console.error("Failed to get structure of " + entry.sourceURL); |
| 41 return null; |
| 42 } |
| 43 var sassProperty = this._sassProperty(struct, entry); |
| 44 if (!sassProperty) |
| 45 return null; |
| 46 return { |
| 47 url: entry.sourceURL, |
| 48 range: sassProperty.range |
| 49 }; |
| 50 }, |
| 51 |
| 52 sassPropertyValueToCSS: function(sassURL, sassValueRange, sourceMap) |
| 53 { |
| 54 var reversedEntries = sourceMap.findEntriesReversed(sassURL, sassValueRa
nge.endLine, sassValueRange.endColumn - 1); |
| 55 var result = []; |
| 56 for (var i = 0; i < reversedEntries.length; ++i) { |
| 57 var value = this._cssValue(reversedEntries[i]); |
| 58 console.assert(value, "Failed to find reversed mapped property value
."); |
| 59 result.push(value); |
| 60 } |
| 61 return result; |
| 62 }, |
| 63 |
| 64 _sassProperty: function(struct, entry) |
| 65 { |
| 66 for (var i = 0; i < struct.properties.length; ++i) { |
| 67 var property = struct.properties[i]; |
| 68 if (this._rangeContainsSourceMapping(property.range, entry)) |
| 69 return property; |
| 70 } |
| 71 return null; |
| 72 }, |
| 73 |
| 74 _sassVariable: function(struct, entry) |
| 75 { |
| 76 for (var i = 0; i < struct.variables.length; ++i) { |
| 77 var variable = struct.variables[i]; |
| 78 if (this._rangeContainsSourceMapping(variable.range, entry)) |
| 79 return variable; |
| 80 } |
| 81 return null; |
| 82 }, |
| 83 |
| 84 _sassValue: function(struct, entry) |
| 85 { |
| 86 var sassProperty = this._sassProperty(struct, entry); |
| 87 if (sassProperty && this._rangeContainsSourceMapping(sassProperty.value.
range, entry)) |
| 88 return sassProperty.value; |
| 89 |
| 90 var sassVariable = this._sassVariable(struct, entry); |
| 91 if (sassVariable && this._rangeContainsSourceMapping(sassVariable.value.
range, entry)) |
| 92 return sassVariable.value; |
| 93 for (var i = 0; i < struct.mixinValues.length; ++i) { |
| 94 var mixinValue = struct.mixinValues[i]; |
| 95 if (this._rangeContainsSourceMapping(mixinValue.range, entry)) |
| 96 return mixinValue; |
| 97 } |
| 98 return null; |
| 99 }, |
| 100 |
| 101 _cssProperty: function(entry) |
| 102 { |
| 103 for (var i = 0; i < this._cssStruct.length; ++i) { |
| 104 var rule = this._cssStruct[i]; |
| 105 for (var j = 0; j < rule.properties.length; ++j) { |
| 106 var property = rule.properties[j]; |
| 107 if (this._rangeContainsCompiledMapping(property.range, entry)) |
| 108 return property; |
| 109 } |
| 110 } |
| 111 return null; |
| 112 }, |
| 113 |
| 114 _cssValue: function(entry) |
| 115 { |
| 116 var cssProperty = this._cssProperty(entry); |
| 117 if (cssProperty && this._rangeContainsCompiledMapping(cssProperty.valueR
ange, entry)) |
| 118 return cssProperty; |
| 119 return null; |
| 120 }, |
| 121 |
| 122 _rangeContainsSourceMapping: function(range, entry) |
| 123 { |
| 124 if (range.startLine === range.endLine) |
| 125 return range.startLine === entry.sourceLineNumber && range.startColu
mn <= entry.sourceColumnNumber && entry.sourceColumnNumber <= range.endColumn; |
| 126 if (range.startLine === entry.sourceLineNumber) |
| 127 return range.startColumn <= entry.sourceColumnNumber; |
| 128 if (range.endLine === entry.sourceLineNumber) |
| 129 return entry.sourceColumnNumber <= range.endColumn; |
| 130 return range.startLine < entry.sourceLineNumber && entry.sourceLineNumbe
r < range.endLine; |
| 131 }, |
| 132 |
| 133 _rangeContainsCompiledMapping: function(range, entry) |
| 134 { |
| 135 if (range.startLine === range.endLine) |
| 136 return range.startLine === entry.lineNumber && range.startColumn <=
entry.columnNumber && entry.columnNumber <= range.endColumn; |
| 137 if (range.startLine === entry.lineNumber) |
| 138 return range.startColumn <= entry.columnNumber; |
| 139 if (range.endLine === entry.lineNumber) |
| 140 return entry.columnNumber <= range.endColumn; |
| 141 return range.startLine < entry.lineNumber && entry.lineNumber < range.en
dLine; |
| 142 }, |
| 143 |
| 144 _structForURL: function(sassURL) |
| 145 { |
| 146 if (this._sassStructs.has(sassURL)) |
| 147 return this._sassStructs.get(sassURL); |
| 148 var source = this._sources.get(sassURL); |
| 149 if (!source) |
| 150 return null; |
| 151 var result = WebInspector.SASSStructureMapping.parseSASS(source); |
| 152 this._sassStructs.set(sassURL, result); |
| 153 return result; |
| 154 } |
| 155 } |
| 156 |
| 157 |
| 158 WebInspector.SASSStructureMapping.SCSSParserStates = { |
| 159 Initial: "Initial", |
| 160 PropertyName: "PropertyName", |
| 161 PropertyValue: "PropertyValue", |
| 162 VariableName: "VariableName", |
| 163 VariableValue: "VariableValue", |
| 164 MixinInclude: "MixinInclude", |
| 165 MixinValue: "MixinValue" |
| 166 } |
| 167 |
| 168 WebInspector.SASSStructureMapping.parseSASS = function(text) |
| 169 { |
| 170 var lines = text.split("\n"); |
| 171 var properties = []; |
| 172 var variables = []; |
| 173 var mixinValues = []; |
| 174 |
| 175 var States = WebInspector.SASSStructureMapping.SCSSParserStates; |
| 176 var state = States.Initial; |
| 177 var property; |
| 178 var variable; |
| 179 var mixin; |
| 180 var UndefTokenType = {}; |
| 181 |
| 182 /** |
| 183 * @param {string} tokenValue |
| 184 * @param {?string} tokenTypes |
| 185 * @param {number} column |
| 186 * @param {number} newColumn |
| 187 */ |
| 188 function processToken(tokenValue, tokenTypes, column, newColumn) |
| 189 { |
| 190 var tokenType = tokenTypes ? tokenTypes.split(" ").keySet() : UndefToken
Type; |
| 191 switch (state) { |
| 192 case States.Initial: |
| 193 if (tokenType["css-variable-2"]) { |
| 194 variable = { |
| 195 name: { |
| 196 content: tokenValue, |
| 197 range: new WebInspector.TextRange(lineNumber, column, li
neNumber, newColumn) |
| 198 }, |
| 199 value: { |
| 200 content: "", |
| 201 }, |
| 202 range: WebInspector.TextRange.createFromLocation(lineNumber,
column) |
| 203 } |
| 204 state = States.VariableName; |
| 205 } else if (tokenType["css-property"] || tokenType["css-meta"]) { |
| 206 property = { |
| 207 name: { |
| 208 content: tokenValue, |
| 209 range: new WebInspector.TextRange(lineNumber, column, li
neNumber, newColumn) |
| 210 }, |
| 211 value: { |
| 212 content: "", |
| 213 }, |
| 214 range: WebInspector.TextRange.createFromLocation(lineNumber,
column) |
| 215 } |
| 216 state = States.PropertyName; |
| 217 } else if (tokenType["css-def"] && tokenValue === "@include") { |
| 218 state = States.MixinInclude; |
| 219 } |
| 220 break; |
| 221 case States.VariableName: |
| 222 if (tokenValue === ")" && tokenType === UndefTokenType) { |
| 223 state = States.Initial; |
| 224 } else if (tokenValue === ":" && tokenType === UndefTokenType) { |
| 225 state = States.VariableValue; |
| 226 variable.value.range = WebInspector.TextRange.createFromLocation
(lineNumber, newColumn); |
| 227 } else if (tokenType !== UndefTokenType) { |
| 228 state = States.Initial; |
| 229 } |
| 230 break; |
| 231 case States.VariableValue: |
| 232 if (tokenValue === ";" && tokenType === UndefTokenType) { |
| 233 variable.value.range.endLine = lineNumber; |
| 234 variable.value.range.endColumn = column; |
| 235 variable.range.endLine = lineNumber; |
| 236 variable.range.endColumn = newColumn; |
| 237 variables.push(variable); |
| 238 state = States.Initial; |
| 239 } else { |
| 240 variable.value.content += tokenValue; |
| 241 } |
| 242 break; |
| 243 case States.PropertyName: |
| 244 if (tokenValue === ":" && tokenType === UndefTokenType) { |
| 245 state = States.PropertyValue; |
| 246 property.value.range = WebInspector.TextRange.createFromLocation
(lineNumber, newColumn); |
| 247 } else if (tokenType["property"]) { |
| 248 property.name.contet += tokenValue; |
| 249 } |
| 250 break; |
| 251 case States.PropertyValue: |
| 252 if (tokenValue === ";" && tokenType === UndefTokenType) { |
| 253 property.value.range.endLine = lineNumber; |
| 254 property.value.range.endColumn = column; |
| 255 property.range.endLine = lineNumber; |
| 256 property.range.endColumn = newColumn; |
| 257 properties.push(property); |
| 258 state = States.Initial; |
| 259 } else { |
| 260 property.value.content += tokenValue; |
| 261 } |
| 262 break; |
| 263 case States.MixinInclude: |
| 264 if (tokenValue === "(" && tokenType === UndefTokenType) { |
| 265 state = States.MixinValue; |
| 266 mixin = { |
| 267 range: WebInspector.TextRange.createFromLocation(lineNumber,
newColumn), |
| 268 value: "" |
| 269 }; |
| 270 } else if (tokenValue === ";" && tokenType === UndefTokenType) { |
| 271 state = States.Initial; |
| 272 if (mixin) |
| 273 mixinValues.push(mixin); |
| 274 mixin = null; |
| 275 } |
| 276 break; |
| 277 case States.MixinValue: |
| 278 if (tokenValue === ")" && tokenType === UndefTokenType) { |
| 279 state = States.MixinInclude; |
| 280 mixin.range.endLine = lineNumber; |
| 281 mixin.range.endColumn = column; |
| 282 } else { |
| 283 mixin.value += tokenValue; |
| 284 } |
| 285 break; |
| 286 default: |
| 287 console.assert(false, "Unknown CSS parser state."); |
| 288 } |
| 289 } |
| 290 var tokenizer = new WebInspector.CodeMirrorUtils.TokenizerFactory().createTo
kenizer("text/x-scss"); |
| 291 var lineNumber; |
| 292 for (lineNumber = 0; lineNumber < lines.length; ++lineNumber) { |
| 293 var line = lines[lineNumber]; |
| 294 tokenizer(line, processToken); |
| 295 } |
| 296 return { |
| 297 variables: variables, |
| 298 properties: properties, |
| 299 mixinValues: mixinValues |
| 300 }; |
| 301 } |
OLD | NEW |