OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 /** Collects several code emitters for the template tool. */ | 5 /** Collects several code emitters for the template tool. */ |
6 library emitters; | 6 library emitters; |
7 | 7 |
8 import 'package:csslib/parser.dart' as css; | 8 import 'package:csslib/parser.dart' as css; |
9 import 'package:csslib/visitor.dart'; | 9 import 'package:csslib/visitor.dart'; |
10 import 'package:html5lib/dom.dart'; | 10 import 'package:html5lib/dom.dart'; |
11 import 'package:html5lib/dom_parsing.dart'; | 11 import 'package:html5lib/dom_parsing.dart'; |
12 import 'package:html5lib/parser.dart'; | 12 import 'package:html5lib/parser.dart'; |
13 import 'package:source_maps/span.dart' show Span, FileLocation; | 13 import 'package:source_maps/span.dart' show Span, FileLocation; |
14 | 14 |
| 15 import 'code_printer.dart'; |
15 import 'compiler.dart'; | 16 import 'compiler.dart'; |
16 import 'code_printer.dart'; | |
17 import 'dart_parser.dart' show DartCodeInfo; | 17 import 'dart_parser.dart' show DartCodeInfo; |
| 18 import 'html5_utils.dart'; |
18 import 'html_css_fixup.dart'; | 19 import 'html_css_fixup.dart'; |
19 import 'html5_utils.dart'; | |
20 import 'info.dart'; | 20 import 'info.dart'; |
21 import 'messages.dart'; | 21 import 'messages.dart'; |
| 22 import 'options.dart'; |
22 import 'paths.dart'; | 23 import 'paths.dart'; |
23 import 'refactor.dart'; | 24 import 'refactor.dart'; |
24 import 'utils.dart'; | 25 import 'utils.dart'; |
25 | 26 |
26 /** | |
27 * Context used by an emitter. Typically representing where to generate code | |
28 * and additional information, such as total number of generated identifiers. | |
29 */ | |
30 class Context { | |
31 final Declarations statics; | |
32 final CodePrinter printer; | |
33 final bool isClass; | |
34 | |
35 Context({Declarations statics, CodePrinter printer, bool isClass: false, | |
36 int indent: 0}) | |
37 : this.statics = statics != null | |
38 ? statics : new Declarations(indent, staticKeyword: isClass), | |
39 this.isClass = isClass, | |
40 this.printer = printer != null | |
41 ? printer : new CodePrinter(isClass ? indent + 1 : indent); | |
42 } | |
43 | |
44 | 27 |
45 /** Only x-tag name element selectors are emitted as [is="x-"]. */ | 28 /** Only x-tag name element selectors are emitted as [is="x-"]. */ |
46 class CssEmitter extends CssPrinter { | 29 class CssEmitter extends CssPrinter { |
47 final Set _componentsTag; | 30 final Set _componentsTag; |
48 | 31 |
49 CssEmitter(this._componentsTag); | 32 CssEmitter(this._componentsTag); |
50 | 33 |
51 /** | 34 /** |
52 * If element selector is a component's tag name, then change selector to | 35 * If element selector is a component's tag name, then change selector to |
53 * find element who's is attribute's the component's name. | 36 * find element who's is attribute's the component's name. |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 String emitComponentStyleSheet(StyleSheet ss, String tagName, | 175 String emitComponentStyleSheet(StyleSheet ss, String tagName, |
193 CssPolyfillKind polyfillKind) => | 176 CssPolyfillKind polyfillKind) => |
194 (new ComponentCssEmitter(tagName, polyfillKind) | 177 (new ComponentCssEmitter(tagName, polyfillKind) |
195 ..visitTree(ss, pretty: true)).toString(); | 178 ..visitTree(ss, pretty: true)).toString(); |
196 | 179 |
197 /** Generates the class corresponding to a single web component. */ | 180 /** Generates the class corresponding to a single web component. */ |
198 class WebComponentEmitter { | 181 class WebComponentEmitter { |
199 final Messages messages; | 182 final Messages messages; |
200 final FileInfo _fileInfo; | 183 final FileInfo _fileInfo; |
201 final CssPolyfillKind cssPolyfillKind; | 184 final CssPolyfillKind cssPolyfillKind; |
202 Context _context; | |
203 | 185 |
204 WebComponentEmitter(this._fileInfo, this.messages, this.cssPolyfillKind) | 186 WebComponentEmitter(this._fileInfo, this.messages, this.cssPolyfillKind); |
205 : _context = new Context(isClass: true, indent: 1); | |
206 | 187 |
207 CodePrinter run(ComponentInfo info, PathMapper pathMapper, | 188 CodePrinter run(ComponentInfo info, PathMapper pathMapper, |
208 TextEditTransaction transaction) { | 189 TextEditTransaction transaction) { |
209 var templateNode = info.elementNode; | 190 var templateNode = info.element.nodes.firstWhere( |
| 191 (n) => n.tagName == 'template', orElse: () => null); |
210 | 192 |
211 // elementNode is pointing at template tag (no attributes). | 193 if (templateNode != null) { |
212 assert(templateNode.tagName == 'element'); | |
213 for (var node in templateNode.nodes) { | |
214 if (node.tagName == 'template') { | |
215 templateNode = node; | |
216 break; | |
217 } | |
218 } | |
219 | |
220 if (info.element.attributes['apply-author-styles'] != null) { | |
221 _context.printer.addLine('if (__root is autogenerated.ShadowRoot) ' | |
222 '__root.applyAuthorStyles = true;'); | |
223 // TODO(jmesserly): warn at runtime if apply-author-styles was not set, | |
224 // and we don't have Shadow DOM support? In that case, styles won't have | |
225 // proper encapsulation. | |
226 } | |
227 | |
228 if (templateNode.tagName == 'template') { | |
229 if (!info.styleSheets.isEmpty && !messages.options.processCss) { | 194 if (!info.styleSheets.isEmpty && !messages.options.processCss) { |
230 // TODO(terry): Only one style tag per component. | 195 // TODO(terry): Only one style tag per component. |
231 | 196 |
232 // TODO(jmesserly): csslib + html5lib should work together. | 197 // TODO(jmesserly): csslib + html5lib should work together. |
233 // We shouldn't need to call a different function to serialize CSS. | 198 // We shouldn't need to call a different function to serialize CSS. |
234 // Calling innerHtml on a StyleElement should be enought - like a real | 199 // Calling innerHtml on a StyleElement should be enought - like a real |
235 // browser. CSSOM and DOM should work together in the same tree. | 200 // browser. CSSOM and DOM should work together in the same tree. |
236 var styleText = emitComponentStyleSheet( | 201 var styleText = emitComponentStyleSheet( |
237 info.styleSheets[0], info.tagName, cssPolyfillKind); | 202 info.styleSheets[0], info.tagName, cssPolyfillKind); |
238 | 203 |
239 templateNode.insertBefore( | 204 templateNode.insertBefore( |
240 new Element.html('<style>\n$styleText\n</style>'), | 205 new Element.html('<style>\n$styleText\n</style>'), |
241 templateNode.hasChildNodes() ? templateNode.children[0] : null); | 206 templateNode.hasChildNodes() ? templateNode.children[0] : null); |
242 } | 207 } |
243 | |
244 _context.statics.add('final', '__shadowTemplate', | |
245 templateNode.sourceSpan, | |
246 "new autogenerated.DocumentFragment.html('''" | |
247 "${escapeDartString(templateNode.innerHtml, triple: true)}" | |
248 "''')"); | |
249 | |
250 var syntax = templateNode.attributes['syntax']; | |
251 if (syntax != null) { | |
252 syntax = escapeDartString(syntax); | |
253 syntax = ", autogenerated.TemplateElement.syntax['$syntax']"; | |
254 } else { | |
255 syntax = ""; | |
256 } | |
257 | |
258 _context.printer | |
259 ..addLine("__root.nodes.add(cloneTemplate(__shadowTemplate));") | |
260 ..addLine("autogenerated_mdv.bindModel(__root, this$syntax);"); | |
261 } | 208 } |
262 | 209 |
263 bool hasExtends = info.extendsComponent != null; | 210 bool hasExtends = info.extendsComponent != null; |
264 var codeInfo = info.userCode; | 211 var codeInfo = info.userCode; |
265 var classDecl = info.classDeclaration; | 212 var classDecl = info.classDeclaration; |
266 if (classDecl == null) return null; | 213 if (classDecl == null) return null; |
267 | 214 |
268 if (transaction == null) { | 215 if (transaction == null) { |
269 transaction = new TextEditTransaction(codeInfo.code, codeInfo.sourceFile); | 216 transaction = new TextEditTransaction(codeInfo.code, codeInfo.sourceFile); |
270 } | 217 } |
271 | 218 |
272 // Expand the headers to include polymer imports, unless they are already | 219 // Expand the headers to include polymer imports, unless they are already |
273 // present. | 220 // present. |
274 var libraryName = (codeInfo.libraryName != null) | 221 var libraryName = (codeInfo.libraryName != null) |
275 ? codeInfo.libraryName | 222 ? codeInfo.libraryName |
276 : info.tagName.replaceAll(new RegExp('[-./]'), '_'); | 223 : info.tagName.replaceAll(new RegExp('[-./]'), '_'); |
277 var header = new CodePrinter(0); | 224 var header = new CodePrinter(0); |
278 header.add(_header(path.basename(info.declaringFile.inputUrl.resolvedPath), | 225 header.add(_header(path.basename(info.declaringFile.inputUrl.resolvedPath), |
279 libraryName)); | 226 libraryName)); |
280 emitImports(codeInfo, info, pathMapper, header); | 227 emitImports(codeInfo, info, pathMapper, header); |
281 header.addLine(''); | 228 header.addLine(''); |
282 transaction.edit(0, codeInfo.directivesEnd, header); | 229 transaction.edit(0, codeInfo.directivesEnd, header); |
283 | 230 |
284 var mangle = cssPolyfillKind == CssPolyfillKind.MANGLED_POLYFILL; | |
285 var cssMapExpression = createCssSelectorsExpression(info, mangle); | |
286 var classBody = new CodePrinter(1) | 231 var classBody = new CodePrinter(1) |
287 ..add('\n') | 232 ..add('\n') |
288 ..addLine('/** Autogenerated from the template. */') | |
289 ..addLine('') | |
290 // TODO(terry): Remove [_css]; after migrating to getScopedCss. | |
291 ..addLine('autogenerated.ScopedCssMapper _css;') | |
292 ..addLine('') | |
293 ..addLine('/** This field is deprecated, use getShadowRoot instead. */') | |
294 ..addLine('get _root => getShadowRoot("${info.tagName}");') | |
295 ..add(_context.statics) | |
296 ..addLine('') | |
297 ..addLine('void initShadow() {') | |
298 ..addLine(hasExtends ? ' super.initShadow();' : null) | |
299 ..addLine(' var __root = createShadowRoot("${info.tagName}");') | |
300 ..addLine(' shadowRootReady(__root, "${info.tagName}");') | |
301 ..addLine(' setScopedCss("${info.tagName}", ' | |
302 'new autogenerated.ScopedCssMapper($cssMapExpression));') | |
303 // TODO(terry): Remove assignment after migrating to getScopedCss. | |
304 ..addLine(' _css = getScopedCss("${info.tagName}");') | |
305 ..add(_context.printer) | |
306 ..addLine('}') | |
307 ..addLine('') | |
308 ..addLine('/** Original code from the component. */'); | 233 ..addLine('/** Original code from the component. */'); |
309 | 234 |
310 var pos = classDecl.leftBracket.end; | 235 var pos = classDecl.leftBracket.end; |
311 transaction.edit(pos, pos, classBody); | 236 transaction.edit(pos, pos, classBody); |
312 | 237 |
313 // Emit all the code in a single printer, keeping track of source-maps. | 238 // Emit all the code in a single printer, keeping track of source-maps. |
314 return transaction.commit(); | 239 return transaction.commit(); |
315 } | 240 } |
316 } | 241 } |
317 | 242 |
318 /** Generates the class corresponding to the main html page. */ | 243 /** The code that will be used to bootstrap the application. */ |
319 class EntryPointEmitter { | 244 CodePrinter generateBootstrapCode( |
320 final GlobalInfo global; | 245 FileInfo info, FileInfo userMainInfo, GlobalInfo global, |
321 final FileInfo _fileInfo; | 246 PathMapper pathMapper, CompilerOptions options) { |
322 Context _context; | |
323 | 247 |
324 EntryPointEmitter(this._fileInfo, this.global) | 248 var printer = new CodePrinter(0) |
325 : _context = new Context(indent: 1); | 249 ..addLine('library app_bootstrap;') |
| 250 ..addLine('') |
| 251 ..addLine("import 'package:polymer/polymer.dart' as polymer;"); |
326 | 252 |
327 CodePrinter run(PathMapper pathMapper, TextEditTransaction transaction, | 253 if (userMainInfo.userCode != null) { |
328 bool rewriteUrls) { | 254 printer..addLine('') |
| 255 ..addLine("import '${pathMapper.importUrlFor(info, userMainInfo)}' " |
| 256 "as userMain;\n"); |
| 257 } |
329 | 258 |
330 var filePath = _fileInfo.inputUrl.resolvedPath; | 259 for (var c in global.components.values) { |
| 260 if (c.hasConflict) continue; |
| 261 printer.addLine("import '${pathMapper.importUrlFor(info, c)}';"); |
| 262 } |
331 | 263 |
332 var codeInfo = _fileInfo.userCode; | 264 printer..addLine('') |
333 if (codeInfo == null) { | 265 ..addLine('void main() {') |
334 assert(transaction == null); | 266 ..indent += 1; |
335 codeInfo = new DartCodeInfo(null, null, [], 'main(){\n}', null); | |
336 } | |
337 | 267 |
338 if (transaction == null) { | 268 if (userMainInfo.userCode != null) printer.addLine('userMain.main();'); |
339 transaction = new TextEditTransaction(codeInfo.code, codeInfo.sourceFile); | |
340 } | |
341 | 269 |
342 var libraryName = codeInfo.libraryName != null | 270 for (var c in global.components.values) { |
343 ? codeInfo.libraryName : _fileInfo.libraryName; | 271 if (c.hasConflict) continue; |
344 var header = new CodePrinter(0); | 272 var tagName = escapeDartString(c.tagName); |
345 header.add(_header(path.basename(filePath), libraryName)); | 273 var cssMapExpression = createCssSelectorsExpression(c, |
346 emitImports(codeInfo, _fileInfo, pathMapper, header, global); | 274 CssPolyfillKind.of(options, c)); |
347 header..addLine('') | 275 printer |
348 ..addLine('') | 276 ..addLine("polymer.setScopedCss('$tagName', $cssMapExpression);") |
349 ..addLine('// Original code'); | 277 ..addLine("polymer.registerPolymerElement(" |
350 transaction.edit(0, codeInfo.directivesEnd, header); | 278 "'$tagName', () => new ${c.className}());"); |
| 279 } |
351 | 280 |
352 var printer = (transaction.commit()) | 281 return printer |
353 ..addLine('') | 282 ..indent -= 1 |
354 ..addLine('// Additional generated code') | 283 ..addLine('}'); |
355 ..addLine('void init_autogenerated() {') | 284 } |
356 ..indent += 1; | |
357 | 285 |
358 for (var c in global.components.values) { | |
359 if (c.hasConflict) continue; | |
360 var tagName = escapeDartString(c.tagName); | |
361 | 286 |
362 printer.addLine("autogenerated.registerPolymerElement(" | |
363 "new autogenerated.Element.html(" | |
364 "'${escapeDartString(c.elementNode.outerHtml)}')" | |
365 ", () => new ${c.className}());"); | |
366 } | |
367 | |
368 return printer | |
369 ..add(_context.statics) | |
370 ..add(_context.printer) | |
371 ..indent -= 1 | |
372 ..addLine('}'); | |
373 } | |
374 } | |
375 | 287 |
376 /** | 288 /** |
377 * List of HTML4 elements which could have relative URL resource: | 289 * List of HTML4 elements which could have relative URL resource: |
378 * | 290 * |
379 * <body background=url>, <img src=url>, <input src=url> | 291 * <body background=url>, <img src=url>, <input src=url> |
380 * | 292 * |
381 * HTML 5: | 293 * HTML 5: |
382 * | 294 * |
383 * <audio src=url>, <command icon=url>, <embed src=url>, | 295 * <audio src=url>, <command icon=url>, <embed src=url>, |
384 * <source src=url>, <video poster=url> and <video src=url> | 296 * <source src=url>, <video poster=url> and <video src=url> |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 var file = codeInfo.sourceFile; | 356 var file = codeInfo.sourceFile; |
445 for (var d in codeInfo.directives) { | 357 for (var d in codeInfo.directives) { |
446 addUnique(d.toString(), file != null ? file.location(d.offset) : null); | 358 addUnique(d.toString(), file != null ? file.location(d.offset) : null); |
447 } | 359 } |
448 } | 360 } |
449 | 361 |
450 final shadowDomJS = new RegExp(r'shadowdom\..*\.js', caseSensitive: false); | 362 final shadowDomJS = new RegExp(r'shadowdom\..*\.js', caseSensitive: false); |
451 | 363 |
452 /** Trim down the html for the main html page. */ | 364 /** Trim down the html for the main html page. */ |
453 void transformMainHtml(Document document, FileInfo fileInfo, | 365 void transformMainHtml(Document document, FileInfo fileInfo, |
454 PathMapper pathMapper, bool hasCss, bool rewriteUrls, Messages messages) { | 366 PathMapper pathMapper, bool hasCss, bool rewriteUrls, |
| 367 Messages messages, GlobalInfo global) { |
455 var filePath = fileInfo.inputUrl.resolvedPath; | 368 var filePath = fileInfo.inputUrl.resolvedPath; |
456 | 369 |
457 bool dartLoaderFound = false; | 370 bool dartLoaderFound = false; |
458 bool shadowDomFound = false; | 371 bool shadowDomFound = false; |
459 for (var tag in document.queryAll('script')) { | 372 for (var tag in document.queryAll('script')) { |
460 var src = tag.attributes['src']; | 373 var src = tag.attributes['src']; |
461 if (src != null) { | 374 if (src != null) { |
462 var last = src.split('/').last; | 375 var last = src.split('/').last; |
463 if (last == 'dart.js' || last == 'testing.js') { | 376 if (last == 'dart.js' || last == 'testing.js') { |
464 dartLoaderFound = true; | 377 dartLoaderFound = true; |
465 } else if (shadowDomJS.hasMatch(last)) { | 378 } else if (shadowDomJS.hasMatch(last)) { |
466 shadowDomFound = true; | 379 shadowDomFound = true; |
467 } | 380 } |
468 } | 381 } |
469 if (tag.attributes['type'] == 'application/dart') { | 382 if (tag.attributes['type'] == 'application/dart') { |
470 tag.remove(); | 383 tag.remove(); |
471 } else if (src != null && rewriteUrls) { | 384 } else if (src != null && rewriteUrls) { |
472 tag.attributes["src"] = pathMapper.transformUrl(filePath, src); | 385 tag.attributes["src"] = pathMapper.transformUrl(filePath, src); |
473 } | 386 } |
474 } | 387 } |
| 388 |
475 for (var tag in document.queryAll('link')) { | 389 for (var tag in document.queryAll('link')) { |
476 var href = tag.attributes['href']; | 390 var href = tag.attributes['href']; |
477 var rel = tag.attributes['rel']; | 391 var rel = tag.attributes['rel']; |
478 if (rel == 'component' || rel == 'components' || rel == 'import') { | 392 if (rel == 'component' || rel == 'components' || rel == 'import') { |
479 tag.remove(); | 393 tag.remove(); |
480 } else if (href != null && rewriteUrls && !hasCss) { | 394 } else if (href != null && rewriteUrls && !hasCss) { |
481 // Only rewrite URL if rewrite on and we're not CSS polyfilling. | 395 // Only rewrite URL if rewrite on and we're not CSS polyfilling. |
482 tag.attributes['href'] = pathMapper.transformUrl(filePath, href); | 396 tag.attributes['href'] = pathMapper.transformUrl(filePath, href); |
483 } | 397 } |
484 } | 398 } |
(...skipping 20 matching lines...) Expand all Loading... |
505 for (var i = styles.length - 1; i > 0 ; i--) { | 419 for (var i = styles.length - 1; i > 0 ; i--) { |
506 styles[i].remove(); | 420 styles[i].remove(); |
507 } | 421 } |
508 } | 422 } |
509 | 423 |
510 // TODO(jmesserly): put this in the global CSS file? | 424 // TODO(jmesserly): put this in the global CSS file? |
511 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#
css-additions | 425 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#
css-additions |
512 document.head.nodes.insert(0, parseFragment( | 426 document.head.nodes.insert(0, parseFragment( |
513 '<style>template { display: none; }</style>')); | 427 '<style>template { display: none; }</style>')); |
514 | 428 |
| 429 // Move all <element> declarations to the main HTML file |
| 430 // TODO(sigmund): remove this once we have HTMLImports implemented. |
| 431 for (var c in global.components.values) { |
| 432 document.body.nodes.insert(0, new Text('\n')); |
| 433 var fragment = c.element; |
| 434 for (var tag in fragment.queryAll('script')) { |
| 435 // TODO(sigmund): leave script tags around when we start using "boot.js" |
| 436 if (tag.attributes['type'] == 'application/dart') { |
| 437 tag.remove(); |
| 438 } |
| 439 } |
| 440 document.body.nodes.insert(0, fragment); |
| 441 } |
| 442 |
| 443 |
515 if (!shadowDomFound) { | 444 if (!shadowDomFound) { |
516 // TODO(jmesserly): we probably shouldn't add this automatically. | 445 // TODO(jmesserly): we probably shouldn't add this automatically. |
517 document.body.nodes.add(parseFragment('<script type="text/javascript" ' | 446 document.body.nodes.add(parseFragment('<script type="text/javascript" ' |
518 'src="packages/shadow_dom/shadow_dom.debug.js"></script>\n')); | 447 'src="packages/shadow_dom/shadow_dom.debug.js"></script>\n')); |
519 } | 448 } |
520 if (!dartLoaderFound) { | 449 if (!dartLoaderFound) { |
521 // TODO(jmesserly): turn this warning on. | 450 // TODO(jmesserly): turn this warning on. |
522 //messages.warning('Missing script to load Dart. ' | 451 //messages.warning('Missing script to load Dart. ' |
523 // 'Please add this line to your HTML file: $dartLoader', | 452 // 'Please add this line to your HTML file: $dartLoader', |
524 // document.body.sourceSpan); | 453 // document.body.sourceSpan); |
| 454 // TODO(sigmund): switch to 'boot.js' |
525 document.body.nodes.add(parseFragment('<script type="text/javascript" ' | 455 document.body.nodes.add(parseFragment('<script type="text/javascript" ' |
526 'src="packages/browser/dart.js"></script>\n')); | 456 'src="packages/browser/dart.js"></script>\n')); |
527 } | 457 } |
528 | 458 |
529 // Insert the "auto-generated" comment after the doctype, otherwise IE will | 459 // Insert the "auto-generated" comment after the doctype, otherwise IE will |
530 // go into quirks mode. | 460 // go into quirks mode. |
531 int commentIndex = 0; | 461 int commentIndex = 0; |
532 DocumentType doctype = find(document.nodes, (n) => n is DocumentType); | 462 DocumentType doctype = find(document.nodes, (n) => n is DocumentType); |
533 if (doctype != null) { | 463 if (doctype != null) { |
534 commentIndex = document.nodes.indexOf(doctype) + 1; | 464 commentIndex = document.nodes.indexOf(doctype) + 1; |
(...skipping 20 matching lines...) Expand all Loading... |
555 // Auto-generated from $filename. | 485 // Auto-generated from $filename. |
556 // DO NOT EDIT. | 486 // DO NOT EDIT. |
557 $lib | 487 $lib |
558 import 'dart:html' as autogenerated; | 488 import 'dart:html' as autogenerated; |
559 import 'dart:svg' as autogenerated_svg; | 489 import 'dart:svg' as autogenerated_svg; |
560 import 'package:mdv/mdv.dart' as autogenerated_mdv; | 490 import 'package:mdv/mdv.dart' as autogenerated_mdv; |
561 import 'package:observe/observe.dart' as __observe; | 491 import 'package:observe/observe.dart' as __observe; |
562 import 'package:polymer/polymer.dart' as autogenerated; | 492 import 'package:polymer/polymer.dart' as autogenerated; |
563 """; | 493 """; |
564 } | 494 } |
OLD | NEW |