| Index: lib/src/compiler.dart | 
| diff --git a/lib/src/compiler.dart b/lib/src/compiler.dart | 
| index 44f7b0d612d54c653461500553b2bbeba47614a3..44c029a13e9afd703e7b124d79418d7f99b7134b 100644 | 
| --- a/lib/src/compiler.dart | 
| +++ b/lib/src/compiler.dart | 
| @@ -163,6 +163,14 @@ class Compiler { | 
| } | 
| } | 
|  | 
| +    // Load stylesheet files referenced by [file]. | 
| +    for (var href in fileInfo.styleSheetHref) { | 
| +      if (!_processed.contains(href)) { | 
| +        _processed.add(href); | 
| +        _tasks.add(_parseStyleSheetFile(href).then(_processStyleSheetFile)); | 
| +      } | 
| +    } | 
| + | 
| // Load .dart files being referenced in the page. | 
| var src = fileInfo.externalFile; | 
| if (src != null && !_processed.contains(src)) { | 
| @@ -196,7 +204,8 @@ class Compiler { | 
| /** Parse [filename] and treat it as a .dart file. */ | 
| Future<SourceFile> _parseDartFile(Path path) { | 
| return fileSystem.readText(path) | 
| -        .then((code) => new SourceFile(path, isDart: true)..code = code) | 
| +        .then((code) => new SourceFile(path, type: SourceFile.DART) | 
| +            ..code = code) | 
| .catchError((e) => _readError(e, path)); | 
| } | 
|  | 
| @@ -237,6 +246,31 @@ class Compiler { | 
| } | 
| } | 
|  | 
| +  /** Parse [filename] and treat it as a .dart file. */ | 
| +  Future<SourceFile> _parseStyleSheetFile(Path path) { | 
| +    return fileSystem.readText(path) | 
| +        .then((code) => | 
| +            new SourceFile(path, type: SourceFile.STYLESHEET)..code = code) | 
| +        .catchError((e) => _readError(e, path)); | 
| +  } | 
| + | 
| +  void _processStyleSheetFile(SourceFile cssFile) { | 
| +    if (!_shouldProcessFile(cssFile)) return; | 
| + | 
| +    files.add(cssFile); | 
| + | 
| +    var fileInfo = new FileInfo(cssFile.path); | 
| +    info[cssFile.path] = fileInfo; | 
| + | 
| +    var uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path, | 
| +        options.rewriteUrls); | 
| +    var styleSheet = _parseCss(cssFile.path.toString(), | 
| +        cssFile.code, uriVisitor, options); | 
| +    if (styleSheet != null) { | 
| +      fileInfo.styleSheets.add(styleSheet); | 
| +    } | 
| +  } | 
| + | 
| Path _getDirectivePath(LibraryInfo libInfo, Directive directive) { | 
| var uriDirective = (directive as UriBasedDirective).uri; | 
| var uri = uriDirective.value; | 
| @@ -417,20 +451,26 @@ class Compiler { | 
| void _analyze() { | 
| var uniqueIds = new IntIterator(); | 
| for (var file in files) { | 
| -      if (file.isDart) continue; | 
| -      _time('Analyzed contents', file.path, () => | 
| -          analyzeFile(file, info, uniqueIds, _messages)); | 
| +      if (file.isHtml) { | 
| +        _time('Analyzed contents', file.path, () => | 
| +            analyzeFile(file, info, uniqueIds, _messages)); | 
| +      } | 
| } | 
| } | 
|  | 
| /** Emit the generated code corresponding to each input file. */ | 
| void _emit() { | 
| for (var file in files) { | 
| -      if (file.isDart) continue; | 
| +      if (file.isDart || file.isStyleSheet) continue; | 
| _time('Codegen', file.path, () { | 
| var fileInfo = info[file.path]; | 
| cleanHtmlNodes(fileInfo); | 
| -        _processStylesheet(fileInfo, options: options); | 
| +        if (!fileInfo.isEntryPoint) { | 
| +          // Check all components files for <style> tags and parse the CSS. | 
| +          var uriVisitor = new UriVisitor(_pathInfo, _mainPath, fileInfo.path, | 
| +              options.rewriteUrls); | 
| +          _processStylesheet(uriVisitor, fileInfo, options: options); | 
| +        } | 
| fixupHtmlCss(fileInfo, options); | 
| _emitComponents(fileInfo); | 
| if (fileInfo.isEntryPoint) { | 
| @@ -439,12 +479,16 @@ class Compiler { | 
| } | 
| }); | 
| } | 
| + | 
| +    if (options.processCss) { | 
| +      _emitAllCss(); | 
| +    } | 
| } | 
|  | 
| /** Emit the main .dart file. */ | 
| void _emitMainDart(SourceFile file) { | 
| var fileInfo = info[file.path]; | 
| -    var printer = new MainPageEmitter(fileInfo) | 
| +    var printer = new MainPageEmitter(fileInfo, options.processCss) | 
| .run(file.document, _pathInfo, _edits[fileInfo.userCode], | 
| options.rewriteUrls); | 
| _emitFileAndSourceMaps(fileInfo, printer, fileInfo.inputPath); | 
| @@ -496,9 +540,62 @@ class Compiler { | 
| document.outerHtml, source: file.path)); | 
| } | 
|  | 
| +  /** Generate an CSS file for all style sheets (main and components). */ | 
| +  void _emitAllCss() { | 
| +    var allCssBuff = new StringBuffer(); | 
| +    var mainFile; | 
| + | 
| +    // Emit all linked style sheet files first. | 
| +    for (var file in files) { | 
| +      var fileInfo = info[file.path]; | 
| +      if (fileInfo.isEntryPoint) mainFile = file; | 
| +      if (file.isStyleSheet) { | 
| +        for (var styleSheet in fileInfo.styleSheets) { | 
| +          allCssBuff.write( | 
| +              '/* ==================================================== */\n' | 
| +              '/* Linked style sheet href = ${file.path.filename} */\n' | 
| +              '/* ==================================================== */\n'); | 
| +          allCssBuff.write(emitStyleSheet(styleSheet)); | 
| +          allCssBuff.write('\n\n'); | 
| +        } | 
| +      } | 
| +    } | 
| + | 
| +    // Emit all CSS in each component (style scoped). | 
| +    for (var file in files) { | 
| +      if (file.isHtml) { | 
| +        var fileInfo = info[file.path]; | 
| +        for (var component in fileInfo.declaredComponents) { | 
| +          for (var styleSheet in component.styleSheets) { | 
| +            allCssBuff.write( | 
| +                '/* ==================================================== */\n' | 
| +                '/* Component ${component.tagName} stylesheet */\n' | 
| +                '/* ==================================================== */\n'); | 
| +            allCssBuff.write(emitStyleSheet(styleSheet, component.tagName)); | 
| +            allCssBuff.write('\n\n'); | 
| +          } | 
| +        } | 
| +      } | 
| +    } | 
| + | 
| +    var allCss = allCssBuff.toString(); | 
| +    if (!allCss.isEmpty) { | 
| +      var allCssFile = '${mainFile.path.filename}.css'; | 
| +      var allCssPath = mainFile.path.directoryPath.append(allCssFile); | 
| +      var allCssOutPath = _pathInfo.outputPath(allCssPath, ''); | 
| +      output.add(new OutputFile(allCssOutPath, allCss)); | 
| +    } | 
| +  } | 
| + | 
| /** Emits the Dart code for all components in [fileInfo]. */ | 
| void _emitComponents(FileInfo fileInfo) { | 
| for (var component in fileInfo.declaredComponents) { | 
| +      // TODO(terry): Handle one stylesheet per component see fixupHtmlCss. | 
| +      if (component.styleSheets.length > 1 && options.processCss) { | 
| +        _messages.warning( | 
| +            'Component has more than one stylesheet' | 
| +            ' - first stylesheet used.', null, file: component.externalFile); | 
| +      } | 
| var printer = new WebComponentEmitter(fileInfo, _messages) | 
| .run(component, _pathInfo, _edits[component.userCode]); | 
| _emitFileAndSourceMaps(component, printer, component.externalFile); | 
| @@ -568,33 +665,57 @@ class Compiler { | 
| } | 
|  | 
| /** Parse all stylesheet for polyfilling assciated with [info]. */ | 
| -void _processStylesheet(info, {CompilerOptions options : null}) { | 
| -  new _ProcessCss(options).visit(info); | 
| +void _processStylesheet(uriVisitor, info, {CompilerOptions options : null}) { | 
| +  new _ProcessCss(uriVisitor, options).visit(info); | 
| +} | 
| + | 
| +StyleSheet _parseCss(String src, String content, UriVisitor uriVisitor, | 
| +                     CompilerOptions options) { | 
| +  if (!content.trim().isEmpty) { | 
| +    // TODO(terry): Add --checked when fully implemented and error handling. | 
| +    var styleSheet = css.parse(content, options: | 
| +      [options.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']); | 
| +    uriVisitor.visitTree(styleSheet); | 
| +    if (options.debugCss) { | 
| +      print('\nCSS source: $src'); | 
| +      print('==========\n'); | 
| +      print(treeToDebugString(styleSheet)); | 
| +    } | 
| +    return styleSheet; | 
| +  } | 
| } | 
|  | 
| /** Post-analysis of style sheet; parsed ready for emitting with polyfill. */ | 
| class _ProcessCss extends InfoVisitor { | 
| +  final UriVisitor uriVisitor; | 
| final CompilerOptions options; | 
| +  ComponentInfo component; | 
|  | 
| -  _ProcessCss(this.options); | 
| - | 
| -  // TODO(terry): Add --checked when fully implemented and error handling too. | 
| -  StyleSheet _parseCss(String cssInput, CompilerOptions option) => | 
| -      css.parse(cssInput, options: | 
| -        [option.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']); | 
| +  _ProcessCss(this.uriVisitor, this.options); | 
|  | 
| void visitComponentInfo(ComponentInfo info) { | 
| -    if (!info.cssSource.isEmpty) { | 
| -      info.styleSheet = _parseCss(info.cssSource.toString(), options); | 
| -      info.cssSource = null;    // Once CSS parsed original not needed. | 
| - | 
| -      if (options.debugCss) { | 
| -        print('\nComponent: ${info.tagName}'); | 
| -        print('==========\n'); | 
| -        print(treeToDebugString(info.styleSheet)); | 
| +    var oldComponent = component; | 
| +    component = info; | 
| + | 
| +    super.visitComponentInfo(info); | 
| + | 
| +    component = oldComponent; | 
| +  } | 
| + | 
| +  void visitElementInfo(ElementInfo info) { | 
| +    if (component != null) { | 
| +      var node = info.node; | 
| +      if (node.tagName == 'style' && node.attributes.containsKey("scoped")) { | 
| +        // Get contents of style tag. | 
| +        var content = node.nodes.single.value; | 
| +        var styleSheet = _parseCss(component.tagName, content, uriVisitor, | 
| +            options); | 
| +        if (styleSheet != null) { | 
| +          component.styleSheets.add(styleSheet); | 
| +        } | 
| } | 
| } | 
|  | 
| -    super.visitComponentInfo(info); | 
| +    super.visitElementInfo(info); | 
| } | 
| } | 
|  |