summaryrefslogtreecommitdiff
path: root/deno_typescript
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2020-07-19 19:49:44 +0200
committerGitHub <noreply@github.com>2020-07-19 19:49:44 +0200
commitfa61956f03491101b6ef64423ea2f1f73af26a73 (patch)
treec3800702071ca78aa4dd71bdd0a59a9bbe460bdd /deno_typescript
parent53adde866dd399aa2509d14508642fce37afb8f5 (diff)
Port internal TS code to JS (#6793)
Co-authored-by: Ryan Dahl <ry@tinyclouds.org>
Diffstat (limited to 'deno_typescript')
-rw-r--r--deno_typescript/compiler_main.js386
-rw-r--r--deno_typescript/lib.rs244
-rw-r--r--deno_typescript/ops.rs163
3 files changed, 2 insertions, 791 deletions
diff --git a/deno_typescript/compiler_main.js b/deno_typescript/compiler_main.js
deleted file mode 100644
index a42f96860..000000000
--- a/deno_typescript/compiler_main.js
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// Because we're bootstrapping the TypeScript compiler without dependencies on
-// Node, this is written in JavaScript, but leverages JSDoc that can be
-// understood by the TypeScript language service, so it allows type safety
-// checking in VSCode.
-
-"use strict";
-
-const ASSETS = "$asset$";
-
-/**
- * @param {string} configText
- * @param {Array<string>} rootNames
- */
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function main(configText, rootNames) {
- ops = Deno.core.ops();
- println(`>>> ts version ${ts.version}`);
- println(`>>> rootNames ${rootNames}`);
-
- const host = new Host();
-
- assert(rootNames.length === 1);
- // If root file is external file, ie. URL with "file://"
- // then create an internal name - in case of bundling
- // cli runtime this is always true.
- const rootFile = rootNames[0];
- const result = externalSpecifierRegEx.exec(rootFile);
- let rootSpecifier = rootFile;
- if (result) {
- const [, specifier] = result;
- const internalSpecifier = `$deno$${specifier}`;
- moduleMap.set(internalSpecifier, rootFile);
- rootSpecifier = internalSpecifier;
- }
- const { options, diagnostics } = configure(configText);
- handleDiagnostics(host, diagnostics);
-
- println(`>>> TS config: ${JSON.stringify(options)}`);
-
- const program = ts.createProgram([rootSpecifier], options, host);
-
- handleDiagnostics(
- host,
- ts.getPreEmitDiagnostics(program).filter(({ code }) => {
- // TS1063: An export assignment cannot be used in a namespace.
- if (code === 1063) return false;
- // TS2691: An import path cannot end with a '.ts' extension. Consider
- // importing 'bad-module' instead.
- if (code === 2691) return false;
- // TS5009: Cannot find the common subdirectory path for the input files.
- if (code === 5009) return false;
- return true;
- }),
- );
-
- const emitResult = program.emit();
- handleDiagnostics(host, emitResult.diagnostics);
-
- dispatch(
- "op_set_emit_result",
- Object.assign(emitResult, { tsVersion: ts.version }),
- );
-}
-
-/**
- * @param {...string} s
- */
-function println(...s) {
- Deno.core.print(s.join(" ") + "\n");
-}
-
-/**
- * @returns {never}
- */
-function unreachable() {
- throw Error("unreachable");
-}
-
-/**
- * @param {unknown} cond
- * @returns {asserts cond}
- */
-function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
-}
-
-/**
- * @param {Uint8Array | null} ui8
- */
-function decodeAscii(ui8) {
- let out = "";
- if (!ui8) {
- return out;
- }
- for (let i = 0; i < ui8.length; i++) {
- out += String.fromCharCode(ui8[i]);
- }
- return out;
-}
-
-/**
- * @param {string} str
- */
-function encode(str) {
- const charCodes = str.split("").map((c) => c.charCodeAt(0));
- const ui8 = new Uint8Array(charCodes);
- return ui8;
-}
-
-/** **Warning!** Op ids must be acquired from Rust using `Deno.core.ops()`
- * before dispatching any action.
- * @type {Record<string, number>}
- */
-let ops;
-
-/**
- * @type {Map<string, string>}
- */
-const moduleMap = new Map();
-
-const externalSpecifierRegEx = /^file:\/{3}\S+\/js(\/\S+\.ts)$/;
-
-/**
- * This is a minimal implementation of a compiler host to be able to allow the
- * creation of runtime bundles. Some of the methods are implemented in a way
- * to just appease the TypeScript compiler, not to necessarily be a general
- * purpose implementation.
- *
- * @implements {ts.CompilerHost}
- */
-class Host {
- /**
- * @param {string} _fileName
- */
- fileExists(_fileName) {
- return true;
- }
-
- /**
- * @param {string} _fileName
- */
- readFile(_fileName) {
- unreachable();
- }
-
- useCaseSensitiveFileNames() {
- return false;
- }
-
- /**
- * @param {ts.CompilerOptions} _options
- */
- getDefaultLibFileName(_options) {
- return "lib.esnext.d.ts";
- }
-
- getDefaultLibLocation() {
- return ASSETS;
- }
-
- getCurrentDirectory() {
- return ".";
- }
-
- /**
- * @param {string} fileName
- * @param {ts.ScriptTarget} languageVersion
- * @param {(message: string) => void} _onError
- * @param {boolean} shouldCreateNewSourceFile
- */
- getSourceFile(
- fileName,
- languageVersion,
- _onError,
- shouldCreateNewSourceFile,
- ) {
- assert(!shouldCreateNewSourceFile); // We haven't yet encountered this.
-
- // This hacks around the fact that TypeScript tries to magically guess the
- // d.ts filename.
- if (fileName.startsWith("$typeRoots$")) {
- assert(fileName.startsWith("$typeRoots$/"));
- assert(fileName.endsWith("/index.d.ts"));
- fileName = fileName
- .replace("$typeRoots$/", "")
- .replace("/index.d.ts", "");
- }
-
- // This looks up any modules that have been mapped to internal names
- const moduleUrl = moduleMap.has(fileName)
- ? moduleMap.get(fileName)
- : fileName;
-
- const { sourceCode } = dispatch("op_load_module", {
- moduleUrl,
- languageVersion,
- shouldCreateNewSourceFile,
- });
-
- const sourceFile = ts.createSourceFile(
- fileName,
- sourceCode,
- languageVersion,
- );
- sourceFile.moduleName = fileName;
- return sourceFile;
- }
-
- /**
- * @param {string} fileName
- * @param {string} data
- * @param {boolean} _writeByteOrderMark
- * @param {((message: string) => void)?} _onError
- * @param {ReadonlyArray<ts.SourceFile>?} sourceFiles
- */
- writeFile(
- fileName,
- data,
- _writeByteOrderMark,
- _onError = null,
- sourceFiles = null,
- ) {
- if (sourceFiles == null) {
- return;
- }
- const moduleName = sourceFiles[sourceFiles.length - 1].moduleName;
- return dispatch("op_write_file", { fileName, moduleName, data });
- }
-
- /**
- * @param {string} _fileName
- * @param {ts.Path} _path
- * @param {ts.ScriptTarget} _languageVersion
- * @param {*} _onError
- * @param {boolean} _shouldCreateNewSourceFile
- */
- getSourceFileByPath(
- _fileName,
- _path,
- _languageVersion,
- _onError,
- _shouldCreateNewSourceFile,
- ) {
- unreachable();
- }
-
- /**
- * @param {string} fileName
- */
- getCanonicalFileName(fileName) {
- return fileName;
- }
-
- getNewLine() {
- return "\n";
- }
-
- /**
- * @param {string[]} moduleNames
- * @param {string} containingFile
- * @return {Array<ts.ResolvedModule | undefined>}
- */
- resolveModuleNames(moduleNames, containingFile) {
- // If the containing file is an internal specifier, map it back to the
- // external specifier
- containingFile = moduleMap.has(containingFile)
- ? moduleMap.get(containingFile)
- : containingFile;
- /** @type {string[]} */
- const resolvedNames = dispatch("op_resolve_module_names", {
- moduleNames,
- containingFile,
- });
- /** @type {ts.ResolvedModule[]} */
- const r = resolvedNames.map((resolvedFileName) => {
- const extension = getExtension(resolvedFileName);
- if (!moduleMap.has(resolvedFileName)) {
- // If we match the external specifier regex, we will then create an internal
- // specifier and then use that when creating the source file
- const result = externalSpecifierRegEx.exec(resolvedFileName);
- if (result) {
- const [, specifier] = result;
- const internalSpecifier = `$deno$${specifier}`;
- moduleMap.set(internalSpecifier, resolvedFileName);
- resolvedFileName = internalSpecifier;
- }
- }
- return { resolvedFileName, extension };
- });
- return r;
- }
-}
-
-/**
- * @param {string} configurationText
- */
-function configure(configurationText) {
- const { config, error } = ts.parseConfigFileTextToJson(
- "tsconfig.json",
- configurationText,
- );
- if (error) {
- return { options: {}, diagnostics: [error] };
- }
- const { options, errors } = ts.convertCompilerOptionsFromJson(
- config.compilerOptions,
- "",
- );
- return {
- options,
- diagnostics: errors.length ? errors : undefined,
- };
-}
-
-/**
- * @param {string} opName
- * @param {Record<string,any>} obj
- */
-function dispatch(opName, obj) {
- const opId = ops[opName];
-
- if (!opId) {
- throw new Error(`Unknown op: ${opName}`);
- }
-
- const s = JSON.stringify(obj);
- const msg = encode(s);
- const resUi8 = Deno.core.dispatch(opId, msg);
- const resStr = decodeAscii(resUi8);
- const res = JSON.parse(resStr);
- if (!res["ok"]) {
- throw Error(`${opName} failed ${res["err"]}. Args: ${JSON.stringify(obj)}`);
- }
- return res["ok"];
-}
-
-/**
- * @param {number} code
- */
-function exit(code) {
- dispatch("op_exit2", { code });
- return unreachable();
-}
-
-// Maximum number of diagnostics to display.
-const MAX_ERRORS = 5;
-
-/**
- * @param {ts.CompilerHost} host
- * @param {ReadonlyArray<ts.Diagnostic> | undefined} diagnostics
- */
-function handleDiagnostics(host, diagnostics) {
- if (diagnostics && diagnostics.length) {
- let rest = 0;
- if (diagnostics.length > MAX_ERRORS) {
- rest = diagnostics.length - MAX_ERRORS;
- diagnostics = diagnostics.slice(0, MAX_ERRORS);
- }
- const msg = ts.formatDiagnosticsWithColorAndContext(diagnostics, host);
- println(msg);
- if (rest) {
- println(`And ${rest} other errors.`);
- }
- exit(1);
- }
-}
-
-/** Returns the TypeScript Extension enum for a given media type.
- * @param {string} fileName
- * @returns {ts.Extension}
- */
-function getExtension(fileName) {
- if (fileName.endsWith(".d.ts")) {
- return ts.Extension.Dts;
- } else if (fileName.endsWith(".ts")) {
- return ts.Extension.Ts;
- } else if (fileName.endsWith(".js")) {
- return ts.Extension.Js;
- } else {
- throw TypeError(`Cannot resolve extension for ${fileName}`);
- }
-}
diff --git a/deno_typescript/lib.rs b/deno_typescript/lib.rs
index f64959e0d..f01993464 100644
--- a/deno_typescript/lib.rs
+++ b/deno_typescript/lib.rs
@@ -1,33 +1,17 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-#![deny(warnings)]
-
extern crate deno_core;
extern crate serde;
extern crate serde_json;
-mod ops;
-use deno_core::js_check;
pub use deno_core::v8_set_flags;
-use deno_core::CoreIsolate;
use deno_core::CoreIsolateState;
-use deno_core::ErrBox;
-use deno_core::ModuleSpecifier;
use deno_core::Op;
use deno_core::OpDispatcher;
-use deno_core::StartupData;
use deno_core::ZeroCopyBuf;
-pub use ops::EmitResult;
-use ops::WrittenFile;
use std::collections::HashMap;
-use std::fs;
-use std::path::Path;
use std::path::PathBuf;
-use std::sync::Arc;
-use std::sync::Mutex;
-static TYPESCRIPT_CODE: &str = include_str!("typescript/lib/typescript.js");
-static COMPILER_CODE: &str = include_str!("compiler_main.js");
-static SYSTEM_LOADER: &str = include_str!("system_loader.js");
+pub static TYPESCRIPT_CODE: &str = include_str!("typescript/lib/typescript.js");
pub fn ts_version() -> String {
let data = include_str!("typescript/package.json");
@@ -35,221 +19,7 @@ pub fn ts_version() -> String {
pkg["version"].as_str().unwrap().to_string()
}
-type ExternCrateModules = HashMap<String, String>;
-
-#[derive(Debug)]
-pub struct TSState {
- bundle: bool,
- exit_code: i32,
- emit_result: Option<EmitResult>,
- /// A list of files emitted by typescript. WrittenFile is tuple of the form
- /// (url, corresponding_module, source_code)
- written_files: Vec<WrittenFile>,
- extern_crate_modules: ExternCrateModules,
-}
-
-fn compiler_op<D>(
- ts_state: Arc<Mutex<TSState>>,
- dispatcher: D,
-) -> impl OpDispatcher
-where
- D: Fn(&mut TSState, &[u8]) -> Op,
-{
- move |_state: &mut CoreIsolateState,
- zero_copy_bufs: &mut [ZeroCopyBuf]|
- -> Op {
- assert_eq!(zero_copy_bufs.len(), 1, "Invalid number of arguments");
- let mut s = ts_state.lock().unwrap();
- dispatcher(&mut s, &zero_copy_bufs[0])
- }
-}
-
-pub struct TSIsolate {
- isolate: CoreIsolate,
- state: Arc<Mutex<TSState>>,
-}
-
-impl TSIsolate {
- fn new(
- bundle: bool,
- maybe_extern_crate_modules: Option<ExternCrateModules>,
- ) -> TSIsolate {
- let mut isolate = CoreIsolate::new(StartupData::None, false);
- js_check(isolate.execute("assets/typescript.js", TYPESCRIPT_CODE));
- js_check(isolate.execute("compiler_main.js", COMPILER_CODE));
-
- let extern_crate_modules = maybe_extern_crate_modules.unwrap_or_default();
-
- let state = Arc::new(Mutex::new(TSState {
- bundle,
- exit_code: 0,
- emit_result: None,
- written_files: Vec::new(),
- extern_crate_modules,
- }));
-
- isolate.register_op(
- "op_load_module",
- compiler_op(state.clone(), ops::json_op(ops::op_load_module)),
- );
- isolate.register_op(
- "op_exit2",
- compiler_op(state.clone(), ops::json_op(ops::op_exit2)),
- );
- isolate.register_op(
- "op_write_file",
- compiler_op(state.clone(), ops::json_op(ops::op_write_file)),
- );
- isolate.register_op(
- "op_resolve_module_names",
- compiler_op(state.clone(), ops::json_op(ops::op_resolve_module_names)),
- );
- isolate.register_op(
- "op_set_emit_result",
- compiler_op(state.clone(), ops::json_op(ops::op_set_emit_result)),
- );
-
- TSIsolate { isolate, state }
- }
-
- // TODO(ry) Instead of Result<Arc<Mutex<TSState>>, ErrBox>, return something
- // like Result<TSState, ErrBox>. I think it would be nicer if this function
- // consumes TSIsolate.
- /// Compiles each module to ESM. Doesn't write any files to disk.
- /// Passes all output via state.
- fn compile(
- mut self,
- config_json: &serde_json::Value,
- root_names: Vec<String>,
- ) -> Result<Arc<Mutex<TSState>>, ErrBox> {
- let root_names_json = serde_json::json!(root_names).to_string();
- let source =
- &format!("main({:?}, {})", config_json.to_string(), root_names_json);
- self.isolate.execute("<anon>", source)?;
- Ok(self.state)
- }
-}
-
-/// Compile provided roots into a single JS bundle.
-///
-/// This function writes compiled bundle to disk at provided path.
-///
-/// Source map file and type declaration file are emitted
-/// alongside the bundle.
-///
-/// To instantiate bundle use returned `module_name`.
-pub fn compile_bundle(
- bundle_filename: &Path,
- root_names: Vec<PathBuf>,
- extern_crate_modules: Option<ExternCrateModules>,
-) -> Result<String, ErrBox> {
- let ts_isolate = TSIsolate::new(true, extern_crate_modules);
-
- let config_json = serde_json::json!({
- "compilerOptions": {
- "declaration": true,
- // In order to help ensure there are no type directed emits in the code
- // which interferes with transpiling only, the setting
- // `"importsNotUsedAsValues"` set to `"error"` will help ensure that items
- // that are written as `import type` are caught and are treated as errors.
- "importsNotUsedAsValues": "error",
- // Emit the source alongside the sourcemaps within a single file;
- // requires --inlineSourceMap or --sourceMap to be set.
- // "inlineSources": true,
- "lib": ["esnext"],
- "listEmittedFiles": true,
- "listFiles": true,
- "module": "system",
- "outFile": bundle_filename,
- "removeComments": true,
- "sourceMap": true,
- "strict": true,
- "target": "esnext",
- "typeRoots" : ["$typeRoots$"],
- },
- });
-
- let root_names_str: Vec<String> = root_names
- .iter()
- .map(|p| {
- if !p.exists() {
- panic!("File not found {}", p.display());
- }
-
- let module_specifier =
- ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap();
- module_specifier.as_str().to_string()
- })
- .collect();
-
- // TODO lift js_check to caller?
- let locked_state = js_check(ts_isolate.compile(&config_json, root_names_str));
- let state = locked_state.lock().unwrap();
- // Assuming that TypeScript has emitted the main file last.
- let main = state.written_files.last().unwrap();
- let module_name = main.module_name.clone();
- Ok(module_name)
-}
-
-#[allow(dead_code)]
-fn print_source_code(code: &str) {
- let mut i = 1;
- for line in code.lines() {
- println!("{:3} {}", i, line);
- i += 1;
- }
-}
-
-/// Create a V8 snapshot.
-pub fn mksnapshot_bundle(
- isolate: &mut CoreIsolate,
- snapshot_filename: &Path,
- bundle_filename: &Path,
- main_module_name: &str,
-) -> Result<(), ErrBox> {
- js_check(isolate.execute("system_loader.js", SYSTEM_LOADER));
- let source_code_vec = std::fs::read(bundle_filename).unwrap();
- let bundle_source_code = std::str::from_utf8(&source_code_vec).unwrap();
- js_check(
- isolate.execute(&bundle_filename.to_string_lossy(), bundle_source_code),
- );
- let script = &format!("__instantiate(\"{}\", false);", main_module_name);
- js_check(isolate.execute("anon", script));
- write_snapshot(isolate, snapshot_filename)?;
- Ok(())
-}
-
-/// Create a V8 snapshot. This differs from mksnapshot_bundle in that is also
-/// runs typescript.js
-pub fn mksnapshot_bundle_ts(
- isolate: &mut CoreIsolate,
- snapshot_filename: &Path,
- bundle_filename: &Path,
- main_module_name: &str,
-) -> Result<(), ErrBox> {
- js_check(isolate.execute("typescript.js", TYPESCRIPT_CODE));
- mksnapshot_bundle(
- isolate,
- snapshot_filename,
- bundle_filename,
- main_module_name,
- )
-}
-
-fn write_snapshot(
- runtime_isolate: &mut CoreIsolate,
- snapshot_filename: &Path,
-) -> Result<(), ErrBox> {
- println!("Creating snapshot...");
- let snapshot = runtime_isolate.snapshot();
- let snapshot_slice: &[u8] = &*snapshot;
- println!("Snapshot size: {}", snapshot_slice.len());
- fs::write(&snapshot_filename, snapshot_slice)?;
- println!("Snapshot written to: {} ", snapshot_filename.display());
- Ok(())
-}
-
-pub fn get_asset(name: &str) -> Option<&'static str> {
+fn get_asset(name: &str) -> Option<&'static str> {
macro_rules! inc {
($e:expr) => {
Some(include_str!(concat!("typescript/lib/", $e)))
@@ -324,16 +94,6 @@ pub fn get_asset(name: &str) -> Option<&'static str> {
}
}
-/// Sets the --trace-serializer V8 flag for debugging snapshots.
-pub fn trace_serializer() {
- let dummy = "foo".to_string();
- let r = deno_core::v8_set_flags(vec![
- dummy.clone(),
- "--trace-serializer".to_string(),
- ]);
- assert_eq!(r, vec![dummy]);
-}
-
/// Warning: Returns a non-JSON op dispatcher. Must be manually attached to
/// CoreIsolate.
pub fn op_fetch_asset<S: ::std::hash::BuildHasher>(
diff --git a/deno_typescript/ops.rs b/deno_typescript/ops.rs
deleted file mode 100644
index f5904af1a..000000000
--- a/deno_typescript/ops.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-use crate::TSState;
-use deno_core::ErrBox;
-use deno_core::ModuleSpecifier;
-use deno_core::Op;
-use serde::Deserialize;
-use serde_json::json;
-use serde_json::Value;
-
-#[derive(Clone, Debug)]
-pub struct WrittenFile {
- pub url: String,
- pub module_name: String,
- pub source_code: String,
-}
-
-type Dispatcher = fn(state: &mut TSState, args: Value) -> Result<Value, ErrBox>;
-
-pub fn json_op(d: Dispatcher) -> impl Fn(&mut TSState, &[u8]) -> Op {
- move |state: &mut TSState, control: &[u8]| {
- let result = serde_json::from_slice(control)
- .map_err(ErrBox::from)
- .and_then(move |args| d(state, args));
-
- let response = match result {
- Ok(v) => json!({ "ok": v }),
- Err(err) => json!({ "err": err.to_string() }),
- };
-
- let x = serde_json::to_string(&response).unwrap();
- let vec = x.into_bytes();
- Op::Sync(vec.into_boxed_slice())
- }
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct LoadModule {
- module_url: String,
- language_version: Option<i32>,
- should_create_new_source_file: bool,
-}
-
-pub fn op_load_module(s: &mut TSState, v: Value) -> Result<Value, ErrBox> {
- let v: LoadModule = serde_json::from_value(v)?;
- let (module_name, source_code) = if v.module_url.starts_with("$asset$/") {
- let asset = v.module_url.replace("$asset$/", "");
-
- let source_code = match crate::get_asset(&asset) {
- Some(code) => code.to_string(),
- None => {
- return Err(
- std::io::Error::new(std::io::ErrorKind::NotFound, "Asset not found")
- .into(),
- );
- }
- };
-
- (asset, source_code)
- } else {
- assert!(!v.module_url.starts_with("$assets$"), "you meant $asset$");
- let module_specifier = ModuleSpecifier::resolve_url_or_path(&v.module_url)?;
- let module_url = module_specifier.as_url();
- match module_url.scheme() {
- "file" => {
- let path = module_url.to_file_path().unwrap();
- println!("cargo:rerun-if-changed={}", path.display());
- (
- module_specifier.as_str().to_string(),
- std::fs::read_to_string(&path)?,
- )
- }
- "crate" => {
- let crate_name = module_url.host_str().unwrap();
- // TODO(afinch7) turn failures here into real error messages.
- let path_prefix = s.extern_crate_modules.get(crate_name).unwrap();
- let path =
- std::path::Path::new(path_prefix).join(&module_url.path()[1..]);
- (
- module_specifier.as_str().to_string(),
- std::fs::read_to_string(&path)?,
- )
- }
- _ => unimplemented!(),
- }
- };
- Ok(json!({
- "moduleName": module_name,
- "sourceCode": source_code,
- }))
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct WriteFile {
- file_name: String,
- data: String,
- module_name: String,
-}
-
-pub fn op_write_file(s: &mut TSState, v: Value) -> Result<Value, ErrBox> {
- let v: WriteFile = serde_json::from_value(v)?;
- let module_specifier = ModuleSpecifier::resolve_url_or_path(&v.file_name)?;
- if s.bundle {
- std::fs::write(&v.file_name, &v.data)?;
- }
- s.written_files.push(WrittenFile {
- url: module_specifier.as_str().to_string(),
- module_name: v.module_name,
- source_code: v.data,
- });
- Ok(json!(true))
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct ResolveModuleNames {
- module_names: Vec<String>,
- containing_file: String,
-}
-
-pub fn op_resolve_module_names(
- _s: &mut TSState,
- v: Value,
-) -> Result<Value, ErrBox> {
- let v: ResolveModuleNames = serde_json::from_value(v).unwrap();
- let mut resolved = Vec::<String>::new();
- let referrer = ModuleSpecifier::resolve_url_or_path(&v.containing_file)?;
- for specifier in v.module_names {
- if specifier.starts_with("$asset$/") {
- resolved.push(specifier.clone());
- } else {
- let ms = ModuleSpecifier::resolve_import(&specifier, referrer.as_str())?;
- resolved.push(ms.as_str().to_string());
- }
- }
- Ok(json!(resolved))
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct Exit {
- code: i32,
-}
-
-pub fn op_exit2(s: &mut TSState, v: Value) -> Result<Value, ErrBox> {
- let v: Exit = serde_json::from_value(v)?;
- s.exit_code = v.code;
- std::process::exit(v.code)
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct EmitResult {
- pub emit_skipped: bool,
- pub diagnostics: Vec<String>,
- pub emitted_files: Vec<String>,
-}
-
-pub fn op_set_emit_result(s: &mut TSState, v: Value) -> Result<Value, ErrBox> {
- let v: EmitResult = serde_json::from_value(v)?;
- s.emit_result = Some(v);
- Ok(json!(true))
-}