| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 /// Set of flags and options passed to the compiler | |
| 6 | |
| 7 import 'dart:io'; | |
| 8 | |
| 9 import 'package:args/args.dart'; | |
| 10 import 'package:cli_util/cli_util.dart' show getSdkDir; | |
| 11 import 'package:logging/logging.dart' show Level; | |
| 12 import 'package:path/path.dart' as path; | |
| 13 import 'package:yaml/yaml.dart'; | |
| 14 | |
| 15 import 'utils.dart' show parseEnum, getEnumName; | |
| 16 | |
| 17 const String _V8_BINARY_DEFAULT = 'node'; | |
| 18 const bool _CLOSURE_DEFAULT = false; | |
| 19 | |
| 20 /// Older V8 versions do not accept default values with destructuring in | |
| 21 /// arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them | |
| 22 /// with regular functions (e.g. `function({a} = {}) { return 1 }`). | |
| 23 /// | |
| 24 /// Supporting the syntax: | |
| 25 /// * Chrome Canary (51) | |
| 26 /// * Firefox | |
| 27 /// | |
| 28 /// Not yet supporting: | |
| 29 /// * Atom (1.5.4) | |
| 30 /// * Electron (0.36.3) | |
| 31 /// | |
| 32 // TODO(ochafik): Simplify this code when our target platforms catch up. | |
| 33 const bool _DESTRUCTURE_NAMED_PARAMS_DEFAULT = false; | |
| 34 | |
| 35 /// Options used to set up Source URI resolution in the analysis context. | |
| 36 class SourceResolverOptions { | |
| 37 /// Whether to resolve 'package:' uris using the multi-package resolver. | |
| 38 final bool useMultiPackage; | |
| 39 | |
| 40 /// Custom URI mappings, such as "dart:foo" -> "path/to/foo.dart" | |
| 41 final Map<String, String> customUrlMappings; | |
| 42 | |
| 43 /// Package root when resolving 'package:' urls the standard way. | |
| 44 final String packageRoot; | |
| 45 | |
| 46 /// List of paths used for the multi-package resolver. | |
| 47 final List<String> packagePaths; | |
| 48 | |
| 49 /// Whether to use a mock-sdk during compilation. | |
| 50 final bool useMockSdk; | |
| 51 | |
| 52 /// Path to the dart-sdk. Null if `useMockSdk` is true or if the path couldn't | |
| 53 /// be determined | |
| 54 final String dartSdkPath; | |
| 55 | |
| 56 const SourceResolverOptions( | |
| 57 {this.useMockSdk: false, | |
| 58 this.dartSdkPath, | |
| 59 this.useMultiPackage: false, | |
| 60 this.customUrlMappings: const {}, | |
| 61 this.packageRoot: 'packages/', | |
| 62 this.packagePaths: const <String>[]}); | |
| 63 } | |
| 64 | |
| 65 enum ModuleFormat { es6, legacy, node } | |
| 66 ModuleFormat parseModuleFormat(String s) => parseEnum(s, ModuleFormat.values); | |
| 67 | |
| 68 // TODO(jmesserly): refactor all codegen options here. | |
| 69 class CodegenOptions { | |
| 70 /// Whether to emit the source map files. | |
| 71 final bool emitSourceMaps; | |
| 72 | |
| 73 /// Whether to force compilation of code with static errors. | |
| 74 final bool forceCompile; | |
| 75 | |
| 76 /// Output directory for generated code. | |
| 77 final String outputDir; | |
| 78 | |
| 79 /// Emit Closure Compiler-friendly code. | |
| 80 final bool closure; | |
| 81 | |
| 82 /// Enable ES6 destructuring of named parameters. | |
| 83 final bool destructureNamedParams; | |
| 84 | |
| 85 /// Which module format to support. | |
| 86 /// Currently 'es6' and 'legacy' are supported. | |
| 87 final ModuleFormat moduleFormat; | |
| 88 | |
| 89 const CodegenOptions( | |
| 90 {this.emitSourceMaps: true, | |
| 91 this.forceCompile: false, | |
| 92 this.closure: _CLOSURE_DEFAULT, | |
| 93 this.destructureNamedParams: _DESTRUCTURE_NAMED_PARAMS_DEFAULT, | |
| 94 this.outputDir, | |
| 95 this.moduleFormat: ModuleFormat.legacy}); | |
| 96 } | |
| 97 | |
| 98 /// Options for devrun. | |
| 99 class RunnerOptions { | |
| 100 /// V8-based binary to be used to run the .js output (d8, iojs, node). | |
| 101 /// Can be just the executable name if it's in the path, or a path to the | |
| 102 /// executable. | |
| 103 final String v8Binary; | |
| 104 | |
| 105 const RunnerOptions({this.v8Binary: _V8_BINARY_DEFAULT}); | |
| 106 } | |
| 107 | |
| 108 /// General options used by the dev compiler and server. | |
| 109 class CompilerOptions { | |
| 110 final SourceResolverOptions sourceOptions; | |
| 111 final CodegenOptions codegenOptions; | |
| 112 final RunnerOptions runnerOptions; | |
| 113 | |
| 114 /// Whether to check the sdk libraries. | |
| 115 final bool checkSdk; | |
| 116 | |
| 117 /// Whether to use colors when interacting on the console. | |
| 118 final bool useColors; | |
| 119 | |
| 120 /// Whether the user asked for help. | |
| 121 final bool help; | |
| 122 | |
| 123 /// Whether the user asked for the app version. | |
| 124 final bool version; | |
| 125 | |
| 126 /// Minimum log-level reported on the command-line. | |
| 127 final Level logLevel; | |
| 128 | |
| 129 /// Location for runtime files, such as `dart_runtime.js`. By default this is | |
| 130 /// inferred to be under `lib/runtime/` in the location of the `dev_compiler` | |
| 131 /// package (if we can infer where that is located). | |
| 132 final String runtimeDir; | |
| 133 | |
| 134 /// The files to compile. | |
| 135 final List<String> inputs; | |
| 136 | |
| 137 /// The base directory for [inputs]. Module imports will be generated relative | |
| 138 /// to this directory. | |
| 139 final String inputBaseDir; | |
| 140 | |
| 141 const CompilerOptions( | |
| 142 {this.sourceOptions: const SourceResolverOptions(), | |
| 143 this.codegenOptions: const CodegenOptions(), | |
| 144 this.runnerOptions: const RunnerOptions(), | |
| 145 this.checkSdk: false, | |
| 146 this.useColors: true, | |
| 147 this.help: false, | |
| 148 this.version: false, | |
| 149 this.logLevel: Level.WARNING, | |
| 150 this.runtimeDir, | |
| 151 this.inputs, | |
| 152 this.inputBaseDir}); | |
| 153 } | |
| 154 | |
| 155 /// Parses options from the command-line | |
| 156 CompilerOptions parseOptions(List<String> argv, {bool forceOutDir: false}) { | |
| 157 ArgResults args = argParser.parse(argv); | |
| 158 bool showUsage = args['help']; | |
| 159 bool showVersion = args['version']; | |
| 160 | |
| 161 var logLevel = Level.WARNING; | |
| 162 var levelName = args['log']; | |
| 163 if (levelName != null) { | |
| 164 levelName = levelName.toUpperCase(); | |
| 165 logLevel = Level.LEVELS | |
| 166 .firstWhere((l) => l.name == levelName, orElse: () => logLevel); | |
| 167 } | |
| 168 var useColors = stdioType(stdout) == StdioType.TERMINAL; | |
| 169 var sdkPath = args['dart-sdk']; | |
| 170 if (sdkPath == null && !args['mock-sdk']) { | |
| 171 sdkPath = getSdkDir(argv).path; | |
| 172 } | |
| 173 var runtimeDir = args['runtime-dir']; | |
| 174 if (runtimeDir == null) { | |
| 175 runtimeDir = _computeRuntimeDir(); | |
| 176 } | |
| 177 var outputDir = args['out']; | |
| 178 if (outputDir == null && forceOutDir) { | |
| 179 outputDir = Directory.systemTemp.createTempSync("dev_compiler_out_").path; | |
| 180 } | |
| 181 | |
| 182 var v8Binary = args['v8-binary']; | |
| 183 if (v8Binary == null) v8Binary = _V8_BINARY_DEFAULT; | |
| 184 | |
| 185 var customUrlMappings = <String, String>{}; | |
| 186 for (var mapping in args['url-mapping']) { | |
| 187 var splitMapping = mapping.split(','); | |
| 188 if (splitMapping.length != 2) { | |
| 189 showUsage = true; | |
| 190 continue; | |
| 191 } | |
| 192 customUrlMappings[splitMapping[0]] = splitMapping[1]; | |
| 193 } | |
| 194 | |
| 195 return new CompilerOptions( | |
| 196 codegenOptions: new CodegenOptions( | |
| 197 emitSourceMaps: args['source-maps'], | |
| 198 forceCompile: args['force-compile'], | |
| 199 closure: args['closure'], | |
| 200 destructureNamedParams: args['destructure-named-params'], | |
| 201 outputDir: outputDir, | |
| 202 moduleFormat: parseModuleFormat(args['modules'])), | |
| 203 sourceOptions: new SourceResolverOptions( | |
| 204 useMockSdk: args['mock-sdk'], | |
| 205 dartSdkPath: sdkPath, | |
| 206 customUrlMappings: customUrlMappings, | |
| 207 useMultiPackage: args['use-multi-package'], | |
| 208 packageRoot: args['package-root'], | |
| 209 packagePaths: args['package-paths'].split(',')), | |
| 210 runnerOptions: new RunnerOptions(v8Binary: v8Binary), | |
| 211 checkSdk: args['sdk-check'], | |
| 212 useColors: useColors, | |
| 213 help: showUsage, | |
| 214 version: showVersion, | |
| 215 logLevel: logLevel, | |
| 216 runtimeDir: runtimeDir, | |
| 217 inputs: args.rest); | |
| 218 } | |
| 219 | |
| 220 final ArgParser argParser = new ArgParser() | |
| 221 ..addFlag('sdk-check', | |
| 222 abbr: 's', help: 'Typecheck sdk libs', defaultsTo: false) | |
| 223 ..addFlag('mock-sdk', | |
| 224 abbr: 'm', help: 'Use a mock Dart SDK', defaultsTo: false) | |
| 225 | |
| 226 // input/output options | |
| 227 ..addOption('out', abbr: 'o', help: 'Output directory', defaultsTo: null) | |
| 228 ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null) | |
| 229 ..addOption('package-root', | |
| 230 abbr: 'p', | |
| 231 help: 'Package root to resolve "package:" imports', | |
| 232 defaultsTo: 'packages/') | |
| 233 ..addOption('url-mapping', | |
| 234 help: '--url-mapping=libraryUri,/path/to/library.dart uses library.dart\n' | |
| 235 'as the source for an import of of "libraryUri".', | |
| 236 allowMultiple: true, | |
| 237 splitCommas: false) | |
| 238 ..addFlag('use-multi-package', | |
| 239 help: 'Whether to use the multi-package resolver for "package:" imports', | |
| 240 defaultsTo: false) | |
| 241 ..addOption('package-paths', | |
| 242 help: 'if using the multi-package resolver, the list of directories to\n' | |
| 243 'look for packages in.', | |
| 244 defaultsTo: '') | |
| 245 ..addFlag('source-maps', | |
| 246 help: 'Whether to emit source map files', defaultsTo: true) | |
| 247 ..addOption('runtime-dir', | |
| 248 help: 'Where to find dev_compiler\'s runtime files', defaultsTo: null) | |
| 249 ..addOption('modules', | |
| 250 help: 'Which module pattern to emit', | |
| 251 allowed: ModuleFormat.values.map(getEnumName).toList(), | |
| 252 allowedHelp: { | |
| 253 getEnumName(ModuleFormat.es6): 'es6 modules', | |
| 254 getEnumName(ModuleFormat.legacy): | |
| 255 'a custom format used by dartdevc, similar to AMD', | |
| 256 getEnumName(ModuleFormat.node): | |
| 257 'node.js modules (https://nodejs.org/api/modules.html)' | |
| 258 }, | |
| 259 defaultsTo: getEnumName(ModuleFormat.legacy)) | |
| 260 | |
| 261 // general options | |
| 262 ..addFlag('help', abbr: 'h', help: 'Display this message') | |
| 263 ..addFlag('version', | |
| 264 negatable: false, help: 'Display the Dev Compiler verion') | |
| 265 ..addFlag('closure', | |
| 266 help: 'Emit Closure Compiler-friendly code (experimental)', | |
| 267 defaultsTo: _CLOSURE_DEFAULT) | |
| 268 ..addFlag('destructure-named-params', | |
| 269 help: 'Destructure named parameters (requires ES6-enabled runtime)', | |
| 270 defaultsTo: _DESTRUCTURE_NAMED_PARAMS_DEFAULT) | |
| 271 ..addFlag('force-compile', | |
| 272 abbr: 'f', help: 'Compile code with static errors', defaultsTo: false) | |
| 273 ..addOption('log', abbr: 'l', help: 'Logging level (defaults to warning)') | |
| 274 ..addOption('v8-binary', | |
| 275 help: 'V8-based binary to run JavaScript output with (iojs, node, d8)', | |
| 276 defaultsTo: _V8_BINARY_DEFAULT); | |
| 277 | |
| 278 // TODO: Switch over to the `pub_cache` package (or the Resource API)? | |
| 279 | |
| 280 const _ENTRY_POINTS = const [ | |
| 281 'dartdevc.dart', | |
| 282 'dev_compiler.dart', | |
| 283 'devrun.dart' | |
| 284 ]; | |
| 285 | |
| 286 final _ENTRY_POINT_SNAPSHOTS = _ENTRY_POINTS.map((f) => "$f.snapshot"); | |
| 287 | |
| 288 /// Tries to find the `lib/runtime/` directory of the dev_compiler package. This | |
| 289 /// works when running devc from it's sources or from a snapshot that is | |
| 290 /// activated via `pub global activate`. | |
| 291 String _computeRuntimeDir() { | |
| 292 var scriptPath = path.fromUri(Platform.script); | |
| 293 var file = path.basename(scriptPath); | |
| 294 var dir = path.dirname(scriptPath); | |
| 295 var lastdir = path.basename(dir); | |
| 296 dir = path.dirname(dir); | |
| 297 | |
| 298 // Both the source dartdevc.dart and the snapshot generated by pub global acti
vate | |
| 299 // are under a bin folder. | |
| 300 if (lastdir != 'bin') return null; | |
| 301 | |
| 302 // And both under a project directory containing a pubspec.lock file. | |
| 303 var lockfile = path.join(dir, 'pubspec.lock'); | |
| 304 if (!new File(lockfile).existsSync()) return null; | |
| 305 | |
| 306 // If running from sources we found it! | |
| 307 if (_ENTRY_POINTS.contains(file)) { | |
| 308 return path.join(dir, 'lib', 'runtime'); | |
| 309 } | |
| 310 | |
| 311 // If running from a pub global snapshot, we need to read the lock file to | |
| 312 // find where the actual sources are located in the pub cache. | |
| 313 if (_ENTRY_POINT_SNAPSHOTS.contains(file)) { | |
| 314 // Note: this depends on implementation details of pub. | |
| 315 var yaml = loadYaml(new File(lockfile).readAsStringSync()); | |
| 316 var info = yaml['packages']['dev_compiler']; | |
| 317 if (info == null) return null; | |
| 318 | |
| 319 var cacheDir; | |
| 320 if (info['source'] == 'hosted') { | |
| 321 cacheDir = path.join( | |
| 322 'hosted', 'pub.dartlang.org', 'dev_compiler-${info["version"]}'); | |
| 323 } else if (info['source'] == 'git') { | |
| 324 var ref = info['description']['resolved-ref']; | |
| 325 cacheDir = path.join('git', 'dev_compiler-${ref}'); | |
| 326 } | |
| 327 | |
| 328 // We should be under "/path/to/pub-cache/global_packages/dev_compiler". | |
| 329 // The pub-cache directory is two levels up, but we verify that the layout | |
| 330 // looks correct. | |
| 331 if (path.basename(dir) != 'dev_compiler') return null; | |
| 332 dir = path.dirname(dir); | |
| 333 if (path.basename(dir) != 'global_packages') return null; | |
| 334 dir = path.dirname(dir); | |
| 335 return path.join(dir, cacheDir, 'lib', 'runtime'); | |
| 336 } | |
| 337 return null; | |
| 338 } | |
| OLD | NEW |