Index: utils/import_mapper/import_mapper.dart |
diff --git a/utils/import_mapper/import_mapper.dart b/utils/import_mapper/import_mapper.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..381b79537c44eff03ea80915cd682472035fd84c |
--- /dev/null |
+++ b/utils/import_mapper/import_mapper.dart |
@@ -0,0 +1,128 @@ |
+// 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('import_mapper'); |
+ |
+#import('dart:io'); |
+// TODO(rnystrom): This should be dart:json. |
+#import('../../lib/json/json.dart'); |
+#import('../../frog/lang.dart'); |
+#import('../../frog/file_system.dart'); |
+#import('../../frog/file_system_vm.dart'); |
+ |
+typedef String ImportHook(ImportContext context, String name); |
+ |
+/** |
+ * Provides contextual information about the current import and environment |
+ * that the import hook can use to resolve an import. |
+ */ |
+class ImportContext { |
+ // TODO(rnystrom): Fill in context here as we figure out what we want. |
+} |
+ |
+/** The generated import map. */ |
+Map<String, String> _importMap; |
+ |
+ImportHook _hook; |
+ |
+/** |
+ * Uses the given import hook to generate an import map for all of the |
+ * libraries used by a [entrypoint]. Returns the generated map object. |
+ */ |
+Map<String, String> generateImportMap(String entrypoint, ImportHook hook) { |
+ _importMap = <String>{}; |
+ _hook = hook; |
+ |
+ // Initialize frog. |
+ final files = new VMFileSystem(); |
+ parseOptions('../../frog', ['', '', '--libdir=../../frog/lib'], files); |
+ initializeWorld(files); |
+ _importMap = {}; |
+ |
+ _walkLibrary(entrypoint); |
+ |
+ return _importMap; |
+} |
+ |
+/** |
+ * Uses the given import hook to generate an import map for all of the |
+ * libraries used by a given entrypoint. The entrypoint is assumed to be |
+ * provided as the first VM command line argument. |
+ * |
+ * Prints the import map data (a JSON object) to stdout. |
+ */ |
+void printImportMap(ImportHook hook) { |
+ // The entrypoint of the library to generate an import map for. |
+ final argv = (new Options()).arguments; |
+ final entrypoint = argv[argv.length - 1]; |
+ |
+ final map = generateImportMap(entrypoint, hook); |
+ print(JSON.stringify(map)); |
+} |
+ |
+/** |
+ * Recursively traverses all of the `#import()` directives in the given library |
+ * entrypoint and runs the import hook on them. [entrypoint] should be a path |
+ * to a library file. |
+ */ |
+void _walkLibrary(String entrypoint) { |
+ // TODO(rnystrom): Do more here when there's context we care about. |
+ final context = new ImportContext(); |
+ |
+ final text = _readFile(entrypoint); |
+ final source = new SourceFile(entrypoint, text); |
+ final parser = new Parser(source, diet: true); |
+ |
+ final definitions = parser.compilationUnit(); |
+ |
+ for (final definition in definitions) { |
+ // Only look at #import directives. |
+ if (definition is! DirectiveDefinition) continue; |
+ DirectiveDefinition directive = definition; |
+ if (directive.name.name != 'import') continue; |
+ |
+ // The first argument is expected to be a string literal. |
+ final name = directive.arguments[0].value.value.actualValue; |
+ |
+ // Only map a given import once. |
+ // TODO(rnystrom): Should invoke the hook again and ensure that it gets |
+ // the same result. It should be an error if the hook isn't |
+ // referentially transparent. |
+ if (!_importMap.containsKey(name)) { |
+ final uri = _hook(context, name); |
+ _importMap[name] = uri; |
+ |
+ // Recurse into this library. |
+ // TODO(rnystrom): Hackish. How should we handle corelib stuff? |
+ if (!uri.startsWith('dart:')) { |
+ _walkLibrary(_getFullPath(entrypoint, uri)); |
+ } |
+ } |
+ } |
+} |
+ |
+// TODO(rnystrom): Copied from frog/library.dart (makeFullPath). |
+/** |
+ * Given the path to a library containing an #import() and the resolved URI for |
+ * that import, gives the full path to that library. |
+ */ |
+String _getFullPath(String importingLibrary, String filename) { |
+ if (filename.startsWith('dart:')) return filename; |
+ // TODO(jmesserly): replace with node.js path.resolve |
+ if (filename.startsWith('/')) return filename; |
+ if (filename.startsWith('file:///')) return filename; |
+ if (filename.startsWith('http://')) return filename; |
+ if (const RegExp('^[a-zA-Z]:/').hasMatch(filename)) return filename; |
+ return joinPaths(dirname(importingLibrary), filename); |
+} |
+ |
+String _readFile(String filename) { |
+ // TODO(rnystrom): There must be an easier way than this. |
+ var file = (new File(filename)).openSync(); |
+ var length = file.lengthSync(); |
+ var buffer = new List<int>(length); |
+ var bytes = file.readListSync(buffer, 0, length); |
+ file.closeSync(); |
+ return new String.fromCharCodes(buffer); |
+} |