Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /// Transfomer that inlines polymer-element definitions from html imports. | 5 /// Transfomer that inlines polymer-element definitions from html imports. |
| 6 library polymer.src.build.import_inliner; | 6 library polymer.src.build.import_inliner; |
| 7 | 7 |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 import 'dart:convert'; | 9 import 'dart:convert'; |
| 10 | 10 |
| 11 import 'package:analyzer/analyzer.dart'; | 11 import 'package:analyzer/analyzer.dart'; |
| 12 import 'package:analyzer/src/generated/ast.dart'; | 12 import 'package:analyzer/src/generated/ast.dart'; |
| 13 import 'package:barback/barback.dart'; | 13 import 'package:barback/barback.dart'; |
| 14 import 'package:code_transformers/assets.dart'; | 14 import 'package:code_transformers/assets.dart'; |
| 15 import 'package:path/path.dart' as path; | 15 import 'package:path/path.dart' as path; |
| 16 import 'package:html5lib/dom.dart' show | 16 import 'package:html5lib/dom.dart' show |
| 17 Document, DocumentFragment, Element, Node; | 17 Document, DocumentFragment, Element, Node; |
| 18 import 'package:html5lib/dom_parsing.dart' show TreeVisitor; | 18 import 'package:html5lib/dom_parsing.dart' show TreeVisitor; |
| 19 import 'package:source_maps/refactor.dart' show TextEditTransaction; | 19 import 'package:source_maps/refactor.dart' show TextEditTransaction; |
| 20 import 'package:source_span/source_span.dart'; | 20 import 'package:source_span/source_span.dart'; |
| 21 | 21 |
| 22 import 'common.dart'; | 22 import 'common.dart'; |
| 23 import 'wrapped_logger.dart'; | |
| 23 | 24 |
| 24 // TODO(sigmund): move to web_components package (dartbug.com/18037). | 25 // TODO(sigmund): move to web_components package (dartbug.com/18037). |
| 25 class _HtmlInliner extends PolymerTransformer { | 26 class _HtmlInliner extends PolymerTransformer { |
| 26 final TransformOptions options; | 27 final TransformOptions options; |
| 27 final Transform transform; | 28 final Transform transform; |
| 28 final TransformLogger logger; | 29 final TransformLogger logger; |
| 29 final AssetId docId; | 30 final AssetId docId; |
| 30 final seen = new Set<AssetId>(); | 31 final seen = new Set<AssetId>(); |
| 31 final scriptIds = <AssetId>[]; | 32 final scriptIds = <AssetId>[]; |
| 32 final extractedFiles = new Set<AssetId>(); | 33 final extractedFiles = new Set<AssetId>(); |
| 33 bool experimentalBootstrap = false; | 34 bool experimentalBootstrap = false; |
| 34 | 35 |
| 35 /// The number of extracted inline Dart scripts. Used as a counter to give | 36 /// The number of extracted inline Dart scripts. Used as a counter to give |
| 36 /// unique-ish filenames. | 37 /// unique-ish filenames. |
| 37 int inlineScriptCounter = 0; | 38 int inlineScriptCounter = 0; |
| 38 | 39 |
| 39 _HtmlInliner(this.options, Transform transform) | 40 _HtmlInliner(TransformOptions options, Transform transform) |
| 40 : transform = transform, | 41 : options = options, |
| 41 logger = transform.logger, | 42 transform = transform, |
| 43 logger = options.releaseMode ? transform.logger : | |
| 44 new WrappedLogger(transform, convertErrorsToWarnings: true), | |
| 42 docId = transform.primaryInput.id; | 45 docId = transform.primaryInput.id; |
| 43 | 46 |
| 44 Future apply() { | 47 Future apply() { |
| 45 seen.add(docId); | 48 seen.add(docId); |
| 46 | 49 |
| 47 Document document; | 50 Document document; |
| 48 bool changed = false; | 51 bool changed = false; |
| 49 | 52 |
| 50 return readPrimaryAsHtml(transform).then((doc) { | 53 return readPrimaryAsHtml(transform).then((doc) { |
| 51 document = doc; | 54 document = doc; |
| 52 changed = new _UrlNormalizer(transform, docId).visit(document) || changed; | 55 changed = new _UrlNormalizer(transform, docId, logger).visit(document) |
| 56 || changed; | |
| 53 | 57 |
| 54 experimentalBootstrap = document.querySelectorAll('link').any((link) => | 58 experimentalBootstrap = document.querySelectorAll('link').any((link) => |
| 55 link.attributes['rel'] == 'import' && | 59 link.attributes['rel'] == 'import' && |
| 56 link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML); | 60 link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML); |
| 57 changed = _extractScripts(document) || changed; | 61 changed = _extractScripts(document) || changed; |
| 58 return _visitImports(document); | 62 return _visitImports(document); |
| 59 }).then((importsFound) { | 63 }).then((importsFound) { |
| 60 changed = changed || importsFound; | 64 changed = changed || importsFound; |
| 61 return _removeScripts(document); | 65 return _removeScripts(document); |
| 62 }).then((scriptsRemoved) { | 66 }).then((scriptsRemoved) { |
| 63 changed = changed || scriptsRemoved; | 67 changed = changed || scriptsRemoved; |
| 64 | 68 |
| 65 var output = transform.primaryInput; | 69 var output = transform.primaryInput; |
| 66 if (changed) output = new Asset.fromString(docId, document.outerHtml); | 70 if (changed) output = new Asset.fromString(docId, document.outerHtml); |
| 67 transform.addOutput(output); | 71 transform.addOutput(output); |
| 68 | 72 |
| 69 // We produce a secondary asset with extra information for later phases. | 73 // We produce a secondary asset with extra information for later phases. |
| 70 transform.addOutput(new Asset.fromString( | 74 transform.addOutput(new Asset.fromString( |
| 71 docId.addExtension('._data'), | 75 docId.addExtension('._data'), |
| 72 JSON.encode({ | 76 JSON.encode({ |
| 73 'experimental_bootstrap': experimentalBootstrap, | 77 'experimental_bootstrap': experimentalBootstrap, |
| 74 'script_ids': scriptIds, | 78 'script_ids': scriptIds, |
| 75 }, toEncodable: (id) => id.serialize()))); | 79 }, toEncodable: (id) => id.serialize()))); |
| 80 | |
| 81 // Write out the logs collected by our [WrappedLogger]. | |
| 82 if (options.injectBuildLogsInOutput && logger is WrappedLogger) { | |
|
Siggi Cherem (dart-lang)
2014/08/06 17:25:22
I'm guessing our invariants guarantee that the sec
jakemac
2014/08/06 19:41:22
Technically not any more, when in release mode we
Siggi Cherem (dart-lang)
2014/08/06 19:50:22
Ah ok - for some reason I thought we didn't let th
jakemac
2014/08/06 19:59:37
I do want to keep the same semantics around conver
| |
| 83 return logger.writeOutput(); | |
| 84 } | |
| 76 }); | 85 }); |
| 77 } | 86 } |
| 78 | 87 |
| 79 /// Visits imports in [document] and add the imported documents to documents. | 88 /// Visits imports in [document] and add the imported documents to documents. |
| 80 /// Documents are added in the order they appear, transitive imports are added | 89 /// Documents are added in the order they appear, transitive imports are added |
| 81 /// first. | 90 /// first. |
| 82 /// | 91 /// |
| 83 /// Returns `true` if and only if the document was changed and should be | 92 /// Returns `true` if and only if the document was changed and should be |
| 84 /// written out. | 93 /// written out. |
| 85 Future<bool> _visitImports(Document document) { | 94 Future<bool> _visitImports(Document document) { |
| 86 bool changed = false; | 95 bool changed = false; |
| 87 | 96 |
| 88 _moveHeadToBody(document); | 97 _moveHeadToBody(document); |
| 89 | 98 |
| 90 // Note: we need to preserve the import order in the generated output. | 99 // Note: we need to preserve the import order in the generated output. |
| 91 return Future.forEach(document.querySelectorAll('link'), (Element tag) { | 100 return Future.forEach(document.querySelectorAll('link'), (Element tag) { |
| 92 var rel = tag.attributes['rel']; | 101 var rel = tag.attributes['rel']; |
| 93 if (rel != 'import' && rel != 'stylesheet') return null; | 102 if (rel != 'import' && rel != 'stylesheet') return null; |
| 94 | 103 |
| 95 // Note: URL has already been normalized so use docId. | 104 // Note: URL has already been normalized so use docId. |
| 96 var href = tag.attributes['href']; | 105 var href = tag.attributes['href']; |
| 97 var id = uriToAssetId(docId, href, transform.logger, tag.sourceSpan, | 106 var id = uriToAssetId(docId, href, logger, tag.sourceSpan, |
| 98 errorOnAbsolute: rel != 'stylesheet'); | 107 errorOnAbsolute: rel != 'stylesheet'); |
| 99 | 108 |
| 100 if (rel == 'import') { | 109 if (rel == 'import') { |
| 101 changed = true; | 110 changed = true; |
| 102 if (id == null || !seen.add(id)) { | 111 if (id == null || !seen.add(id)) { |
| 103 tag.remove(); | 112 tag.remove(); |
| 104 return null; | 113 return null; |
| 105 } | 114 } |
| 106 return _inlineImport(id, tag); | 115 return _inlineImport(id, tag); |
| 107 | 116 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 // Move the node into the body, where its contents will be placed. | 148 // Move the node into the body, where its contents will be placed. |
| 140 doc.body.insertBefore(node, insertionPoint); | 149 doc.body.insertBefore(node, insertionPoint); |
| 141 } | 150 } |
| 142 } | 151 } |
| 143 } | 152 } |
| 144 | 153 |
| 145 /// Loads an asset identified by [id], visits its imports and collects its | 154 /// Loads an asset identified by [id], visits its imports and collects its |
| 146 /// html imports. Then inlines it into the main document. | 155 /// html imports. Then inlines it into the main document. |
| 147 Future _inlineImport(AssetId id, Element link) { | 156 Future _inlineImport(AssetId id, Element link) { |
| 148 return readAsHtml(id, transform).catchError((error) { | 157 return readAsHtml(id, transform).catchError((error) { |
| 149 transform.logger.error( | 158 logger.error( |
| 150 "Failed to inline html import: $error", asset: id, | 159 "Failed to inline html import: $error", asset: id, |
| 151 span: link.sourceSpan); | 160 span: link.sourceSpan); |
| 152 }).then((doc) { | 161 }).then((doc) { |
| 153 if (doc == null) return false; | 162 if (doc == null) return false; |
| 154 new _UrlNormalizer(transform, id).visit(doc); | 163 new _UrlNormalizer(transform, id, logger).visit(doc); |
| 155 return _visitImports(doc).then((_) { | 164 return _visitImports(doc).then((_) { |
| 156 // _UrlNormalizer already ensures there is a library name. | 165 // _UrlNormalizer already ensures there is a library name. |
| 157 _extractScripts(doc, injectLibraryName: false); | 166 _extractScripts(doc, injectLibraryName: false); |
| 158 | 167 |
| 159 // TODO(jmesserly): figure out how this is working in vulcanizer. | 168 // TODO(jmesserly): figure out how this is working in vulcanizer. |
| 160 // Do they produce a <body> tag with a <head> and <body> inside? | 169 // Do they produce a <body> tag with a <head> and <body> inside? |
| 161 var imported = new DocumentFragment(); | 170 var imported = new DocumentFragment(); |
| 162 imported.nodes..addAll(doc.head.nodes)..addAll(doc.body.nodes); | 171 imported.nodes..addAll(doc.head.nodes)..addAll(doc.body.nodes); |
| 163 link.replaceWith(imported); | 172 link.replaceWith(imported); |
| 164 }); | 173 }); |
| 165 }); | 174 }); |
| 166 } | 175 } |
| 167 | 176 |
| 168 Future _inlineStylesheet(AssetId id, Element link) { | 177 Future _inlineStylesheet(AssetId id, Element link) { |
| 169 return transform.readInputAsString(id).catchError((error) { | 178 return transform.readInputAsString(id).catchError((error) { |
| 170 // TODO(jakemac): Move this warning to the linter once we can make it run | 179 // TODO(jakemac): Move this warning to the linter once we can make it run |
| 171 // always (see http://dartbug.com/17199). Then hide this error and replace | 180 // always (see http://dartbug.com/17199). Then hide this error and replace |
| 172 // with a comment pointing to the linter error (so we don't double warn). | 181 // with a comment pointing to the linter error (so we don't double warn). |
| 173 transform.logger.warning( | 182 logger.warning( |
| 174 "Failed to inline stylesheet: $error", asset: id, | 183 "Failed to inline stylesheet: $error", asset: id, |
| 175 span: link.sourceSpan); | 184 span: link.sourceSpan); |
| 176 }).then((css) { | 185 }).then((css) { |
| 177 if (css == null) return; | 186 if (css == null) return; |
| 178 css = new _UrlNormalizer(transform, id).visitCss(css); | 187 css = new _UrlNormalizer(transform, id, logger).visitCss(css); |
| 179 var styleElement = new Element.tag('style')..text = css; | 188 var styleElement = new Element.tag('style')..text = css; |
| 180 // Copy over the extra attributes from the link tag to the style tag. | 189 // Copy over the extra attributes from the link tag to the style tag. |
| 181 // This adds support for no-shim, shim-shadowdom, etc. | 190 // This adds support for no-shim, shim-shadowdom, etc. |
| 182 link.attributes.forEach((key, value) { | 191 link.attributes.forEach((key, value) { |
| 183 if (!IGNORED_LINKED_STYLE_ATTRS.contains(key)) { | 192 if (!IGNORED_LINKED_STYLE_ATTRS.contains(key)) { |
| 184 styleElement.attributes[key] = value; | 193 styleElement.attributes[key] = value; |
| 185 } | 194 } |
| 186 }); | 195 }); |
| 187 link.replaceWith(styleElement); | 196 link.replaceWith(styleElement); |
| 188 }); | 197 }); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 /// Counter used to ensure that every library name we inject is unique. | 329 /// Counter used to ensure that every library name we inject is unique. |
| 321 int _count = 0; | 330 int _count = 0; |
| 322 | 331 |
| 323 /// Path to the top level folder relative to the transform primaryInput. | 332 /// Path to the top level folder relative to the transform primaryInput. |
| 324 /// This should just be some arbitrary # of ../'s. | 333 /// This should just be some arbitrary # of ../'s. |
| 325 final String topLevelPath; | 334 final String topLevelPath; |
| 326 | 335 |
| 327 /// Whether or not the normalizer has changed something in the tree. | 336 /// Whether or not the normalizer has changed something in the tree. |
| 328 bool changed = false; | 337 bool changed = false; |
| 329 | 338 |
| 330 _UrlNormalizer(transform, this.sourceId) | 339 final TransformLogger logger; |
| 340 | |
| 341 _UrlNormalizer(transform, this.sourceId, this.logger) | |
| 331 : transform = transform, | 342 : transform = transform, |
| 332 topLevelPath = | 343 topLevelPath = |
| 333 '../' * (transform.primaryInput.id.path.split('/').length - 2); | 344 '../' * (transform.primaryInput.id.path.split('/').length - 2); |
| 334 | 345 |
| 335 visit(Node node) { | 346 visit(Node node) { |
| 336 super.visit(node); | 347 super.visit(node); |
| 337 return changed; | 348 return changed; |
| 338 } | 349 } |
| 339 | 350 |
| 340 visitElement(Element node) { | 351 visitElement(Element node) { |
| 341 // TODO(jakemac): Support custom elements that extend html elements which | 352 // TODO(jakemac): Support custom elements that extend html elements which |
| 342 // have url-like attributes. This probably means keeping a list of which | 353 // have url-like attributes. This probably means keeping a list of which |
| 343 // html elements support each url-like attribute. | 354 // html elements support each url-like attribute. |
| 344 if (!isCustomTagName(node.localName)) { | 355 if (!isCustomTagName(node.localName)) { |
| 345 node.attributes.forEach((name, value) { | 356 node.attributes.forEach((name, value) { |
| 346 if (_urlAttributes.contains(name)) { | 357 if (_urlAttributes.contains(name)) { |
| 347 if (!name.startsWith('_') && value.contains(_BINDING_REGEX)) { | 358 if (!name.startsWith('_') && value.contains(_BINDING_REGEX)) { |
| 348 transform.logger.warning( | 359 logger.warning( |
| 349 'When using bindings with the "$name" attribute you may ' | 360 'When using bindings with the "$name" attribute you may ' |
| 350 'experience errors in certain browsers. Please use the ' | 361 'experience errors in certain browsers. Please use the ' |
| 351 '"_$name" attribute instead. For more information, see ' | 362 '"_$name" attribute instead. For more information, see ' |
| 352 'http://goo.gl/5av8cU', span: node.sourceSpan, asset: sourceId); | 363 'http://goo.gl/5av8cU', span: node.sourceSpan, asset: sourceId); |
| 353 } else if (name.startsWith('_') && !value.contains(_BINDING_REGEX)) { | 364 } else if (name.startsWith('_') && !value.contains(_BINDING_REGEX)) { |
| 354 transform.logger.warning( | 365 logger.warning( |
| 355 'The "$name" attribute is only supported when using bindings. ' | 366 'The "$name" attribute is only supported when using bindings. ' |
| 356 'Please change to the "${name.substring(1)}" attribute.', | 367 'Please change to the "${name.substring(1)}" attribute.', |
| 357 span: node.sourceSpan, asset: sourceId); | 368 span: node.sourceSpan, asset: sourceId); |
| 358 } | 369 } |
| 359 if (value != '' && !value.trim().startsWith(_BINDING_REGEX)) { | 370 if (value != '' && !value.trim().startsWith(_BINDING_REGEX)) { |
| 360 node.attributes[name] = _newUrl(value, node.sourceSpan); | 371 node.attributes[name] = _newUrl(value, node.sourceSpan); |
| 361 changed = changed || value != node.attributes[name]; | 372 changed = changed || value != node.attributes[name]; |
| 362 } | 373 } |
| 363 } | 374 } |
| 364 }); | 375 }); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 400 String visitInlineDart(String code) { | 411 String visitInlineDart(String code) { |
| 401 var unit = parseDirectives(code, suppressErrors: true); | 412 var unit = parseDirectives(code, suppressErrors: true); |
| 402 var file = new SourceFile(code, url: spanUrlFor(sourceId, transform)); | 413 var file = new SourceFile(code, url: spanUrlFor(sourceId, transform)); |
| 403 var output = new TextEditTransaction(code, file); | 414 var output = new TextEditTransaction(code, file); |
| 404 var foundLibraryDirective = false; | 415 var foundLibraryDirective = false; |
| 405 for (Directive directive in unit.directives) { | 416 for (Directive directive in unit.directives) { |
| 406 if (directive is UriBasedDirective) { | 417 if (directive is UriBasedDirective) { |
| 407 var uri = directive.uri.stringValue; | 418 var uri = directive.uri.stringValue; |
| 408 var span = _getSpan(file, directive.uri); | 419 var span = _getSpan(file, directive.uri); |
| 409 | 420 |
| 410 var id = uriToAssetId(sourceId, uri, transform.logger, span, | 421 var id = uriToAssetId(sourceId, uri, logger, span, |
| 411 errorOnAbsolute: false); | 422 errorOnAbsolute: false); |
| 412 if (id == null) continue; | 423 if (id == null) continue; |
| 413 | 424 |
| 414 var primaryId = transform.primaryInput.id; | 425 var primaryId = transform.primaryInput.id; |
| 415 var newUri = assetUrlFor(id, primaryId, transform.logger); | 426 var newUri = assetUrlFor(id, primaryId, logger); |
| 416 if (newUri != uri) { | 427 if (newUri != uri) { |
| 417 output.edit(span.start.offset, span.end.offset, "'$newUri'"); | 428 output.edit(span.start.offset, span.end.offset, "'$newUri'"); |
| 418 } | 429 } |
| 419 } else if (directive is LibraryDirective) { | 430 } else if (directive is LibraryDirective) { |
| 420 foundLibraryDirective = true; | 431 foundLibraryDirective = true; |
| 421 } | 432 } |
| 422 } | 433 } |
| 423 | 434 |
| 424 if (!foundLibraryDirective) { | 435 if (!foundLibraryDirective) { |
| 425 // Ensure all inline scripts also have a library name. | 436 // Ensure all inline scripts also have a library name. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 449 hrefToParse = '${href.substring(0, firstBinding)}$placeholder'; | 460 hrefToParse = '${href.substring(0, firstBinding)}$placeholder'; |
| 450 } | 461 } |
| 451 | 462 |
| 452 var uri = Uri.parse(hrefToParse); | 463 var uri = Uri.parse(hrefToParse); |
| 453 if (uri.isAbsolute) return href; | 464 if (uri.isAbsolute) return href; |
| 454 if (!uri.scheme.isEmpty) return href; | 465 if (!uri.scheme.isEmpty) return href; |
| 455 if (!uri.host.isEmpty) return href; | 466 if (!uri.host.isEmpty) return href; |
| 456 if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI. | 467 if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI. |
| 457 if (path.isAbsolute(href)) return href; | 468 if (path.isAbsolute(href)) return href; |
| 458 | 469 |
| 459 var id = uriToAssetId(sourceId, hrefToParse, transform.logger, span); | 470 var id = uriToAssetId(sourceId, hrefToParse, logger, span); |
| 460 if (id == null) return href; | 471 if (id == null) return href; |
| 461 var primaryId = transform.primaryInput.id; | 472 var primaryId = transform.primaryInput.id; |
| 462 | 473 |
| 463 // Build the new path, placing back any suffixes that we stripped earlier. | 474 // Build the new path, placing back any suffixes that we stripped earlier. |
| 464 var prefix = (firstBinding == -1) ? id.path | 475 var prefix = (firstBinding == -1) ? id.path |
| 465 : id.path.substring(0, id.path.length - placeholder.length); | 476 : id.path.substring(0, id.path.length - placeholder.length); |
| 466 var suffix = (firstBinding == -1) ? '' : href.substring(firstBinding); | 477 var suffix = (firstBinding == -1) ? '' : href.substring(firstBinding); |
| 467 var newPath = '$prefix$suffix'; | 478 var newPath = '$prefix$suffix'; |
| 468 | 479 |
| 469 if (newPath.startsWith('lib/')) { | 480 if (newPath.startsWith('lib/')) { |
| 470 return '${topLevelPath}packages/${id.package}/${newPath.substring(4)}'; | 481 return '${topLevelPath}packages/${id.package}/${newPath.substring(4)}'; |
| 471 } | 482 } |
| 472 | 483 |
| 473 if (newPath.startsWith('asset/')) { | 484 if (newPath.startsWith('asset/')) { |
| 474 return '${topLevelPath}assets/${id.package}/${newPath.substring(6)}'; | 485 return '${topLevelPath}assets/${id.package}/${newPath.substring(6)}'; |
| 475 } | 486 } |
| 476 | 487 |
| 477 if (primaryId.package != id.package) { | 488 if (primaryId.package != id.package) { |
| 478 // Techincally we shouldn't get there | 489 // Techincally we shouldn't get there |
| 479 transform.logger.error("don't know how to include $id from $primaryId", | 490 logger.error("don't know how to include $id from $primaryId", span: span); |
| 480 span: span); | |
| 481 return href; | 491 return href; |
| 482 } | 492 } |
| 483 | 493 |
| 484 var builder = path.url; | 494 var builder = path.url; |
| 485 return builder.relative(builder.join('/', newPath), | 495 return builder.relative(builder.join('/', newPath), |
| 486 from: builder.join('/', builder.dirname(primaryId.path))); | 496 from: builder.join('/', builder.dirname(primaryId.path))); |
| 487 } | 497 } |
| 488 } | 498 } |
| 489 | 499 |
| 490 /// HTML attributes that expect a URL value. | 500 /// HTML attributes that expect a URL value. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 512 /// style tag except these ones. | 522 /// style tag except these ones. |
| 513 const IGNORED_LINKED_STYLE_ATTRS = | 523 const IGNORED_LINKED_STYLE_ATTRS = |
| 514 const ['charset', 'href', 'href-lang', 'rel', 'rev']; | 524 const ['charset', 'href', 'href-lang', 'rel', 'rev']; |
| 515 | 525 |
| 516 /// Global RegExp objects. | 526 /// Global RegExp objects. |
| 517 final _INVALID_LIB_CHARS_REGEX = new RegExp('[^a-z0-9_]'); | 527 final _INVALID_LIB_CHARS_REGEX = new RegExp('[^a-z0-9_]'); |
| 518 final _NUM_REGEX = new RegExp('[0-9]'); | 528 final _NUM_REGEX = new RegExp('[0-9]'); |
| 519 final _BINDING_REGEX = new RegExp(r'(({{.*}})|(\[\[.*\]\]))'); | 529 final _BINDING_REGEX = new RegExp(r'(({{.*}})|(\[\[.*\]\]))'); |
| 520 | 530 |
| 521 _getSpan(SourceFile file, AstNode node) => file.span(node.offset, node.end); | 531 _getSpan(SourceFile file, AstNode node) => file.span(node.offset, node.end); |
| OLD | NEW |