Index: pkg/polymer/lib/src/paths.dart |
diff --git a/pkg/polymer/lib/src/paths.dart b/pkg/polymer/lib/src/paths.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..34037d95fd4d818e806a40b18d7bccb9fbfd62af |
--- /dev/null |
+++ b/pkg/polymer/lib/src/paths.dart |
@@ -0,0 +1,170 @@ |
+// Copyright (c) 2013, 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. |
+ |
+/** |
+ * Holds path information that is used by the WebUI compiler to find files, |
+ * compute their output location and relative paths between them. |
+ */ |
+library polymer.src.paths; |
+ |
+import 'info.dart' show UrlInfo; |
+import 'messages.dart'; |
+import 'summary.dart'; |
+import 'utils.dart' show path, pathToUrl; |
+ |
+/** |
+ * Stores information about paths and computes mappings between input and output |
+ * path locations. |
+ */ |
+class PathMapper { |
+ /** |
+ * Common prefix to all input paths that are read from the file system. The |
+ * output generated by the compiler will reflect the directory structure |
+ * starting from [_baseDir]. For instance, if [_baseDir] is `a/b/c` and |
+ * [_outputDir] is `g/h/`, then the corresponding output file for |
+ * `a/b/c/e/f.html` will be under `g/h/e/f.html.dart`. |
+ */ |
+ final String _baseDir; |
+ |
+ /** Base path where all output is generated. */ |
+ final String _outputDir; |
+ |
+ /** The package root directory. */ |
+ final String packageRoot; |
+ |
+ /** Whether to add prefixes and to output file names. */ |
+ final bool _mangleFilenames; |
+ |
+ final bool _rewriteUrls; |
+ |
+ bool get _rewritePackageImports => _rewriteUrls || !_mangleFilenames; |
+ |
+ /** Default prefix added to all filenames. */ |
+ static const String _DEFAULT_PREFIX = '_'; |
+ |
+ PathMapper(String baseDir, String outputDir, this.packageRoot, |
+ bool forceMangle, this._rewriteUrls) |
+ : _baseDir = baseDir, |
+ _outputDir = outputDir, |
+ _mangleFilenames = forceMangle || (baseDir == outputDir); |
+ |
+ /** Add a prefix and [suffix] if [_mangleFilenames] is true */ |
+ String mangle(String name, String suffix, [bool forceSuffix = false]) => |
+ _mangleFilenames ? "$_DEFAULT_PREFIX$name$suffix" |
+ : (forceSuffix ? "$name$suffix" : name); |
+ |
+ /** |
+ * Checks that `input.resolvedPath` is a valid input path. It must be in |
+ * [_baseDir] and must not be in the [_outputDir]. If not, an error message |
+ * is added to [messages]. |
+ */ |
+ bool checkInputPath(UrlInfo input, Messages messages) { |
+ if (_mangleFilenames) return true; |
+ var canonicalized = path.normalize(input.resolvedPath); |
+ var parentDir = '..${path.separator}'; |
+ if (!path.relative(canonicalized, from: _outputDir).startsWith(parentDir)) { |
+ messages.error( |
+ 'The file ${input.resolvedPath} cannot be processed. ' |
+ 'Files cannot be under the output folder (${_outputDir}).', |
+ input.sourceSpan); |
+ return false; |
+ } |
+ if (path.relative(canonicalized, from: _baseDir).startsWith(parentDir)) { |
+ messages.error( |
+ 'The file ${input.resolvedPath} cannot be processed. ' |
+ 'All processed files must be under the base folder (${_baseDir}), you' |
+ ' can specify the base folder using the --basedir flag.', |
+ input.sourceSpan); |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ /** |
+ * The path to the output file corresponding to [input], by adding |
+ * [_DEFAULT_PREFIX] and a [suffix] to its file name. |
+ */ |
+ String outputPath(String input, String suffix, [bool forceSuffix = false]) => |
+ path.join(outputDirPath(input), |
+ mangle(path.basename(input), suffix, forceSuffix)); |
+ |
+ /** The path to the output file corresponding to [info]. */ |
+ String outputLibraryPath(LibrarySummary lib) => |
+ path.join(outputDirPath(lib.dartCodeUrl.resolvedPath), |
+ lib.outputFilename); |
+ |
+ /** The corresponding output directory for [input]'s directory. */ |
+ String outputDirPath(String input) { |
+ return _rewritePackages(path.normalize( |
+ path.join(_outputDir, path.relative( |
+ path.dirname(input), from: _baseDir)))); |
+ } |
+ |
+ /** |
+ * We deal with `packages/` directories in a very special way. We assume it |
+ * points to resources loaded from other pub packages. If an output directory |
+ * is specified, the compiler will create a packages symlink so that |
+ * `package:` imports work. |
+ * |
+ * To make it possible to share components through pub, we allow using tags of |
+ * the form `<link rel="import" href="packages/...">`, so that you can |
+ * refer to components within the packages symlink. Regardless of whether an |
+ * --out option was given to the compiler, we don't want to generate files |
+ * inside `packages/` for those components. Instead we will generate such |
+ * code in a special directory called `_from_packages/`. |
+ */ |
+ String _rewritePackages(String outputPath) { |
+ // TODO(jmesserly): this should match against packageRoot instead. |
+ if (!outputPath.contains('packages')) return outputPath; |
+ if (!_rewritePackageImports) return outputPath; |
+ var segments = path.split(outputPath); |
+ return path.joinAll( |
+ segments.map((s) => s == 'packages' ? '_from_packages' : s)); |
+ } |
+ |
+ /** |
+ * Returns a url to import/export the output library represented by [target] |
+ * from the output library of [src]. In other words, a url to import or export |
+ * `target.outputFilename` from `src.outputFilename`. |
+ */ |
+ String importUrlFor(LibrarySummary src, LibrarySummary target) { |
+ if (!_rewritePackageImports && |
+ target.dartCodeUrl.url.startsWith('package:')) { |
+ return pathToUrl(path.join(path.dirname(target.dartCodeUrl.url), |
+ target.outputFilename)); |
+ } |
+ var srcDir = path.dirname(src.dartCodeUrl.resolvedPath); |
+ var relDir = path.relative( |
+ path.dirname(target.dartCodeUrl.resolvedPath), from: srcDir); |
+ return pathToUrl(_rewritePackages(path.normalize( |
+ path.join(relDir, target.outputFilename)))); |
+ } |
+ |
+ /** |
+ * Transforms a [target] url seen in [src] (e.g. a Dart import, a .css href in |
+ * an HTML file, etc) into a corresponding url from the output file associated |
+ * with [src]. This will keep 'package:', 'dart:', path-absolute, and absolute |
+ * urls intact, but it will fix relative paths to walk from the output |
+ * directory back to the input directory. An exception will be thrown if |
+ * [target] is not under [_baseDir]. |
+ */ |
+ String transformUrl(String src, String target) { |
+ var uri = Uri.parse(target); |
+ if (uri.isAbsolute) return target; |
+ if (!uri.scheme.isEmpty) return target; |
+ if (!uri.host.isEmpty) return target; |
+ if (uri.path.isEmpty) return target; // Implies standalone ? or # in URI. |
+ if (path.isAbsolute(target)) return target; |
+ |
+ return pathToUrl(path.normalize(path.relative( |
+ path.join(path.dirname(src), target), from: outputDirPath(src)))); |
+ } |
+} |
+ |
+/** |
+ * Returns a "mangled" name, with a prefix and [suffix] depending on the |
+ * compiler's settings. [forceSuffix] causes [suffix] to be appended even if |
+ * the compiler is not mangling names. |
+ */ |
+typedef String NameMangler(String name, String suffix, [bool forceSuffix]); |