| // Copyright (c) 2023, 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. |
| |
| import 'package:dev_compiler/dev_compiler.dart'; |
| import 'package:dev_compiler/src/command/command.dart'; |
| import 'package:dev_compiler/src/js_ast/js_ast.dart'; |
| import 'package:front_end/src/api_unstable/ddc.dart' as fe; |
| import 'package:kernel/target/targets.dart'; |
| |
| /// Result compiling using [compileFromMemory]. |
| /// |
| /// This is meant for testing and therefore include not only the resulting |
| /// [Program] various artifacts of the compilation. |
| class MemoryCompilerResult { |
| final fe.DdcResult ddcResult; |
| final ProgramCompiler compiler; |
| final Program program; |
| final List<fe.DiagnosticMessage> errors; |
| |
| MemoryCompilerResult( |
| this.ddcResult, this.compiler, this.program, this.errors); |
| } |
| |
| /// Result of compiling using [componentFromMemory]. |
| /// |
| /// This is meant for use in tests and performs the front end compilation to |
| /// components without calling DDC. |
| class MemoryComponentResult { |
| final fe.DdcResult ddcResult; |
| final List<fe.DiagnosticMessage> errors; |
| |
| MemoryComponentResult(this.ddcResult, this.errors); |
| } |
| |
| /// Uri used as the base uri for files provided in memory through the |
| /// [MemoryFileSystem]. |
| Uri memoryDirectory = Uri.parse('memory://'); |
| |
| /// Compiles [entryPoint] to a kernel `Component` using the [memoryFiles] as |
| /// sources. |
| /// |
| /// [memoryFiles] maps relative paths to their source text. [entryPoint] must |
| /// be absolute, using [memoryDirectory] as a base uri to refer to a file from |
| /// [memoryFiles]. |
| Future<MemoryComponentResult> componentFromMemory( |
| Map<String, String> memoryFiles, Uri entryPoint, |
| {Map<fe.ExperimentalFlag, bool>? explicitExperimentalFlags}) async { |
| var errors = <fe.DiagnosticMessage>[]; |
| void diagnosticMessageHandler(fe.DiagnosticMessage message) { |
| if (message.severity == fe.Severity.error) { |
| errors.add(message); |
| } |
| fe.printDiagnosticMessage(message, print); |
| } |
| |
| var memoryFileSystem = fe.MemoryFileSystem(memoryDirectory); |
| for (var entry in memoryFiles.entries) { |
| memoryFileSystem |
| .entityForUri(memoryDirectory.resolve(entry.key)) |
| .writeAsStringSync(entry.value); |
| } |
| var compilerState = fe.initializeCompiler( |
| null, |
| false, |
| sourcePathToUri(getSdkPath()), |
| sourcePathToUri(defaultSdkSummaryPath), |
| null, |
| sourcePathToUri(defaultLibrarySpecPath), |
| [], |
| DevCompilerTarget(TargetFlags(trackWidgetCreation: false)), |
| fileSystem: fe.HybridFileSystem(memoryFileSystem), |
| environmentDefines: {}, |
| explicitExperimentalFlags: explicitExperimentalFlags); |
| var result = |
| await fe.compile(compilerState, [entryPoint], diagnosticMessageHandler); |
| if (result == null) { |
| throw 'Memory compilation failed'; |
| } |
| return MemoryComponentResult(result, errors); |
| } |
| |
| /// Compiles [entryPoint] to JavaScript using the [memoryFiles] as sources. |
| /// |
| /// [memoryFiles] maps relative paths to their source text. [entryPoint] must |
| /// be absolute, using [memoryDirectory] as a base uri to refer to a file from |
| /// [memoryFiles]. |
| Future<MemoryCompilerResult> compileFromMemory( |
| Map<String, String> memoryFiles, Uri entryPoint, |
| {Map<fe.ExperimentalFlag, bool>? explicitExperimentalFlags}) async { |
| var MemoryComponentResult(ddcResult: result, :errors) = |
| await componentFromMemory(memoryFiles, entryPoint); |
| var options = Options(moduleName: 'test'); |
| var compiler = |
| // TODO(nshahan): Do we need to support [importToSummary] and |
| // [summaryToModule]. |
| ProgramCompiler(result.component, result.classHierarchy, options, {}, {}); |
| |
| var jsModule = compiler.emitModule(result.compiledLibraries); |
| |
| return MemoryCompilerResult(result, compiler, jsModule, errors); |
| } |