| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library sourcemap.diff; | 5 library sourcemap.diff; |
| 6 | 6 |
| 7 import 'package:compiler/src/io/source_file.dart'; | 7 import 'package:compiler/src/io/source_file.dart'; |
| 8 | 8 |
| 9 import 'html_parts.dart'; | 9 import 'html_parts.dart'; |
| 10 import 'output_structure.dart'; | 10 import 'output_structure.dart'; |
| 11 import 'sourcemap_helper.dart'; | 11 import 'sourcemap_helper.dart'; |
| 12 import 'sourcemap_html_helper.dart'; | 12 import 'sourcemap_html_helper.dart'; |
| 13 | 13 |
| 14 enum DiffKind { | 14 enum DiffKind { UNMATCHED, MATCHING, IDENTICAL, } |
| 15 UNMATCHED, | |
| 16 MATCHING, | |
| 17 IDENTICAL, | |
| 18 } | |
| 19 | 15 |
| 20 /// Id for an output column. | 16 /// Id for an output column. |
| 21 class DiffColumn { | 17 class DiffColumn { |
| 22 final String type; | 18 final String type; |
| 23 final int index; | 19 final int index; |
| 24 | 20 |
| 25 const DiffColumn(this.type, [this.index]); | 21 const DiffColumn(this.type, [this.index]); |
| 26 | 22 |
| 27 int get hashCode => type.hashCode * 19 + index.hashCode * 23; | 23 int get hashCode => type.hashCode * 19 + index.hashCode * 23; |
| 28 | 24 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 final Map<CodeLine, List<CodeLine>> jsToDartMap; | 57 final Map<CodeLine, List<CodeLine>> jsToDartMap; |
| 62 | 58 |
| 63 CodeLinesColumnBlock(this.jsCodeLines, this.jsToDartMap); | 59 CodeLinesColumnBlock(this.jsCodeLines, this.jsToDartMap); |
| 64 | 60 |
| 65 void printHtmlOn(StringBuffer htmlBuffer, HtmlPrintContext context) { | 61 void printHtmlOn(StringBuffer htmlBuffer, HtmlPrintContext context) { |
| 66 if (jsCodeLines.isNotEmpty) { | 62 if (jsCodeLines.isNotEmpty) { |
| 67 htmlBuffer.write('<table style="width:100%">'); | 63 htmlBuffer.write('<table style="width:100%">'); |
| 68 for (CodeLine codeLine in jsCodeLines) { | 64 for (CodeLine codeLine in jsCodeLines) { |
| 69 htmlBuffer.write('<tr><td class="${ClassNames.innerCell}">'); | 65 htmlBuffer.write('<tr><td class="${ClassNames.innerCell}">'); |
| 70 codeLine.printHtmlOn(htmlBuffer, context); | 66 codeLine.printHtmlOn(htmlBuffer, context); |
| 71 htmlBuffer.write( | 67 htmlBuffer.write('</td><td ' |
| 72 '</td><td ' | |
| 73 'class="${ClassNames.innerCell} ${ClassNames.sourceMapped}">'); | 68 'class="${ClassNames.innerCell} ${ClassNames.sourceMapped}">'); |
| 74 List<CodeLine> lines = jsToDartMap[codeLine]; | 69 List<CodeLine> lines = jsToDartMap[codeLine]; |
| 75 if (lines != null) { | 70 if (lines != null) { |
| 76 for (CodeLine line in lines) { | 71 for (CodeLine line in lines) { |
| 77 line.printHtmlOn(htmlBuffer, | 72 line.printHtmlOn(htmlBuffer, context.from(includeAnnotation: (a) { |
| 78 context.from(includeAnnotation: (a) { | 73 CodeLineAnnotation annotation = a.data; |
| 79 CodeLineAnnotation annotation = a.data; | 74 return annotation.annotationType.isSourceMapped; |
| 80 return annotation.annotationType.isSourceMapped; | 75 })); |
| 81 })); | |
| 82 } | 76 } |
| 83 } | 77 } |
| 84 htmlBuffer.write('</td></tr>'); | 78 htmlBuffer.write('</td></tr>'); |
| 85 } | 79 } |
| 86 htmlBuffer.write('</table>'); | 80 htmlBuffer.write('</table>'); |
| 87 } | 81 } |
| 88 } | 82 } |
| 89 } | 83 } |
| 90 | 84 |
| 91 /// A list of columns that should align in output. | 85 /// A list of columns that should align in output. |
| 92 class DiffBlock { | 86 class DiffBlock { |
| 93 final DiffKind kind; | 87 final DiffKind kind; |
| 94 Map<DiffColumn, DiffColumnBlock> _columns = <DiffColumn, DiffColumnBlock>{}; | 88 Map<DiffColumn, DiffColumnBlock> _columns = <DiffColumn, DiffColumnBlock>{}; |
| 95 | 89 |
| 96 DiffBlock(this.kind); | 90 DiffBlock(this.kind); |
| 97 | 91 |
| 98 void addColumnBlock(DiffColumn column, DiffColumnBlock block) { | 92 void addColumnBlock(DiffColumn column, DiffColumnBlock block) { |
| 99 _columns[column] = block; | 93 _columns[column] = block; |
| 100 } | 94 } |
| 101 | 95 |
| 102 Iterable<DiffColumn> get columns => _columns.keys; | 96 Iterable<DiffColumn> get columns => _columns.keys; |
| 103 | 97 |
| 104 void printHtmlOn(DiffColumn column, | 98 void printHtmlOn( |
| 105 StringBuffer htmlBuffer, | 99 DiffColumn column, StringBuffer htmlBuffer, HtmlPrintContext context) { |
| 106 HtmlPrintContext context) { | |
| 107 DiffColumnBlock block = _columns[column]; | 100 DiffColumnBlock block = _columns[column]; |
| 108 if (block != null) { | 101 if (block != null) { |
| 109 block.printHtmlOn(htmlBuffer, context); | 102 block.printHtmlOn(htmlBuffer, context); |
| 110 } | 103 } |
| 111 } | 104 } |
| 112 } | 105 } |
| 113 | 106 |
| 114 | |
| 115 /// Align the content of [list1] and [list2]. | 107 /// Align the content of [list1] and [list2]. |
| 116 /// | 108 /// |
| 117 /// If provided, [range1] and [range2] aligned the subranges of [list1] and | 109 /// If provided, [range1] and [range2] aligned the subranges of [list1] and |
| 118 /// [list2], otherwise the whole lists are aligned. | 110 /// [list2], otherwise the whole lists are aligned. |
| 119 /// | 111 /// |
| 120 /// If provided, [match] determines the equality between members of [list1] and | 112 /// If provided, [match] determines the equality between members of [list1] and |
| 121 /// [list2], otherwise `==` is used. | 113 /// [list2], otherwise `==` is used. |
| 122 /// | 114 /// |
| 123 /// [handleSkew] is called when a subrange of one list is not found in the | 115 /// [handleSkew] is called when a subrange of one list is not found in the |
| 124 /// other. | 116 /// other. |
| 125 /// | 117 /// |
| 126 /// [handleMatched] is called when two indices match up. | 118 /// [handleMatched] is called when two indices match up. |
| 127 /// | 119 /// |
| 128 /// [handleUnmatched] is called when two indices don't match up (none are found | 120 /// [handleUnmatched] is called when two indices don't match up (none are found |
| 129 /// in the other list). | 121 /// in the other list). |
| 130 void align(List list1, | 122 void align(List list1, List list2, |
| 131 List list2, | 123 {Interval range1, |
| 132 {Interval range1, | 124 Interval range2, |
| 133 Interval range2, | 125 bool match(a, b), |
| 134 bool match(a, b), | 126 void handleSkew(int listIndex, Interval range), |
| 135 void handleSkew(int listIndex, Interval range), | 127 void handleMatched(List<int> indices), |
| 136 void handleMatched(List<int> indices), | 128 void handleUnmatched(List<int> indices)}) { |
| 137 void handleUnmatched(List<int> indices)}) { | |
| 138 if (match == null) { | 129 if (match == null) { |
| 139 match = (a, b) => a == b; | 130 match = (a, b) => a == b; |
| 140 } | 131 } |
| 141 | 132 |
| 142 if (range1 == null) { | 133 if (range1 == null) { |
| 143 range1 = new Interval(0, list1.length); | 134 range1 = new Interval(0, list1.length); |
| 144 } | 135 } |
| 145 if (range2 == null) { | 136 if (range2 == null) { |
| 146 range2 = new Interval(0, list2.length); | 137 range2 = new Interval(0, list2.length); |
| 147 } | 138 } |
| 148 | 139 |
| 149 Interval findInOther( | 140 Interval findInOther(List thisLines, Interval thisRange, List otherLines, |
| 150 List thisLines, Interval thisRange, | 141 Interval otherRange) { |
| 151 List otherLines, Interval otherRange) { | |
| 152 for (int index = otherRange.from; index < otherRange.to; index++) { | 142 for (int index = otherRange.from; index < otherRange.to; index++) { |
| 153 if (match(thisLines[thisRange.from], otherLines[index])) { | 143 if (match(thisLines[thisRange.from], otherLines[index])) { |
| 154 int offset = 1; | 144 int offset = 1; |
| 155 while (thisRange.from + offset < thisRange.to && | 145 while (thisRange.from + offset < thisRange.to && |
| 156 otherRange.from + offset < otherRange.to && | 146 otherRange.from + offset < otherRange.to && |
| 157 match(thisLines[thisRange.from + offset], | 147 match(thisLines[thisRange.from + offset], |
| 158 otherLines[otherRange.from + offset])) { | 148 otherLines[otherRange.from + offset])) { |
| 159 offset++; | 149 offset++; |
| 160 } | 150 } |
| 161 return new Interval(index, index + offset); | 151 return new Interval(index, index + offset); |
| 162 } | 152 } |
| 163 } | 153 } |
| 164 return null; | 154 return null; |
| 165 } | 155 } |
| 166 | 156 |
| 167 int start1 = range1.from; | 157 int start1 = range1.from; |
| 168 int end1 = range1.to; | 158 int end1 = range1.to; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 handleSkew(0, new Interval(start1, end1)); | 212 handleSkew(0, new Interval(start1, end1)); |
| 223 } | 213 } |
| 224 if (start2 < end2) { | 214 if (start2 < end2) { |
| 225 handleSkew(1, new Interval(start2, end2)); | 215 handleSkew(1, new Interval(start2, end2)); |
| 226 } | 216 } |
| 227 } | 217 } |
| 228 | 218 |
| 229 /// Create a list of blocks containing the diff of the two output [structures] | 219 /// Create a list of blocks containing the diff of the two output [structures] |
| 230 /// and the corresponding Dart code. | 220 /// and the corresponding Dart code. |
| 231 List<DiffBlock> createDiffBlocks( | 221 List<DiffBlock> createDiffBlocks( |
| 232 List<OutputStructure> structures, | 222 List<OutputStructure> structures, SourceFileManager sourceFileManager) { |
| 233 SourceFileManager sourceFileManager) { | |
| 234 return new DiffCreator(structures, sourceFileManager).computeBlocks(); | 223 return new DiffCreator(structures, sourceFileManager).computeBlocks(); |
| 235 } | 224 } |
| 236 | 225 |
| 237 class DiffCreator { | 226 class DiffCreator { |
| 238 final List<OutputStructure> structures; | 227 final List<OutputStructure> structures; |
| 239 final SourceFileManager sourceFileManager; | 228 final SourceFileManager sourceFileManager; |
| 240 | 229 |
| 241 List<List<CodeLine>> inputLines; | 230 List<List<CodeLine>> inputLines; |
| 242 | 231 |
| 243 List<int> nextInputLine = [0, 0]; | 232 List<int> nextInputLine = [0, 0]; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 256 sources.add(entity.codeSource); | 245 sources.add(entity.codeSource); |
| 257 } | 246 } |
| 258 } | 247 } |
| 259 return sources; | 248 return sources; |
| 260 } | 249 } |
| 261 | 250 |
| 262 /// Create a block with the code from [codeSources]. The [CodeSource]s in | 251 /// Create a block with the code from [codeSources]. The [CodeSource]s in |
| 263 /// [mainSources] are tagged as original code sources, the rest as inlined | 252 /// [mainSources] are tagged as original code sources, the rest as inlined |
| 264 /// code sources. | 253 /// code sources. |
| 265 DiffColumnBlock codeLinesFromCodeSources( | 254 DiffColumnBlock codeLinesFromCodeSources( |
| 266 Iterable<CodeSource> mainSources, | 255 Iterable<CodeSource> mainSources, Iterable<CodeSource> codeSources) { |
| 267 Iterable<CodeSource> codeSources) { | |
| 268 List<HtmlPart> parts = <HtmlPart>[]; | 256 List<HtmlPart> parts = <HtmlPart>[]; |
| 269 for (CodeSource codeSource in codeSources) { | 257 for (CodeSource codeSource in codeSources) { |
| 270 //parts.addAll(codeLinesFromCodeSource(codeSource)); | 258 //parts.addAll(codeLinesFromCodeSource(codeSource)); |
| 271 String className = | 259 String className = mainSources.contains(codeSource) |
| 272 mainSources.contains(codeSource) | 260 ? ClassNames.originalDart |
| 273 ? ClassNames.originalDart : ClassNames.inlinedDart; | 261 : ClassNames.inlinedDart; |
| 274 parts.add( | 262 parts.add(new TagPart('div', |
| 275 new TagPart('div', | 263 properties: {'class': className}, |
| 276 properties: {'class': className}, | 264 content: codeLinesFromCodeSource(codeSource))); |
| 277 content: codeLinesFromCodeSource(codeSource))); | |
| 278 } | 265 } |
| 279 return new PartsColumnBlock(parts); | 266 return new PartsColumnBlock(parts); |
| 280 } | 267 } |
| 281 | 268 |
| 282 /// Adds all [CodeSource]s used in [dartCodeLines] to [codeSourceSet]. | 269 /// Adds all [CodeSource]s used in [dartCodeLines] to [codeSourceSet]. |
| 283 void collectCodeSources(Set<CodeSource> codeSourceSet, | 270 void collectCodeSources(Set<CodeSource> codeSourceSet, |
| 284 Map<CodeLine, List<CodeLine>> dartCodeLines) { | 271 Map<CodeLine, List<CodeLine>> dartCodeLines) { |
| 285 for (List<CodeLine> codeLines in dartCodeLines.values) { | 272 for (List<CodeLine> codeLines in dartCodeLines.values) { |
| 286 for (CodeLine dartCodeLine in codeLines) { | 273 for (CodeLine dartCodeLine in codeLines) { |
| 287 if (dartCodeLine.lineAnnotation != null) { | 274 if (dartCodeLine.lineAnnotation != null) { |
| 288 codeSourceSet.add(dartCodeLine.lineAnnotation); | 275 codeSourceSet.add(dartCodeLine.lineAnnotation); |
| 289 } | 276 } |
| 290 } | 277 } |
| 291 } | 278 } |
| 292 } | 279 } |
| 293 | 280 |
| 294 /// Checks that lines are added in sequence without gaps or duplicates. | 281 /// Checks that lines are added in sequence without gaps or duplicates. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 309 print(inputLines[index][i++].code); | 296 print(inputLines[index][i++].code); |
| 310 } | 297 } |
| 311 } | 298 } |
| 312 } | 299 } |
| 313 nextInputLine[index] = range.to; | 300 nextInputLine[index] = range.to; |
| 314 } | 301 } |
| 315 | 302 |
| 316 /// Creates a block containing the code lines in [range] from input number | 303 /// Creates a block containing the code lines in [range] from input number |
| 317 /// [index]. If [codeSource] is provided, the block will contain a | 304 /// [index]. If [codeSource] is provided, the block will contain a |
| 318 /// corresponding Dart code column. | 305 /// corresponding Dart code column. |
| 319 void handleSkew( | 306 void handleSkew(int index, Interval range, |
| 320 int index, | |
| 321 Interval range, | |
| 322 [Iterable<CodeSource> mainCodeSources = const <CodeSource>[]]) { | 307 [Iterable<CodeSource> mainCodeSources = const <CodeSource>[]]) { |
| 323 if (range.isEmpty) return; | 308 if (range.isEmpty) return; |
| 324 | 309 |
| 325 Set<CodeSource> codeSources = new Set<CodeSource>(); | 310 Set<CodeSource> codeSources = new Set<CodeSource>(); |
| 326 codeSources.addAll(mainCodeSources); | 311 codeSources.addAll(mainCodeSources); |
| 327 | 312 |
| 328 DiffBlock block = new DiffBlock(DiffKind.UNMATCHED); | 313 DiffBlock block = new DiffBlock(DiffKind.UNMATCHED); |
| 329 checkLineInvariant(index, range); | 314 checkLineInvariant(index, range); |
| 330 List<CodeLine> jsCodeLines = | 315 List<CodeLine> jsCodeLines = |
| 331 inputLines[index].sublist(range.from, range.to); | 316 inputLines[index].sublist(range.from, range.to); |
| 332 Map<CodeLine, List<CodeLine>> dartCodeLines = | 317 Map<CodeLine, List<CodeLine>> dartCodeLines = |
| 333 dartCodeLinesFromJsCodeLines(jsCodeLines); | 318 dartCodeLinesFromJsCodeLines(jsCodeLines); |
| 334 block.addColumnBlock( | 319 block.addColumnBlock(new DiffColumn('js', index), |
| 335 new DiffColumn('js', index), | |
| 336 new CodeLinesColumnBlock(jsCodeLines, dartCodeLines)); | 320 new CodeLinesColumnBlock(jsCodeLines, dartCodeLines)); |
| 337 collectCodeSources(codeSources, dartCodeLines); | 321 collectCodeSources(codeSources, dartCodeLines); |
| 338 | 322 |
| 339 if (codeSources.isNotEmpty) { | 323 if (codeSources.isNotEmpty) { |
| 340 block.addColumnBlock( | 324 block.addColumnBlock(const DiffColumn('dart'), |
| 341 const DiffColumn('dart'), | |
| 342 codeLinesFromCodeSources(mainCodeSources, codeSources)); | 325 codeLinesFromCodeSources(mainCodeSources, codeSources)); |
| 343 } | 326 } |
| 344 blocks.add(block); | 327 blocks.add(block); |
| 345 } | 328 } |
| 346 | 329 |
| 347 /// Create a block containing the code lines in [ranges] from the | 330 /// Create a block containing the code lines in [ranges] from the |
| 348 /// corresponding JavaScript inputs. If [codeSource] is provided, the block | 331 /// corresponding JavaScript inputs. If [codeSource] is provided, the block |
| 349 /// will contain a corresponding Dart code column. | 332 /// will contain a corresponding Dart code column. |
| 350 void addLines( | 333 void addLines(DiffKind kind, List<Interval> ranges, |
| 351 DiffKind kind, | |
| 352 List<Interval> ranges, | |
| 353 [Iterable<CodeSource> mainCodeSources = const <CodeSource>[]]) { | 334 [Iterable<CodeSource> mainCodeSources = const <CodeSource>[]]) { |
| 354 if (ranges.every((range) => range.isEmpty)) return; | 335 if (ranges.every((range) => range.isEmpty)) return; |
| 355 | 336 |
| 356 Set<CodeSource> codeSources = new Set<CodeSource>(); | 337 Set<CodeSource> codeSources = new Set<CodeSource>(); |
| 357 codeSources.addAll(mainCodeSources); | 338 codeSources.addAll(mainCodeSources); |
| 358 | 339 |
| 359 DiffBlock block = new DiffBlock(kind); | 340 DiffBlock block = new DiffBlock(kind); |
| 360 for (int i = 0; i < ranges.length; i++) { | 341 for (int i = 0; i < ranges.length; i++) { |
| 361 checkLineInvariant(i, ranges[i]); | 342 checkLineInvariant(i, ranges[i]); |
| 362 List<CodeLine> jsCodeLines = | 343 List<CodeLine> jsCodeLines = |
| 363 inputLines[i].sublist(ranges[i].from, ranges[i].to); | 344 inputLines[i].sublist(ranges[i].from, ranges[i].to); |
| 364 Map<CodeLine, List<CodeLine>> dartCodeLines = | 345 Map<CodeLine, List<CodeLine>> dartCodeLines = |
| 365 dartCodeLinesFromJsCodeLines(jsCodeLines); | 346 dartCodeLinesFromJsCodeLines(jsCodeLines); |
| 366 block.addColumnBlock( | 347 block.addColumnBlock(new DiffColumn('js', i), |
| 367 new DiffColumn('js', i), | |
| 368 new CodeLinesColumnBlock(jsCodeLines, dartCodeLines)); | 348 new CodeLinesColumnBlock(jsCodeLines, dartCodeLines)); |
| 369 collectCodeSources(codeSources, dartCodeLines); | 349 collectCodeSources(codeSources, dartCodeLines); |
| 370 } | 350 } |
| 371 if (codeSources.isNotEmpty) { | 351 if (codeSources.isNotEmpty) { |
| 372 block.addColumnBlock(const DiffColumn('dart'), | 352 block.addColumnBlock(const DiffColumn('dart'), |
| 373 codeLinesFromCodeSources(mainCodeSources, codeSources)); | 353 codeLinesFromCodeSources(mainCodeSources, codeSources)); |
| 374 } | 354 } |
| 375 blocks.add(block); | 355 blocks.add(block); |
| 376 } | 356 } |
| 377 | 357 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 395 if (currentUnmatchedIntervals != null) { | 375 if (currentUnmatchedIntervals != null) { |
| 396 addLines(DiffKind.UNMATCHED, currentUnmatchedIntervals); | 376 addLines(DiffKind.UNMATCHED, currentUnmatchedIntervals); |
| 397 } | 377 } |
| 398 currentUnmatchedIntervals = null; | 378 currentUnmatchedIntervals = null; |
| 399 } | 379 } |
| 400 | 380 |
| 401 List<Interval> updateIntervals(List<Interval> current, List<int> indices) { | 381 List<Interval> updateIntervals(List<Interval> current, List<int> indices) { |
| 402 if (current == null) { | 382 if (current == null) { |
| 403 return [ | 383 return [ |
| 404 new Interval(indices[0], indices[0] + 1), | 384 new Interval(indices[0], indices[0] + 1), |
| 405 new Interval(indices[1], indices[1] + 1)]; | 385 new Interval(indices[1], indices[1] + 1) |
| 386 ]; |
| 406 } else { | 387 } else { |
| 407 current[0] = | 388 current[0] = new Interval(current[0].from, indices[0] + 1); |
| 408 new Interval(current[0].from, indices[0] + 1); | 389 current[1] = new Interval(current[1].from, indices[1] + 1); |
| 409 current[1] = | |
| 410 new Interval(current[1].from, indices[1] + 1); | |
| 411 return current; | 390 return current; |
| 412 } | 391 } |
| 413 } | 392 } |
| 414 | 393 |
| 415 align( | 394 align(inputLines[0], inputLines[1], |
| 416 inputLines[0], | |
| 417 inputLines[1], | |
| 418 range1: range1, | 395 range1: range1, |
| 419 range2: range2, | 396 range2: range2, |
| 420 match: match, | 397 match: match, handleSkew: (int listIndex, Interval range) { |
| 421 handleSkew: (int listIndex, Interval range) { | 398 flushMatching(); |
| 422 flushMatching(); | 399 flushUnmatched(); |
| 423 flushUnmatched(); | 400 handleSkew(listIndex, range); |
| 424 handleSkew(listIndex, range); | 401 }, handleMatched: (List<int> indices) { |
| 425 }, | 402 flushUnmatched(); |
| 426 handleMatched: (List<int> indices) { | 403 currentMatchedIntervals = |
| 427 flushUnmatched(); | 404 updateIntervals(currentMatchedIntervals, indices); |
| 428 currentMatchedIntervals = | 405 }, handleUnmatched: (List<int> indices) { |
| 429 updateIntervals(currentMatchedIntervals, indices); | 406 flushMatching(); |
| 430 }, | 407 currentUnmatchedIntervals = |
| 431 handleUnmatched: (List<int> indices) { | 408 updateIntervals(currentUnmatchedIntervals, indices); |
| 432 flushMatching(); | 409 }); |
| 433 currentUnmatchedIntervals = | |
| 434 updateIntervals(currentUnmatchedIntervals, indices); | |
| 435 }); | |
| 436 | 410 |
| 437 flushMatching(); | 411 flushMatching(); |
| 438 flushUnmatched(); | 412 flushUnmatched(); |
| 439 } | 413 } |
| 440 | 414 |
| 441 /// Adds the top level blocks in [childRange] for structure [index]. | 415 /// Adds the top level blocks in [childRange] for structure [index]. |
| 442 void addBlock(int index, Interval childRange) { | 416 void addBlock(int index, Interval childRange) { |
| 443 addSkewedChildren(index, structures[index], childRange); | 417 addSkewedChildren(index, structures[index], childRange); |
| 444 } | 418 } |
| 445 | 419 |
| 446 /// Adds the [entity] from structure [index]. If the [entity] supports child | 420 /// Adds the [entity] from structure [index]. If the [entity] supports child |
| 447 /// entities, these are process individually. Otherwise the lines from | 421 /// entities, these are process individually. Otherwise the lines from |
| 448 /// [entity] are added directly. | 422 /// [entity] are added directly. |
| 449 void addSkewedEntity(int index, OutputEntity entity) { | 423 void addSkewedEntity(int index, OutputEntity entity) { |
| 450 if (entity.canHaveChildren) { | 424 if (entity.canHaveChildren) { |
| 451 handleSkew(index, entity.header); | 425 handleSkew(index, entity.header); |
| 452 addSkewedChildren( | 426 addSkewedChildren(index, entity, new Interval(0, entity.children.length)); |
| 453 index, entity, new Interval(0, entity.children.length)); | |
| 454 handleSkew(index, entity.footer); | 427 handleSkew(index, entity.footer); |
| 455 } else { | 428 } else { |
| 456 handleSkew(index, entity.interval, codeSourceFromEntities([entity])); | 429 handleSkew(index, entity.interval, codeSourceFromEntities([entity])); |
| 457 } | 430 } |
| 458 } | 431 } |
| 459 | 432 |
| 460 /// Adds the children of [parent] in [childRange] from structure [index]. | 433 /// Adds the children of [parent] in [childRange] from structure [index]. |
| 461 void addSkewedChildren(int index, OutputEntity parent, Interval childRange) { | 434 void addSkewedChildren(int index, OutputEntity parent, Interval childRange) { |
| 462 for (int i = childRange.from; i < childRange.to; i++) { | 435 for (int i = childRange.from; i < childRange.to; i++) { |
| 463 addSkewedEntity(index, parent.getChild(i)); | 436 addSkewedEntity(index, parent.getChild(i)); |
| 464 } | 437 } |
| 465 } | 438 } |
| 466 | 439 |
| 467 /// Adds the members of the [classes] aligned. | 440 /// Adds the members of the [classes] aligned. |
| 468 void addMatchingContainers(List<OutputEntity> classes) { | 441 void addMatchingContainers(List<OutputEntity> classes) { |
| 469 addLines(DiffKind.MATCHING, classes.map((c) => c.header).toList()); | 442 addLines(DiffKind.MATCHING, classes.map((c) => c.header).toList()); |
| 470 align(classes[0].children, classes[1].children, | 443 align(classes[0].children, classes[1].children, |
| 471 match: (a, b) => a.name == b.name, | 444 match: (a, b) => a.name == b.name, |
| 472 handleSkew: (int listIndex, Interval childRange) { | 445 handleSkew: (int listIndex, Interval childRange) { |
| 473 addSkewedChildren(listIndex, classes[listIndex], childRange); | 446 addSkewedChildren(listIndex, classes[listIndex], childRange); |
| 474 }, | 447 }, handleMatched: (List<int> indices) { |
| 475 handleMatched: (List<int> indices) { | 448 List<BasicEntity> entities = [ |
| 476 List<BasicEntity> entities = [ | 449 classes[0].getChild(indices[0]), |
| 477 classes[0].getChild(indices[0]), | 450 classes[1].getChild(indices[1]) |
| 478 classes[1].getChild(indices[1])]; | 451 ]; |
| 479 if (entities.every((e) => e is Statics)) { | 452 if (entities.every((e) => e is Statics)) { |
| 480 addMatchingContainers(entities); | 453 addMatchingContainers(entities); |
| 481 } else { | 454 } else { |
| 482 addLines(DiffKind.MATCHING, | 455 addLines(DiffKind.MATCHING, entities.map((e) => e.interval).toList(), |
| 483 entities.map((e) => e.interval).toList(), | 456 codeSourceFromEntities(entities)); |
| 484 codeSourceFromEntities(entities)); | 457 } |
| 485 } | 458 }, handleUnmatched: (List<int> indices) { |
| 486 }, | 459 List<Interval> intervals = [ |
| 487 handleUnmatched: (List<int> indices) { | 460 classes[0].getChild(indices[0]).interval, |
| 488 List<Interval> intervals = [ | 461 classes[1].getChild(indices[1]).interval |
| 489 classes[0].getChild(indices[0]).interval, | 462 ]; |
| 490 classes[1].getChild(indices[1]).interval]; | 463 addLines(DiffKind.UNMATCHED, intervals); |
| 491 addLines(DiffKind.UNMATCHED, intervals); | 464 }); |
| 492 }); | |
| 493 addLines(DiffKind.MATCHING, classes.map((c) => c.footer).toList()); | 465 addLines(DiffKind.MATCHING, classes.map((c) => c.footer).toList()); |
| 494 } | 466 } |
| 495 | 467 |
| 496 /// Adds the library blocks in [indices] from the corresponding | 468 /// Adds the library blocks in [indices] from the corresponding |
| 497 /// [OutputStructure]s, aligning their content. | 469 /// [OutputStructure]s, aligning their content. |
| 498 void addMatchingBlocks(List<int> indices) { | 470 void addMatchingBlocks(List<int> indices) { |
| 499 List<LibraryBlock> blocks = [ | 471 List<LibraryBlock> blocks = [ |
| 500 structures[0].getChild(indices[0]), | 472 structures[0].getChild(indices[0]), |
| 501 structures[1].getChild(indices[1])]; | 473 structures[1].getChild(indices[1]) |
| 474 ]; |
| 502 | 475 |
| 503 addLines(DiffKind.MATCHING, blocks.map((b) => b.header).toList()); | 476 addLines(DiffKind.MATCHING, blocks.map((b) => b.header).toList()); |
| 504 align(blocks[0].children, blocks[1].children, | 477 align(blocks[0].children, blocks[1].children, |
| 505 match: (a, b) => a.name == b.name, | 478 match: (a, b) => a.name == b.name, |
| 506 handleSkew: (int listIndex, Interval childRange) { | 479 handleSkew: (int listIndex, Interval childRange) { |
| 507 addSkewedChildren( | 480 addSkewedChildren(listIndex, blocks[listIndex], childRange); |
| 508 listIndex, blocks[listIndex], childRange); | 481 }, handleMatched: (List<int> indices) { |
| 509 }, | 482 List<BasicEntity> entities = [ |
| 510 handleMatched: (List<int> indices) { | 483 blocks[0].getChild(indices[0]), |
| 511 List<BasicEntity> entities = [ | 484 blocks[1].getChild(indices[1]) |
| 512 blocks[0].getChild(indices[0]), | 485 ]; |
| 513 blocks[1].getChild(indices[1])]; | 486 if (entities.every((e) => e is LibraryClass)) { |
| 514 if (entities.every((e) => e is LibraryClass)) { | 487 addMatchingContainers(entities); |
| 515 addMatchingContainers(entities); | 488 } else { |
| 516 } else { | 489 addLines(DiffKind.MATCHING, entities.map((e) => e.interval).toList(), |
| 517 addLines( | 490 codeSourceFromEntities(entities)); |
| 518 DiffKind.MATCHING, | 491 } |
| 519 entities.map((e) => e.interval).toList(), | 492 }, handleUnmatched: (List<int> indices) { |
| 520 codeSourceFromEntities(entities)); | 493 List<Interval> intervals = [ |
| 521 } | 494 blocks[0].getChild(indices[0]).interval, |
| 522 }, | 495 blocks[1].getChild(indices[1]).interval |
| 523 handleUnmatched: (List<int> indices) { | 496 ]; |
| 524 List<Interval> intervals = [ | 497 addLines(DiffKind.UNMATCHED, intervals); |
| 525 blocks[0].getChild(indices[0]).interval, | 498 }); |
| 526 blocks[1].getChild(indices[1]).interval]; | |
| 527 addLines(DiffKind.UNMATCHED, intervals); | |
| 528 }); | |
| 529 addLines(DiffKind.MATCHING, blocks.map((b) => b.footer).toList()); | 499 addLines(DiffKind.MATCHING, blocks.map((b) => b.footer).toList()); |
| 530 } | 500 } |
| 531 | 501 |
| 532 /// Adds the lines of the blocks in [indices] from the corresponding | 502 /// Adds the lines of the blocks in [indices] from the corresponding |
| 533 /// [OutputStructure]s. | 503 /// [OutputStructure]s. |
| 534 void addUnmatchedBlocks(List<int> indices) { | 504 void addUnmatchedBlocks(List<int> indices) { |
| 535 List<LibraryBlock> blocks = [ | 505 List<LibraryBlock> blocks = [ |
| 536 structures[0].getChild(indices[0]), | 506 structures[0].getChild(indices[0]), |
| 537 structures[1].getChild(indices[1])]; | 507 structures[1].getChild(indices[1]) |
| 508 ]; |
| 538 addLines(DiffKind.UNMATCHED, [blocks[0].interval, blocks[1].interval]); | 509 addLines(DiffKind.UNMATCHED, [blocks[0].interval, blocks[1].interval]); |
| 539 } | 510 } |
| 540 | 511 |
| 541 /// Computes the diff blocks for [OutputStructure]s. | 512 /// Computes the diff blocks for [OutputStructure]s. |
| 542 List<DiffBlock> computeBlocks() { | 513 List<DiffBlock> computeBlocks() { |
| 543 addRaw(structures[0].header, structures[1].header); | 514 addRaw(structures[0].header, structures[1].header); |
| 544 | 515 |
| 545 align(structures[0].children, | 516 align(structures[0].children, structures[1].children, |
| 546 structures[1].children, | 517 match: (a, b) => a.name == b.name, |
| 547 match: (a, b) => a.name == b.name, | 518 handleSkew: addBlock, |
| 548 handleSkew: addBlock, | 519 handleMatched: addMatchingBlocks, |
| 549 handleMatched: addMatchingBlocks, | 520 handleUnmatched: addUnmatchedBlocks); |
| 550 handleUnmatched: addUnmatchedBlocks); | |
| 551 | 521 |
| 552 addRaw(structures[0].footer, structures[1].footer); | 522 addRaw(structures[0].footer, structures[1].footer); |
| 553 | 523 |
| 554 return blocks; | 524 return blocks; |
| 555 } | 525 } |
| 556 | 526 |
| 557 /// Creates html lines for code lines in [codeSource]. The [sourceFileManager] | 527 /// Creates html lines for code lines in [codeSource]. The [sourceFileManager] |
| 558 /// is used to read that text from the source URIs. | 528 /// is used to read that text from the source URIs. |
| 559 List<HtmlPart> codeLinesFromCodeSource(CodeSource codeSource) { | 529 List<HtmlPart> codeLinesFromCodeSource(CodeSource codeSource) { |
| 560 List<HtmlPart> lines = <HtmlPart>[]; | 530 List<HtmlPart> lines = <HtmlPart>[]; |
| 561 SourceFile sourceFile = sourceFileManager.getSourceFile(codeSource.uri); | 531 SourceFile sourceFile = sourceFileManager.getSourceFile(codeSource.uri); |
| 562 String elementName = codeSource.name; | 532 String elementName = codeSource.name; |
| 563 HtmlLine line = new HtmlLine(); | 533 HtmlLine line = new HtmlLine(); |
| 564 line.htmlParts.add(new ConstHtmlPart('<span class="comment">')); | 534 line.htmlParts.add(new ConstHtmlPart('<span class="comment">')); |
| 565 line.htmlParts.add(new HtmlText( | 535 line.htmlParts.add(new HtmlText('${elementName}: ${sourceFile.filename}')); |
| 566 '${elementName}: ${sourceFile.filename}')); | |
| 567 line.htmlParts.add(new ConstHtmlPart('</span>')); | 536 line.htmlParts.add(new ConstHtmlPart('</span>')); |
| 568 lines.add(line); | 537 lines.add(line); |
| 569 if (codeSource.begin != null) { | 538 if (codeSource.begin != null) { |
| 570 int startLine = sourceFile.getLine(codeSource.begin); | 539 int startLine = sourceFile.getLine(codeSource.begin); |
| 571 int endLine = sourceFile.getLine(codeSource.end) + 1; | 540 int endLine = sourceFile.getLine(codeSource.end) + 1; |
| 572 for (CodeLine codeLine in convertAnnotatedCodeToCodeLines( | 541 for (CodeLine codeLine in convertAnnotatedCodeToCodeLines( |
| 573 sourceFile.slowText(), | 542 sourceFile.slowText(), const <Annotation>[], |
| 574 const <Annotation>[], | 543 startLine: startLine, endLine: endLine)) { |
| 575 startLine: startLine, | |
| 576 endLine: endLine)) { | |
| 577 codeLine.lineAnnotation = codeSource; | 544 codeLine.lineAnnotation = codeSource; |
| 578 lines.add(codeLine); | 545 lines.add(codeLine); |
| 579 } | 546 } |
| 580 } | 547 } |
| 581 return lines; | 548 return lines; |
| 582 } | 549 } |
| 583 | 550 |
| 584 /// Creates a map from JavaScript [CodeLine]s in [jsCodeLines] to the Dart | 551 /// Creates a map from JavaScript [CodeLine]s in [jsCodeLines] to the Dart |
| 585 /// [CodeLine]s references in the source information. | 552 /// [CodeLine]s references in the source information. |
| 586 Map<CodeLine, List<CodeLine>> dartCodeLinesFromJsCodeLines( | 553 Map<CodeLine, List<CodeLine>> dartCodeLinesFromJsCodeLines( |
| 587 List<CodeLine> jsCodeLines) { | 554 List<CodeLine> jsCodeLines) { |
| 588 Map<CodeLine, Interval> codeLineInterval = <CodeLine, Interval>{}; | 555 Map<CodeLine, Interval> codeLineInterval = <CodeLine, Interval>{}; |
| 589 Map<CodeLine, List<CodeLine>> jsToDartMap = <CodeLine, List<CodeLine>>{}; | 556 Map<CodeLine, List<CodeLine>> jsToDartMap = <CodeLine, List<CodeLine>>{}; |
| 590 List<Annotation> annotations = <Annotation>[]; | 557 List<Annotation> annotations = <Annotation>[]; |
| 591 Uri currentUri; | 558 Uri currentUri; |
| 592 Interval interval; | 559 Interval interval; |
| 593 | 560 |
| 594 Map<Uri, Set<CodeSource>> codeSourceMap = <Uri, Set<CodeSource>>{}; | 561 Map<Uri, Set<CodeSource>> codeSourceMap = <Uri, Set<CodeSource>>{}; |
| 595 | 562 |
| 596 for (CodeLine jsCodeLine in jsCodeLines) { | 563 for (CodeLine jsCodeLine in jsCodeLines) { |
| 597 for (Annotation annotation in jsCodeLine.annotations) { | 564 for (Annotation annotation in jsCodeLine.annotations) { |
| 598 CodeLineAnnotation codeLineAnnotation = annotation.data; | 565 CodeLineAnnotation codeLineAnnotation = annotation.data; |
| 599 for (CodeSource codeSource in codeLineAnnotation.codeSources) { | 566 for (CodeSource codeSource in codeLineAnnotation.codeSources) { |
| 600 codeSourceMap.putIfAbsent(codeSource.uri, | 567 codeSourceMap |
| 601 () => new Set<CodeSource>()).add(codeSource); | 568 .putIfAbsent(codeSource.uri, () => new Set<CodeSource>()) |
| 569 .add(codeSource); |
| 602 } | 570 } |
| 603 } | 571 } |
| 604 } | 572 } |
| 605 | 573 |
| 606 void flush() { | 574 void flush() { |
| 607 if (currentUri == null) return; | 575 if (currentUri == null) return; |
| 608 | 576 |
| 609 Set<CodeSource> codeSources = codeSourceMap[currentUri]; | 577 Set<CodeSource> codeSources = codeSourceMap[currentUri]; |
| 610 SourceFile sourceFile = sourceFileManager.getSourceFile(currentUri); | 578 SourceFile sourceFile = sourceFileManager.getSourceFile(currentUri); |
| 611 List<CodeLine> annotatedDartCodeLines = | 579 List<CodeLine> annotatedDartCodeLines = convertAnnotatedCodeToCodeLines( |
| 612 convertAnnotatedCodeToCodeLines( | 580 sourceFile.slowText(), annotations, |
| 613 sourceFile.slowText(), | 581 startLine: interval.from, endLine: interval.to, uri: currentUri); |
| 614 annotations, | |
| 615 startLine: interval.from, | |
| 616 endLine: interval.to, | |
| 617 uri: currentUri); | |
| 618 if (codeSources != null) { | 582 if (codeSources != null) { |
| 619 CodeSource currentCodeSource; | 583 CodeSource currentCodeSource; |
| 620 Interval currentLineInterval; | 584 Interval currentLineInterval; |
| 621 for (CodeLine dartCodeLine in annotatedDartCodeLines) { | 585 for (CodeLine dartCodeLine in annotatedDartCodeLines) { |
| 622 if (currentCodeSource == null || | 586 if (currentCodeSource == null || |
| 623 !currentLineInterval.contains(dartCodeLine.lineNo)) { | 587 !currentLineInterval.contains(dartCodeLine.lineNo)) { |
| 624 currentCodeSource = null; | 588 currentCodeSource = null; |
| 625 for (CodeSource codeSource in codeSources) { | 589 for (CodeSource codeSource in codeSources) { |
| 626 Interval interval = new Interval( | 590 Interval interval = new Interval( |
| 627 sourceFile.getLine(codeSource.begin), | 591 sourceFile.getLine(codeSource.begin), |
| (...skipping 13 matching lines...) Expand all Loading... |
| 641 | 605 |
| 642 int index = 0; | 606 int index = 0; |
| 643 for (CodeLine jsCodeLine in codeLineInterval.keys) { | 607 for (CodeLine jsCodeLine in codeLineInterval.keys) { |
| 644 List<CodeLine> dartCodeLines = | 608 List<CodeLine> dartCodeLines = |
| 645 jsToDartMap.putIfAbsent(jsCodeLine, () => <CodeLine>[]); | 609 jsToDartMap.putIfAbsent(jsCodeLine, () => <CodeLine>[]); |
| 646 if (dartCodeLines.isEmpty && index < annotatedDartCodeLines.length) { | 610 if (dartCodeLines.isEmpty && index < annotatedDartCodeLines.length) { |
| 647 dartCodeLines.add(annotatedDartCodeLines[index++]); | 611 dartCodeLines.add(annotatedDartCodeLines[index++]); |
| 648 } | 612 } |
| 649 } | 613 } |
| 650 while (index < annotatedDartCodeLines.length) { | 614 while (index < annotatedDartCodeLines.length) { |
| 651 jsToDartMap[codeLineInterval.keys.last].add( | 615 jsToDartMap[codeLineInterval.keys.last] |
| 652 annotatedDartCodeLines[index++]); | 616 .add(annotatedDartCodeLines[index++]); |
| 653 } | 617 } |
| 654 | 618 |
| 655 currentUri = null; | 619 currentUri = null; |
| 656 } | 620 } |
| 657 | 621 |
| 658 void restart(CodeLine codeLine, CodeLocation codeLocation, int line) { | 622 void restart(CodeLine codeLine, CodeLocation codeLocation, int line) { |
| 659 flush(); | 623 flush(); |
| 660 | 624 |
| 661 currentUri = codeLocation.uri; | 625 currentUri = codeLocation.uri; |
| 662 interval = new Interval(line, line + 1); | 626 interval = new Interval(line, line + 1); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 674 int line = sourceFile.getLine(location.offset); | 638 int line = sourceFile.getLine(location.offset); |
| 675 if (currentUri != location.uri) { | 639 if (currentUri != location.uri) { |
| 676 restart(jsCodeLine, location, line); | 640 restart(jsCodeLine, location, line); |
| 677 } else if (interval.inWindow(line, windowSize: 2)) { | 641 } else if (interval.inWindow(line, windowSize: 2)) { |
| 678 interval = interval.include(line); | 642 interval = interval.include(line); |
| 679 codeLineInterval[jsCodeLine] = interval; | 643 codeLineInterval[jsCodeLine] = interval; |
| 680 } else { | 644 } else { |
| 681 restart(jsCodeLine, location, line); | 645 restart(jsCodeLine, location, line); |
| 682 } | 646 } |
| 683 | 647 |
| 684 annotations.add(new Annotation( | 648 annotations.add(new Annotation(codeLineAnnotation.annotationType, |
| 685 codeLineAnnotation.annotationType, | 649 location.offset, 'id=${codeLineAnnotation.annotationId}', |
| 686 location.offset, | |
| 687 'id=${codeLineAnnotation.annotationId}', | |
| 688 data: codeLineAnnotation)); | 650 data: codeLineAnnotation)); |
| 689 } | 651 } |
| 690 } | 652 } |
| 691 } | 653 } |
| 692 flush(); | 654 flush(); |
| 693 return jsToDartMap; | 655 return jsToDartMap; |
| 694 } | 656 } |
| 695 } | 657 } |
| 696 | 658 |
| 697 const DiffColumn column_js0 = const DiffColumn('js', 0); | 659 const DiffColumn column_js0 = const DiffColumn('js', 0); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 final int index; | 711 final int index; |
| 750 final String className; | 712 final String className; |
| 751 final bool isSourceMapped; | 713 final bool isSourceMapped; |
| 752 | 714 |
| 753 const AnnotationType(this.index, this.className, this.isSourceMapped); | 715 const AnnotationType(this.index, this.className, this.isSourceMapped); |
| 754 | 716 |
| 755 static const List<AnnotationType> values = const <AnnotationType>[ | 717 static const List<AnnotationType> values = const <AnnotationType>[ |
| 756 WITH_SOURCE_INFO, | 718 WITH_SOURCE_INFO, |
| 757 WITHOUT_SOURCE_INFO, | 719 WITHOUT_SOURCE_INFO, |
| 758 ADDITIONAL_SOURCE_INFO, | 720 ADDITIONAL_SOURCE_INFO, |
| 759 UNUSED_SOURCE_INFO]; | 721 UNUSED_SOURCE_INFO |
| 722 ]; |
| 760 } | 723 } |
| 761 | 724 |
| 762 class CodeLineAnnotation { | 725 class CodeLineAnnotation { |
| 763 final int annotationId; | 726 final int annotationId; |
| 764 final AnnotationType annotationType; | 727 final AnnotationType annotationType; |
| 765 final List<CodeLocation> codeLocations; | 728 final List<CodeLocation> codeLocations; |
| 766 final List<CodeSource> codeSources; | 729 final List<CodeSource> codeSources; |
| 767 final String stepInfo; | 730 final String stepInfo; |
| 768 int sourceMappingIndex; | 731 int sourceMappingIndex; |
| 769 | 732 |
| 770 CodeLineAnnotation( | 733 CodeLineAnnotation( |
| 771 {this.annotationId, | 734 {this.annotationId, |
| 772 this.annotationType, | 735 this.annotationType, |
| 773 this.codeLocations, | 736 this.codeLocations, |
| 774 this.codeSources, | 737 this.codeSources, |
| 775 this.stepInfo, | 738 this.stepInfo, |
| 776 this.sourceMappingIndex}); | 739 this.sourceMappingIndex}); |
| 777 | 740 |
| 778 Map toJson(JsonStrategy strategy) { | 741 Map toJson(JsonStrategy strategy) { |
| 779 return { | 742 return { |
| 780 'annotationId': annotationId, | 743 'annotationId': annotationId, |
| 781 'annotationType': annotationType.index, | 744 'annotationType': annotationType.index, |
| 782 'codeLocations': codeLocations.map((l) => l.toJson(strategy)).toList(), | 745 'codeLocations': codeLocations.map((l) => l.toJson(strategy)).toList(), |
| 783 'codeSources': codeSources.map((c) => c.toJson()).toList(), | 746 'codeSources': codeSources.map((c) => c.toJson()).toList(), |
| 784 'stepInfo': stepInfo, | 747 'stepInfo': stepInfo, |
| 785 'sourceMappingIndex': sourceMappingIndex, | 748 'sourceMappingIndex': sourceMappingIndex, |
| 786 }; | 749 }; |
| 787 } | 750 } |
| 788 | 751 |
| 789 static fromJson(Map json, JsonStrategy strategy) { | 752 static fromJson(Map json, JsonStrategy strategy) { |
| 790 return new CodeLineAnnotation( | 753 return new CodeLineAnnotation( |
| 791 annotationId: json['id'], | 754 annotationId: json['id'], |
| 792 annotationType: AnnotationType.values[json['annotationType']], | 755 annotationType: AnnotationType.values[json['annotationType']], |
| 793 codeLocations: json['codeLocations'] | 756 codeLocations: json['codeLocations'] |
| 794 .map((j) => CodeLocation.fromJson(j, strategy)) | 757 .map((j) => CodeLocation.fromJson(j, strategy)) |
| 795 .toList(), | 758 .toList(), |
| 796 codeSources: json['codeSources'] | 759 codeSources: |
| 797 .map((j) => CodeSource.fromJson(j)) | 760 json['codeSources'].map((j) => CodeSource.fromJson(j)).toList(), |
| 798 .toList(), | |
| 799 stepInfo: json['stepInfo'], | 761 stepInfo: json['stepInfo'], |
| 800 sourceMappingIndex: json['sourceMappingIndex']); | 762 sourceMappingIndex: json['sourceMappingIndex']); |
| 801 } | 763 } |
| 802 } | 764 } |
| OLD | NEW |