diff --git a/lib/tools/common.dart b/lib/tools/common.dart index a6eb482b5..1cf05f0eb 100644 --- a/lib/tools/common.dart +++ b/lib/tools/common.dart @@ -3,15 +3,11 @@ library angular.tools.common; class DirectiveInfo { String selector; String template; - List expressionAttrs = []; - List expressions = []; + List expressionAttrs; + List expressions; DirectiveInfo([this.selector, this.expressionAttrs, this.expressions]) { - if (expressionAttrs == null) { - expressionAttrs = []; - } - if (expressions == null) { - expressions = []; - } + if (expressionAttrs == null) expressionAttrs = []; + if (expressions == null) expressions = []; } } @@ -30,15 +26,9 @@ class DirectiveMetadata { DirectiveMetadata([this.className, this.type, this.selector, this.attributeMappings, this.exportExpressionAttrs, this.exportExpressions]) { - if (attributeMappings == null) { - attributeMappings = {}; - } - if (exportExpressions == null) { - exportExpressions = []; - } - if (exportExpressionAttrs == null) { - exportExpressionAttrs = []; - } + if (attributeMappings == null) attributeMappings = {}; + if (exportExpressions == null) exportExpressions = []; + if (exportExpressionAttrs == null) exportExpressionAttrs = []; } } diff --git a/lib/tools/expression_extractor.dart b/lib/tools/expression_extractor.dart index e59705d1c..fb32b158c 100644 --- a/lib/tools/expression_extractor.dart +++ b/lib/tools/expression_extractor.dart @@ -23,8 +23,7 @@ main(args) { } IoService ioService = new IoServiceImpl(); - var packageRoots = - (args.length < 6) ? [Platform.packageRoot] : args.sublist(5); + var packageRoots = args.length < 6 ? [Platform.packageRoot] : args.sublist(5); var sourceCrawler = new SourceCrawlerImpl(packageRoots); var sourceMetadataExtractor = new SourceMetadataExtractor(); List directives = @@ -38,17 +37,10 @@ main(args) { var headerFile = args[2]; var footerFile = args[3]; var outputFile = args[4]; - var printer; - if (outputFile == '--') { - printer = stdout; - } else { - printer = new File(outputFile).openWrite(); - } + var printer = outputFile == '--' ? stdout : new File(outputFile).openWrite(); // Output the header file first. - if (headerFile != '') { - printer.write(_readFile(headerFile)); - } + if (headerFile != '') printer.write(_readFile(headerFile)); printer.write('// Found ${expressions.length} expressions\n'); Module module = new Module() @@ -67,9 +59,7 @@ main(args) { // Output footer last. - if (footerFile != '') { - printer.write(_readFile(footerFile)); - } + if (footerFile != '') printer.write(_readFile(footerFile)); } String _readFile(String filePath) => new File(filePath).readAsStringSync(); diff --git a/lib/tools/html_extractor.dart b/lib/tools/html_extractor.dart index a9b0b02bf..349a50b09 100644 --- a/lib/tools/html_extractor.dart +++ b/lib/tools/html_extractor.dart @@ -18,9 +18,7 @@ class HtmlExpressionExtractor { HtmlExpressionExtractor(this.directiveInfos) { for (DirectiveInfo directiveInfo in directiveInfos) { expressions.addAll(directiveInfo.expressions); - if (directiveInfo.template != null) { - parseHtml(directiveInfo.template); - } + if (directiveInfo.template != null) parseHtml(directiveInfo.template); } } @@ -69,9 +67,7 @@ class HtmlExpressionExtractor { visitNodes(List nodes, NodeVisitor visitor) { for (Node node in nodes) { visitor(node); - if (node.nodes.length > 0) { - visitNodes(node.nodes, visitor); - } + if (node.nodes.isNotEmpty) visitNodes(node.nodes, visitor); } } } diff --git a/lib/tools/io.dart b/lib/tools/io.dart index e6d7de8c4..b3b169bd2 100644 --- a/lib/tools/io.dart +++ b/lib/tools/io.dart @@ -3,7 +3,7 @@ library angular.io; typedef FsVisitor(String file); /** - * A simple mockabe wrapper around dart:io that can be used without introducing + * A simple mockable wrapper around dart:io that can be used without introducing * direct dependencies on dart:io. */ abstract class IoService { diff --git a/lib/tools/io_impl.dart b/lib/tools/io_impl.dart index 9cbf134d8..9142f24a2 100644 --- a/lib/tools/io_impl.dart +++ b/lib/tools/io_impl.dart @@ -9,7 +9,7 @@ class IoServiceImpl implements IoService { new File(filePath).readAsStringSync(); void visitFs(String rootDir, FsVisitor visitor) { - Directory root = new Directory(rootDir); + var root = new Directory(rootDir); if (!FileSystemEntity.isDirectorySync(rootDir)) { throw 'Expected $rootDir to be a directory!'; } diff --git a/lib/tools/selector.dart b/lib/tools/selector.dart index 16ec0864c..79779c969 100644 --- a/lib/tools/selector.dart +++ b/lib/tools/selector.dart @@ -11,8 +11,8 @@ class ContainsSelector { } } -RegExp _SELECTOR_REGEXP = new RegExp(r'^(?:([\w\-]+)|(?:\.([\w\-]+))|(?:\[([\w\-\*]+)(?:=([^\]]*))?\]))'); -RegExp _COMMENT_COMPONENT_REGEXP = new RegExp(r'^\[([\w\-]+)(?:\=(.*))?\]$'); +RegExp _SELECTOR_REGEXP = new RegExp(r'^(?:([-\w]+)|(?:\.([-\w]+))|(?:\[([-\w*]+)(?:=([^\]]*))?\]))'); +RegExp _COMMENT_COMPONENT_REGEXP = new RegExp(r'^\[([-\w]+)(?:\=(.*))?\]$'); RegExp _CONTAINS_REGEXP = new RegExp(r'^:contains\(\/(.+)\/\)$'); // RegExp _ATTR_CONTAINS_REGEXP = new RegExp(r'^\[\*=\/(.+)\/\]$'); // @@ -22,17 +22,17 @@ class _SelectorPart { final String attrName; final String attrValue; - const _SelectorPart.fromElement(String this.element) + const _SelectorPart.fromElement(this.element) : className = null, attrName = null, attrValue = null; - const _SelectorPart.fromClass(String this.className) + const _SelectorPart.fromClass(this.className) : element = null, attrName = null, attrValue = null; - const _SelectorPart.fromAttribute(String this.attrName, String this.attrValue) + const _SelectorPart.fromAttribute(this.attrName, this.attrValue) : element = null, className = null; - toString() => + String toString() => element == null ? (className == null ? (attrValue == '' ? '[$attrName]' : '[$attrName=$attrValue]') @@ -68,19 +68,13 @@ List<_SelectorPart> _splitCss(String selector) { bool matchesNode(Node node, String selector) { var match, selectorParts; if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) { - if (node is! Text) { - return false; - } + if (node is! Text) return false; return new RegExp(match.group(1)).hasMatch((node as Text).text); } else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) { - if (node is! Element) { - return false; - } + if (node is! Element) return false; var regexp = new RegExp(match.group(1)); for (String attrName in node.attributes.keys) { - if (regexp.hasMatch(node.attributes[attrName])) { - return true; - } + if (regexp.hasMatch(node.attributes[attrName])) return true; } return false; } else if ((selectorParts = _splitCss(selector)) != null) { @@ -90,9 +84,7 @@ bool matchesNode(Node node, String selector) { bool stillGood = true; selectorParts.forEach((_SelectorPart part) { if (part.element != null) { - if (nodeName != part.element) { - stillGood = false; - } + if (nodeName != part.element) stillGood = false; } else if (part.className != null) { if (node.attributes['class'] == null || !node.attributes['class'].split(' ').contains(part.className)) { @@ -116,5 +108,5 @@ bool matchesNode(Node node, String selector) { String _matchingKey(Iterable keys, String attrName) => keys.firstWhere( - (key) => new RegExp('^${attrName.replaceAll('*', r'[\w\-]+')}\$').hasMatch(key.toString()), + (key) => new RegExp('^${attrName.replaceAll('*', r'[-\w]+')}\$').hasMatch(key.toString()), orElse: () => null); diff --git a/lib/tools/source_crawler_impl.dart b/lib/tools/source_crawler_impl.dart index 654e25535..ee2bb0636 100644 --- a/lib/tools/source_crawler_impl.dart +++ b/lib/tools/source_crawler_impl.dart @@ -16,20 +16,19 @@ class SourceCrawlerImpl implements SourceCrawler { SourceCrawlerImpl(this.packageRoots); void crawl(String entryPoint, CompilationUnitVisitor visitor) { - List visited = []; - List toVisit = []; + final visited = new Set(); + final toVisit = new Set(); if (entryPoint.startsWith(PACKAGE_PREFIX)) { var path = resolvePackagePath(entryPoint); - if (path == null) { - throw 'Unable to resolve $entryPoint'; - } + if (path == null) throw 'Unable to resolve $entryPoint'; toVisit.add(path); } else { toVisit.add(entryPoint); } while (toVisit.isNotEmpty) { - var currentFile = toVisit.removeAt(0); + var currentFile = toVisit.first; + toVisit.remove(currentFile); visited.add(currentFile); var file = new File(currentFile); // Possible source file doesn't exist. For example if it is generated. @@ -42,8 +41,8 @@ class SourceCrawlerImpl implements SourceCrawler { } void processImports(CompilationUnit cu, String currentDir, - String currentFile, List visited, - List toVisit) { + String currentFile, Set visited, + Set toVisit) { cu.directives.forEach((Directive directive) { if (directive is ImportDirective || directive is PartDirective || @@ -52,10 +51,7 @@ class SourceCrawlerImpl implements SourceCrawler { String canonicalFile = canonicalizeImportPath( currentDir, currentFile, import.uri.stringValue); if (canonicalFile == null) return; - if (!visited.contains(canonicalFile) && - !toVisit.contains(canonicalFile)) { - toVisit.add(canonicalFile); - } + if (!visited.contains(canonicalFile)) toVisit.add(canonicalFile); } }); } @@ -64,12 +60,8 @@ class SourceCrawlerImpl implements SourceCrawler { String currentFile, String uri) { // ignore core libraries - if (uri.startsWith('dart:')) { - return null; - } - if (uri.startsWith(PACKAGE_PREFIX)) { - return resolvePackagePath(uri); - } + if (uri.startsWith('dart:')) return null; + if (uri.startsWith(PACKAGE_PREFIX)) return resolvePackagePath(uri); // relative import. if (uri.startsWith('../')) { while (uri.startsWith('../')) { @@ -83,18 +75,14 @@ class SourceCrawlerImpl implements SourceCrawler { String resolvePackagePath(String uri) { for (String packageRoot in packageRoots) { var resolvedPath = _packageUriResolver(uri, packageRoot); - if (new File(resolvedPath).existsSync()) { - return resolvedPath; - } + if (new File(resolvedPath).existsSync()) return resolvedPath; } return null; } String _packageUriResolver(String uri, String packageRoot) { var packagePath = uri.substring(PACKAGE_PREFIX.length); - if (!packageRoot.endsWith('/')) { - packageRoot = packageRoot + '/'; - } + if (!packageRoot.endsWith('/')) packageRoot = packageRoot + '/'; return packageRoot + packagePath; } } diff --git a/lib/tools/source_metadata_extractor.dart b/lib/tools/source_metadata_extractor.dart index 2319657e9..fdabc1b0f 100644 --- a/lib/tools/source_metadata_extractor.dart +++ b/lib/tools/source_metadata_extractor.dart @@ -30,18 +30,16 @@ class SourceMetadataExtractor { List gatherDirectiveInfo(root, SourceCrawler sourceCrawler) { sourceCrawler.crawl(root, metadataVisitor); - List directives = []; + final directives = []; metadataVisitor.metadata.forEach((DirectiveMetadata meta) { - DirectiveInfo dirInfo = new DirectiveInfo(); + var dirInfo = new DirectiveInfo(); dirInfo.selector = meta.selector; dirInfo.template = meta.template; meta.attributeMappings.forEach((attrName, mappingSpec) { var spec = _specs .firstWhere((specPrefix) => mappingSpec.startsWith(specPrefix), orElse: () => throw '$mappingSpec no matching spec'); - if (spec != '@') { - dirInfo.expressionAttrs.add(attrName); - } + if (spec != '@') dirInfo.expressionAttrs.add(attrName); if (mappingSpec.length == 1) { // Shorthand. Remove. // TODO(pavelgj): Figure out if short-hand LHS should be expanded // and added to the expressions list. @@ -98,9 +96,7 @@ class SourceMetadataExtractor { dirInfo.expressionAttrs.forEach((String attr) { if (attr == '.') { var matches = _ATTR_SELECTOR_REGEXP.allMatches(dirInfo.selector); - if (matches.length > 0) { - reprocessedAttrs.add(matches.last.group(1)); - } + if (matches.isNotEmpty) reprocessedAttrs.add(matches.last.group(1)); } else { reprocessedAttrs.add(attr); } @@ -125,11 +121,12 @@ class DirectiveMetadataCollectingVisitor { // Check class annotations for presense of NgComponent/NgDirective. DirectiveMetadata meta; clazz.metadata.forEach((Annotation ann) { - if (ann.arguments == null) return; // Ignore non-class annotations. + if (ann.arguments == null) return; + // Ignore non-class annotations. // TODO(pavelj): this is not a safe check for the type of the // annotations, but good enough for now. if (ann.name.name != 'NgComponent' - && ann.name.name != 'NgDirective') return; + && ann.name.name != 'NgDirective') return; bool isComponent = ann.name.name == 'NgComponent'; @@ -141,63 +138,69 @@ class DirectiveMetadataCollectingVisitor { ann.arguments.arguments.forEach((Expression arg) { if (arg is NamedExpression) { NamedExpression namedArg = arg; - var paramName = namedArg.name.label.name; - if (paramName == 'selector') { - meta.selector = assertString(namedArg.expression).stringValue; - } - if (paramName == 'template') { - meta.template = assertString(namedArg.expression).stringValue; - } - if (paramName == 'map') { - MapLiteral map = namedArg.expression; - map.entries.forEach((MapLiteralEntry entry) { - meta.attributeMappings[assertString(entry.key).stringValue] = - assertString(entry.value).stringValue; - }); - } - if (paramName == 'exportExpressions') { - meta.exportExpressions = getStringValues(namedArg.expression); - } - if (paramName == 'exportExpressionAttrs') { - meta.exportExpressionAttrs = getStringValues(namedArg.expression); + switch (namedArg.name.label.name) { + case 'selector': + meta.selector = assertString(namedArg.expression).stringValue; + break; + + case 'template': + meta.template = assertString(namedArg.expression).stringValue; + break; + + case 'map': + MapLiteral map = namedArg.expression; + map.entries.forEach((MapLiteralEntry entry) { + meta.attributeMappings[assertString(entry.key).stringValue] = + assertString(entry.value).stringValue; + }); + break; + + case 'exportExpressions': + meta.exportExpressions = getStringValues(namedArg.expression); + break; + + case 'exportExpressionAttrs': + meta.exportExpressionAttrs = + getStringValues(namedArg.expression); + break; } } }); - }); - // Check fields/getters/setter for presense of attr mapping annotations. - if (meta != null) { - clazz.members.forEach((ClassMember member) { - if (member is FieldDeclaration || - (member is MethodDeclaration && - (member.isSetter || member.isGetter))) { - member.metadata.forEach((Annotation ann) { - if (_attrAnnotationsToSpec.containsKey(ann.name.name)) { - String fieldName; - if (member is FieldDeclaration) { - fieldName = member.fields.variables.first.name.name; - } else { // MethodDeclaration - fieldName = (member as MethodDeclaration).name.name; + // Check fields/getters/setter for presence of attr mapping annotations. + if (meta != null) { + clazz.members.forEach((ClassMember mbr) { + if (mbr is FieldDeclaration || + mbr is MethodDeclaration && (mbr.isSetter || mbr.isGetter)) { + mbr.metadata.forEach((Annotation ann) { + if (_attrAnnotationsToSpec.containsKey(ann.name.name)) { + String fieldName; + if (mbr is FieldDeclaration) { + fieldName = mbr.fields.variables.first.name.name; + } else { + // MethodDeclaration + fieldName = (mbr as MethodDeclaration).name.name; + } + StringLiteral attNameLiteral = ann.arguments.arguments.first; + if (meta.attributeMappings + .containsKey(attNameLiteral.stringValue)) { + throw 'Attribute mapping already defined for ' + '${clazz.name}.$fieldName'; + } + meta.attributeMappings[attNameLiteral.stringValue] = + _attrAnnotationsToSpec[ann.name.name] + fieldName; } - StringLiteral attNameLiteral = ann.arguments.arguments.first; - if (meta.attributeMappings - .containsKey(attNameLiteral.stringValue)) { - throw 'Attribute mapping already defined for ' - '${clazz.name}.$fieldName'; - } - meta.attributeMappings[attNameLiteral.stringValue] = - _attrAnnotationsToSpec[ann.name.name] + fieldName; - } - }); - } - }); - } + }); + } + }); + } + }); }); } } List getStringValues(ListLiteral listLiteral) { - List res = []; + var res = []; for (Expression element in listLiteral.elements) { res.add(assertString(element).stringValue); } diff --git a/lib/tools/template_cache_annotation.dart b/lib/tools/template_cache_annotation.dart index 111ed1a51..b920cb4c6 100644 --- a/lib/tools/template_cache_annotation.dart +++ b/lib/tools/template_cache_annotation.dart @@ -16,6 +16,6 @@ class NgTemplateCache { // override the default caching behavior for NgComponent annotation. final bool cache; - const NgTemplateCache( - {this.preCacheUrls : const [], this.cache : true}); + const NgTemplateCache({this.preCacheUrls : const [], + this.cache : true}); } diff --git a/lib/tools/template_cache_generator.dart b/lib/tools/template_cache_generator.dart index cc9c2b0b7..dd5f2313c 100644 --- a/lib/tools/template_cache_generator.dart +++ b/lib/tools/template_cache_generator.dart @@ -26,9 +26,9 @@ const SYSTEM_PACKAGE_ROOT = '%SYSTEM_PACKAGE_ROOT%'; main(args) { if (args.length < 4) { print('Usage: templace_cache_generator path_to_entry_point sdk_path ' - 'output package_root1,package_root2,...|$SYSTEM_PACKAGE_ROOT ' - 'patternUrl1,rewriteTo1;patternUrl2,rewriteTo2 ' - 'blacklistClass1,blacklistClass2'); + 'output package_root1,package_root2,...|$SYSTEM_PACKAGE_ROOT ' + 'patternUrl1,rewriteTo1;patternUrl2,rewriteTo2 ' + 'blacklistClass1,blacklistClass2'); exit(1); } @@ -37,11 +37,12 @@ main(args) { var output = args[2]; var outputLibrary = args[3]; var packageRoots = args[4] == SYSTEM_PACKAGE_ROOT ? - [Platform.packageRoot] : args[4].split(','); + [Platform.packageRoot] : + args[4].split(','); Map urlRewriters = parseUrlRemapping(args[5]); - Set blacklistedClasses = (args.length > 6) - ? new Set.from(args[6].split(',')) - : new Set(); + Set blacklistedClasses = (args.length > 6) ? + new Set.from(args[6].split(',')) : + new Set(); print('sdkPath: $sdkPath'); print('entryPoint: $entryPoint'); @@ -51,8 +52,7 @@ main(args) { print('url rewritters: ' + args[5]); print('blacklistedClasses: ' + blacklistedClasses.join(', ')); - - Map templates = {}; + var templates = {}; var c = new SourceCrawler(sdkPath, packageRoots); var visitor = @@ -62,29 +62,25 @@ main(args) { visitor(compilationUnit, source.canonicalPath)); var sink = new File(output).openWrite(); - return printTemplateCache( - templates, urlRewriters, outputLibrary, sink).then((_) { - return sink.flush(); - }); + return printTemplateCache(templates, urlRewriters, outputLibrary, sink) + .then((_) => sink.flush()); } Map parseUrlRemapping(String argument) { Map result = new LinkedHashMap(); - if (argument.isEmpty) { - return result; - } + if (argument.isEmpty) return result; argument.split(";").forEach((String pair) { - List remapping = pair.split(","); + var remapping = pair.split(","); result[new RegExp(remapping[0])] = remapping[1]; }); return result; } printTemplateCache(Map templateKeyMap, - Map urlRewriters, - String outputLibrary, - IOSink outSink) { + Map urlRewriters, + String outputLibrary, + IOSink outSink) { outSink.write(fileHeader(outputLibrary)); @@ -111,9 +107,9 @@ printTemplateCache(Map templateKeyMap, } class TemplateCollectingVisitor { - Map templates; - Set blacklistedClasses; - SourceCrawler sourceCrawler; + final Map templates; + final Set blacklistedClasses; + final SourceCrawler sourceCrawler; TemplateCollectingVisitor(this.templates, this.blacklistedClasses, this.sourceCrawler); @@ -133,7 +129,7 @@ class TemplateCollectingVisitor { // We only care about classes. if (declaration is! ClassDeclaration) return; ClassDeclaration clazz = declaration; - List cacheUris = []; + var cacheUris = []; bool cache = true; clazz.metadata.forEach((Annotation ann) { if (ann.arguments == null) return; // Ignore non-class annotations. @@ -141,9 +137,11 @@ class TemplateCollectingVisitor { switch (ann.name.name) { case 'NgComponent': - extractNgComponentMetadata(ann, cacheUris); break; + extractNgComponentMetadata(ann, cacheUris); + break; case 'NgTemplateCache': - cache = extractNgTemplateCache(ann, cacheUris); break; + cache = extractNgTemplateCache(ann, cacheUris); + break; } }); if (cache && cacheUris.isNotEmpty) { @@ -181,8 +179,8 @@ class TemplateCollectingVisitor { var paramName = namedArg.name.label.name; if (paramName == 'preCacheUrls') { assertList(namedArg.expression).elements - ..forEach((expression) => - cacheUris.add(assertString(expression).stringValue)); + ..forEach((expression) => + cacheUris.add(assertString(expression).stringValue)); } if (paramName == 'cache') { cache = assertBoolean(namedArg.expression).value; @@ -202,10 +200,9 @@ class TemplateCollectingVisitor { } String findAssetFileLocation(String uri, Source srcPath) { - if (uri.startsWith('/')) { - // Absolute Path from working directory. - return '.${uri}'; - } + // Absolute Path from working directory. + if (uri.startsWith('/')) return '.${uri}'; + // Otherwise let the sourceFactory resolve for packages, and relative paths. Source source = sourceCrawler.context.sourceFactory .resolveUri(srcPath, uri); diff --git a/lib/tools/transformer/expression_generator.dart b/lib/tools/transformer/expression_generator.dart index 6dba7e369..d4565d70c 100644 --- a/lib/tools/transformer/expression_generator.dart +++ b/lib/tools/transformer/expression_generator.dart @@ -48,8 +48,8 @@ class ExpressionGenerator extends Transformer with ResolverTransformer { .forEach(htmlExtractor.parseHtml) .then((_) { var module = new Module() - ..type(Parser, implementedBy: DynamicParser) - ..type(ParserBackend, implementedBy: DartGetterSetterGen); + ..type(Parser, implementedBy: DynamicParser) + ..type(ParserBackend, implementedBy: DartGetterSetterGen); var injector = new DynamicInjector(modules: [module], allowImplicitInjection: true); @@ -82,28 +82,31 @@ class ExpressionGenerator extends Transformer with ResolverTransformer { .toList(); // Get all of the contents of templates in @NgComponent(templateUrl:'...') - gatherReferencedUris(transform, resolver, options, - templatesOnly: true).then((templates) { - templates.values.forEach(controller.add); - }).then((_) { - // Add any HTML files referencing this Dart file. - return _findHtmlEntry(transform); - }).then((htmlRefId) { - if (htmlRefId != null) { - assets.add(htmlRefId); - } - Future.wait( - // Add any manually specified HTML files. - assets.map((id) => transform.readInputAsString(id)) - .map((future) => - future.then(controller.add).catchError((e) { - transform.logger.warning('Unable to find $id from html_files ' - 'in pubspec.yaml.'); - })) - ).then((_) { - controller.close(); + gatherReferencedUris(transform, resolver, options, templatesOnly: true) + .then((templates) { + templates.values.forEach(controller.add); + }) + .then((_) { + // Add any HTML files referencing this Dart file. + return _findHtmlEntry(transform); + }) + .then((htmlRefId) { + if (htmlRefId != null) assets.add(htmlRefId); + Future + .wait( + // Add any manually specified HTML files. + assets + .map((id) => transform.readInputAsString(id)) + .map((future) => future + .then(controller.add) + .catchError((e) { + transform.logger.warning('Unable to find $id from ' + t'html_files in pubspec.yaml.'); + }))) + .then((_) { + controller.close(); + }); }); - }); return controller.stream; } @@ -148,7 +151,8 @@ class _LibrarySourceCrawler implements SourceCrawler { _LibrarySourceCrawler(this.libraries); void crawl(String entryPoint, CompilationUnitVisitor visitor) { - libraries.expand((lib) => lib.units) + libraries + .expand((lib) => lib.units) .map((compilationUnitElement) => compilationUnitElement.node) .forEach(visitor); } diff --git a/lib/tools/transformer/metadata_extractor.dart b/lib/tools/transformer/metadata_extractor.dart index 4af1b497c..61a30fd95 100644 --- a/lib/tools/transformer/metadata_extractor.dart +++ b/lib/tools/transformer/metadata_extractor.dart @@ -18,16 +18,14 @@ class AnnotatedType { * Finds all the libraries referenced by the annotations */ Iterable get referencedLibraries { - var libs = new Set(); - libs.add(type.library); + var libs = new Set()..add(type.library); var libCollector = new _LibraryCollector(); - for (var annotation in annotations) { - annotation.accept(libCollector); - } - libs.addAll(libCollector.libraries); + annotations.forEach((a) { + a.accept(libCollector); + }); - return libs; + return libs..addAll(libCollector.libraries); } void writeClassAnnotations(StringBuffer sink, TransformLogger logger, @@ -53,12 +51,11 @@ class AnnotatedType { * Helper which finds all libraries referenced within the provided AST. */ class _LibraryCollector extends GeneralizingAstVisitor { - final Set libraries = new Set(); + final libraries = new Set(); + void visitSimpleIdentifier(SimpleIdentifier s) { var element = s.bestElement; - if (element != null) { - libraries.add(element.library); - } + if (element != null) libraries.add(element.library); } } @@ -84,8 +81,7 @@ class _AnnotationWriter { var len = sink.length; if (!_writeAnnotation(annotation)) { var str = sink.toString(); - sink.clear(); - sink.write(str.substring(0, len)); + sink..clear()..write(str.substring(0, len)); return false; } return true; @@ -97,9 +93,7 @@ class _AnnotationWriter { sink.write('const ${prefixes[element.library]}' '${element.enclosingElement.name}'); // Named constructors - if (!element.name.isEmpty) { - sink.write('.${element.name}'); - } + if (element.name.isNotEmpty) sink.write('.${element.name}'); sink.write('('); if (!_writeArguments(annotation)) return false; sink.write(')'); @@ -112,7 +106,7 @@ class _AnnotationWriter { return false; } - /** Writes the arguments for a type constructor. */ + /// Writes the arguments for a type constructor. bool _writeArguments(Annotation annotation) { var args = annotation.arguments; var index = 0; @@ -123,9 +117,7 @@ class _AnnotationWriter { } else { if (!_writeExpression(arg)) return false; } - if (++index < args.arguments.length) { - sink.write(', '); - } + if (++index < args.arguments.length) sink.write(', '); } return true; } @@ -152,9 +144,7 @@ class _AnnotationWriter { if (!_writeExpression(entry.key)) return false; sink.write(': '); if (!_writeExpression(entry.value)) return false; - if (++index < expression.entries.length) { - sink.write(', '); - } + if (++index < expression.entries.length) sink.write(', '); } sink.write('}'); return true; @@ -185,8 +175,10 @@ class _AnnotationWriter { return true; } } - if (expression is BooleanLiteral || expression is DoubleLiteral || - expression is IntegerLiteral || expression is NullLiteral) { + if (expression is BooleanLiteral || + expression is DoubleLiteral || + expression is IntegerLiteral || + expression is NullLiteral) { sink.write(expression.toSource()); return true; } @@ -218,7 +210,7 @@ class AnnotationExtractor { ClassElement ngAnnotationType; /// Resolved annotations that this will pick up for members. - final List _annotationElements = []; + final _annotationElements = []; AnnotationExtractor(this.logger, this.resolver, this.outputId) { for (var annotation in _angularAnnotationNames) { @@ -229,10 +221,11 @@ class AnnotationExtractor { } _annotationElements.add(type.unnamedConstructor); } - ngAnnotationType = resolver.getType('angular.core.annotation_src.AbstractNgAnnotation'); + ngAnnotationType = + resolver.getType('angular.core.annotation_src.AbstractNgAnnotation'); if (ngAnnotationType == null) { logger.warning('Unable to resolve AbstractNgAnnotation, ' - 'skipping member annotations.'); + 'skipping member annotations.'); } } @@ -240,7 +233,8 @@ class AnnotationExtractor { AnnotatedType extractAnnotations(ClassElement cls) { if (resolver.getImportUri(cls.library, from: outputId) == null) { warn('Dropping annotations for ${cls.name} because the ' - 'containing file cannot be imported (must be in a lib folder).', cls); + 'containing file cannot be imported (must be in a lib folder).', + cls); return null; } @@ -258,10 +252,8 @@ class AnnotationExtractor { annotation.parent.element); return false; } - if (element is! ConstructorElement) { - // Only keeping constructor elements. - return false; - } + // Only keeping constructor elements. + if (element is! ConstructorElement) return false; ConstructorElement ctor = element; var cls = ctor.enclosingElement; if (!cls.isPublic) { @@ -270,10 +262,7 @@ class AnnotationExtractor { return false; } // Skip all non-Ng* Attributes. - if (!cls.name.startsWith('Ng')) { - return false; - } - return true; + return cls.name.startsWith('Ng'); }).toList(); @@ -297,8 +286,10 @@ class AnnotationExtractor { return type; } - /// Folds all AttrFieldAnnotations into the AbstractNgAnnotation annotation on the - /// class. + /** + * Folds all AttrFieldAnnotations into the AbstractNgAnnotation annotation on + * the class. + */ void _foldMemberAnnotations(Map memberAnnotations, AnnotatedType type) { // Filter down to AbstractNgAnnotation constructors. @@ -308,6 +299,7 @@ class AnnotationExtractor { return element.enclosingElement.type.isAssignableTo( ngAnnotationType.type); }); + if (ngAnnotations.isEmpty) { warn('Found field annotation but no class directives.', type.type); return; @@ -319,9 +311,7 @@ class AnnotationExtractor { var ctor = a.element; for (var param in ctor.parameters) { - if (param.parameterKind != ParameterKind.NAMED) { - continue; - } + if (param.parameterKind != ParameterKind.NAMED) continue; if (param.name == 'map' && param.type.isAssignableTo(mapType)) { return true; } @@ -331,57 +321,56 @@ class AnnotationExtractor { if (acceptableAnnotations.isEmpty) { warn('Could not find a constructor for member annotations in ' - '$ngAnnotations', type.type); + '$ngAnnotations', type.type); return; } - // Default to using the first acceptable annotation- not sure if - // more than one should ever occur. - var sourceAnnotation = acceptableAnnotations.first; - - // Clone the annotation so we don't modify the one in the persistent AST. - var index = type.annotations.indexOf(sourceAnnotation); - var annotation = new AstCloner().visitAnnotation(sourceAnnotation); - ResolutionCopier.copyResolutionData(sourceAnnotation, annotation); - type.annotations[index] = annotation; - - var mapArg = annotation.arguments.arguments.firstWhere((arg) => - (arg is NamedExpression) && (arg.name.label.name == 'map'), - orElse: () => null); - - // If we don't have a 'map' parameter yet, add one. - if (mapArg == null) { - var map = new MapLiteral(null, null, null, [], null); - var label = new Label(new SimpleIdentifier( - new _GeneratedToken(TokenType.STRING, 'map')), - new _GeneratedToken(TokenType.COLON, ':')); - mapArg = new NamedExpression(label, map); - annotation.arguments.arguments.add(mapArg); - } + // Merge attribute annotations in all of the class annotations + acceptableAnnotations.forEach((srcAnnotation) { + // Clone the annotation so we don't modify the one in the persistent AST. + var index = type.annotations.indexOf(srcAnnotation); + var annotation = new AstCloner().visitAnnotation(srcAnnotation); + ResolutionCopier.copyResolutionData(srcAnnotation, annotation); + type.annotations[index] = annotation; + + var mapArg = annotation.arguments.arguments.firstWhere( + (arg) => (arg is NamedExpression) && (arg.name.label.name == 'map'), + orElse: () => null); + + // If we don't have a 'map' parameter yet, add one. + if (mapArg == null) { + var map = new MapLiteral(null, null, null, [], null); + var label = new Label(new SimpleIdentifier( + new _GeneratedToken(TokenType.STRING, 'map')), + new _GeneratedToken(TokenType.COLON, ':')); + mapArg = new NamedExpression(label, map); + annotation.arguments.arguments.add(mapArg); + } - var map = mapArg.expression; - if (map is! MapLiteral) { - warn('Expected \'map\' argument of $annotation to be a map literal', - type.type); - return; - } - memberAnnotations.forEach((memberName, annotation) { - var key = annotation.arguments.arguments.first; - // If the key already exists then it means we have two annotations for - // same member. - if (map.entries.any((entry) => entry.key.toString() == key.toString())) { - warn('Directive $annotation already contains an entry for $key', - type.type); + var map = mapArg.expression; + if (map is! MapLiteral) { + warn('Expected \'map\' argument of $annotation to be a map literal', + type.type); return; } + memberAnnotations.forEach((memberName, annotation) { + var key = annotation.arguments.arguments.first; + // If the key already exists then it means we have two annotations for + // same member. + if (map.entries.any((entry) => entry.key.toString() == key.toString())) { + warn('Directive $annotation already contains an entry for $key', + type.type); + return; + } - var typeName = annotation.element.enclosingElement.name; - var value = '${_annotationToMapping[typeName]}$memberName'; - var entry = new MapLiteralEntry( - key, - new _GeneratedToken(TokenType.COLON, ':'), - new SimpleStringLiteral(stringToken(value), value)); - map.entries.add(entry); + var typeName = annotation.element.enclosingElement.name; + var value = '${_annotationToMapping[typeName]}$memberName'; + var entry = new MapLiteralEntry( + key, + new _GeneratedToken(TokenType.COLON, ':'), + new SimpleStringLiteral(stringToken(value), value)); + map.entries.add(entry); + }); }); } @@ -408,7 +397,7 @@ class _GeneratedToken extends Token { class _AnnotationVisitor extends GeneralizingAstVisitor { final List allowedMemberAnnotations; final List classAnnotations = []; - final Map> memberAnnotations = {}; + final memberAnnotations = >{}; _AnnotationVisitor(this.allowedMemberAnnotations); @@ -430,5 +419,5 @@ class _AnnotationVisitor extends GeneralizingAstVisitor { } bool get hasAnnotations => - !classAnnotations.isEmpty || !memberAnnotations.isEmpty; + classAnnotations.isNotEmpty || memberAnnotations.isNotEmpty; } diff --git a/lib/tools/transformer/options.dart b/lib/tools/transformer/options.dart index f95f2ab51..497fb1d75 100644 --- a/lib/tools/transformer/options.dart +++ b/lib/tools/transformer/options.dart @@ -33,12 +33,13 @@ class TransformOptions { TransformOptions({String sdkDirectory, List htmlFiles, Map templateUriRewrites, - di.TransformOptions diOptions}) : - sdkDirectory = sdkDirectory, - htmlFiles = htmlFiles != null ? htmlFiles : [], - templateUriRewrites = templateUriRewrites != null ? - templateUriRewrites : {}, - diOptions = diOptions { + di.TransformOptions diOptions}) + : sdkDirectory = sdkDirectory, + htmlFiles = htmlFiles != null ? htmlFiles : [], + templateUriRewrites = templateUriRewrites != null ? + templateUriRewrites : {}, + diOptions = diOptions + { if (sdkDirectory == null) throw new ArgumentError('sdkDirectory must be provided.'); } diff --git a/lib/tools/transformer/referenced_uris.dart b/lib/tools/transformer/referenced_uris.dart index 4ddf14893..20ca6ea59 100644 --- a/lib/tools/transformer/referenced_uris.dart +++ b/lib/tools/transformer/referenced_uris.dart @@ -23,7 +23,7 @@ class _Processor { final Transform transform; final Resolver resolver; final TransformOptions options; - final Map templateUriRewrites = {}; + final templateUriRewrites = {}; final bool skipNonCached; final bool templatesOnly; @@ -31,8 +31,9 @@ class _Processor { ConstructorElement componentAnnotation; static const String cacheAnnotationName = - 'angular.template_cache_annotation.NgTemplateCache'; - static const String componentAnnotationName = 'angular.core.annotation_src.NgComponent'; + 'angular.template_cache_annotation.NgTemplateCache'; + static const String componentAnnotationName = + 'angular.core.annotation_src.NgComponent'; _Processor(this.transform, this.resolver, this.options, this.skipNonCached, this.templatesOnly) { @@ -64,8 +65,8 @@ class _Processor { .where((type) => type.node != null) .expand(_AnnotatedElement.fromElement) .where((e) => - (e.annotation.element == cacheAnnotation || - e.annotation.element == componentAnnotation)) + e.annotation.element == cacheAnnotation || + e.annotation.element == componentAnnotation) .toList(); var uriToEntry = {}; @@ -107,9 +108,7 @@ class _Processor { if (paramName == 'templateUrl') { var entry = extractString('templateUrl', arg.expression, annotation.element); - if (entry != null) { - entries.add(entry); - } + if (entry != null) entries.add(entry); } else if (paramName == 'cssUrl' && !templatesOnly) { entries.addAll(extractListOrString(paramName, arg.expression, annotation.element)); @@ -220,11 +219,7 @@ class _Processor { templateUriRewrites.forEach((regexp, replacement) { uri = uri.replaceFirst(regexp, replacement); }); - // Normalize packages/ uri's to be /packages/ - if (uri.startsWith('packages/')) { - uri = '/' + uri; - } - return uri; + return uri.startsWith('packages/') ? '/' + uri : uri; } void warn(String msg, Element element) { diff --git a/test/tools/html_extractor_spec.dart b/test/tools/html_extractor_spec.dart index 976e19442..f175dd2ad 100644 --- a/test/tools/html_extractor_spec.dart +++ b/test/tools/html_extractor_spec.dart @@ -12,9 +12,7 @@ void main() { it('should extract text mustache expressions', () { var ioService = new MockIoService({ - 'foo.html': r''' -
foo {{ctrl.bar}} baz {{aux}}
- ''' + 'foo.html': r'
foo {{ctrl.bar}} baz {{aux}}
' }); var extractor = new HtmlExpressionExtractor([]); @@ -25,9 +23,7 @@ void main() { it('should extract attribute mustache expressions', () { var ioService = new MockIoService({ - 'foo.html': r''' -
- ''' + 'foo.html': r'
' }); var extractor = new HtmlExpressionExtractor([]); @@ -38,9 +34,7 @@ void main() { it('should extract ng-repeat expressions', () { var ioService = new MockIoService({ - 'foo.html': r''' -
- ''' + 'foo.html': r'
' }); var extractor = new HtmlExpressionExtractor([]); @@ -62,9 +56,7 @@ void main() { it('should extract expressions from expression attributes', () { var ioService = new MockIoService({ - 'foo.html': r''' - - ''' + 'foo.html': r'' }); var extractor = new HtmlExpressionExtractor([ @@ -77,9 +69,7 @@ void main() { it('should ignore ng-repeat while extracting attribute expressions', () { var ioService = new MockIoService({ - 'foo.html': r''' -
- ''' + 'foo.html': r'
' }); var extractor = new HtmlExpressionExtractor([ diff --git a/test/tools/mock_io_service.dart b/test/tools/mock_io_service.dart index 589d761d1..3fadb66fa 100644 --- a/test/tools/mock_io_service.dart +++ b/test/tools/mock_io_service.dart @@ -9,9 +9,7 @@ class MockIoService implements IoService { MockIoService(this.mockData); String readAsStringSync(String filePath) { - if (!mockData.containsKey(filePath)) { - throw 'file not found'; - } + if (!mockData.containsKey(filePath)) throw 'file not found'; return mockData[filePath]; } diff --git a/test/tools/source_metadata_extractor_spec.dart b/test/tools/source_metadata_extractor_spec.dart index 49f1beb80..bb7f4cff6 100644 --- a/test/tools/source_metadata_extractor_spec.dart +++ b/test/tools/source_metadata_extractor_spec.dart @@ -116,7 +116,7 @@ void main() { } flattenList(list, map) => list.map(map).fold([], (prev, exprs) => -new List.from(prev)..addAll(exprs)); + new List.from(prev)..addAll(exprs)); List extractDirectiveInfo(List metadata) { var sourceCrawler = new MockSourceCrawler(); @@ -129,7 +129,7 @@ class MockDirectiveMetadataCollectingVisitor implements DirectiveMetadataCollectingVisitor { List metadata; - MockDirectiveMetadataCollectingVisitor(List this.metadata); + MockDirectiveMetadataCollectingVisitor(this.metadata); call(CompilationUnit cu) { // do nothing diff --git a/test/tools/transformer/metadata_generator_spec.dart b/test/tools/transformer/metadata_generator_spec.dart index 810ea9329..19f76369d 100644 --- a/test/tools/transformer/metadata_generator_spec.dart +++ b/test/tools/transformer/metadata_generator_spec.dart @@ -115,7 +115,12 @@ main() { 'a|web/main.dart': ''' import 'package:angular/angular.dart'; - @NgDirective(map: {'another-expression': '=>anotherExpression'}) + @NgDirective( + selector: 'first', + map: {'first-expression': '=>anotherExpression'}) + @NgDirective( + selector: 'second', + map: {'second-expression': '=>anotherExpression'}) class Engine { set anotherExpression(Function) {} @@ -132,8 +137,13 @@ main() { ], classes: { 'import_0.Engine': [ - 'const import_1.NgDirective(map: const {' - '\'another-expression\': \'=>anotherExpression\', ' + 'const import_1.NgDirective(selector: \'first\', ' + 'map: const {' + '\'first-expression\': \'=>anotherExpression\', ' + '\'two-way-stuff\': \'<=>twoWayStuff\'})', + 'const import_1.NgDirective(selector: \'second\', ' + 'map: const {' + '\'second-expression\': \'=>anotherExpression\', ' '\'two-way-stuff\': \'<=>twoWayStuff\'})', ] });