| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 /// Tests code generation. | 5 /// Tests code generation. |
| 6 /// Runs Dart Dev Compiler on all input in the `codegen` directory and checks | 6 /// Runs Dart Dev Compiler on all input in the `codegen` directory and checks |
| 7 /// that the output is what we expected. | 7 /// that the output is what we expected. |
| 8 library dev_compiler.test.codegen_test; | 8 library dev_compiler.test.codegen_test; |
| 9 | 9 |
| 10 import 'dart:io'; | 10 import 'dart:convert' show JSON; |
| 11 import 'package:analyzer/src/generated/engine.dart' | 11 import 'dart:io' show Directory, File, Platform; |
| 12 show AnalysisContext, AnalysisEngine, Logger; | 12 import 'package:args/args.dart' show ArgParser, ArgResults; |
| 13 import 'package:analyzer/src/generated/java_engine.dart' show CaughtException; | |
| 14 import 'package:analyzer/src/generated/source_io.dart'; | |
| 15 import 'package:args/args.dart'; | |
| 16 import 'package:cli_util/cli_util.dart' show getSdkDir; | |
| 17 import 'package:logging/logging.dart' show Level; | |
| 18 import 'package:path/path.dart' as path; | 13 import 'package:path/path.dart' as path; |
| 19 import 'package:test/test.dart'; | 14 import 'package:test/test.dart' show group, test; |
| 20 | 15 |
| 21 import 'package:dev_compiler/devc.dart'; | 16 import 'package:analyzer/analyzer.dart' |
| 22 import 'package:dev_compiler/src/analysis_context.dart'; | 17 show |
| 23 import 'package:dev_compiler/src/compiler.dart' show defaultRuntimeFiles; | 18 ExportDirective, |
| 24 import 'package:dev_compiler/src/options.dart'; | 19 ImportDirective, |
| 25 import 'package:dev_compiler/src/report.dart' show LogReporter; | 20 StringLiteral, |
| 26 | 21 UriBasedDirective, |
| 22 parseDirectives; |
| 23 import 'package:analyzer/src/generated/source.dart' show Source; |
| 24 import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions; |
| 25 import 'package:dev_compiler/src/compiler/compiler.dart' |
| 26 show BuildUnit, CompilerOptions, ModuleCompiler; |
| 27 import 'testing.dart' show testDirectory; | 27 import 'testing.dart' show testDirectory; |
| 28 import 'multitest.dart'; | 28 import 'multitest.dart' show extractTestsFromMultitest, isMultiTest; |
| 29 import '../tool/build_sdk.dart' as build_sdk; |
| 30 import 'package:dev_compiler/src/compiler/compiler.dart'; |
| 29 | 31 |
| 30 final ArgParser argParser = new ArgParser() | 32 final ArgParser argParser = new ArgParser() |
| 31 ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null); | 33 ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null); |
| 32 | 34 |
| 33 final inputDir = path.join(testDirectory, 'codegen'); | |
| 34 | |
| 35 Iterable<String> _findTests(String dir, RegExp filePattern) { | |
| 36 var files = new Directory(dir) | |
| 37 .listSync() | |
| 38 .where((f) => f is File) | |
| 39 .map((f) => f.path) | |
| 40 .where((p) => p.endsWith('.dart') && filePattern.hasMatch(p)); | |
| 41 if (dir != inputDir) { | |
| 42 files = files | |
| 43 .where((p) => p.endsWith('_test.dart') || p.endsWith('_multi.dart')); | |
| 44 } | |
| 45 return files; | |
| 46 } | |
| 47 | |
| 48 main(arguments) { | 35 main(arguments) { |
| 49 if (arguments == null) arguments = []; | 36 if (arguments == null) arguments = []; |
| 50 ArgResults args = argParser.parse(arguments); | 37 ArgResults args = argParser.parse(arguments); |
| 51 var filePattern = new RegExp(args.rest.length > 0 ? args.rest[0] : '.'); | 38 var filePattern = new RegExp(args.rest.length > 0 ? args.rest[0] : '.'); |
| 52 var compilerMessages = new StringBuffer(); | |
| 53 var loggerSub; | |
| 54 | 39 |
| 55 bool codeCoverage = Platform.environment.containsKey('COVERALLS_TOKEN'); | 40 var expectDir = path.join(inputDir, 'expect'); |
| 41 var testDirs = ['language', path.join('lib', 'typed_data')]; |
| 56 | 42 |
| 57 setUp(() { | 43 var multitests = expandMultiTests(testDirs, filePattern); |
| 58 compilerMessages.clear(); | 44 |
| 59 loggerSub = setupLogger(Level.CONFIG, compilerMessages.writeln); | 45 // Build packages tests depend on |
| 46 var compiler = new ModuleCompiler( |
| 47 new AnalyzerOptions(customUrlMappings: packageUrlMappings)); |
| 48 |
| 49 group('dartdevc package', () { |
| 50 _buildPackages(compiler, expectDir); |
| 51 |
| 52 test('matcher', () { |
| 53 _buildMatcher(compiler, expectDir); |
| 54 }); |
| 60 }); | 55 }); |
| 61 | 56 |
| 62 tearDown(() { | 57 test('dartdevc sunflower', () { |
| 63 if (loggerSub != null) { | 58 _buildSunflower(compiler, expectDir); |
| 64 loggerSub.cancel(); | |
| 65 loggerSub = null; | |
| 66 } | |
| 67 }); | 59 }); |
| 68 | 60 |
| 69 var expectDir = path.join(inputDir, 'expect'); | 61 // Our default compiler options. Individual tests can override these. |
| 70 | 62 var defaultOptions = ['--no-source-map', '--no-summarize']; |
| 71 BatchCompiler createCompiler(DartUriResolver sdkResolver, | 63 var compilerArgParser = CompilerOptions.addArguments(new ArgParser()); |
| 72 {bool checkSdk: false, | |
| 73 bool sourceMaps: false, | |
| 74 bool destructureNamedParams: false, | |
| 75 bool closure: false, | |
| 76 ModuleFormat moduleFormat: ModuleFormat.legacy}) { | |
| 77 String _testCodegenPath(String p1, [String p2]) => | |
| 78 path.join(testDirectory, 'codegen', p1, p2); | |
| 79 | |
| 80 var context = createAnalysisContextWithSources( | |
| 81 new SourceResolverOptions(customUrlMappings: { | |
| 82 'package:expect/expect.dart': _testCodegenPath('expect.dart'), | |
| 83 'package:async_helper/async_helper.dart': | |
| 84 _testCodegenPath('async_helper.dart'), | |
| 85 'package:unittest/unittest.dart': _testCodegenPath('unittest.dart'), | |
| 86 'package:dom/dom.dart': _testCodegenPath('sunflower', 'dom.dart') | |
| 87 }), | |
| 88 sdkResolver: sdkResolver); | |
| 89 | |
| 90 // TODO(jmesserly): add a way to specify flags in the test file, so | |
| 91 // they're more self-contained. | |
| 92 var runtimeDir = path.join(path.dirname(testDirectory), 'lib', 'runtime'); | |
| 93 var options = new CompilerOptions( | |
| 94 codegenOptions: new CodegenOptions( | |
| 95 outputDir: expectDir, | |
| 96 emitSourceMaps: sourceMaps, | |
| 97 closure: closure, | |
| 98 destructureNamedParams: destructureNamedParams, | |
| 99 forceCompile: checkSdk, | |
| 100 moduleFormat: moduleFormat), | |
| 101 useColors: false, | |
| 102 checkSdk: checkSdk, | |
| 103 runtimeDir: runtimeDir, | |
| 104 inputBaseDir: inputDir); | |
| 105 var reporter = new LogReporter(context); | |
| 106 return new BatchCompiler(context, options, reporter: reporter); | |
| 107 } | |
| 108 | |
| 109 bool compile(BatchCompiler compiler, String filePath) { | |
| 110 compiler.compileFromUriString(filePath, (String url) { | |
| 111 // Write compiler messages to disk. | |
| 112 var messagePath = '${path.withoutExtension(url)}.txt'; | |
| 113 var file = new File(messagePath); | |
| 114 var message = ''' | |
| 115 // Messages from compiling ${path.basenameWithoutExtension(url)}.dart | |
| 116 $compilerMessages'''; | |
| 117 var dir = file.parent; | |
| 118 if (!dir.existsSync()) dir.createSync(recursive: true); | |
| 119 file.writeAsStringSync(message); | |
| 120 compilerMessages.clear(); | |
| 121 }); | |
| 122 return !compiler.failure; | |
| 123 } | |
| 124 | |
| 125 var testDirs = <String>['language', path.join('lib', 'typed_data')]; | |
| 126 | |
| 127 var multitests = new Set<String>(); | |
| 128 { | |
| 129 // Expand wacky multitests into a bunch of test files. | |
| 130 // We'll compile each one as if it was an input. | |
| 131 for (var testDir in testDirs) { | |
| 132 var fullDir = path.join(inputDir, testDir); | |
| 133 var testFiles = _findTests(fullDir, filePattern); | |
| 134 | |
| 135 for (var filePath in testFiles) { | |
| 136 if (filePath.endsWith('_multi.dart')) continue; | |
| 137 | |
| 138 var contents = new File(filePath).readAsStringSync(); | |
| 139 if (isMultiTest(contents)) { | |
| 140 multitests.add(filePath); | |
| 141 | |
| 142 var tests = new Map<String, String>(); | |
| 143 var outcomes = new Map<String, Set<String>>(); | |
| 144 extractTestsFromMultitest(filePath, contents, tests, outcomes); | |
| 145 | |
| 146 var filename = path.basenameWithoutExtension(filePath); | |
| 147 tests.forEach((name, contents) { | |
| 148 new File(path.join(fullDir, '${filename}_${name}_multi.dart')) | |
| 149 .writeAsStringSync(contents); | |
| 150 }); | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 var realSdkResolver = createSdkPathResolver(getSdkDir().path); | |
| 157 var batchCompiler = createCompiler(realSdkResolver); | |
| 158 | 64 |
| 159 var allDirs = [null]; | 65 var allDirs = [null]; |
| 160 allDirs.addAll(testDirs); | 66 allDirs.addAll(testDirs); |
| 161 for (var dir in allDirs) { | 67 for (var dir in allDirs) { |
| 162 if (codeCoverage && dir != null) continue; | 68 if (codeCoverage && dir != null) continue; |
| 163 | 69 |
| 164 group('dartdevc ' + path.join('test', 'codegen', dir), () { | 70 group('dartdevc ' + path.join('test', 'codegen', dir), () { |
| 165 var outDir = new Directory(path.join(expectDir, dir)); | 71 var outDir = new Directory(path.join(expectDir, dir)); |
| 166 if (!outDir.existsSync()) outDir.createSync(recursive: true); | 72 if (!outDir.existsSync()) outDir.createSync(recursive: true); |
| 167 | 73 |
| 168 var testFiles = _findTests(path.join(inputDir, dir), filePattern); | 74 var testFiles = _findTests(path.join(inputDir, dir), filePattern); |
| 169 for (var filePath in testFiles) { | 75 for (var filePath in testFiles) { |
| 170 if (multitests.contains(filePath)) continue; | 76 if (multitests.contains(filePath)) continue; |
| 171 | 77 |
| 172 var filename = path.basenameWithoutExtension(filePath); | 78 var filename = path.basenameWithoutExtension(filePath); |
| 173 | 79 |
| 174 test('$filename.dart', () { | 80 test('$filename.dart', () { |
| 175 // TODO(jmesserly): this was added to get some coverage of source maps | 81 // Check if we need to use special compile options. |
| 176 // and closure annotations. | 82 var contents = new File(filePath).readAsStringSync(); |
| 177 // We need a more comprehensive strategy to test them. | 83 var match = |
| 178 var sourceMaps = filename == 'map_keys'; | 84 new RegExp(r'// compile options: (.*)').matchAsPrefix(contents); |
| 179 var closure = filename == 'closure'; | 85 |
| 180 var destructureNamedParams = filename == 'destructuring' || closure; | 86 var args = new List.from(defaultOptions); |
| 181 var moduleFormat = filename == 'es6_modules' || closure | 87 if (match != null) { |
| 182 ? ModuleFormat.es6 | 88 args.addAll(match.group(1).split(' ')); |
| 183 : filename == 'node_modules' | 89 } |
| 184 ? ModuleFormat.node | 90 var options = |
| 185 : ModuleFormat.legacy; | 91 new CompilerOptions.fromArguments(compilerArgParser.parse(args)); |
| 186 var success; | 92 |
| 187 // TODO(vsm): Is it okay to reuse the same context here? If there is | 93 // Collect any other files we've imported. |
| 188 // overlap between test files, we may need separate ones for each | 94 var files = new Set<String>(); |
| 189 // compiler. | 95 _collectTransitiveImports(contents, files, from: filePath); |
| 190 var compiler = (sourceMaps || | 96 |
| 191 closure || | 97 var unit = new BuildUnit(filename, files.toList(), _moduleForLibrary); |
| 192 destructureNamedParams || | 98 var module = compiler.compile(unit, options); |
| 193 moduleFormat != ModuleFormat.legacy) | 99 _writeModule(path.join(outDir.path, filename), module); |
| 194 ? createCompiler(realSdkResolver, | |
| 195 sourceMaps: sourceMaps, | |
| 196 destructureNamedParams: destructureNamedParams, | |
| 197 closure: closure, | |
| 198 moduleFormat: moduleFormat) | |
| 199 : batchCompiler; | |
| 200 success = compile(compiler, filePath); | |
| 201 | |
| 202 var outFile = new File(path.join(outDir.path, '$filename.js')); | |
| 203 expect(!success || outFile.existsSync(), true, | |
| 204 reason: '${outFile.path} was created if compilation succeeds'); | |
| 205 }); | 100 }); |
| 206 } | 101 } |
| 207 }); | 102 }); |
| 208 } | 103 } |
| 209 | 104 |
| 210 if (codeCoverage) { | 105 if (codeCoverage) { |
| 211 group('sdk', () { | 106 test('build_sdk code coverage', () { |
| 212 // The analyzer does not bubble exception messages for certain internal | 107 var generatedSdkDir = |
| 213 // dart:* library failures, such as failing to find | 108 path.join(testDirectory, '..', 'tool', 'generated_sdk'); |
| 214 // "_internal/libraries.dart". Instead it produces an opaque "failed to | 109 return build_sdk.main(['--dart-sdk', generatedSdkDir, '-o', expectDir]); |
| 215 // instantiate dart:core" message. To remedy this we hook up an analysis | |
| 216 // logger that prints these messages. | |
| 217 var savedLogger; | |
| 218 setUp(() { | |
| 219 savedLogger = AnalysisEngine.instance.logger; | |
| 220 AnalysisEngine.instance.logger = new PrintLogger(); | |
| 221 }); | |
| 222 tearDown(() { | |
| 223 AnalysisEngine.instance.logger = savedLogger; | |
| 224 }); | |
| 225 | |
| 226 test('devc dart:core', () { | |
| 227 var testSdkResolver = createSdkPathResolver( | |
| 228 path.join(testDirectory, '..', 'tool', 'generated_sdk')); | |
| 229 | |
| 230 // Get the test SDK. We use a checked in copy so test expectations can | |
| 231 // be generated against a specific SDK version. | |
| 232 var compiler = createCompiler(testSdkResolver, checkSdk: true); | |
| 233 compile(compiler, 'dart:core'); | |
| 234 var outFile = new File(path.join(expectDir, 'dart/core.js')); | |
| 235 expect(outFile.existsSync(), true, | |
| 236 reason: '${outFile.path} was created for dart:core'); | |
| 237 }); | |
| 238 }); | 110 }); |
| 239 } | 111 } |
| 240 | 112 } |
| 241 var expectedRuntime = | 113 |
| 242 defaultRuntimeFiles.map((f) => 'dev_compiler/runtime/$f'); | 114 void _writeModule(String outPath, JSModuleFile result) { |
| 243 | 115 new Directory(path.dirname(outPath)).createSync(recursive: true); |
| 244 test('devc jscodegen sunflower.html', () { | 116 |
| 245 var filePath = path.join(inputDir, 'sunflower', 'sunflower.html'); | 117 result.errors.add(''); // for trailing newline |
| 246 var success = compile(batchCompiler, filePath); | 118 new File(outPath + '.txt').writeAsStringSync(result.errors.join('\n')); |
| 247 | 119 |
| 248 var expectedFiles = ['sunflower.html', 'sunflower.js',]; | 120 if (result.isValid) { |
| 249 | 121 new File(outPath + '.js').writeAsStringSync(result.code); |
| 250 for (var filepath in expectedFiles) { | 122 if (result.sourceMap != null) { |
| 251 var outFile = new File(path.join(expectDir, 'sunflower', filepath)); | 123 var mapPath = outPath + '.js.map'; |
| 252 expect(outFile.existsSync(), success, | 124 new File(mapPath) |
| 253 reason: '${outFile.path} was created iff compilation succeeds'); | 125 .writeAsStringSync(JSON.encode(result.placeSourceMap(mapPath))); |
| 254 } | 126 } |
| 255 }); | 127 } |
| 256 | 128 } |
| 257 test('devc jscodegen html_input.html', () { | 129 |
| 258 var filePath = path.join(inputDir, 'html_input.html'); | 130 void _buildSunflower(ModuleCompiler compiler, String expectDir) { |
| 259 var success = compile(batchCompiler, filePath); | 131 var files = ['sunflower', 'circle', 'painter'] |
| 260 | 132 .map((f) => path.join(inputDir, 'sunflower', '$f.dart')) |
| 261 var expectedFiles = [ | 133 .toList(); |
| 262 'html_input.html', | 134 var input = new BuildUnit('sunflower', files, _moduleForLibrary); |
| 263 'dir/html_input_a.js', | 135 var options = new CompilerOptions(summarizeApi: false); |
| 264 'dir/html_input_b.js', | 136 |
| 265 'dir/html_input_c.js', | 137 var built = compiler.compile(input, options); |
| 266 'dir/html_input_d.js', | 138 _writeModule(path.join(expectDir, 'sunflower', 'sunflower'), built); |
| 267 'dir/html_input_e.js' | 139 } |
| 268 ]..addAll(expectedRuntime); | 140 |
| 269 | 141 void _buildPackages(ModuleCompiler compiler, String expectDir) { |
| 270 for (var filepath in expectedFiles) { | 142 // Note: we don't summarize these, as we're going to rely on our in-memory |
| 271 var outFile = new File(path.join(expectDir, filepath)); | 143 // shared analysis context for caching, and `_moduleForLibrary` below |
| 272 expect(outFile.existsSync(), success, | 144 // understands these are from other modules. |
| 273 reason: '${outFile.path} was created iff compilation succeeds'); | 145 var options = new CompilerOptions(sourceMap: false, summarizeApi: false); |
| 146 |
| 147 for (var uri in packageUrlMappings.keys) { |
| 148 assert(uri.startsWith('package:')); |
| 149 var uriPath = uri.substring('package:'.length); |
| 150 var name = path.basenameWithoutExtension(uriPath); |
| 151 test(name, () { |
| 152 var input = new BuildUnit(name, [uri], _moduleForLibrary); |
| 153 var built = compiler.compile(input, options); |
| 154 |
| 155 var outPath = path.join(expectDir, path.withoutExtension(uriPath)); |
| 156 _writeModule(outPath, built); |
| 157 }); |
| 158 } |
| 159 } |
| 160 |
| 161 void _buildMatcher(ModuleCompiler compiler, String expectDir) { |
| 162 var options = new CompilerOptions(sourceMap: false, summarizeApi: false); |
| 163 |
| 164 var filePath = path.join(inputDir, 'packages', 'matcher', 'matcher.dart'); |
| 165 var contents = new File(filePath).readAsStringSync(); |
| 166 |
| 167 // Collect any other files we've imported. |
| 168 var files = new Set<String>(); |
| 169 _collectTransitiveImports(contents, files, from: filePath); |
| 170 |
| 171 var unit = new BuildUnit('matcher', files.toList(), _moduleForLibrary); |
| 172 var module = compiler.compile(unit, options); |
| 173 |
| 174 var outPath = path.join(expectDir, 'matcher', 'matcher'); |
| 175 _writeModule(outPath, module); |
| 176 } |
| 177 |
| 178 String _moduleForLibrary(Source source) { |
| 179 var scheme = source.uri.scheme; |
| 180 if (scheme == 'package') { |
| 181 return source.uri.pathSegments.first; |
| 182 } |
| 183 throw new Exception('Module not found for library "${source.fullName}"'); |
| 184 } |
| 185 |
| 186 /// Expands wacky multitests into a bunch of test files. |
| 187 /// |
| 188 /// We'll compile each one as if it was an input. |
| 189 /// NOTE: this will write the individual test files to disk. |
| 190 Set<String> expandMultiTests(List testDirs, RegExp filePattern) { |
| 191 var multitests = new Set<String>(); |
| 192 |
| 193 for (var testDir in testDirs) { |
| 194 var fullDir = path.join(inputDir, testDir); |
| 195 var testFiles = _findTests(fullDir, filePattern); |
| 196 |
| 197 for (var filePath in testFiles) { |
| 198 if (filePath.endsWith('_multi.dart')) continue; |
| 199 |
| 200 var contents = new File(filePath).readAsStringSync(); |
| 201 if (isMultiTest(contents)) { |
| 202 multitests.add(filePath); |
| 203 |
| 204 var tests = new Map<String, String>(); |
| 205 var outcomes = new Map<String, Set<String>>(); |
| 206 extractTestsFromMultitest(filePath, contents, tests, outcomes); |
| 207 |
| 208 var filename = path.basenameWithoutExtension(filePath); |
| 209 tests.forEach((name, contents) { |
| 210 new File(path.join(fullDir, '${filename}_${name}_multi.dart')) |
| 211 .writeAsStringSync(contents); |
| 212 }); |
| 213 } |
| 274 } | 214 } |
| 275 }); | 215 } |
| 276 } | 216 return multitests; |
| 277 | 217 } |
| 278 /// An implementation of analysis engine's [Logger] that prints. | 218 |
| 279 class PrintLogger implements Logger { | 219 // TODO(jmesserly): switch this to a .packages file. |
| 280 @override | 220 final packageUrlMappings = { |
| 281 void logError(String message, [CaughtException exception]) { | 221 'package:expect/expect.dart': path.join(inputDir, 'expect.dart'), |
| 282 print('[AnalysisEngine] error $message $exception'); | 222 'package:async_helper/async_helper.dart': |
| 283 } | 223 path.join(inputDir, 'async_helper.dart'), |
| 284 | 224 'package:unittest/unittest.dart': path.join(inputDir, 'unittest.dart'), |
| 285 void logInformation(String message, [CaughtException exception]) {} | 225 'package:js/js.dart': path.join(inputDir, 'packages', 'js', 'js.dart') |
| 286 void logInformation2(String message, Object exception) {} | 226 }; |
| 287 } | 227 |
| 228 final codeCoverage = Platform.environment.containsKey('COVERALLS_TOKEN'); |
| 229 |
| 230 final inputDir = path.join(testDirectory, 'codegen'); |
| 231 |
| 232 Iterable<String> _findTests(String dir, RegExp filePattern) { |
| 233 var files = new Directory(dir) |
| 234 .listSync() |
| 235 .where((f) => f is File) |
| 236 .map((f) => f.path) |
| 237 .where((p) => p.endsWith('.dart') && filePattern.hasMatch(p)); |
| 238 if (dir != inputDir) { |
| 239 files = files |
| 240 .where((p) => p.endsWith('_test.dart') || p.endsWith('_multi.dart')); |
| 241 } |
| 242 return files; |
| 243 } |
| 244 |
| 245 /// Parse directives from [contents] and find the complete set of transitive |
| 246 /// imports, reading files as needed. |
| 247 /// |
| 248 /// This will not include dart:* libraries, as those are implicitly available. |
| 249 void _collectTransitiveImports(String contents, Set<String> libraries, |
| 250 {String from}) { |
| 251 if (!libraries.add(from)) return; |
| 252 |
| 253 var unit = parseDirectives(contents, name: from, suppressErrors: true); |
| 254 for (var d in unit.directives) { |
| 255 if (d is ImportDirective || d is ExportDirective) { |
| 256 String uri = _resolveDirective(d); |
| 257 if (uri == null || |
| 258 uri.startsWith('dart:') || |
| 259 uri.startsWith('package:')) { |
| 260 continue; |
| 261 } |
| 262 |
| 263 var f = new File(path.join(path.dirname(from), uri)); |
| 264 if (f.existsSync()) { |
| 265 _collectTransitiveImports(f.readAsStringSync(), libraries, |
| 266 from: f.path); |
| 267 } |
| 268 } |
| 269 } |
| 270 } |
| 271 |
| 272 /// Simplified from ParseDartTask.resolveDirective. |
| 273 String _resolveDirective(UriBasedDirective directive) { |
| 274 StringLiteral uriLiteral = directive.uri; |
| 275 String uriContent = uriLiteral.stringValue; |
| 276 if (uriContent != null) { |
| 277 uriContent = uriContent.trim(); |
| 278 directive.uriContent = uriContent; |
| 279 } |
| 280 return directive.validate() == null ? uriContent : null; |
| 281 } |
| OLD | NEW |