| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library compiler; | 5 library compiler; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection' show SplayTreeMap; | 8 import 'dart:collection' show SplayTreeMap; |
| 9 import 'dart:convert'; | |
| 10 | 9 |
| 11 import 'package:analyzer_experimental/src/generated/ast.dart' show Directive, Ur
iBasedDirective; | |
| 12 import 'package:csslib/visitor.dart' show StyleSheet, treeToDebugString; | 10 import 'package:csslib/visitor.dart' show StyleSheet, treeToDebugString; |
| 13 import 'package:html5lib/dom.dart'; | 11 import 'package:html5lib/dom.dart'; |
| 14 import 'package:html5lib/parser.dart'; | 12 import 'package:html5lib/parser.dart'; |
| 15 import 'package:source_maps/span.dart' show Span; | |
| 16 import 'package:source_maps/refactor.dart' show TextEditTransaction; | |
| 17 import 'package:source_maps/printer.dart'; | |
| 18 | 13 |
| 19 import 'analyzer.dart'; | 14 import 'analyzer.dart'; |
| 20 import 'css_analyzer.dart' show analyzeCss, findUrlsImported, | 15 import 'css_analyzer.dart' show analyzeCss, findUrlsImported, |
| 21 findImportsInStyleSheet, parseCss; | 16 findImportsInStyleSheet, parseCss; |
| 22 import 'css_emitters.dart' show rewriteCssUris, | 17 import 'css_emitters.dart' show rewriteCssUris, |
| 23 emitComponentStyleSheet, emitOriginalCss, emitStyleSheet; | 18 emitComponentStyleSheet, emitOriginalCss, emitStyleSheet; |
| 24 import 'dart_parser.dart'; | |
| 25 import 'file_system.dart'; | 19 import 'file_system.dart'; |
| 26 import 'files.dart'; | 20 import 'files.dart'; |
| 27 import 'info.dart'; | 21 import 'info.dart'; |
| 28 import 'messages.dart'; | 22 import 'messages.dart'; |
| 29 import 'compiler_options.dart'; | 23 import 'compiler_options.dart'; |
| 30 import 'utils.dart'; | 24 import 'utils.dart'; |
| 31 | 25 |
| 32 /** | 26 /** |
| 33 * Parses an HTML file [contents] and returns a DOM-like tree. | 27 * Parses an HTML file [contents] and returns a DOM-like tree. |
| 34 * Note that [contents] will be a [String] if coming from a browser-based | 28 * Note that [contents] will be a [String] if coming from a browser-based |
| (...skipping 24 matching lines...) Expand all Loading... |
| 59 String _packageRoot; | 53 String _packageRoot; |
| 60 String _resetCssFile; | 54 String _resetCssFile; |
| 61 StyleSheet _cssResetStyleSheet; | 55 StyleSheet _cssResetStyleSheet; |
| 62 Messages _messages; | 56 Messages _messages; |
| 63 | 57 |
| 64 FutureGroup _tasks; | 58 FutureGroup _tasks; |
| 65 Set _processed; | 59 Set _processed; |
| 66 | 60 |
| 67 /** Information about source [files] given their href. */ | 61 /** Information about source [files] given their href. */ |
| 68 final Map<String, FileInfo> info = new SplayTreeMap<String, FileInfo>(); | 62 final Map<String, FileInfo> info = new SplayTreeMap<String, FileInfo>(); |
| 69 final _edits = new Map<DartCodeInfo, TextEditTransaction>(); | |
| 70 | 63 |
| 71 final GlobalInfo global = new GlobalInfo(); | 64 final GlobalInfo global = new GlobalInfo(); |
| 72 | 65 |
| 73 /** Creates a compiler with [options] using [fileSystem]. */ | 66 /** Creates a compiler with [options] using [fileSystem]. */ |
| 74 Compiler(this.fileSystem, this.options, this._messages) { | 67 Compiler(this.fileSystem, this.options, this._messages) { |
| 75 _mainPath = options.inputFile; | 68 _mainPath = options.inputFile; |
| 76 var mainDir = path.dirname(_mainPath); | 69 var mainDir = path.dirname(_mainPath); |
| 77 var baseDir = options.baseDir != null ? options.baseDir : mainDir; | 70 var baseDir = options.baseDir != null ? options.baseDir : mainDir; |
| 78 _packageRoot = options.packageRoot != null ? options.packageRoot | 71 _packageRoot = options.packageRoot != null ? options.packageRoot |
| 79 : path.join(path.dirname(_mainPath), 'packages'); | 72 : path.join(path.dirname(_mainPath), 'packages'); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 | 123 |
| 131 void _processHtmlFile(UrlInfo inputUrl, SourceFile file) { | 124 void _processHtmlFile(UrlInfo inputUrl, SourceFile file) { |
| 132 if (file == null) return; | 125 if (file == null) return; |
| 133 | 126 |
| 134 bool isEntryPoint = _processed.length == 1; | 127 bool isEntryPoint = _processed.length == 1; |
| 135 | 128 |
| 136 files.add(file); | 129 files.add(file); |
| 137 | 130 |
| 138 var fileInfo = _time('Analyzed definitions', inputUrl.url, () { | 131 var fileInfo = _time('Analyzed definitions', inputUrl.url, () { |
| 139 return analyzeDefinitions(global, inputUrl, file.document, _packageRoot, | 132 return analyzeDefinitions(global, inputUrl, file.document, _packageRoot, |
| 140 _messages, isEntryPoint: isEntryPoint); | 133 _messages); |
| 141 }); | 134 }); |
| 142 info[inputUrl.resolvedPath] = fileInfo; | 135 info[inputUrl.resolvedPath] = fileInfo; |
| 143 | 136 |
| 144 if (isEntryPoint && _resetCssFile != null) { | 137 if (isEntryPoint && _resetCssFile != null) { |
| 145 _processed.add(_resetCssFile); | 138 _processed.add(_resetCssFile); |
| 146 _tasks.add(_parseCssFile(new UrlInfo(_resetCssFile, _resetCssFile, | 139 _tasks.add(_parseCssFile(new UrlInfo(_resetCssFile, _resetCssFile, |
| 147 null))); | 140 null))); |
| 148 } | 141 } |
| 149 | 142 |
| 150 _processImports(fileInfo); | |
| 151 | |
| 152 // Load component files referenced by [file]. | 143 // Load component files referenced by [file]. |
| 153 for (var link in fileInfo.componentLinks) { | 144 for (var link in fileInfo.componentLinks) { |
| 154 _loadFile(link, _parseHtmlFile); | 145 _loadFile(link, _parseHtmlFile); |
| 155 } | 146 } |
| 156 | 147 |
| 157 // Load stylesheet files referenced by [file]. | 148 // Load stylesheet files referenced by [file]. |
| 158 for (var link in fileInfo.styleSheetHrefs) { | 149 for (var link in fileInfo.styleSheetHrefs) { |
| 159 _loadFile(link, _parseCssFile); | 150 _loadFile(link, _parseCssFile); |
| 160 } | 151 } |
| 161 | 152 |
| 162 // Load .dart files being referenced in the page. | |
| 163 _loadFile(fileInfo.externalFile, _parseDartFile); | |
| 164 | |
| 165 // Process any @imports inside of a <style> tag. | 153 // Process any @imports inside of a <style> tag. |
| 166 var urlInfos = findUrlsImported(fileInfo, fileInfo.inputUrl, _packageRoot, | 154 var urlInfos = findUrlsImported(fileInfo, fileInfo.inputUrl, _packageRoot, |
| 167 file.document, _messages, options); | 155 file.document, _messages, options); |
| 168 for (var urlInfo in urlInfos) { | 156 for (var urlInfo in urlInfos) { |
| 169 _loadFile(urlInfo, _parseCssFile); | 157 _loadFile(urlInfo, _parseCssFile); |
| 170 } | 158 } |
| 171 | 159 |
| 172 // Load .dart files being referenced in components. | 160 // Load .dart files being referenced in components. |
| 173 for (var component in fileInfo.declaredComponents) { | 161 for (var component in fileInfo.declaredComponents) { |
| 174 if (component.externalFile != null) { | |
| 175 _loadFile(component.externalFile, _parseDartFile); | |
| 176 } else if (component.userCode != null) { | |
| 177 _processImports(component); | |
| 178 } | |
| 179 | |
| 180 // Process any @imports inside of the <style> tag in a component. | 162 // Process any @imports inside of the <style> tag in a component. |
| 181 var urlInfos = findUrlsImported(component, | 163 var urlInfos = findUrlsImported(component, fileInfo.inputUrl, |
| 182 component.declaringFile.inputUrl, _packageRoot, component.element, | 164 _packageRoot, component.element, _messages, options); |
| 183 _messages, options); | |
| 184 for (var urlInfo in urlInfos) { | 165 for (var urlInfo in urlInfos) { |
| 185 _loadFile(urlInfo, _parseCssFile); | 166 _loadFile(urlInfo, _parseCssFile); |
| 186 } | 167 } |
| 187 } | 168 } |
| 188 } | 169 } |
| 189 | 170 |
| 190 /** | 171 /** |
| 191 * Helper function to load [urlInfo] and parse it using [loadAndParse] if it | 172 * Helper function to load [urlInfo] and parse it using [loadAndParse] if it |
| 192 * hasn't been loaded before. | 173 * hasn't been loaded before. |
| 193 */ | 174 */ |
| (...skipping 13 matching lines...) Expand all Loading... |
| 207 .catchError((e) => _readError(e, inputUrl)) | 188 .catchError((e) => _readError(e, inputUrl)) |
| 208 .then((source) { | 189 .then((source) { |
| 209 if (source == null) return; | 190 if (source == null) return; |
| 210 var file = new SourceFile(filePath); | 191 var file = new SourceFile(filePath); |
| 211 file.document = _time('Parsed', filePath, | 192 file.document = _time('Parsed', filePath, |
| 212 () => parseHtml(source, filePath, _messages)); | 193 () => parseHtml(source, filePath, _messages)); |
| 213 _processHtmlFile(inputUrl, file); | 194 _processHtmlFile(inputUrl, file); |
| 214 }); | 195 }); |
| 215 } | 196 } |
| 216 | 197 |
| 217 /** Parse a Dart file. */ | |
| 218 Future _parseDartFile(UrlInfo inputUrl) { | |
| 219 var filePath = inputUrl.resolvedPath; | |
| 220 return fileSystem.readText(filePath) | |
| 221 .catchError((e) => _readError(e, inputUrl)) | |
| 222 .then((code) { | |
| 223 if (code == null) return; | |
| 224 var file = new SourceFile(filePath, type: SourceFile.DART); | |
| 225 file.code = code; | |
| 226 _processDartFile(inputUrl, file); | |
| 227 }); | |
| 228 } | |
| 229 | |
| 230 /** Parse a stylesheet file. */ | 198 /** Parse a stylesheet file. */ |
| 231 Future _parseCssFile(UrlInfo inputUrl) { | 199 Future _parseCssFile(UrlInfo inputUrl) { |
| 232 if (!options.emulateScopedCss) { | 200 if (!options.emulateScopedCss) { |
| 233 return new Future<SourceFile>.value(null); | 201 return new Future<SourceFile>.value(null); |
| 234 } | 202 } |
| 235 var filePath = inputUrl.resolvedPath; | 203 var filePath = inputUrl.resolvedPath; |
| 236 return fileSystem.readText(filePath) | 204 return fileSystem.readText(filePath) |
| 237 .catchError((e) => _readError(e, inputUrl, isWarning: true)) | 205 .catchError((e) => _readError(e, inputUrl, isWarning: true)) |
| 238 .then((code) { | 206 .then((code) { |
| 239 if (code == null) return; | 207 if (code == null) return; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 250 message = '$message. original message:\n $error'; | 218 message = '$message. original message:\n $error'; |
| 251 } | 219 } |
| 252 if (isWarning) { | 220 if (isWarning) { |
| 253 _messages.warning(message, inputUrl.sourceSpan); | 221 _messages.warning(message, inputUrl.sourceSpan); |
| 254 } else { | 222 } else { |
| 255 _messages.error(message, inputUrl.sourceSpan); | 223 _messages.error(message, inputUrl.sourceSpan); |
| 256 } | 224 } |
| 257 return null; | 225 return null; |
| 258 } | 226 } |
| 259 | 227 |
| 260 void _processDartFile(UrlInfo inputUrl, SourceFile dartFile) { | |
| 261 if (dartFile == null) return; | |
| 262 | |
| 263 files.add(dartFile); | |
| 264 | |
| 265 var resolvedPath = inputUrl.resolvedPath; | |
| 266 var fileInfo = new FileInfo(inputUrl); | |
| 267 info[resolvedPath] = fileInfo; | |
| 268 fileInfo.inlinedCode = parseDartCode(resolvedPath, dartFile.code); | |
| 269 _processImports(fileInfo); | |
| 270 } | |
| 271 | |
| 272 void _processImports(LibraryInfo library) { | |
| 273 if (library.userCode == null) return; | |
| 274 | |
| 275 for (var directive in library.userCode.directives) { | |
| 276 _loadFile(_getDirectiveUrlInfo(library, directive), _parseDartFile); | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 void _processCssFile(UrlInfo inputUrl, SourceFile cssFile) { | 228 void _processCssFile(UrlInfo inputUrl, SourceFile cssFile) { |
| 281 if (cssFile == null) return; | 229 if (cssFile == null) return; |
| 282 | 230 |
| 283 files.add(cssFile); | 231 files.add(cssFile); |
| 284 | 232 |
| 285 var fileInfo = new FileInfo(inputUrl); | 233 var fileInfo = new FileInfo(inputUrl); |
| 286 info[inputUrl.resolvedPath] = fileInfo; | 234 info[inputUrl.resolvedPath] = fileInfo; |
| 287 | 235 |
| 288 var styleSheet = parseCss(cssFile.code, _messages, options); | 236 var styleSheet = parseCss(cssFile.code, _messages, options); |
| 289 if (inputUrl.url == _resetCssFile) { | 237 if (inputUrl.url == _resetCssFile) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 300 var urlInfos = _time('CSS imports', processingFile, () => | 248 var urlInfos = _time('CSS imports', processingFile, () => |
| 301 findImportsInStyleSheet(styleSheet, _packageRoot, inputUrl, _messages)); | 249 findImportsInStyleSheet(styleSheet, _packageRoot, inputUrl, _messages)); |
| 302 | 250 |
| 303 for (var urlInfo in urlInfos) { | 251 for (var urlInfo in urlInfos) { |
| 304 if (urlInfo == null) break; | 252 if (urlInfo == null) break; |
| 305 // Load any @imported stylesheet files referenced in this style sheet. | 253 // Load any @imported stylesheet files referenced in this style sheet. |
| 306 _loadFile(urlInfo, _parseCssFile); | 254 _loadFile(urlInfo, _parseCssFile); |
| 307 } | 255 } |
| 308 } | 256 } |
| 309 | 257 |
| 310 String _directiveUri(Directive directive) { | |
| 311 var uriDirective = (directive as UriBasedDirective).uri; | |
| 312 return (uriDirective as dynamic).value; | |
| 313 } | |
| 314 | |
| 315 UrlInfo _getDirectiveUrlInfo(LibraryInfo library, Directive directive) { | |
| 316 var uri = _directiveUri(directive); | |
| 317 if (uri.startsWith('dart:')) return null; | |
| 318 if (uri.startsWith('package:') && uri.startsWith('package:polymer/')) { | |
| 319 // Don't process our own package -- we'll implement @observable manually. | |
| 320 return null; | |
| 321 } | |
| 322 | |
| 323 var span = library.userCode.sourceFile.span( | |
| 324 directive.offset, directive.end); | |
| 325 return UrlInfo.resolve(uri, library.dartCodeUrl, span, _packageRoot, | |
| 326 _messages); | |
| 327 } | |
| 328 | |
| 329 /** | |
| 330 * Finds all Dart code libraries. | |
| 331 * Each library will have [LibraryInfo.inlinedCode] that is non-null. | |
| 332 * Also each inlinedCode will be unique. | |
| 333 */ | |
| 334 List<LibraryInfo> _findAllDartLibraries() { | |
| 335 var libs = <LibraryInfo>[]; | |
| 336 void _addLibrary(LibraryInfo lib) { | |
| 337 if (lib.inlinedCode != null) libs.add(lib); | |
| 338 } | |
| 339 | |
| 340 for (var sourceFile in files) { | |
| 341 var file = info[sourceFile.path]; | |
| 342 _addLibrary(file); | |
| 343 file.declaredComponents.forEach(_addLibrary); | |
| 344 } | |
| 345 | |
| 346 // Assert that each file path is unique. | |
| 347 assert(_uniquePaths(libs)); | |
| 348 return libs; | |
| 349 } | |
| 350 | |
| 351 bool _uniquePaths(List<LibraryInfo> libs) { | |
| 352 var seen = new Set(); | |
| 353 for (var lib in libs) { | |
| 354 if (seen.contains(lib.inlinedCode)) { | |
| 355 throw new StateError('internal error: ' | |
| 356 'duplicate user code for ${lib.dartCodeUrl.resolvedPath}.' | |
| 357 ' Files were: $files'); | |
| 358 } | |
| 359 seen.add(lib.inlinedCode); | |
| 360 } | |
| 361 return true; | |
| 362 } | |
| 363 | |
| 364 /** | |
| 365 * This method computes which Dart files have been modified, starting | |
| 366 * from [transformed] and marking recursively through all files that import | |
| 367 * the modified files. | |
| 368 */ | |
| 369 void _findModifiedDartFiles(List<LibraryInfo> libraries, | |
| 370 List<FileInfo> transformed) { | |
| 371 | |
| 372 if (transformed.length == 0) return; | |
| 373 | |
| 374 // Compute files that reference each file, then use this information to | |
| 375 // flip the modified bit transitively. This is a lot simpler than trying | |
| 376 // to compute it the other way because of circular references. | |
| 377 for (var lib in libraries) { | |
| 378 for (var directive in lib.userCode.directives) { | |
| 379 var importPath = _getDirectiveUrlInfo(lib, directive); | |
| 380 if (importPath == null) continue; | |
| 381 | |
| 382 var importInfo = info[importPath.resolvedPath]; | |
| 383 if (importInfo != null) { | |
| 384 importInfo.referencedBy.add(lib); | |
| 385 } | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 // Propegate the modified bit to anything that references a modified file. | |
| 390 void setModified(LibraryInfo library) { | |
| 391 if (library.modified) return; | |
| 392 library.modified = true; | |
| 393 library.referencedBy.forEach(setModified); | |
| 394 } | |
| 395 transformed.forEach(setModified); | |
| 396 | |
| 397 for (var lib in libraries) { | |
| 398 // We don't need this anymore, so free it. | |
| 399 lib.referencedBy = null; | |
| 400 } | |
| 401 } | |
| 402 | |
| 403 /** Run the analyzer on every input html file. */ | 258 /** Run the analyzer on every input html file. */ |
| 404 void _analyze() { | 259 void _analyze() { |
| 405 var uniqueIds = new IntIterator(); | 260 var uniqueIds = new IntIterator(); |
| 406 for (var file in files) { | 261 for (var file in files) { |
| 407 if (file.isHtml) { | 262 if (file.isHtml) { |
| 408 _time('Analyzed contents', file.path, () => | 263 _time('Analyzed contents', file.path, () => |
| 409 analyzeFile(file, info, uniqueIds, global, _messages, | 264 analyzeFile(file, info, uniqueIds, global, _messages, |
| 410 options.emulateScopedCss)); | 265 options.emulateScopedCss)); |
| 411 } | 266 } |
| 412 } | 267 } |
| 413 } | 268 } |
| 414 | 269 |
| 415 // TODO(jmesserly): refactor this and other CSS related transforms out of | 270 // TODO(jmesserly): refactor this and other CSS related transforms out of |
| 416 // Compiler. | 271 // Compiler. |
| 417 /** | 272 /** |
| 418 * Generate an CSS file for all style sheets (main and components). | 273 * Generate an CSS file for all style sheets (main and components). |
| 419 * Returns true if a file was generated, otherwise false. | 274 * Returns true if a file was generated, otherwise false. |
| 420 */ | 275 */ |
| 421 bool _emitAllCss() { | 276 bool _emitAllCss() { |
| 422 if (!options.emulateScopedCss) return false; | 277 if (!options.emulateScopedCss) return false; |
| 423 | 278 |
| 424 var buff = new StringBuffer(); | 279 var buff = new StringBuffer(); |
| 425 | 280 |
| 426 // Emit all linked style sheet files first. | 281 // Emit all linked style sheet files first. |
| 427 for (var file in files) { | 282 for (var file in files) { |
| 428 var css = new StringBuffer(); | 283 var css = new StringBuffer(); |
| 429 var fileInfo = info[file.path]; | 284 var fileInfo = info[file.path]; |
| 430 if (file.isStyleSheet) { | 285 if (file.isStyleSheet) { |
| 431 for (var styleSheet in fileInfo.styleSheets) { | 286 for (var styleSheet in fileInfo.styleSheets) { |
| 432 // Translate any URIs in CSS. | |
| 433 rewriteCssUris(_pathMapper, fileInfo.inputUrl.resolvedPath, | |
| 434 options.rewriteUrls, styleSheet); | |
| 435 css.write( | 287 css.write( |
| 436 '/* Auto-generated from style sheet href = ${file.path} */\n' | 288 '/* Auto-generated from style sheet href = ${file.path} */\n' |
| 437 '/* DO NOT EDIT. */\n\n'); | 289 '/* DO NOT EDIT. */\n\n'); |
| 438 css.write(emitStyleSheet(styleSheet, fileInfo)); | 290 css.write(emitStyleSheet(styleSheet, fileInfo)); |
| 439 css.write('\n\n'); | 291 css.write('\n\n'); |
| 440 } | 292 } |
| 441 } | 293 } |
| 442 } | 294 } |
| 443 | 295 |
| 444 // Emit all CSS for each component (style scoped). | 296 // Emit all CSS for each component (style scoped). |
| 445 for (var file in files) { | 297 for (var file in files) { |
| 446 if (file.isHtml) { | 298 if (file.isHtml) { |
| 447 var fileInfo = info[file.path]; | 299 var fileInfo = info[file.path]; |
| 448 for (var component in fileInfo.declaredComponents) { | 300 for (var component in fileInfo.declaredComponents) { |
| 449 for (var styleSheet in component.styleSheets) { | 301 for (var styleSheet in component.styleSheets) { |
| 450 // Translate any URIs in CSS. | 302 // Translate any URIs in CSS. |
| 451 rewriteCssUris(_pathMapper, fileInfo.inputUrl.resolvedPath, | |
| 452 options.rewriteUrls, styleSheet); | |
| 453 | |
| 454 if (buff.isEmpty) { | 303 if (buff.isEmpty) { |
| 455 buff.write( | 304 buff.write( |
| 456 '/* Auto-generated from components style tags. */\n' | 305 '/* Auto-generated from components style tags. */\n' |
| 457 '/* DO NOT EDIT. */\n\n'); | 306 '/* DO NOT EDIT. */\n\n'); |
| 458 } | 307 } |
| 459 buff.write( | 308 buff.write( |
| 460 '/* ==================================================== \n' | 309 '/* ==================================================== \n' |
| 461 ' Component ${component.tagName} stylesheet \n' | 310 ' Component ${component.tagName} stylesheet \n' |
| 462 ' ==================================================== */\n'); | 311 ' ==================================================== */\n'); |
| 463 | 312 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 483 } else { | 332 } else { |
| 484 buff.write(emitOriginalCss(styleSheet)); | 333 buff.write(emitOriginalCss(styleSheet)); |
| 485 } | 334 } |
| 486 buff.write('\n\n'); | 335 buff.write('\n\n'); |
| 487 } | 336 } |
| 488 } | 337 } |
| 489 } | 338 } |
| 490 } | 339 } |
| 491 | 340 |
| 492 if (buff.isEmpty) return false; | 341 if (buff.isEmpty) return false; |
| 493 | |
| 494 var cssPath = _pathMapper.outputPath(_mainPath, '.css', true); | |
| 495 output.add(new OutputFile(cssPath, buff.toString())); | |
| 496 return true; | 342 return true; |
| 497 } | 343 } |
| 498 | 344 |
| 499 _time(String logMessage, String filePath, callback(), | 345 _time(String logMessage, String filePath, callback(), |
| 500 {bool printTime: false}) { | 346 {bool printTime: false}) { |
| 501 var message = new StringBuffer(); | 347 var message = new StringBuffer(); |
| 502 message.write(logMessage); | 348 message.write(logMessage); |
| 503 var filename = path.basename(filePath); | 349 var filename = path.basename(filePath); |
| 504 for (int i = (60 - logMessage.length - filename.length); i > 0 ; i--) { | 350 for (int i = (60 - logMessage.length - filename.length); i > 0 ; i--) { |
| 505 message.write(' '); | 351 message.write(' '); |
| 506 } | 352 } |
| 507 message.write(filename); | 353 message.write(filename); |
| 508 return time(message.toString(), callback, | 354 return time(message.toString(), callback, |
| 509 printTime: options.verbose || printTime); | 355 printTime: options.verbose || printTime); |
| 510 } | 356 } |
| 511 } | 357 } |
| OLD | NEW |