Index: pkg/polymer/lib/src/utils.dart |
diff --git a/pkg/polymer/lib/src/utils.dart b/pkg/polymer/lib/src/utils.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..da79dc2478dfff2db0e557b7b6d063a6fa28db3c |
--- /dev/null |
+++ b/pkg/polymer/lib/src/utils.dart |
@@ -0,0 +1,177 @@ |
+// Copyright (c) 2012, 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 polymer.src.utils; |
+ |
+import 'dart:async'; |
+import 'package:path/path.dart' show Builder; |
+export 'utils_observe.dart' show toCamelCase, toHyphenedName; |
+ |
+/** |
+ * An instance of the pathos library builder. We could just use the default |
+ * builder in pathos, but we add this indirection to make it possible to run |
+ * unittest for windows paths. |
+ */ |
+Builder path = new Builder(); |
+ |
+/** Convert a OS specific path into a url. */ |
+String pathToUrl(String relPath) => |
+ (path.separator == '/') ? relPath : path.split(relPath).join('/'); |
+ |
+/** |
+ * Invokes [callback], logs how long it took to execute in ms, and returns |
+ * whatever [callback] returns. The log message will be printed if [printTime] |
+ * is true. |
+ */ |
+time(String logMessage, callback(), |
+ {bool printTime: false, bool useColors: false}) { |
+ final watch = new Stopwatch(); |
+ watch.start(); |
+ var result = callback(); |
+ watch.stop(); |
+ final duration = watch.elapsedMilliseconds; |
+ if (printTime) { |
+ _printMessage(logMessage, duration, useColors); |
+ } |
+ return result; |
+} |
+ |
+/** |
+ * Invokes [callback], logs how long it takes from the moment [callback] is |
+ * executed until the future it returns is completed. Returns the future |
+ * returned by [callback]. The log message will be printed if [printTime] |
+ * is true. |
+ */ |
+Future asyncTime(String logMessage, Future callback(), |
+ {bool printTime: false, bool useColors: false}) { |
+ final watch = new Stopwatch(); |
+ watch.start(); |
+ return callback()..then((_) { |
+ watch.stop(); |
+ final duration = watch.elapsedMilliseconds; |
+ if (printTime) { |
+ _printMessage(logMessage, duration, useColors); |
+ } |
+ }); |
+} |
+ |
+void _printMessage(String logMessage, int duration, bool useColors) { |
+ var buf = new StringBuffer(); |
+ buf.write(logMessage); |
+ for (int i = logMessage.length; i < 60; i++) buf.write(' '); |
+ buf.write(' -- '); |
+ if (useColors) { |
+ buf.write(GREEN_COLOR); |
+ } |
+ if (duration < 10) buf.write(' '); |
+ if (duration < 100) buf.write(' '); |
+ buf..write(duration)..write(' ms'); |
+ if (useColors) { |
+ buf.write(NO_COLOR); |
+ } |
+ print(buf.toString()); |
+} |
+ |
+// Color constants used for generating messages. |
+final String GREEN_COLOR = '\u001b[32m'; |
+final String RED_COLOR = '\u001b[31m'; |
+final String MAGENTA_COLOR = '\u001b[35m'; |
+final String NO_COLOR = '\u001b[0m'; |
+ |
+/** A future that waits until all added [Future]s complete. */ |
+// TODO(sigmund): this should be part of the futures/core libraries. |
+class FutureGroup { |
+ static const _FINISHED = -1; |
+ |
+ int _pending = 0; |
+ Future _failedTask; |
+ final Completer<List> _completer = new Completer<List>(); |
+ final List results = []; |
+ |
+ /** Gets the task that failed, if any. */ |
+ Future get failedTask => _failedTask; |
+ |
+ /** |
+ * Wait for [task] to complete. |
+ * |
+ * If this group has already been marked as completed, you'll get a |
+ * [StateError]. |
+ * |
+ * If this group has a [failedTask], new tasks will be ignored, because the |
+ * error has already been signaled. |
+ */ |
+ void add(Future task) { |
+ if (_failedTask != null) return; |
+ if (_pending == _FINISHED) throw new StateError("Future already completed"); |
+ |
+ _pending++; |
+ var i = results.length; |
+ results.add(null); |
+ task.then((res) { |
+ results[i] = res; |
+ if (_failedTask != null) return; |
+ _pending--; |
+ if (_pending == 0) { |
+ _pending = _FINISHED; |
+ _completer.complete(results); |
+ } |
+ }, onError: (e) { |
+ if (_failedTask != null) return; |
+ _failedTask = task; |
+ _completer.completeError(e, getAttachedStackTrace(e)); |
+ }); |
+ } |
+ |
+ Future<List> get future => _completer.future; |
+} |
+ |
+ |
+/** |
+ * Escapes [text] for use in a Dart string. |
+ * [single] specifies single quote `'` vs double quote `"`. |
+ * [triple] indicates that a triple-quoted string, such as `'''` or `"""`. |
+ */ |
+String escapeDartString(String text, {bool single: true, bool triple: false}) { |
+ // Note: don't allocate anything until we know we need it. |
+ StringBuffer result = null; |
+ |
+ for (int i = 0; i < text.length; i++) { |
+ int code = text.codeUnitAt(i); |
+ var replace = null; |
+ switch (code) { |
+ case 92/*'\\'*/: replace = r'\\'; break; |
+ case 36/*r'$'*/: replace = r'\$'; break; |
+ case 34/*'"'*/: if (!single) replace = r'\"'; break; |
+ case 39/*"'"*/: if (single) replace = r"\'"; break; |
+ case 10/*'\n'*/: if (!triple) replace = r'\n'; break; |
+ case 13/*'\r'*/: if (!triple) replace = r'\r'; break; |
+ |
+ // Note: we don't escape unicode characters, under the assumption that |
+ // writing the file in UTF-8 will take care of this. |
+ |
+ // TODO(jmesserly): do we want to replace any other non-printable |
+ // characters (such as \f) for readability? |
+ } |
+ |
+ if (replace != null && result == null) { |
+ result = new StringBuffer(text.substring(0, i)); |
+ } |
+ |
+ if (result != null) result.write(replace != null ? replace : text[i]); |
+ } |
+ |
+ return result == null ? text : result.toString(); |
+} |
+ |
+/** Iterates through an infinite sequence, starting from zero. */ |
+class IntIterator implements Iterator<int> { |
+ int _next = -1; |
+ |
+ int get current => _next < 0 ? null : _next; |
+ |
+ bool moveNext() { |
+ _next++; |
+ return true; |
+ } |
+} |