| 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 /** | 5 /** |
| 6 * Datatypes holding information extracted by the analyzer and used by later | 6 * Datatypes holding information extracted by the analyzer and used by later |
| 7 * phases of the compiler. | 7 * phases of the compiler. |
| 8 */ | 8 */ |
| 9 library polymer.src.info; | 9 library polymer.src.info; |
| 10 | 10 |
| 11 import 'dart:collection' show SplayTreeMap, LinkedHashMap; | 11 import 'dart:collection' show SplayTreeMap, LinkedHashMap; |
| 12 | 12 |
| 13 import 'package:analyzer_experimental/src/generated/ast.dart'; | |
| 14 import 'package:csslib/visitor.dart'; | 13 import 'package:csslib/visitor.dart'; |
| 15 import 'package:html5lib/dom.dart'; | 14 import 'package:html5lib/dom.dart'; |
| 16 import 'package:source_maps/span.dart' show Span; | 15 import 'package:source_maps/span.dart' show Span; |
| 17 | 16 |
| 18 import 'dart_parser.dart' show DartCodeInfo; | |
| 19 import 'messages.dart'; | 17 import 'messages.dart'; |
| 20 import 'summary.dart'; | |
| 21 import 'utils.dart'; | 18 import 'utils.dart'; |
| 22 | 19 |
| 23 /** | 20 /** |
| 24 * Information that is global. Roughly corresponds to `window` and `document`. | 21 * Information that is global. Roughly corresponds to `window` and `document`. |
| 25 */ | 22 */ |
| 26 class GlobalInfo { | 23 class GlobalInfo { |
| 27 /** | 24 /** |
| 28 * Pseudo-element names exposed in a component via a pseudo attribute. | 25 * Pseudo-element names exposed in a component via a pseudo attribute. |
| 29 * The name is only available from CSS (not Dart code) so they're mangled. | 26 * The name is only available from CSS (not Dart code) so they're mangled. |
| 30 * The same pseudo-element in different components maps to the same | 27 * The same pseudo-element in different components maps to the same |
| 31 * mangled name (as the pseudo-element is scoped inside of the component). | 28 * mangled name (as the pseudo-element is scoped inside of the component). |
| 32 */ | 29 */ |
| 33 final Map<String, String> pseudoElements = <String, String>{}; | 30 final Map<String, String> pseudoElements = <String, String>{}; |
| 34 | 31 |
| 35 /** All components declared in the application. */ | 32 /** All components declared in the application. */ |
| 36 final Map<String, ComponentInfo> components = new SplayTreeMap(); | 33 final Map<String, ComponentInfo> components = new SplayTreeMap(); |
| 37 } | 34 } |
| 38 | 35 |
| 39 /** | 36 /** |
| 40 * Information for any library-like input. We consider each HTML file a library, | 37 * Information for any library-like input. We consider each HTML file a library, |
| 41 * and each component declaration a library as well. Hence we use this as a base | 38 * and each component declaration a library as well. Hence we use this as a base |
| 42 * class for both [FileInfo] and [ComponentInfo]. Both HTML files and components | 39 * class for both [FileInfo] and [ComponentInfo]. Both HTML files and components |
| 43 * can have .dart code provided by the user for top-level user scripts and | 40 * can have .dart code provided by the user for top-level user scripts and |
| 44 * component-level behavior code. This code can either be inlined in the HTML | 41 * component-level behavior code. This code can either be inlined in the HTML |
| 45 * file or included in a script tag with the "src" attribute. | 42 * file or included in a script tag with the "src" attribute. |
| 46 */ | 43 */ |
| 47 abstract class LibraryInfo implements LibrarySummary { | 44 abstract class LibraryInfo { |
| 48 | |
| 49 /** Whether there is any code associated with the page/component. */ | |
| 50 bool get codeAttached => inlinedCode != null || externalFile != null; | |
| 51 | |
| 52 /** | |
| 53 * The actual inlined code. Use [userCode] if you want the code from this file | |
| 54 * or from an external file. | |
| 55 */ | |
| 56 DartCodeInfo inlinedCode; | |
| 57 | |
| 58 /** | |
| 59 * If this library's code was loaded using a script tag (e.g. in a component), | |
| 60 * [externalFile] has the path to such Dart file relative from the compiler's | |
| 61 * base directory. | |
| 62 */ | |
| 63 UrlInfo externalFile; | |
| 64 | |
| 65 /** Info asscociated with [externalFile], if any. */ | |
| 66 FileInfo externalCode; | |
| 67 | |
| 68 /** | |
| 69 * The inverse of [externalCode]. If this .dart file was imported via a script | |
| 70 * tag, this refers to the HTML file that imported it. | |
| 71 */ | |
| 72 LibraryInfo htmlFile; | |
| 73 | |
| 74 /** File where the top-level code was defined. */ | |
| 75 UrlInfo get dartCodeUrl; | |
| 76 | |
| 77 /** | |
| 78 * Name of the file that will hold any generated Dart code for this library | |
| 79 * unit. Note this is initialized after parsing. | |
| 80 */ | |
| 81 String outputFilename; | |
| 82 | |
| 83 /** Parsed cssSource. */ | 45 /** Parsed cssSource. */ |
| 84 List<StyleSheet> styleSheets = []; | 46 List<StyleSheet> styleSheets = []; |
| 85 | |
| 86 /** This is used in transforming Dart code to track modified files. */ | |
| 87 bool modified = false; | |
| 88 | |
| 89 /** | |
| 90 * This is used in transforming Dart code to compute files that reference | |
| 91 * [modified] files. | |
| 92 */ | |
| 93 List<FileInfo> referencedBy = []; | |
| 94 | |
| 95 /** | |
| 96 * Components used within this library unit. For [FileInfo] these are | |
| 97 * components used directly in the page. For [ComponentInfo] these are | |
| 98 * components used within their shadowed template. | |
| 99 */ | |
| 100 final Map<ComponentSummary, bool> usedComponents = | |
| 101 new LinkedHashMap<ComponentSummary, bool>(); | |
| 102 | |
| 103 /** | |
| 104 * The actual code, either inlined or from an external file, or `null` if none | |
| 105 * was defined. | |
| 106 */ | |
| 107 DartCodeInfo get userCode => | |
| 108 externalCode != null ? externalCode.inlinedCode : inlinedCode; | |
| 109 } | 47 } |
| 110 | 48 |
| 111 /** Information extracted at the file-level. */ | 49 /** Information extracted at the file-level. */ |
| 112 class FileInfo extends LibraryInfo implements HtmlFileSummary { | 50 class FileInfo extends LibraryInfo { |
| 113 /** Relative path to this file from the compiler's base directory. */ | 51 /** Relative path to this file from the compiler's base directory. */ |
| 114 final UrlInfo inputUrl; | 52 final UrlInfo inputUrl; |
| 115 | 53 |
| 116 /** | 54 /** |
| 117 * Whether this file should be treated as the entry point of the web app, i.e. | |
| 118 * the file users navigate to in their browser. This will be true if this file | |
| 119 * was passed in the command line to the dwc compiler, and the | |
| 120 * `--components_only` flag was omitted. | |
| 121 */ | |
| 122 final bool isEntryPoint; | |
| 123 | |
| 124 // TODO(terry): Ensure that that the libraryName is a valid identifier: | |
| 125 // a..z || A..Z || _ [a..z || A..Z || 0..9 || _]* | |
| 126 String get libraryName => | |
| 127 path.basename(inputUrl.resolvedPath).replaceAll('.', '_'); | |
| 128 | |
| 129 /** File where the top-level code was defined. */ | |
| 130 UrlInfo get dartCodeUrl => externalFile != null ? externalFile : inputUrl; | |
| 131 | |
| 132 /** | |
| 133 * All custom element definitions in this file. This may contain duplicates. | 55 * All custom element definitions in this file. This may contain duplicates. |
| 134 * Normally you should use [components] for lookup. | 56 * Normally you should use [components] for lookup. |
| 135 */ | 57 */ |
| 136 final List<ComponentInfo> declaredComponents = new List<ComponentInfo>(); | 58 final List<ComponentInfo> declaredComponents = new List<ComponentInfo>(); |
| 137 | 59 |
| 138 /** | 60 /** |
| 139 * All custom element definitions defined in this file or imported via | 61 * All custom element definitions defined in this file or imported via |
| 140 *`<link rel='components'>` tag. Maps from the tag name to the component | 62 *`<link rel='components'>` tag. Maps from the tag name to the component |
| 141 * information. This map is sorted by the tag name. | 63 * information. This map is sorted by the tag name. |
| 142 */ | 64 */ |
| 143 final Map<String, ComponentSummary> components = | 65 final Map<String, ComponentInfo> components = |
| 144 new SplayTreeMap<String, ComponentSummary>(); | 66 new SplayTreeMap<String, ComponentInfo>(); |
| 145 | 67 |
| 146 /** Files imported with `<link rel="import">` */ | 68 /** Files imported with `<link rel="import">` */ |
| 147 final List<UrlInfo> componentLinks = <UrlInfo>[]; | 69 final List<UrlInfo> componentLinks = <UrlInfo>[]; |
| 148 | 70 |
| 149 /** Files imported with `<link rel="stylesheet">` */ | 71 /** Files imported with `<link rel="stylesheet">` */ |
| 150 final List<UrlInfo> styleSheetHrefs = <UrlInfo>[]; | 72 final List<UrlInfo> styleSheetHrefs = <UrlInfo>[]; |
| 151 | 73 |
| 152 /** Root is associated with the body node. */ | 74 FileInfo(this.inputUrl); |
| 153 Element body; | |
| 154 | |
| 155 FileInfo(this.inputUrl, [this.isEntryPoint = false]); | |
| 156 | |
| 157 /** | |
| 158 * Query for an [Element] matching the provided [tag], starting from the | |
| 159 * [body]. | |
| 160 */ | |
| 161 Element query(String tag) => body.query(tag); | |
| 162 } | 75 } |
| 163 | 76 |
| 164 | 77 |
| 165 /** Information about a web component definition declared locally. */ | 78 /** Information about a web component definition declared locally. */ |
| 166 // TODO(sigmund): use a mixin to pull in ComponentSummary. | 79 class ComponentInfo extends LibraryInfo { |
| 167 class ComponentInfo extends LibraryInfo implements ComponentSummary { | |
| 168 /** The file that declares this component. */ | |
| 169 final FileInfo declaringFile; | |
| 170 | 80 |
| 171 /** The component tag name, defined with the `name` attribute on `element`. */ | 81 /** The component tag name, defined with the `name` attribute on `element`. */ |
| 172 final String tagName; | 82 final String tagName; |
| 173 | 83 |
| 174 /** | 84 /** |
| 175 * The tag name that this component extends, defined with the `extends` | 85 * The tag name that this component extends, defined with the `extends` |
| 176 * attribute on `element`. | 86 * attribute on `element`. |
| 177 */ | 87 */ |
| 178 final String extendsTag; | 88 final String extendsTag; |
| 179 | 89 |
| 180 /** | 90 /** |
| 181 * The component info associated with the [extendsTag] name, if any. | 91 * The component info associated with the [extendsTag] name, if any. |
| 182 * This will be `null` if the component extends a built-in HTML tag, or | 92 * This will be `null` if the component extends a built-in HTML tag, or |
| 183 * if the analyzer has not run yet. | 93 * if the analyzer has not run yet. |
| 184 */ | 94 */ |
| 185 ComponentSummary extendsComponent; | 95 ComponentInfo extendsComponent; |
| 186 | |
| 187 /** The Dart class containing the component's behavior. */ | |
| 188 String className; | |
| 189 | |
| 190 /** The Dart class declaration. */ | |
| 191 ClassDeclaration get classDeclaration => _classDeclaration; | |
| 192 ClassDeclaration _classDeclaration; | |
| 193 | 96 |
| 194 /** The declaring `<element>` tag. */ | 97 /** The declaring `<element>` tag. */ |
| 195 final Node element; | 98 final Node element; |
| 196 | 99 |
| 197 /** File where this component was defined. */ | |
| 198 UrlInfo get dartCodeUrl => externalFile != null | |
| 199 ? externalFile : declaringFile.inputUrl; | |
| 200 | |
| 201 /** | 100 /** |
| 202 * True if [tagName] was defined by more than one component. If this happened | 101 * True if [tagName] was defined by more than one component. If this happened |
| 203 * we will skip over the component. | 102 * we will skip over the component. |
| 204 */ | 103 */ |
| 205 bool hasConflict = false; | 104 bool hasConflict = false; |
| 206 | 105 |
| 207 ComponentInfo(this.element, this.declaringFile, this.tagName, | 106 ComponentInfo(this.element, this.tagName, this.extendsTag); |
| 208 this.extendsTag); | |
| 209 | 107 |
| 210 /** | 108 /** |
| 211 * Gets the HTML tag extended by the base of the component hierarchy. | 109 * Gets the HTML tag extended by the base of the component hierarchy. |
| 212 * Equivalent to [extendsTag] if this inherits directly from an HTML element, | 110 * Equivalent to [extendsTag] if this inherits directly from an HTML element, |
| 213 * in other words, if [extendsComponent] is null. | 111 * in other words, if [extendsComponent] is null. |
| 214 */ | 112 */ |
| 215 String get baseExtendsTag => | 113 String get baseExtendsTag => |
| 216 extendsComponent == null ? extendsTag : extendsComponent.baseExtendsTag; | 114 extendsComponent == null ? extendsTag : extendsComponent.baseExtendsTag; |
| 217 | 115 |
| 218 Span get sourceSpan => element.sourceSpan; | 116 Span get sourceSpan => element.sourceSpan; |
| 219 | 117 |
| 220 /** Is apply-author-styles enabled. */ | 118 /** Is apply-author-styles enabled. */ |
| 221 bool get hasAuthorStyles => | 119 bool get hasAuthorStyles => |
| 222 element.attributes.containsKey('apply-author-styles'); | 120 element.attributes.containsKey('apply-author-styles'); |
| 223 | 121 |
| 224 /** | 122 String toString() => '#<ComponentInfo $tagName>'; |
| 225 * Finds the declaring class, and initializes [className] and | |
| 226 * [classDeclaration]. Also [userCode] is generated if there was no script. | |
| 227 */ | |
| 228 void findClassDeclaration(Messages messages) { | |
| 229 var constructor = element.attributes['constructor']; | |
| 230 className = constructor != null ? constructor : | |
| 231 toCamelCase(tagName, startUppercase: true); | |
| 232 | |
| 233 // If we don't have any code, generate a small class definition, and | |
| 234 // pretend the user wrote it as inlined code. | |
| 235 if (userCode == null) { | |
| 236 var superclass = extendsComponent != null ? extendsComponent.className | |
| 237 : 'autogenerated.PolymerElement'; | |
| 238 inlinedCode = new DartCodeInfo(null, null, [], | |
| 239 'class $className extends $superclass {\n}', null); | |
| 240 } | |
| 241 | |
| 242 var code = userCode.code; | |
| 243 _classDeclaration = userCode.findClass(className); | |
| 244 if (_classDeclaration == null) { | |
| 245 // Check for deprecated x-tags implied constructor. | |
| 246 if (tagName.startsWith('x-') && constructor == null) { | |
| 247 var oldCtor = toCamelCase(tagName.substring(2), startUppercase: true); | |
| 248 _classDeclaration = userCode.findClass(oldCtor); | |
| 249 if (_classDeclaration != null) { | |
| 250 messages.warning('Implied constructor name for x-tags has changed to ' | |
| 251 '"$className". You should rename your class or add a ' | |
| 252 'constructor="$oldCtor" attribute to the element declaration. ' | |
| 253 'Also custom tags are not required to start with "x-" if their ' | |
| 254 'name has at least one dash.', | |
| 255 element.sourceSpan); | |
| 256 className = oldCtor; | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 if (_classDeclaration == null) { | |
| 261 messages.error('please provide a class definition ' | |
| 262 'for $className:\n $code', element.sourceSpan); | |
| 263 return; | |
| 264 } | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 String toString() => '#<ComponentInfo $tagName ' | |
| 269 '${inlinedCode != null ? "inline" : "from ${dartCodeUrl.resolvedPath}"}>'; | |
| 270 } | 123 } |
| 271 | 124 |
| 272 | 125 |
| 273 /** | 126 /** |
| 274 * Information extracted about a URL that refers to another file. This is | 127 * Information extracted about a URL that refers to another file. This is |
| 275 * mainly introduced to be able to trace back where URLs come from when | 128 * mainly introduced to be able to trace back where URLs come from when |
| 276 * reporting errors. | 129 * reporting errors. |
| 277 */ | 130 */ |
| 278 class UrlInfo { | 131 class UrlInfo { |
| 279 /** Original url. */ | 132 /** Original url. */ |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 return new UrlInfo(url, target, span); | 174 return new UrlInfo(url, target, span); |
| 322 } | 175 } |
| 323 | 176 |
| 324 bool operator ==(UrlInfo other) => | 177 bool operator ==(UrlInfo other) => |
| 325 url == other.url && resolvedPath == other.resolvedPath; | 178 url == other.url && resolvedPath == other.resolvedPath; |
| 326 | 179 |
| 327 int get hashCode => resolvedPath.hashCode; | 180 int get hashCode => resolvedPath.hashCode; |
| 328 | 181 |
| 329 String toString() => "#<UrlInfo url: $url, resolvedPath: $resolvedPath>"; | 182 String toString() => "#<UrlInfo url: $url, resolvedPath: $resolvedPath>"; |
| 330 } | 183 } |
| OLD | NEW |