Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(706)

Unified Diff: web_components/lib/build/import_inliner.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « web_components/lib/build/import_crawler.dart ('k') | web_components/lib/build/messages.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: web_components/lib/build/import_inliner.dart
diff --git a/web_components/lib/build/import_inliner.dart b/web_components/lib/build/import_inliner.dart
deleted file mode 100644
index 1f562a7459202f1e2bcf891a30f6b4ed83e0bae6..0000000000000000000000000000000000000000
--- a/web_components/lib/build/import_inliner.dart
+++ /dev/null
@@ -1,366 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-library web_components.build.import_inliner;
-
-import 'dart:async';
-import 'dart:collection' show LinkedHashMap;
-import 'package:barback/barback.dart';
-import 'package:code_transformers/assets.dart';
-import 'package:code_transformers/messages/build_logger.dart';
-import 'package:html/dom.dart';
-import 'package:html/dom_parsing.dart' show TreeVisitor;
-import 'package:path/path.dart' as path;
-import 'package:source_span/source_span.dart';
-import 'common.dart';
-import 'import_crawler.dart';
-import 'messages.dart';
-
-/// Transformer which inlines all html imports found from the entry points. This
-/// deletes all dart scripts found during the inlining, so the
-/// [ScriptCompactorTransformer] should be ran first if there are any dart files
-/// in html imports.
-class ImportInlinerTransformer extends Transformer {
- final List<String> entryPoints;
- final List<String> bindingStartDelimiters;
-
- ImportInlinerTransformer(
- [this.entryPoints, this.bindingStartDelimiters = const []]);
-
- bool isPrimary(AssetId id) {
- if (entryPoints != null) return entryPoints.contains(id.path);
- // If no entry point is supplied, then any html file under web/ or test/ is
- // an entry point.
- return (id.path.startsWith('web/') || id.path.startsWith('test/')) &&
- id.path.endsWith('.html');
- }
-
- apply(Transform transform) {
- var logger = new BuildLogger(transform, convertErrorsToWarnings: true);
- return new ImportInliner(transform, transform.primaryInput.id, logger,
- bindingStartDelimiters: bindingStartDelimiters).run();
- }
-}
-
-/// Helper class which actually does all the inlining of html imports for a
-/// single entry point.
-class ImportInliner {
- // Can be an AggregateTransform or Transform
- final transform;
- // The primary input to start from.
- final AssetId primaryInput;
- // The logger to use.
- final BuildLogger logger;
- // The start delimiters for template bindings, such as '{{' or '[['.
- final List<String> bindingStartDelimiters;
-
- ImportInliner(this.transform, this.primaryInput, this.logger,
- {this.bindingStartDelimiters: const []});
-
- Future run() {
- var crawler = new ImportCrawler(transform, primaryInput, logger);
- return crawler.crawlImports().then((imports) {
- var primaryDocument = imports[primaryInput].document;
-
- // Normalize urls in the entry point.
- var changed = new _UrlNormalizer(
- primaryInput, primaryInput, logger, bindingStartDelimiters)
- .visit(primaryDocument);
-
- // Inline things if needed, always have at least one (the entry point).
- if (imports.length > 1) {
- _inlineImports(primaryDocument, imports);
- } else if (!changed &&
- primaryDocument.querySelectorAll('link[rel="import"]').where(
- (import) => import.attributes['type'] != 'css').length ==
- 0) {
- // If there were no url changes and no imports, then we are done.
- return;
- }
-
- primaryDocument
- .querySelectorAll('link[rel="import"]')
- .where((import) => import.attributes['type'] != 'css')
- .forEach((element) => element.remove());
-
- transform.addOutput(
- new Asset.fromString(primaryInput, primaryDocument.outerHtml));
- });
- }
-
- void _inlineImports(
- Document primaryDocument, LinkedHashMap<AssetId, ImportData> imports) {
- // Add a hidden div at the top of the body, this is where we will inline
- // all the imports.
- var importWrapper = new Element.tag('div')..attributes['hidden'] = '';
- var firstElement = primaryDocument.body.firstChild;
- if (firstElement != null) {
- primaryDocument.body.insertBefore(importWrapper, firstElement);
- } else {
- primaryDocument.body.append(importWrapper);
- }
-
- // Move all scripts/stylesheets/imports into the wrapper to maintain
- // ordering.
- _moveHeadToWrapper(primaryDocument, importWrapper);
-
- // Add all the other imports!
- imports.forEach((AssetId asset, ImportData data) {
- if (asset == primaryInput) return;
- var document = data.document;
- // Remove all dart script tags.
- document
- .querySelectorAll('script[type="$dartType"]')
- .forEach((script) => script.remove());
- // Normalize urls in attributes and inline css.
- new _UrlNormalizer(data.fromId, asset, logger, bindingStartDelimiters)
- .visit(document);
- // Replace the import with its contents by appending the nodes
- // immediately before the import one at a time, and then removing the
- // import from the document.
- var element = data.element;
- var parent = element.parent;
- document.head.nodes
- .toList(growable: false)
- .forEach((child) => parent.insertBefore(child, element));
- document.body.nodes
- .toList(growable: false)
- .forEach((child) => parent.insertBefore(child, element));
- element.remove();
- });
- }
-}
-
-/// To preserve the order of scripts with respect to inlined
-/// link rel=import, we move both of those into the body before we do any
-/// inlining. We do not start doing this until the first import is found
-/// however, as some scripts do need to be ran in the head to work
-/// properly (webcomponents.js for instance).
-///
-/// Note: we do this for stylesheets as well to preserve ordering with
-/// respect to eachother, because stylesheets can be pulled in transitively
-/// from imports.
-void _moveHeadToWrapper(Document doc, Element wrapper) {
- var foundImport = false;
- for (var node in doc.head.nodes.toList(growable: false)) {
- if (node is! Element) continue;
- var tag = node.localName;
- var type = node.attributes['type'];
- var rel = node.attributes['rel'];
- if (tag == 'link' && rel == 'import') foundImport = true;
- if (!foundImport) continue;
- if (tag == 'style' ||
- tag == 'script' &&
- (type == null || type == jsType || type == dartType) ||
- tag == 'link' && (rel == 'stylesheet' || rel == 'import')) {
- // Move the node into the wrapper, where its contents will be placed.
- // This wrapper is a hidden div to prevent inlined html from causing a
- // FOUC.
- wrapper.append(node);
- }
- }
-}
-
-/// Internally adjusts urls in the html that we are about to inline.
-// TODO(jakemac): Everything from here down is almost an exact copy from the
-// polymer package. We should consolidate this logic by either removing it
-// completely from polymer or exposing it publicly here and using that in
-// polymer.
-class _UrlNormalizer extends TreeVisitor {
- /// [AssetId] for the main entry point.
- final AssetId primaryInput;
-
- /// Asset where the original content (and original url) was found.
- final AssetId sourceId;
-
- /// Counter used to ensure that every library name we inject is unique.
- int _count = 0;
-
- /// Path to the top level folder relative to the transform primaryInput.
- /// This should just be some arbitrary # of ../'s.
- final String topLevelPath;
-
- /// Whether or not the normalizer has changed something in the tree.
- bool changed = false;
-
- // The start delimiters for template bindings, such as '{{' or '[['. If these
- // are found before the first `/` in a url, then the url will not be
- // normalized.
- final List<String> bindingStartDelimiters;
-
- final BuildLogger logger;
-
- _UrlNormalizer(AssetId primaryInput, this.sourceId, this.logger,
- this.bindingStartDelimiters)
- : primaryInput = primaryInput,
- topLevelPath = '../' * (path.url.split(primaryInput.path).length - 2);
-
- bool visit(Node node) {
- super.visit(node);
- return changed;
- }
-
- visitElement(Element node) {
- // TODO(jakemac): Support custom elements that extend html elements which
- // have url-like attributes. This probably means keeping a list of which
- // html elements support each url-like attribute.
- if (!isCustomTagName(node.localName)) {
- node.attributes.forEach((name, value) {
- if (_urlAttributes.contains(name)) {
- node.attributes[name] = _newUrl(value, node.sourceSpan);
- changed = value != node.attributes[name];
- }
- });
- }
- if (node.localName == 'style') {
- node.text = visitCss(node.text);
- } else if (node.localName == 'script' &&
- node.attributes['type'] == dartType &&
- !node.attributes.containsKey('src')) {
- changed = true;
- }
- return super.visitElement(node);
- }
-
- static final _url = new RegExp(r'url\(([^)]*)\)', multiLine: true);
- static final _quote = new RegExp('["\']', multiLine: true);
-
- /// Visit the CSS text and replace any relative URLs so we can inline it.
- // Ported from:
- // https://github.com/Polymer/vulcanize/blob/c14f63696797cda18dc3d372b78aa3378acc691f/lib/vulcan.js#L149
- // TODO(jmesserly): use csslib here instead? Parsing with RegEx is sadness.
- // Maybe it's reliable enough for finding URLs in CSS? I'm not sure.
- String visitCss(String cssText) {
- var url = spanUrlFor(sourceId, primaryInput, logger);
- var src = new SourceFile(cssText, url: url);
- return cssText.replaceAllMapped(_url, (match) {
- changed = true;
- // Extract the URL, without any surrounding quotes.
- var span = src.span(match.start, match.end);
- var href = match[1].replaceAll(_quote, '');
- href = _newUrl(href, span);
- return 'url($href)';
- });
- }
-
- String _newUrl(String href, SourceSpan span) {
- // We only want to parse the part of the href leading up to the first
- // folder, anything after that is not informative.
- var hrefToParse;
- var firstFolder = href.indexOf('/');
- if (firstFolder == -1) {
- hrefToParse = href;
- } else if (firstFolder == 0) {
- return href;
- } else {
- // Special case packages and assets urls.
- if (href.contains('packages/')) {
- var suffix = href.substring(href.indexOf('packages/') + 9);
- return '${topLevelPath}packages/$suffix';
- } else if (href.contains('assets/')) {
- var suffix = href.substring(href.indexOf('assets/') + 7);
- return '${topLevelPath}packages/$suffix';
- }
-
- hrefToParse = '${href.substring(0, firstFolder + 1)}';
- }
-
- // If we found a binding before the first `/`, then just return the original
- // href, we can't determine anything about it.
- if (bindingStartDelimiters.any((d) => hrefToParse.contains(d))) return href;
-
- Uri uri;
- // Various template systems introduce invalid characters to uris which would
- // be typically replaced at runtime. Parse errors are assumed to be caused
- // by this, and we just return the original href in that case.
- try {
- uri = Uri.parse(hrefToParse);
- } catch (e) {
- return href;
- }
- if (uri.isAbsolute) return href;
- if (uri.scheme.isNotEmpty) return href;
- if (uri.host.isNotEmpty) return href;
- if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI.
- if (path.isAbsolute(hrefToParse)) return href;
-
- var id = uriToAssetId(sourceId, hrefToParse, logger, span);
- if (id == null) return href;
-
- // Build the new path, placing back any suffixes that we stripped earlier.
- var prefix =
- (firstFolder == -1) ? id.path : id.path.substring(0, id.path.length);
- var suffix = (firstFolder == -1) ? '' : href.substring(firstFolder);
- var newPath = '$prefix$suffix';
-
- if (newPath.startsWith('lib/')) {
- return '${topLevelPath}packages/${id.package}/${newPath.substring(4)}';
- }
-
- if (newPath.startsWith('asset/')) {
- return '${topLevelPath}assets/${id.package}/${newPath.substring(6)}';
- }
-
- if (primaryInput.package != id.package) {
- // Technically we shouldn't get there
- logger.error(internalErrorDontKnowHowToImport
- .create({'target': id, 'source': primaryInput, 'extra': ''}),
- span: span);
- return href;
- }
-
- var builder = path.url;
- return builder.normalize(builder.relative(builder.join('/', newPath),
- from: builder.join('/', builder.dirname(primaryInput.path))));
- }
-}
-
-/// Returns true if this is a valid custom element name. See:
-/// <http://w3c.github.io/webcomponents/spec/custom/#dfn-custom-element-type>
-bool isCustomTagName(String name) {
- if (name == null || !name.contains('-')) return false;
- return !invalidTagNames.containsKey(name);
-}
-
-/// These names have meaning in SVG or MathML, so they aren't allowed as custom
-/// tags. See [isCustomTagName].
-const invalidTagNames = const {
- 'annotation-xml': '',
- 'color-profile': '',
- 'font-face': '',
- 'font-face-src': '',
- 'font-face-uri': '',
- 'font-face-format': '',
- 'font-face-name': '',
- 'missing-glyph': '',
-};
-
-/// HTML attributes that expect a URL value.
-/// <http://dev.w3.org/html5/spec/section-index.html#attributes-1>
-///
-/// Every one of these attributes is a URL in every context where it is used in
-/// the DOM. The comments show every DOM element where an attribute can be used.
-///
-/// The _* version of each attribute is also supported, see http://goo.gl/5av8cU
-const _urlAttributes = const [
- 'action',
- '_action', // in form
- 'background',
- '_background', // in body
- 'cite',
- '_cite', // in blockquote, del, ins, q
- 'data',
- '_data', // in object
- 'formaction',
- '_formaction', // in button, input
- 'href',
- '_href', // in a, area, link, base, command
- 'icon',
- '_icon', // in command
- 'manifest',
- '_manifest', // in html
- 'poster',
- '_poster', // in video
- 'src',
- '_src', // in audio, embed, iframe, img, input, script, source, track,video
-];
« no previous file with comments | « web_components/lib/build/import_crawler.dart ('k') | web_components/lib/build/messages.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698