| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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 | |
| 5 WebInspector.SASSSupport = {}; | 4 WebInspector.SASSSupport = {}; |
| 6 | 5 |
| 7 /** | 6 /** |
| 8 * @param {string} url | 7 * @param {string} url |
| 9 * @param {string} content | 8 * @param {string} content |
| 10 * @return {!Promise<!WebInspector.SASSSupport.AST>} | 9 * @return {!Promise<!WebInspector.SASSSupport.AST>} |
| 11 */ | 10 */ |
| 12 WebInspector.SASSSupport.parseSCSS = function(url, content) | 11 WebInspector.SASSSupport.parseSCSS = function(url, content) { |
| 13 { | 12 var text = new WebInspector.Text(content); |
| 14 var text = new WebInspector.Text(content); | 13 var document = new WebInspector.SASSSupport.ASTDocument(url, text); |
| 15 var document = new WebInspector.SASSSupport.ASTDocument(url, text); | 14 |
| 16 | 15 return WebInspector.formatterWorkerPool.runTask('parseSCSS', {content: content
}).then(onParsed); |
| 17 return WebInspector.formatterWorkerPool.runTask("parseSCSS", {content: conte
nt}).then(onParsed); | 16 |
| 18 | 17 /** |
| 19 /** | 18 * @param {?MessageEvent} event |
| 20 * @param {?MessageEvent} event | 19 * @return {!WebInspector.SASSSupport.AST} |
| 21 * @return {!WebInspector.SASSSupport.AST} | 20 */ |
| 22 */ | 21 function onParsed(event) { |
| 23 function onParsed(event) | 22 if (!event) |
| 24 { | 23 return new WebInspector.SASSSupport.AST(document, []); |
| 25 if (!event) | 24 var data = /** @type {!Array<!Object>} */ (event.data); |
| 26 return new WebInspector.SASSSupport.AST(document, []); | 25 var rules = []; |
| 27 var data = /** @type {!Array<!Object>} */(event.data); | 26 for (var i = 0; i < data.length; ++i) { |
| 28 var rules = []; | 27 var rulePayload = data[i]; |
| 29 for (var i = 0; i < data.length; ++i) { | 28 var selectors = rulePayload.selectors.map(createTextNode); |
| 30 var rulePayload = data[i]; | 29 var properties = rulePayload.properties.map(createProperty); |
| 31 var selectors = rulePayload.selectors.map(createTextNode); | 30 var range = WebInspector.TextRange.fromObject(rulePayload.styleRange); |
| 32 var properties = rulePayload.properties.map(createProperty); | 31 var rule = new WebInspector.SASSSupport.Rule(document, selectors, range, p
roperties); |
| 33 var range = WebInspector.TextRange.fromObject(rulePayload.styleRange
); | 32 rules.push(rule); |
| 34 var rule = new WebInspector.SASSSupport.Rule(document, selectors, ra
nge, properties); | 33 } |
| 35 rules.push(rule); | 34 return new WebInspector.SASSSupport.AST(document, rules); |
| 36 } | 35 } |
| 37 return new WebInspector.SASSSupport.AST(document, rules); | 36 |
| 38 } | 37 /** |
| 39 | 38 * @param {!Object} payload |
| 40 /** | 39 */ |
| 41 * @param {!Object} payload | 40 function createTextNode(payload) { |
| 42 */ | 41 var range = WebInspector.TextRange.fromObject(payload); |
| 43 function createTextNode(payload) | 42 var value = text.extract(range); |
| 44 { | 43 return new WebInspector.SASSSupport.TextNode(document, text.extract(range),
range); |
| 45 var range = WebInspector.TextRange.fromObject(payload); | 44 } |
| 46 var value = text.extract(range); | 45 |
| 47 return new WebInspector.SASSSupport.TextNode(document, text.extract(rang
e), range); | 46 /** |
| 48 } | 47 * @param {!Object} payload |
| 49 | 48 */ |
| 50 /** | 49 function createProperty(payload) { |
| 51 * @param {!Object} payload | 50 var name = createTextNode(payload.name); |
| 52 */ | 51 var value = createTextNode(payload.value); |
| 53 function createProperty(payload) | 52 return new WebInspector.SASSSupport.Property( |
| 54 { | 53 document, name, value, WebInspector.TextRange.fromObject(payload.range),
payload.disabled); |
| 55 var name = createTextNode(payload.name); | 54 } |
| 56 var value = createTextNode(payload.value); | 55 }; |
| 57 return new WebInspector.SASSSupport.Property(document, name, value, WebI
nspector.TextRange.fromObject(payload.range), payload.disabled); | 56 |
| 58 } | 57 /** |
| 59 }; | 58 * @unrestricted |
| 60 | 59 */ |
| 61 /** | 60 WebInspector.SASSSupport.ASTDocument = class { |
| 62 * @constructor | 61 /** |
| 63 * @param {string} url | 62 * @param {string} url |
| 64 * @param {!WebInspector.Text} text | 63 * @param {!WebInspector.Text} text |
| 65 */ | 64 */ |
| 66 WebInspector.SASSSupport.ASTDocument = function(url, text) | 65 constructor(url, text) { |
| 67 { | |
| 68 this.url = url; | 66 this.url = url; |
| 69 this.text = text; | 67 this.text = text; |
| 70 this.edits = []; | 68 this.edits = []; |
| 71 }; | 69 } |
| 72 | 70 |
| 73 WebInspector.SASSSupport.ASTDocument.prototype = { | 71 /** |
| 72 * @return {!WebInspector.SASSSupport.ASTDocument} |
| 73 */ |
| 74 clone() { |
| 75 return new WebInspector.SASSSupport.ASTDocument(this.url, this.text); |
| 76 } |
| 77 |
| 78 /** |
| 79 * @return {boolean} |
| 80 */ |
| 81 hasChanged() { |
| 82 return !!this.edits.length; |
| 83 } |
| 84 |
| 85 /** |
| 86 * @return {!WebInspector.Text} |
| 87 */ |
| 88 newText() { |
| 89 this.edits.stableSort(sequentialOrder); |
| 90 var text = this.text; |
| 91 for (var i = this.edits.length - 1; i >= 0; --i) { |
| 92 var range = this.edits[i].oldRange; |
| 93 var newText = this.edits[i].newText; |
| 94 text = new WebInspector.Text(text.replaceRange(range, newText)); |
| 95 } |
| 96 return text; |
| 97 |
| 74 /** | 98 /** |
| 75 * @return {!WebInspector.SASSSupport.ASTDocument} | 99 * @param {!WebInspector.SourceEdit} edit1 |
| 100 * @param {!WebInspector.SourceEdit} edit2 |
| 101 * @return {number} |
| 76 */ | 102 */ |
| 77 clone: function() | 103 function sequentialOrder(edit1, edit2) { |
| 78 { | 104 var range1 = edit1.oldRange.collapseToStart(); |
| 79 return new WebInspector.SASSSupport.ASTDocument(this.url, this.text); | 105 var range2 = edit2.oldRange.collapseToStart(); |
| 80 }, | 106 if (range1.equal(range2)) |
| 81 | 107 return 0; |
| 82 /** | 108 return range1.follows(range2) ? 1 : -1; |
| 83 * @return {boolean} | 109 } |
| 84 */ | 110 } |
| 85 hasChanged: function() | 111 }; |
| 86 { | 112 |
| 87 return !!this.edits.length; | 113 /** |
| 88 }, | 114 * @unrestricted |
| 89 | 115 */ |
| 90 /** | 116 WebInspector.SASSSupport.Node = class { |
| 91 * @return {!WebInspector.Text} | 117 /** |
| 92 */ | 118 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 93 newText: function() | 119 */ |
| 94 { | 120 constructor(document) { |
| 95 this.edits.stableSort(sequentialOrder); | |
| 96 var text = this.text; | |
| 97 for (var i = this.edits.length - 1; i >= 0; --i) { | |
| 98 var range = this.edits[i].oldRange; | |
| 99 var newText = this.edits[i].newText; | |
| 100 text = new WebInspector.Text(text.replaceRange(range, newText)); | |
| 101 } | |
| 102 return text; | |
| 103 | |
| 104 /** | |
| 105 * @param {!WebInspector.SourceEdit} edit1 | |
| 106 * @param {!WebInspector.SourceEdit} edit2 | |
| 107 * @return {number} | |
| 108 */ | |
| 109 function sequentialOrder(edit1, edit2) | |
| 110 { | |
| 111 var range1 = edit1.oldRange.collapseToStart(); | |
| 112 var range2 = edit2.oldRange.collapseToStart(); | |
| 113 if (range1.equal(range2)) | |
| 114 return 0; | |
| 115 return range1.follows(range2) ? 1 : -1; | |
| 116 } | |
| 117 }, | |
| 118 }; | |
| 119 | |
| 120 /** | |
| 121 * @constructor | |
| 122 * @param {!WebInspector.SASSSupport.ASTDocument} document | |
| 123 */ | |
| 124 WebInspector.SASSSupport.Node = function(document) | |
| 125 { | |
| 126 this.document = document; | 121 this.document = document; |
| 127 }; | 122 } |
| 128 | 123 }; |
| 129 /** | 124 |
| 130 * @constructor | 125 /** |
| 131 * @extends {WebInspector.SASSSupport.Node} | 126 * @unrestricted |
| 132 * @param {!WebInspector.SASSSupport.ASTDocument} document | 127 */ |
| 133 * @param {string} text | 128 WebInspector.SASSSupport.TextNode = class extends WebInspector.SASSSupport.Node
{ |
| 134 * @param {!WebInspector.TextRange} range | 129 /** |
| 135 */ | 130 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 136 WebInspector.SASSSupport.TextNode = function(document, text, range) | 131 * @param {string} text |
| 137 { | 132 * @param {!WebInspector.TextRange} range |
| 138 WebInspector.SASSSupport.Node.call(this, document); | 133 */ |
| 134 constructor(document, text, range) { |
| 135 super(document); |
| 139 this.text = text; | 136 this.text = text; |
| 140 this.range = range; | 137 this.range = range; |
| 141 }; | 138 } |
| 142 | 139 |
| 143 WebInspector.SASSSupport.TextNode.prototype = { | 140 /** |
| 144 /** | 141 * @param {string} newText |
| 145 * @param {string} newText | 142 */ |
| 146 */ | 143 setText(newText) { |
| 147 setText: function(newText) | 144 if (this.text === newText) |
| 148 { | 145 return; |
| 149 if (this.text === newText) | 146 this.text = newText; |
| 150 return; | 147 this.document.edits.push(new WebInspector.SourceEdit(this.document.url, this
.range, newText)); |
| 151 this.text = newText; | 148 } |
| 152 this.document.edits.push(new WebInspector.SourceEdit(this.document.url,
this.range, newText)); | 149 |
| 153 }, | 150 /** |
| 154 | 151 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 155 /** | 152 * @return {!WebInspector.SASSSupport.TextNode} |
| 156 * @param {!WebInspector.SASSSupport.ASTDocument} document | 153 */ |
| 157 * @return {!WebInspector.SASSSupport.TextNode} | 154 clone(document) { |
| 158 */ | 155 return new WebInspector.SASSSupport.TextNode(document, this.text, this.range
.clone()); |
| 159 clone: function(document) | 156 } |
| 160 { | 157 |
| 161 return new WebInspector.SASSSupport.TextNode(document, this.text, this.r
ange.clone()); | 158 /** |
| 162 }, | 159 * @param {!WebInspector.SASSSupport.TextNode} other |
| 163 | 160 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node
>=} outNodeMapping |
| 164 /** | 161 * @return {boolean} |
| 165 * @param {!WebInspector.SASSSupport.TextNode} other | 162 */ |
| 166 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.No
de>=} outNodeMapping | 163 match(other, outNodeMapping) { |
| 167 * @return {boolean} | 164 if (this.text.trim() !== other.text.trim()) |
| 168 */ | 165 return false; |
| 169 match: function(other, outNodeMapping) | 166 if (outNodeMapping) |
| 170 { | 167 outNodeMapping.set(this, other); |
| 171 if (this.text.trim() !== other.text.trim()) | 168 return true; |
| 172 return false; | 169 } |
| 173 if (outNodeMapping) | 170 }; |
| 174 outNodeMapping.set(this, other); | 171 |
| 175 return true; | 172 /** |
| 176 }, | 173 * @unrestricted |
| 177 | 174 */ |
| 178 __proto__: WebInspector.SASSSupport.Node.prototype | 175 WebInspector.SASSSupport.Property = class extends WebInspector.SASSSupport.Node
{ |
| 179 }; | 176 /** |
| 180 | 177 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 181 /** | 178 * @param {!WebInspector.SASSSupport.TextNode} name |
| 182 * @constructor | 179 * @param {!WebInspector.SASSSupport.TextNode} value |
| 183 * @extends {WebInspector.SASSSupport.Node} | 180 * @param {!WebInspector.TextRange} range |
| 184 * @param {!WebInspector.SASSSupport.ASTDocument} document | 181 * @param {boolean} disabled |
| 185 * @param {!WebInspector.SASSSupport.TextNode} name | 182 */ |
| 186 * @param {!WebInspector.SASSSupport.TextNode} value | 183 constructor(document, name, value, range, disabled) { |
| 187 * @param {!WebInspector.TextRange} range | 184 super(document); |
| 188 * @param {boolean} disabled | |
| 189 */ | |
| 190 WebInspector.SASSSupport.Property = function(document, name, value, range, disab
led) | |
| 191 { | |
| 192 WebInspector.SASSSupport.Node.call(this, document); | |
| 193 this.name = name; | 185 this.name = name; |
| 194 this.value = value; | 186 this.value = value; |
| 195 this.range = range; | 187 this.range = range; |
| 196 this.name.parent = this; | 188 this.name.parent = this; |
| 197 this.value.parent = this; | 189 this.value.parent = this; |
| 198 this.disabled = disabled; | 190 this.disabled = disabled; |
| 199 }; | 191 } |
| 200 | 192 |
| 201 WebInspector.SASSSupport.Property.prototype = { | 193 /** |
| 202 /** | 194 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 203 * @param {!WebInspector.SASSSupport.ASTDocument} document | 195 * @return {!WebInspector.SASSSupport.Property} |
| 204 * @return {!WebInspector.SASSSupport.Property} | 196 */ |
| 205 */ | 197 clone(document) { |
| 206 clone: function(document) | 198 return new WebInspector.SASSSupport.Property( |
| 207 { | 199 document, this.name.clone(document), this.value.clone(document), this.ra
nge.clone(), this.disabled); |
| 208 return new WebInspector.SASSSupport.Property(document, this.name.clone(d
ocument), this.value.clone(document), this.range.clone(), this.disabled); | 200 } |
| 209 }, | 201 |
| 210 | 202 /** |
| 211 /** | 203 * @param {function(!WebInspector.SASSSupport.Node)} callback |
| 212 * @param {function(!WebInspector.SASSSupport.Node)} callback | 204 */ |
| 213 */ | 205 visit(callback) { |
| 214 visit: function(callback) | 206 callback(this); |
| 215 { | 207 callback(this.name); |
| 216 callback(this); | 208 callback(this.value); |
| 217 callback(this.name); | 209 } |
| 218 callback(this.value); | 210 |
| 219 }, | 211 /** |
| 220 | 212 * @param {!WebInspector.SASSSupport.Property} other |
| 221 /** | 213 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node
>=} outNodeMapping |
| 222 * @param {!WebInspector.SASSSupport.Property} other | 214 * @return {boolean} |
| 223 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.No
de>=} outNodeMapping | 215 */ |
| 224 * @return {boolean} | 216 match(other, outNodeMapping) { |
| 225 */ | 217 if (this.disabled !== other.disabled) |
| 226 match: function(other, outNodeMapping) | 218 return false; |
| 227 { | 219 if (outNodeMapping) |
| 228 if (this.disabled !== other.disabled) | 220 outNodeMapping.set(this, other); |
| 229 return false; | 221 return this.name.match(other.name, outNodeMapping) && this.value.match(other
.value, outNodeMapping); |
| 230 if (outNodeMapping) | 222 } |
| 231 outNodeMapping.set(this, other); | 223 |
| 232 return this.name.match(other.name, outNodeMapping) && this.value.match(o
ther.value, outNodeMapping); | 224 /** |
| 233 }, | 225 * @param {boolean} disabled |
| 234 | 226 */ |
| 235 /** | 227 setDisabled(disabled) { |
| 236 * @param {boolean} disabled | 228 if (this.disabled === disabled) |
| 237 */ | 229 return; |
| 238 setDisabled: function(disabled) | 230 this.disabled = disabled; |
| 239 { | 231 if (disabled) { |
| 240 if (this.disabled === disabled) | 232 var oldRange1 = WebInspector.TextRange.createFromLocation(this.range.start
Line, this.range.startColumn); |
| 241 return; | 233 var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1, '/*
'); |
| 242 this.disabled = disabled; | 234 var oldRange2 = WebInspector.TextRange.createFromLocation(this.range.endLi
ne, this.range.endColumn); |
| 243 if (disabled) { | 235 var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2, ' */
'); |
| 244 var oldRange1 = WebInspector.TextRange.createFromLocation(this.range
.startLine, this.range.startColumn); | 236 this.document.edits.push(edit1, edit2); |
| 245 var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1
, "/* "); | 237 return; |
| 246 var oldRange2 = WebInspector.TextRange.createFromLocation(this.range
.endLine, this.range.endColumn); | 238 } |
| 247 var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2
, " */"); | 239 var oldRange1 = new WebInspector.TextRange( |
| 248 this.document.edits.push(edit1, edit2); | 240 this.range.startLine, this.range.startColumn, this.range.startLine, this
.name.range.startColumn); |
| 249 return; | 241 var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1, ''); |
| 250 } | 242 |
| 251 var oldRange1 = new WebInspector.TextRange(this.range.startLine, this.ra
nge.startColumn, this.range.startLine, this.name.range.startColumn); | 243 var propertyText = this.document.text.extract(this.range); |
| 252 var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1, ""
); | 244 var endsWithSemicolon = propertyText.slice(0, -2).trim().endsWith(';'); |
| 253 | 245 var oldRange2 = new WebInspector.TextRange( |
| 254 var propertyText = this.document.text.extract(this.range); | 246 this.range.endLine, this.value.range.endColumn + (endsWithSemicolon ? 1
: 0), this.range.endLine, |
| 255 var endsWithSemicolon = propertyText.slice(0, -2).trim().endsWith(";"); | 247 this.range.endColumn); |
| 256 var oldRange2 = new WebInspector.TextRange(this.range.endLine, this.valu
e.range.endColumn + (endsWithSemicolon ? 1 : 0), this.range.endLine, this.range.
endColumn); | 248 var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2, ''); |
| 257 var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2, ""
); | 249 this.document.edits.push(edit1, edit2); |
| 258 this.document.edits.push(edit1, edit2); | 250 } |
| 259 }, | 251 |
| 260 | 252 remove() { |
| 261 remove: function() | 253 console.assert(this.parent); |
| 262 { | 254 var rule = this.parent; |
| 263 console.assert(this.parent); | 255 var index = rule.properties.indexOf(this); |
| 264 var rule = this.parent; | 256 rule.properties.splice(index, 1); |
| 265 var index = rule.properties.indexOf(this); | 257 this.parent = null; |
| 266 rule.properties.splice(index, 1); | 258 |
| 267 this.parent = null; | 259 var lineRange = new WebInspector.TextRange(this.range.startLine, 0, this.ran
ge.endLine + 1, 0); |
| 268 | 260 var oldRange; |
| 269 var lineRange = new WebInspector.TextRange(this.range.startLine, 0, this
.range.endLine + 1, 0); | 261 if (this.document.text.extract(lineRange).trim() === this.document.text.extr
act(this.range).trim()) |
| 270 var oldRange; | 262 oldRange = lineRange; |
| 271 if (this.document.text.extract(lineRange).trim() === this.document.text.
extract(this.range).trim()) | 263 else |
| 272 oldRange = lineRange; | 264 oldRange = this.range; |
| 273 else | 265 this.document.edits.push(new WebInspector.SourceEdit(this.document.url, oldR
ange, '')); |
| 274 oldRange = this.range; | 266 } |
| 275 this.document.edits.push(new WebInspector.SourceEdit(this.document.url,
oldRange, "")); | 267 }; |
| 276 }, | 268 |
| 277 | 269 /** |
| 278 __proto__: WebInspector.SASSSupport.Node.prototype | 270 * @unrestricted |
| 279 }; | 271 */ |
| 280 | 272 WebInspector.SASSSupport.Rule = class extends WebInspector.SASSSupport.Node { |
| 281 /** | 273 /** |
| 282 * @constructor | 274 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 283 * @extends {WebInspector.SASSSupport.Node} | 275 * @param {!Array<!WebInspector.SASSSupport.TextNode>} selectors |
| 284 * @param {!WebInspector.SASSSupport.ASTDocument} document | 276 * @param {!WebInspector.TextRange} styleRange |
| 285 * @param {!Array<!WebInspector.SASSSupport.TextNode>} selectors | 277 * @param {!Array<!WebInspector.SASSSupport.Property>} properties |
| 286 * @param {!WebInspector.TextRange} styleRange | 278 */ |
| 287 * @param {!Array<!WebInspector.SASSSupport.Property>} properties | 279 constructor(document, selectors, styleRange, properties) { |
| 288 */ | 280 super(document); |
| 289 WebInspector.SASSSupport.Rule = function(document, selectors, styleRange, proper
ties) | |
| 290 { | |
| 291 WebInspector.SASSSupport.Node.call(this, document); | |
| 292 this.selectors = selectors; | 281 this.selectors = selectors; |
| 293 this.properties = properties; | 282 this.properties = properties; |
| 294 this.styleRange = styleRange; | 283 this.styleRange = styleRange; |
| 295 | 284 |
| 296 var blockStartRange = styleRange.collapseToStart(); | 285 var blockStartRange = styleRange.collapseToStart(); |
| 297 blockStartRange.startColumn -= 1; | 286 blockStartRange.startColumn -= 1; |
| 298 this.blockStart = new WebInspector.SASSSupport.TextNode(document, this.docum
ent.text.extract(blockStartRange), blockStartRange); | 287 this.blockStart = |
| 288 new WebInspector.SASSSupport.TextNode(document, this.document.text.extra
ct(blockStartRange), blockStartRange); |
| 299 this.blockStart.parent = this; | 289 this.blockStart.parent = this; |
| 300 | 290 |
| 301 for (var i = 0; i < this.properties.length; ++i) | 291 for (var i = 0; i < this.properties.length; ++i) |
| 302 this.properties[i].parent = this; | 292 this.properties[i].parent = this; |
| 303 | 293 |
| 304 this._hasTrailingSemicolon = !this.properties.length || this.document.text.e
xtract(this.properties.peekLast().range).endsWith(";"); | 294 this._hasTrailingSemicolon = |
| 305 }; | 295 !this.properties.length || this.document.text.extract(this.properties.pe
ekLast().range).endsWith(';'); |
| 306 | 296 } |
| 307 WebInspector.SASSSupport.Rule.prototype = { | 297 |
| 308 /** | 298 /** |
| 309 * @param {!WebInspector.SASSSupport.ASTDocument} document | 299 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 310 * @return {!WebInspector.SASSSupport.Rule} | 300 * @return {!WebInspector.SASSSupport.Rule} |
| 311 */ | 301 */ |
| 312 clone: function(document) | 302 clone(document) { |
| 313 { | 303 var properties = []; |
| 314 var properties = []; | 304 for (var i = 0; i < this.properties.length; ++i) |
| 315 for (var i = 0; i < this.properties.length; ++i) | 305 properties.push(this.properties[i].clone(document)); |
| 316 properties.push(this.properties[i].clone(document)); | 306 var selectors = []; |
| 317 var selectors = []; | 307 for (var i = 0; i < this.selectors.length; ++i) |
| 318 for (var i = 0; i < this.selectors.length; ++i) | 308 selectors.push(this.selectors[i].clone(document)); |
| 319 selectors.push(this.selectors[i].clone(document)); | 309 return new WebInspector.SASSSupport.Rule(document, selectors, this.styleRang
e.clone(), properties); |
| 320 return new WebInspector.SASSSupport.Rule(document, selectors, this.style
Range.clone(), properties); | 310 } |
| 321 }, | 311 |
| 322 | 312 /** |
| 323 /** | 313 * @param {function(!WebInspector.SASSSupport.Node)} callback |
| 324 * @param {function(!WebInspector.SASSSupport.Node)} callback | 314 */ |
| 325 */ | 315 visit(callback) { |
| 326 visit: function(callback) | 316 callback(this); |
| 327 { | 317 for (var i = 0; i < this.selectors.length; ++i) |
| 328 callback(this); | 318 callback(this.selectors[i]); |
| 329 for (var i = 0; i < this.selectors.length; ++i) | 319 callback(this.blockStart); |
| 330 callback(this.selectors[i]); | 320 for (var i = 0; i < this.properties.length; ++i) |
| 331 callback(this.blockStart); | 321 this.properties[i].visit(callback); |
| 332 for (var i = 0; i < this.properties.length; ++i) | 322 } |
| 333 this.properties[i].visit(callback); | 323 |
| 334 }, | 324 /** |
| 335 | 325 * @param {!WebInspector.SASSSupport.Rule} other |
| 336 /** | 326 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node
>=} outNodeMapping |
| 337 * @param {!WebInspector.SASSSupport.Rule} other | 327 * @return {boolean} |
| 338 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.No
de>=} outNodeMapping | 328 */ |
| 339 * @return {boolean} | 329 match(other, outNodeMapping) { |
| 340 */ | 330 if (this.selectors.length !== other.selectors.length) |
| 341 match: function(other, outNodeMapping) | 331 return false; |
| 342 { | 332 if (this.properties.length !== other.properties.length) |
| 343 if (this.selectors.length !== other.selectors.length) | 333 return false; |
| 344 return false; | 334 if (outNodeMapping) |
| 345 if (this.properties.length !== other.properties.length) | 335 outNodeMapping.set(this, other); |
| 346 return false; | 336 var result = this.blockStart.match(other.blockStart, outNodeMapping); |
| 347 if (outNodeMapping) | 337 for (var i = 0; result && i < this.selectors.length; ++i) |
| 348 outNodeMapping.set(this, other); | 338 result = result && this.selectors[i].match(other.selectors[i], outNodeMapp
ing); |
| 349 var result = this.blockStart.match(other.blockStart, outNodeMapping); | 339 for (var i = 0; result && i < this.properties.length; ++i) |
| 350 for (var i = 0; result && i < this.selectors.length; ++i) | 340 result = result && this.properties[i].match(other.properties[i], outNodeMa
pping); |
| 351 result = result && this.selectors[i].match(other.selectors[i], outNo
deMapping); | 341 return result; |
| 352 for (var i = 0; result && i < this.properties.length; ++i) | 342 } |
| 353 result = result && this.properties[i].match(other.properties[i], out
NodeMapping); | 343 |
| 354 return result; | 344 _addTrailingSemicolon() { |
| 355 }, | 345 if (this._hasTrailingSemicolon || !this.properties) |
| 356 | 346 return; |
| 357 _addTrailingSemicolon: function() | 347 this._hasTrailingSemicolon = true; |
| 358 { | 348 this.document.edits.push( |
| 359 if (this._hasTrailingSemicolon || !this.properties) | 349 new WebInspector.SourceEdit(this.document.url, this.properties.peekLast(
).range.collapseToEnd(), ';')); |
| 360 return; | 350 } |
| 361 this._hasTrailingSemicolon = true; | 351 |
| 362 this.document.edits.push(new WebInspector.SourceEdit(this.document.url,
this.properties.peekLast().range.collapseToEnd(), ";")); | 352 /** |
| 363 }, | 353 * @param {?WebInspector.SASSSupport.Property} anchorProperty |
| 364 | 354 * @param {!Array<string>} nameTexts |
| 365 /** | 355 * @param {!Array<string>} valueTexts |
| 366 * @param {?WebInspector.SASSSupport.Property} anchorProperty | 356 * @param {!Array<boolean>} disabledStates |
| 367 * @param {!Array<string>} nameTexts | 357 * @return {!Array<!WebInspector.SASSSupport.Property>} |
| 368 * @param {!Array<string>} valueTexts | 358 */ |
| 369 * @param {!Array<boolean>} disabledStates | 359 insertProperties(anchorProperty, nameTexts, valueTexts, disabledStates) { |
| 370 * @return {!Array<!WebInspector.SASSSupport.Property>} | 360 console.assert( |
| 371 */ | 361 nameTexts.length === valueTexts.length && valueTexts.length === disabled
States.length, |
| 372 insertProperties: function(anchorProperty, nameTexts, valueTexts, disabledSt
ates) | 362 'Input array should be of the same size.'); |
| 373 { | 363 |
| 374 console.assert(nameTexts.length === valueTexts.length && valueTexts.leng
th === disabledStates.length, "Input array should be of the same size."); | 364 this._addTrailingSemicolon(); |
| 375 | 365 var newProperties = []; |
| 376 this._addTrailingSemicolon(); | 366 var index = anchorProperty ? this.properties.indexOf(anchorProperty) : -1; |
| 377 var newProperties = []; | 367 for (var i = 0; i < nameTexts.length; ++i) { |
| 378 var index = anchorProperty ? this.properties.indexOf(anchorProperty) : -
1; | 368 var nameText = nameTexts[i]; |
| 379 for (var i = 0; i < nameTexts.length; ++i) { | 369 var valueText = valueTexts[i]; |
| 380 var nameText = nameTexts[i]; | 370 var disabled = disabledStates[i]; |
| 381 var valueText = valueTexts[i]; | 371 this.document.edits.push(this._insertPropertyEdit(anchorProperty, nameText
, valueText, disabled)); |
| 382 var disabled = disabledStates[i]; | 372 |
| 383 this.document.edits.push(this._insertPropertyEdit(anchorProperty, na
meText, valueText, disabled)); | 373 var name = new WebInspector.SASSSupport.TextNode( |
| 384 | 374 this.document, nameText, WebInspector.TextRange.createFromLocation(0,
0)); |
| 385 var name = new WebInspector.SASSSupport.TextNode(this.document, name
Text, WebInspector.TextRange.createFromLocation(0, 0)); | 375 var value = new WebInspector.SASSSupport.TextNode( |
| 386 var value = new WebInspector.SASSSupport.TextNode(this.document, val
ueText, WebInspector.TextRange.createFromLocation(0, 0)); | 376 this.document, valueText, WebInspector.TextRange.createFromLocation(0,
0)); |
| 387 var newProperty = new WebInspector.SASSSupport.Property(this.documen
t, name, value, WebInspector.TextRange.createFromLocation(0, 0), disabled); | 377 var newProperty = new WebInspector.SASSSupport.Property( |
| 388 | 378 this.document, name, value, WebInspector.TextRange.createFromLocation(
0, 0), disabled); |
| 389 this.properties.splice(index + i + 1, 0, newProperty); | 379 |
| 390 newProperty.parent = this; | 380 this.properties.splice(index + i + 1, 0, newProperty); |
| 391 newProperties.push(newProperty); | 381 newProperty.parent = this; |
| 392 } | 382 newProperties.push(newProperty); |
| 393 return newProperties; | 383 } |
| 394 }, | 384 return newProperties; |
| 395 | 385 } |
| 396 /** | 386 |
| 397 * @param {?WebInspector.SASSSupport.Property} anchorProperty | 387 /** |
| 398 * @param {string} nameText | 388 * @param {?WebInspector.SASSSupport.Property} anchorProperty |
| 399 * @param {string} valueText | 389 * @param {string} nameText |
| 400 * @param {boolean} disabled | 390 * @param {string} valueText |
| 401 * @return {!WebInspector.SourceEdit} | 391 * @param {boolean} disabled |
| 402 */ | 392 * @return {!WebInspector.SourceEdit} |
| 403 _insertPropertyEdit: function(anchorProperty, nameText, valueText, disabled) | 393 */ |
| 404 { | 394 _insertPropertyEdit(anchorProperty, nameText, valueText, disabled) { |
| 405 var anchorRange = anchorProperty ? anchorProperty.range : this.blockStar
t.range; | 395 var anchorRange = anchorProperty ? anchorProperty.range : this.blockStart.ra
nge; |
| 406 var indent = this._computePropertyIndent(); | 396 var indent = this._computePropertyIndent(); |
| 407 var leftComment = disabled ? "/* " : ""; | 397 var leftComment = disabled ? '/* ' : ''; |
| 408 var rightComment = disabled ? " */" : ""; | 398 var rightComment = disabled ? ' */' : ''; |
| 409 var newText = String.sprintf("\n%s%s%s: %s;%s", indent, leftComment, nam
eText, valueText, rightComment); | 399 var newText = String.sprintf('\n%s%s%s: %s;%s', indent, leftComment, nameTex
t, valueText, rightComment); |
| 410 return new WebInspector.SourceEdit(this.document.url, anchorRange.collap
seToEnd(), newText); | 400 return new WebInspector.SourceEdit(this.document.url, anchorRange.collapseTo
End(), newText); |
| 411 }, | 401 } |
| 412 | 402 |
| 413 /** | 403 /** |
| 414 * @return {string} | 404 * @return {string} |
| 415 */ | 405 */ |
| 416 _computePropertyIndent: function() | 406 _computePropertyIndent() { |
| 417 { | 407 var indentProperty = this.properties.find(property => !property.range.isEmpt
y()); |
| 418 var indentProperty = this.properties.find(property => !property.range.is
Empty()); | 408 var result = ''; |
| 419 var result = ""; | 409 if (indentProperty) { |
| 420 if (indentProperty) { | 410 result = this.document.text.extract(new WebInspector.TextRange( |
| 421 result = this.document.text.extract(new WebInspector.TextRange(inden
tProperty.range.startLine, 0, indentProperty.range.startLine, indentProperty.ran
ge.startColumn)); | 411 indentProperty.range.startLine, 0, indentProperty.range.startLine, ind
entProperty.range.startColumn)); |
| 422 } else { | 412 } else { |
| 423 var lineNumber = this.blockStart.range.startLine; | 413 var lineNumber = this.blockStart.range.startLine; |
| 424 var columnNumber = this.blockStart.range.startColumn; | 414 var columnNumber = this.blockStart.range.startColumn; |
| 425 var baseLine = this.document.text.extract(new WebInspector.TextRange
(lineNumber, 0, lineNumber, columnNumber)); | 415 var baseLine = this.document.text.extract(new WebInspector.TextRange(lineN
umber, 0, lineNumber, columnNumber)); |
| 426 result = WebInspector.TextUtils.lineIndent(baseLine) + WebInspector.
moduleSetting("textEditorIndent").get(); | 416 result = WebInspector.TextUtils.lineIndent(baseLine) + WebInspector.module
Setting('textEditorIndent').get(); |
| 427 } | 417 } |
| 428 return result.isWhitespace() ? result : ""; | 418 return result.isWhitespace() ? result : ''; |
| 429 }, | 419 } |
| 430 | 420 }; |
| 431 __proto__: WebInspector.SASSSupport.Node.prototype | 421 |
| 432 }; | 422 /** |
| 433 | 423 * @unrestricted |
| 434 /** | 424 */ |
| 435 * @constructor | 425 WebInspector.SASSSupport.AST = class extends WebInspector.SASSSupport.Node { |
| 436 * @extends {WebInspector.SASSSupport.Node} | 426 /** |
| 437 * @param {!WebInspector.SASSSupport.ASTDocument} document | 427 * @param {!WebInspector.SASSSupport.ASTDocument} document |
| 438 * @param {!Array<!WebInspector.SASSSupport.Rule>} rules | 428 * @param {!Array<!WebInspector.SASSSupport.Rule>} rules |
| 439 */ | 429 */ |
| 440 WebInspector.SASSSupport.AST = function(document, rules) | 430 constructor(document, rules) { |
| 441 { | 431 super(document); |
| 442 WebInspector.SASSSupport.Node.call(this, document); | |
| 443 this.rules = rules; | 432 this.rules = rules; |
| 444 for (var i = 0; i < rules.length; ++i) | 433 for (var i = 0; i < rules.length; ++i) |
| 445 rules[i].parent = this; | 434 rules[i].parent = this; |
| 446 }; | 435 } |
| 447 | 436 |
| 448 WebInspector.SASSSupport.AST.prototype = { | 437 /** |
| 438 * @return {!WebInspector.SASSSupport.AST} |
| 439 */ |
| 440 clone() { |
| 441 var document = this.document.clone(); |
| 442 var rules = []; |
| 443 for (var i = 0; i < this.rules.length; ++i) |
| 444 rules.push(this.rules[i].clone(document)); |
| 445 return new WebInspector.SASSSupport.AST(document, rules); |
| 446 } |
| 447 |
| 448 /** |
| 449 * @param {!WebInspector.SASSSupport.AST} other |
| 450 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node
>=} outNodeMapping |
| 451 * @return {boolean} |
| 452 */ |
| 453 match(other, outNodeMapping) { |
| 454 if (other.document.url !== this.document.url) |
| 455 return false; |
| 456 if (other.rules.length !== this.rules.length) |
| 457 return false; |
| 458 if (outNodeMapping) |
| 459 outNodeMapping.set(this, other); |
| 460 var result = true; |
| 461 for (var i = 0; result && i < this.rules.length; ++i) |
| 462 result = result && this.rules[i].match(other.rules[i], outNodeMapping); |
| 463 return result; |
| 464 } |
| 465 |
| 466 /** |
| 467 * @param {function(!WebInspector.SASSSupport.Node)} callback |
| 468 */ |
| 469 visit(callback) { |
| 470 callback(this); |
| 471 for (var i = 0; i < this.rules.length; ++i) |
| 472 this.rules[i].visit(callback); |
| 473 } |
| 474 |
| 475 /** |
| 476 * @param {number} lineNumber |
| 477 * @param {number} columnNumber |
| 478 * @return {?WebInspector.SASSSupport.TextNode} |
| 479 */ |
| 480 findNodeForPosition(lineNumber, columnNumber) { |
| 481 this._ensureNodePositionsIndex(); |
| 482 var index = this._sortedTextNodes.lowerBound({lineNumber: lineNumber, column
Number: columnNumber}, nodeComparator); |
| 483 var node = this._sortedTextNodes[index]; |
| 484 if (!node) |
| 485 return null; |
| 486 return node.range.containsLocation(lineNumber, columnNumber) ? node : null; |
| 487 |
| 449 /** | 488 /** |
| 450 * @return {!WebInspector.SASSSupport.AST} | 489 * @param {!{lineNumber: number, columnNumber: number}} position |
| 490 * @param {!WebInspector.SASSSupport.TextNode} textNode |
| 491 * @return {number} |
| 451 */ | 492 */ |
| 452 clone: function() | 493 function nodeComparator(position, textNode) { |
| 453 { | 494 return textNode.range.compareToPosition(position.lineNumber, position.colu
mnNumber); |
| 454 var document = this.document.clone(); | 495 } |
| 455 var rules = []; | 496 } |
| 456 for (var i = 0; i < this.rules.length; ++i) | 497 |
| 457 rules.push(this.rules[i].clone(document)); | 498 _ensureNodePositionsIndex() { |
| 458 return new WebInspector.SASSSupport.AST(document, rules); | 499 if (this._sortedTextNodes) |
| 459 }, | 500 return; |
| 501 this._sortedTextNodes = []; |
| 502 this.visit(onNode.bind(this)); |
| 503 this._sortedTextNodes.sort(nodeComparator); |
| 460 | 504 |
| 461 /** | 505 /** |
| 462 * @param {!WebInspector.SASSSupport.AST} other | 506 * @param {!WebInspector.SASSSupport.Node} node |
| 463 * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.No
de>=} outNodeMapping | 507 * @this {WebInspector.SASSSupport.AST} |
| 464 * @return {boolean} | |
| 465 */ | 508 */ |
| 466 match: function(other, outNodeMapping) | 509 function onNode(node) { |
| 467 { | 510 if (!(node instanceof WebInspector.SASSSupport.TextNode)) |
| 468 if (other.document.url !== this.document.url) | 511 return; |
| 469 return false; | 512 this._sortedTextNodes.push(node); |
| 470 if (other.rules.length !== this.rules.length) | 513 } |
| 471 return false; | |
| 472 if (outNodeMapping) | |
| 473 outNodeMapping.set(this, other); | |
| 474 var result = true; | |
| 475 for (var i = 0; result && i < this.rules.length; ++i) | |
| 476 result = result && this.rules[i].match(other.rules[i], outNodeMappin
g); | |
| 477 return result; | |
| 478 }, | |
| 479 | 514 |
| 480 /** | 515 /** |
| 481 * @param {function(!WebInspector.SASSSupport.Node)} callback | 516 * @param {!WebInspector.SASSSupport.TextNode} text1 |
| 517 * @param {!WebInspector.SASSSupport.TextNode} text2 |
| 518 * @return {number} |
| 482 */ | 519 */ |
| 483 visit: function(callback) | 520 function nodeComparator(text1, text2) { |
| 484 { | 521 return WebInspector.TextRange.comparator(text1.range, text2.range); |
| 485 callback(this); | 522 } |
| 486 for (var i = 0; i < this.rules.length; ++i) | 523 } |
| 487 this.rules[i].visit(callback); | |
| 488 }, | |
| 489 | |
| 490 /** | |
| 491 * @param {number} lineNumber | |
| 492 * @param {number} columnNumber | |
| 493 * @return {?WebInspector.SASSSupport.TextNode} | |
| 494 */ | |
| 495 findNodeForPosition: function(lineNumber, columnNumber) | |
| 496 { | |
| 497 this._ensureNodePositionsIndex(); | |
| 498 var index = this._sortedTextNodes.lowerBound({lineNumber: lineNumber, co
lumnNumber: columnNumber}, nodeComparator); | |
| 499 var node = this._sortedTextNodes[index]; | |
| 500 if (!node) | |
| 501 return null; | |
| 502 return node.range.containsLocation(lineNumber, columnNumber) ? node : nu
ll; | |
| 503 | |
| 504 /** | |
| 505 * @param {!{lineNumber: number, columnNumber: number}} position | |
| 506 * @param {!WebInspector.SASSSupport.TextNode} textNode | |
| 507 * @return {number} | |
| 508 */ | |
| 509 function nodeComparator(position, textNode) | |
| 510 { | |
| 511 return textNode.range.compareToPosition(position.lineNumber, positio
n.columnNumber); | |
| 512 } | |
| 513 }, | |
| 514 | |
| 515 _ensureNodePositionsIndex: function() | |
| 516 { | |
| 517 if (this._sortedTextNodes) | |
| 518 return; | |
| 519 this._sortedTextNodes = []; | |
| 520 this.visit(onNode.bind(this)); | |
| 521 this._sortedTextNodes.sort(nodeComparator); | |
| 522 | |
| 523 /** | |
| 524 * @param {!WebInspector.SASSSupport.Node} node | |
| 525 * @this {WebInspector.SASSSupport.AST} | |
| 526 */ | |
| 527 function onNode(node) | |
| 528 { | |
| 529 if (!(node instanceof WebInspector.SASSSupport.TextNode)) | |
| 530 return; | |
| 531 this._sortedTextNodes.push(node); | |
| 532 } | |
| 533 | |
| 534 /** | |
| 535 * @param {!WebInspector.SASSSupport.TextNode} text1 | |
| 536 * @param {!WebInspector.SASSSupport.TextNode} text2 | |
| 537 * @return {number} | |
| 538 */ | |
| 539 function nodeComparator(text1, text2) | |
| 540 { | |
| 541 return WebInspector.TextRange.comparator(text1.range, text2.range); | |
| 542 } | |
| 543 }, | |
| 544 | |
| 545 __proto__: WebInspector.SASSSupport.Node.prototype | |
| 546 }; | 524 }; |
| 547 | 525 |
| 548 /** @enum {string} */ | 526 /** @enum {string} */ |
| 549 WebInspector.SASSSupport.PropertyChangeType = { | 527 WebInspector.SASSSupport.PropertyChangeType = { |
| 550 PropertyAdded: "PropertyAdded", | 528 PropertyAdded: 'PropertyAdded', |
| 551 PropertyRemoved: "PropertyRemoved", | 529 PropertyRemoved: 'PropertyRemoved', |
| 552 PropertyToggled: "PropertyToggled", | 530 PropertyToggled: 'PropertyToggled', |
| 553 ValueChanged: "ValueChanged", | 531 ValueChanged: 'ValueChanged', |
| 554 NameChanged: "NameChanged" | 532 NameChanged: 'NameChanged' |
| 555 }; | 533 }; |
| 556 | 534 |
| 557 /** | 535 /** |
| 558 * @constructor | 536 * @unrestricted |
| 559 * @param {!WebInspector.SASSSupport.PropertyChangeType} type | 537 */ |
| 560 * @param {!WebInspector.SASSSupport.Rule} oldRule | 538 WebInspector.SASSSupport.PropertyChange = class { |
| 561 * @param {!WebInspector.SASSSupport.Rule} newRule | 539 /** |
| 562 * @param {number} oldPropertyIndex | 540 * @param {!WebInspector.SASSSupport.PropertyChangeType} type |
| 563 * @param {number} newPropertyIndex | 541 * @param {!WebInspector.SASSSupport.Rule} oldRule |
| 564 */ | 542 * @param {!WebInspector.SASSSupport.Rule} newRule |
| 565 WebInspector.SASSSupport.PropertyChange = function(type, oldRule, newRule, oldPr
opertyIndex, newPropertyIndex) | 543 * @param {number} oldPropertyIndex |
| 566 { | 544 * @param {number} newPropertyIndex |
| 545 */ |
| 546 constructor(type, oldRule, newRule, oldPropertyIndex, newPropertyIndex) { |
| 567 this.type = type; | 547 this.type = type; |
| 568 this.oldRule = oldRule; | 548 this.oldRule = oldRule; |
| 569 this.newRule = newRule; | 549 this.newRule = newRule; |
| 570 this.oldPropertyIndex = oldPropertyIndex; | 550 this.oldPropertyIndex = oldPropertyIndex; |
| 571 this.newPropertyIndex = newPropertyIndex; | 551 this.newPropertyIndex = newPropertyIndex; |
| 572 }; | 552 } |
| 573 | 553 |
| 574 WebInspector.SASSSupport.PropertyChange.prototype = { | 554 /** |
| 575 /** | 555 * @return {?WebInspector.SASSSupport.Property} |
| 576 * @return {?WebInspector.SASSSupport.Property} | 556 */ |
| 577 */ | 557 oldProperty() { |
| 578 oldProperty: function() | 558 return this.oldRule.properties[this.oldPropertyIndex] || null; |
| 579 { | 559 } |
| 580 return this.oldRule.properties[this.oldPropertyIndex] || null; | 560 |
| 581 }, | 561 /** |
| 582 | 562 * @return {?WebInspector.SASSSupport.Property} |
| 583 /** | 563 */ |
| 584 * @return {?WebInspector.SASSSupport.Property} | 564 newProperty() { |
| 585 */ | 565 return this.newRule.properties[this.newPropertyIndex] || null; |
| 586 newProperty: function() | 566 } |
| 587 { | 567 }; |
| 588 return this.newRule.properties[this.newPropertyIndex] || null; | 568 |
| 589 } | 569 /** |
| 590 }; | 570 * @unrestricted |
| 591 | 571 */ |
| 592 /** | 572 WebInspector.SASSSupport.ASTDiff = class { |
| 593 * @constructor | 573 /** |
| 594 * @param {string} url | 574 * @param {string} url |
| 595 * @param {!WebInspector.SASSSupport.AST} oldAST | 575 * @param {!WebInspector.SASSSupport.AST} oldAST |
| 596 * @param {!WebInspector.SASSSupport.AST} newAST | 576 * @param {!WebInspector.SASSSupport.AST} newAST |
| 597 * @param {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSupport.Te
xtNode>} mapping | 577 * @param {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSupport.
TextNode>} mapping |
| 598 * @param {!Array<!WebInspector.SASSSupport.PropertyChange>} changes | 578 * @param {!Array<!WebInspector.SASSSupport.PropertyChange>} changes |
| 599 */ | 579 */ |
| 600 WebInspector.SASSSupport.ASTDiff = function(url, oldAST, newAST, mapping, change
s) | 580 constructor(url, oldAST, newAST, mapping, changes) { |
| 601 { | |
| 602 this.url = url; | 581 this.url = url; |
| 603 this.mapping = mapping; | 582 this.mapping = mapping; |
| 604 this.changes = changes; | 583 this.changes = changes; |
| 605 this.oldAST = oldAST; | 584 this.oldAST = oldAST; |
| 606 this.newAST = newAST; | 585 this.newAST = newAST; |
| 607 }; | 586 } |
| 608 | 587 }; |
| 609 /** | 588 |
| 589 /** |
| 610 * @param {!WebInspector.SASSSupport.AST} oldAST | 590 * @param {!WebInspector.SASSSupport.AST} oldAST |
| 611 * @param {!WebInspector.SASSSupport.AST} newAST | 591 * @param {!WebInspector.SASSSupport.AST} newAST |
| 612 * @return {!WebInspector.SASSSupport.ASTDiff} | 592 * @return {!WebInspector.SASSSupport.ASTDiff} |
| 613 */ | 593 */ |
| 614 WebInspector.SASSSupport.diffModels = function(oldAST, newAST) | 594 WebInspector.SASSSupport.diffModels = function(oldAST, newAST) { |
| 615 { | 595 console.assert(oldAST.rules.length === newAST.rules.length, 'Not implemented f
or rule diff.'); |
| 616 console.assert(oldAST.rules.length === newAST.rules.length, "Not implemented
for rule diff."); | 596 console.assert(oldAST.document.url === newAST.document.url, 'Diff makes sense
for models with the same url.'); |
| 617 console.assert(oldAST.document.url === newAST.document.url, "Diff makes sens
e for models with the same url."); | 597 var T = WebInspector.SASSSupport.PropertyChangeType; |
| 618 var T = WebInspector.SASSSupport.PropertyChangeType; | 598 var changes = []; |
| 619 var changes = []; | 599 /** @type {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSupport.
TextNode>} */ |
| 620 /** @type {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSuppor
t.TextNode>} */ | 600 var mapping = new Map(); |
| 621 var mapping = new Map(); | 601 for (var i = 0; i < oldAST.rules.length; ++i) { |
| 622 for (var i = 0; i < oldAST.rules.length; ++i) { | 602 var oldRule = oldAST.rules[i]; |
| 623 var oldRule = oldAST.rules[i]; | 603 var newRule = newAST.rules[i]; |
| 624 var newRule = newAST.rules[i]; | 604 computeRuleDiff(mapping, oldRule, newRule); |
| 625 computeRuleDiff(mapping, oldRule, newRule); | 605 } |
| 606 return new WebInspector.SASSSupport.ASTDiff(oldAST.document.url, oldAST, newAS
T, mapping, changes); |
| 607 |
| 608 /** |
| 609 * @param {!WebInspector.SASSSupport.PropertyChangeType} type |
| 610 * @param {!WebInspector.SASSSupport.Rule} oldRule |
| 611 * @param {!WebInspector.SASSSupport.Rule} newRule |
| 612 * @param {number} oldPropertyIndex |
| 613 * @param {number} newPropertyIndex |
| 614 */ |
| 615 function addChange(type, oldRule, newRule, oldPropertyIndex, newPropertyIndex)
{ |
| 616 changes.push( |
| 617 new WebInspector.SASSSupport.PropertyChange(type, oldRule, newRule, oldP
ropertyIndex, newPropertyIndex)); |
| 618 } |
| 619 |
| 620 /** |
| 621 * @param {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSupport.
TextNode>} mapping |
| 622 * @param {!WebInspector.SASSSupport.Rule} oldRule |
| 623 * @param {!WebInspector.SASSSupport.Rule} newRule |
| 624 */ |
| 625 function computeRuleDiff(mapping, oldRule, newRule) { |
| 626 var oldLines = []; |
| 627 for (var i = 0; i < oldRule.properties.length; ++i) |
| 628 oldLines.push(oldRule.properties[i].name.text.trim() + ':' + oldRule.prope
rties[i].value.text.trim()); |
| 629 var newLines = []; |
| 630 for (var i = 0; i < newRule.properties.length; ++i) |
| 631 newLines.push(newRule.properties[i].name.text.trim() + ':' + newRule.prope
rties[i].value.text.trim()); |
| 632 var diff = WebInspector.Diff.lineDiff(oldLines, newLines); |
| 633 diff = WebInspector.Diff.convertToEditDiff(diff); |
| 634 |
| 635 var p1 = 0, p2 = 0; |
| 636 for (var i = 0; i < diff.length; ++i) { |
| 637 var token = diff[i]; |
| 638 if (token[0] === WebInspector.Diff.Operation.Delete) { |
| 639 for (var j = 0; j < token[1]; ++j) |
| 640 addChange(T.PropertyRemoved, oldRule, newRule, p1++, p2); |
| 641 } else if (token[0] === WebInspector.Diff.Operation.Insert) { |
| 642 for (var j = 0; j < token[1]; ++j) |
| 643 addChange(T.PropertyAdded, oldRule, newRule, p1, p2++); |
| 644 } else { |
| 645 for (var j = 0; j < token[1]; ++j) |
| 646 computePropertyDiff(mapping, oldRule, newRule, p1++, p2++); |
| 647 } |
| 626 } | 648 } |
| 627 return new WebInspector.SASSSupport.ASTDiff(oldAST.document.url, oldAST, new
AST, mapping, changes); | 649 } |
| 628 | 650 |
| 629 /** | 651 /** |
| 630 * @param {!WebInspector.SASSSupport.PropertyChangeType} type | 652 * @param {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSupport.
TextNode>} mapping |
| 631 * @param {!WebInspector.SASSSupport.Rule} oldRule | 653 * @param {!WebInspector.SASSSupport.Rule} oldRule |
| 632 * @param {!WebInspector.SASSSupport.Rule} newRule | 654 * @param {!WebInspector.SASSSupport.Rule} newRule |
| 633 * @param {number} oldPropertyIndex | 655 * @param {number} oldPropertyIndex |
| 634 * @param {number} newPropertyIndex | 656 * @param {number} newPropertyIndex |
| 635 */ | 657 */ |
| 636 function addChange(type, oldRule, newRule, oldPropertyIndex, newPropertyInde
x) | 658 function computePropertyDiff(mapping, oldRule, newRule, oldPropertyIndex, newP
ropertyIndex) { |
| 637 { | 659 var oldProperty = oldRule.properties[oldPropertyIndex]; |
| 638 changes.push(new WebInspector.SASSSupport.PropertyChange(type, oldRule,
newRule, oldPropertyIndex, newPropertyIndex)); | 660 var newProperty = newRule.properties[newPropertyIndex]; |
| 639 } | 661 mapping.set(oldProperty.name, newProperty.name); |
| 640 | 662 mapping.set(oldProperty.value, newProperty.value); |
| 641 /** | 663 if (oldProperty.name.text.trim() !== newProperty.name.text.trim()) |
| 642 * @param {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSuppor
t.TextNode>} mapping | 664 addChange(T.NameChanged, oldRule, newRule, oldPropertyIndex, newPropertyIn
dex); |
| 643 * @param {!WebInspector.SASSSupport.Rule} oldRule | 665 if (oldProperty.value.text.trim() !== newProperty.value.text.trim()) |
| 644 * @param {!WebInspector.SASSSupport.Rule} newRule | 666 addChange(T.ValueChanged, oldRule, newRule, oldPropertyIndex, newPropertyI
ndex); |
| 645 */ | 667 if (oldProperty.disabled !== newProperty.disabled) |
| 646 function computeRuleDiff(mapping, oldRule, newRule) | 668 addChange(T.PropertyToggled, oldRule, newRule, oldPropertyIndex, newProper
tyIndex); |
| 647 { | 669 } |
| 648 var oldLines = []; | |
| 649 for (var i = 0; i < oldRule.properties.length; ++i) | |
| 650 oldLines.push(oldRule.properties[i].name.text.trim() + ":" + oldRule
.properties[i].value.text.trim()); | |
| 651 var newLines = []; | |
| 652 for (var i = 0; i < newRule.properties.length; ++i) | |
| 653 newLines.push(newRule.properties[i].name.text.trim() + ":" + newRule
.properties[i].value.text.trim()); | |
| 654 var diff = WebInspector.Diff.lineDiff(oldLines, newLines); | |
| 655 diff = WebInspector.Diff.convertToEditDiff(diff); | |
| 656 | |
| 657 var p1 = 0, p2 = 0; | |
| 658 for (var i = 0; i < diff.length; ++i) { | |
| 659 var token = diff[i]; | |
| 660 if (token[0] === WebInspector.Diff.Operation.Delete) { | |
| 661 for (var j = 0; j < token[1]; ++j) | |
| 662 addChange(T.PropertyRemoved, oldRule, newRule, p1++, p2); | |
| 663 } else if (token[0] === WebInspector.Diff.Operation.Insert) { | |
| 664 for (var j = 0; j < token[1]; ++j) | |
| 665 addChange(T.PropertyAdded, oldRule, newRule, p1, p2++); | |
| 666 } else { | |
| 667 for (var j = 0; j < token[1]; ++j) | |
| 668 computePropertyDiff(mapping, oldRule, newRule, p1++, p2++); | |
| 669 } | |
| 670 } | |
| 671 } | |
| 672 | |
| 673 /** | |
| 674 * @param {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSuppor
t.TextNode>} mapping | |
| 675 * @param {!WebInspector.SASSSupport.Rule} oldRule | |
| 676 * @param {!WebInspector.SASSSupport.Rule} newRule | |
| 677 * @param {number} oldPropertyIndex | |
| 678 * @param {number} newPropertyIndex | |
| 679 */ | |
| 680 function computePropertyDiff(mapping, oldRule, newRule, oldPropertyIndex, ne
wPropertyIndex) | |
| 681 { | |
| 682 var oldProperty = oldRule.properties[oldPropertyIndex]; | |
| 683 var newProperty = newRule.properties[newPropertyIndex]; | |
| 684 mapping.set(oldProperty.name, newProperty.name); | |
| 685 mapping.set(oldProperty.value, newProperty.value); | |
| 686 if (oldProperty.name.text.trim() !== newProperty.name.text.trim()) | |
| 687 addChange(T.NameChanged, oldRule, newRule, oldPropertyIndex, newProp
ertyIndex); | |
| 688 if (oldProperty.value.text.trim() !== newProperty.value.text.trim()) | |
| 689 addChange(T.ValueChanged, oldRule, newRule, oldPropertyIndex, newPro
pertyIndex); | |
| 690 if (oldProperty.disabled !== newProperty.disabled) | |
| 691 addChange(T.PropertyToggled, oldRule, newRule, oldPropertyIndex, new
PropertyIndex); | |
| 692 } | |
| 693 }; | 670 }; |
| OLD | NEW |