mirror of
https://github.com/denoland/deno.git
synced 2025-01-12 00:54:02 -05:00
refactor(cli): runtime compiler APIs consolidated to Deno.emit() (#8799)
Closes: #4752
This commit is contained in:
parent
5f4e1767fe
commit
012f99bd9a
14 changed files with 592 additions and 516 deletions
|
@ -44,11 +44,10 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
|
||||||
"UnixListenOptions",
|
"UnixListenOptions",
|
||||||
"WritePermissionDescriptor",
|
"WritePermissionDescriptor",
|
||||||
"applySourceMap",
|
"applySourceMap",
|
||||||
"bundle",
|
|
||||||
"compile",
|
|
||||||
"connect",
|
"connect",
|
||||||
"consoleSize",
|
"consoleSize",
|
||||||
"createHttpClient",
|
"createHttpClient",
|
||||||
|
"emit",
|
||||||
"formatDiagnostics",
|
"formatDiagnostics",
|
||||||
"futime",
|
"futime",
|
||||||
"futimeSync",
|
"futimeSync",
|
||||||
|
@ -77,7 +76,6 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
|
||||||
"symlinkSync",
|
"symlinkSync",
|
||||||
"systemMemoryInfo",
|
"systemMemoryInfo",
|
||||||
"systemCpuInfo",
|
"systemCpuInfo",
|
||||||
"transpileOnly",
|
|
||||||
"umask",
|
"umask",
|
||||||
"utime",
|
"utime",
|
||||||
"utimeSync",
|
"utimeSync",
|
||||||
|
|
188
cli/dts/lib.deno.unstable.d.ts
vendored
188
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -290,6 +290,8 @@ declare namespace Deno {
|
||||||
/** Base directory to resolve non-relative module names. Defaults to
|
/** Base directory to resolve non-relative module names. Defaults to
|
||||||
* `undefined`. */
|
* `undefined`. */
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
|
/** The character set of the input files. Defaults to `"utf8"`. */
|
||||||
|
charset?: string;
|
||||||
/** Report errors in `.js` files. Use in conjunction with `allowJs`. Defaults
|
/** Report errors in `.js` files. Use in conjunction with `allowJs`. Defaults
|
||||||
* to `false`. */
|
* to `false`. */
|
||||||
checkJs?: boolean;
|
checkJs?: boolean;
|
||||||
|
@ -338,9 +340,6 @@ declare namespace Deno {
|
||||||
/** Emit the source alongside the source maps within a single file; requires
|
/** Emit the source alongside the source maps within a single file; requires
|
||||||
* `inlineSourceMap` or `sourceMap` to be set. Defaults to `false`. */
|
* `inlineSourceMap` or `sourceMap` to be set. Defaults to `false`. */
|
||||||
inlineSources?: boolean;
|
inlineSources?: boolean;
|
||||||
/** Perform additional checks to ensure that transpile only would be safe.
|
|
||||||
* Defaults to `true`. */
|
|
||||||
isolatedModules?: boolean;
|
|
||||||
/** Support JSX in `.tsx` files: `"react"`, `"preserve"`, `"react-native"`.
|
/** Support JSX in `.tsx` files: `"react"`, `"preserve"`, `"react-native"`.
|
||||||
* Defaults to `"react"`. */
|
* Defaults to `"react"`. */
|
||||||
jsx?: "react" | "preserve" | "react-native";
|
jsx?: "react" | "preserve" | "react-native";
|
||||||
|
@ -393,12 +392,17 @@ declare namespace Deno {
|
||||||
/** Do not emit `"use strict"` directives in module output. Defaults to
|
/** Do not emit `"use strict"` directives in module output. Defaults to
|
||||||
* `false`. */
|
* `false`. */
|
||||||
noImplicitUseStrict?: boolean;
|
noImplicitUseStrict?: boolean;
|
||||||
|
/** Do not include the default library file (`lib.d.ts`). Defaults to
|
||||||
|
* `false`. */
|
||||||
|
noLib?: boolean;
|
||||||
/** Do not add triple-slash references or module import targets to the list of
|
/** Do not add triple-slash references or module import targets to the list of
|
||||||
* compiled files. Defaults to `false`. */
|
* compiled files. Defaults to `false`. */
|
||||||
noResolve?: boolean;
|
noResolve?: boolean;
|
||||||
/** Disable strict checking of generic signatures in function types. Defaults
|
/** Disable strict checking of generic signatures in function types. Defaults
|
||||||
* to `false`. */
|
* to `false`. */
|
||||||
noStrictGenericChecks?: boolean;
|
noStrictGenericChecks?: boolean;
|
||||||
|
/** Include 'undefined' in index signature results. Defaults to `false`. */
|
||||||
|
noUncheckedIndexedAccess?: boolean;
|
||||||
/** Report errors on unused locals. Defaults to `false`. */
|
/** Report errors on unused locals. Defaults to `false`. */
|
||||||
noUnusedLocals?: boolean;
|
noUnusedLocals?: boolean;
|
||||||
/** Report errors on unused parameters. Defaults to `false`. */
|
/** Report errors on unused parameters. Defaults to `false`. */
|
||||||
|
@ -487,122 +491,78 @@ declare namespace Deno {
|
||||||
useDefineForClassFields?: boolean;
|
useDefineForClassFields?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** **UNSTABLE**: new API, yet to be vetted.
|
interface ImportMap {
|
||||||
*
|
imports: Record<string, string>;
|
||||||
* The results of a transpile only command, where the `source` contains the
|
scopes?: Record<string, Record<string, string>>;
|
||||||
* emitted source, and `map` optionally contains the source map. */
|
|
||||||
export interface TranspileOnlyResult {
|
|
||||||
source: string;
|
|
||||||
map?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** **UNSTABLE**: new API, yet to be vetted.
|
interface EmitOptions {
|
||||||
*
|
/** Indicate that the source code should be emitted to a single file
|
||||||
* Takes a set of TypeScript sources and resolves to a map where the key was
|
* JavaScript bundle that is an ES module (`"esm"`). */
|
||||||
* the original file name provided in sources and the result contains the
|
bundle?: "esm";
|
||||||
* `source` and optionally the `map` from the transpile operation. This does no
|
/** If `true` then the sources will be typed checked, returning any
|
||||||
* type checking and validation, it effectively "strips" the types from the
|
* diagnostic errors in the result. If `false` type checking will be
|
||||||
* file.
|
* skipped. Defaults to `true`.
|
||||||
*
|
*
|
||||||
* ```ts
|
* *Note* by default, only TypeScript will be type checked, just like on
|
||||||
* const results = await Deno.transpileOnly({
|
* the command line. Use the `compilerOptions` options of `checkJs` to
|
||||||
* "foo.ts": `const foo: string = "foo";`
|
* enable type checking of JavaScript. */
|
||||||
* });
|
check?: boolean;
|
||||||
* ```
|
/** A set of options that are aligned to TypeScript compiler options that
|
||||||
*
|
* are supported by Deno. */
|
||||||
* @param sources A map where the key is the filename and the value is the text
|
compilerOptions?: CompilerOptions;
|
||||||
* to transpile. The filename is only used in the transpile and
|
/** An [import-map](https://deno.land/manual/linking_to_external_code/import_maps#import-maps)
|
||||||
* not resolved, for example to fill in the source name in the
|
* which will be applied to the imports. */
|
||||||
* source map.
|
importMap?: ImportMap;
|
||||||
* @param options An option object of options to send to the compiler. This is
|
/** An absolute path to an [import-map](https://deno.land/manual/linking_to_external_code/import_maps#import-maps).
|
||||||
* a subset of ts.CompilerOptions which can be supported by Deno.
|
* Required to be specified if an `importMap` is specified to be able to
|
||||||
* If unsupported option is passed then the API will throw an error.
|
* determine resolution of relative paths. If a `importMap` is not
|
||||||
*/
|
* specified, then it will assumed the file path points to an import map on
|
||||||
export function transpileOnly(
|
* disk and will be attempted to be loaded based on current runtime
|
||||||
sources: Record<string, string>,
|
* permissions.
|
||||||
options?: CompilerOptions,
|
*/
|
||||||
): Promise<Record<string, TranspileOnlyResult>>;
|
importMapPath?: string;
|
||||||
|
/** A record of sources to use when doing the emit. If provided, Deno will
|
||||||
|
* use these sources instead of trying to resolve the modules externally. */
|
||||||
|
sources?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
/** **UNSTABLE**: new API, yet to be vetted.
|
interface EmitResult {
|
||||||
*
|
/** Diagnostic messages returned from the type checker (`tsc`). */
|
||||||
* Takes a root module name, and optionally a record set of sources. Resolves
|
diagnostics: Diagnostic[];
|
||||||
* with a compiled set of modules and possibly diagnostics if the compiler
|
/** Any emitted files. If bundled, then the JavaScript will have the
|
||||||
* encountered any issues. If just a root name is provided, the modules
|
* key of `deno:///bundle.js` with an optional map (based on
|
||||||
* will be resolved as if the root module had been passed on the command line.
|
* `compilerOptions`) in `deno:///bundle.js.map`. */
|
||||||
*
|
files: Record<string, string>;
|
||||||
* If sources are passed, all modules will be resolved out of this object, where
|
/** An optional array of any compiler options that were ignored by Deno. */
|
||||||
* the key is the module name and the value is the content. The extension of
|
ignoredOptions?: string[];
|
||||||
* the module name will be used to determine the media type of the module.
|
/** An array of internal statistics related to the emit, for diagnostic
|
||||||
*
|
* purposes. */
|
||||||
* ```ts
|
stats: Array<[string, number]>;
|
||||||
* const [ maybeDiagnostics1, output1 ] = await Deno.compile("foo.ts");
|
}
|
||||||
*
|
|
||||||
* const [ maybeDiagnostics2, output2 ] = await Deno.compile("/foo.ts", {
|
|
||||||
* "/foo.ts": `export * from "./bar.ts";`,
|
|
||||||
* "/bar.ts": `export const bar = "bar";`
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param rootName The root name of the module which will be used as the
|
|
||||||
* "starting point". If no `sources` is specified, Deno will
|
|
||||||
* resolve the module externally as if the `rootName` had been
|
|
||||||
* specified on the command line.
|
|
||||||
* @param sources An optional key/value map of sources to be used when resolving
|
|
||||||
* modules, where the key is the module name, and the value is
|
|
||||||
* the source content. The extension of the key will determine
|
|
||||||
* the media type of the file when processing. If supplied,
|
|
||||||
* Deno will not attempt to resolve any modules externally.
|
|
||||||
* @param options An optional object of options to send to the compiler. This is
|
|
||||||
* a subset of ts.CompilerOptions which can be supported by Deno.
|
|
||||||
*/
|
|
||||||
export function compile(
|
|
||||||
rootName: string,
|
|
||||||
sources?: Record<string, string>,
|
|
||||||
options?: CompilerOptions,
|
|
||||||
): Promise<[Diagnostic[] | undefined, Record<string, string>]>;
|
|
||||||
|
|
||||||
/** **UNSTABLE**: new API, yet to be vetted.
|
/**
|
||||||
*
|
* **UNSTABLE**: new API, yet to be vetted.
|
||||||
* `bundle()` is part the compiler API. A full description of this functionality
|
*
|
||||||
* can be found in the [manual](https://deno.land/manual/runtime/compiler_apis#denobundle).
|
* Similar to the command line functionality of `deno run` or `deno cache`,
|
||||||
*
|
* `Deno.emit()` provides a way to provide Deno arbitrary JavaScript
|
||||||
* Takes a root module name, and optionally a record set of sources. Resolves
|
* or TypeScript and have it return JavaScript based on the options and
|
||||||
* with a single JavaScript string (and bundle diagnostics if issues arise with
|
* settings provided. The source code can either be provided or the modules
|
||||||
* the bundling) that is like the output of a `deno bundle` command. If just
|
* can be fetched and resolved in line with the behavior of the command line.
|
||||||
* a root name is provided, the modules will be resolved as if the root module
|
*
|
||||||
* had been passed on the command line.
|
* Requires `allow-read` and/or `allow-net` if sources are not provided.
|
||||||
*
|
*
|
||||||
* If sources are passed, all modules will be resolved out of this object, where
|
* @param rootSpecifier The specifier that will be used as the entry point.
|
||||||
* the key is the module name and the value is the content. The extension of the
|
* If no sources are provided, then the specifier would
|
||||||
* module name will be used to determine the media type of the module.
|
* be the same as if you typed it on the command line for
|
||||||
*
|
* `deno run`. If sources are provided, it should match
|
||||||
* ```ts
|
* one of the names of the sources.
|
||||||
* // equivalent to "deno bundle foo.ts" from the command line
|
* @param options A set of options to be used with the emit.
|
||||||
* const [ maybeDiagnostics1, output1 ] = await Deno.bundle("foo.ts");
|
|
||||||
*
|
|
||||||
* const [ maybeDiagnostics2, output2 ] = await Deno.bundle("/foo.ts", {
|
|
||||||
* "/foo.ts": `export * from "./bar.ts";`,
|
|
||||||
* "/bar.ts": `export const bar = "bar";`
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param rootName The root name of the module which will be used as the
|
|
||||||
* "starting point". If no `sources` is specified, Deno will
|
|
||||||
* resolve the module externally as if the `rootName` had been
|
|
||||||
* specified on the command line.
|
|
||||||
* @param sources An optional key/value map of sources to be used when resolving
|
|
||||||
* modules, where the key is the module name, and the value is
|
|
||||||
* the source content. The extension of the key will determine
|
|
||||||
* the media type of the file when processing. If supplied,
|
|
||||||
* Deno will not attempt to resolve any modules externally.
|
|
||||||
* @param options An optional object of options to send to the compiler. This is
|
|
||||||
* a subset of ts.CompilerOptions which can be supported by Deno.
|
|
||||||
*/
|
*/
|
||||||
export function bundle(
|
export function emit(
|
||||||
rootName: string,
|
rootSpecifier: string | URL,
|
||||||
sources?: Record<string, string>,
|
options?: EmitOptions,
|
||||||
options?: CompilerOptions,
|
): Promise<EmitResult>;
|
||||||
): Promise<[Diagnostic[] | undefined, string]>;
|
|
||||||
|
|
||||||
/** **UNSTABLE**: Should not have same name as `window.location` type. */
|
/** **UNSTABLE**: Should not have same name as `window.location` type. */
|
||||||
interface Location {
|
interface Location {
|
||||||
|
|
|
@ -497,18 +497,27 @@ impl Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct Stats(pub Vec<(String, u128)>);
|
pub struct Stats(pub Vec<(String, u32)>);
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Stats {
|
impl<'de> Deserialize<'de> for Stats {
|
||||||
fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let items: Vec<(String, u128)> = Deserialize::deserialize(deserializer)?;
|
let items: Vec<(String, u32)> = Deserialize::deserialize(deserializer)?;
|
||||||
Ok(Stats(items))
|
Ok(Stats(items))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for Stats {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
Serialize::serialize(&self.0, serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Stats {
|
impl fmt::Display for Stats {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(f, "Compilation statistics:")?;
|
writeln!(f, "Compilation statistics:")?;
|
||||||
|
@ -620,6 +629,10 @@ impl Default for BundleType {
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct EmitOptions {
|
pub struct EmitOptions {
|
||||||
|
/// If true, then code will be type checked, otherwise type checking will be
|
||||||
|
/// skipped. If false, then swc will be used for the emit, otherwise tsc will
|
||||||
|
/// be used.
|
||||||
|
pub check: bool,
|
||||||
/// Indicate the form the result of the emit should take.
|
/// Indicate the form the result of the emit should take.
|
||||||
pub bundle_type: BundleType,
|
pub bundle_type: BundleType,
|
||||||
/// If `true` then debug logging will be output from the isolate.
|
/// If `true` then debug logging will be output from the isolate.
|
||||||
|
@ -769,8 +782,8 @@ impl Graph {
|
||||||
|
|
||||||
let s = self.emit_bundle(&root_specifier, &ts_config.into())?;
|
let s = self.emit_bundle(&root_specifier, &ts_config.into())?;
|
||||||
let stats = Stats(vec![
|
let stats = Stats(vec![
|
||||||
("Files".to_string(), self.modules.len() as u128),
|
("Files".to_string(), self.modules.len() as u32),
|
||||||
("Total time".to_string(), start.elapsed().as_millis()),
|
("Total time".to_string(), start.elapsed().as_millis() as u32),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok((s, stats, maybe_ignored_options))
|
Ok((s, stats, maybe_ignored_options))
|
||||||
|
@ -918,18 +931,22 @@ impl Graph {
|
||||||
/// emitting single modules as well as bundles, using Deno module resolution
|
/// emitting single modules as well as bundles, using Deno module resolution
|
||||||
/// or supplied sources.
|
/// or supplied sources.
|
||||||
pub fn emit(
|
pub fn emit(
|
||||||
self,
|
mut self,
|
||||||
options: EmitOptions,
|
options: EmitOptions,
|
||||||
) -> Result<(HashMap<String, String>, ResultInfo), AnyError> {
|
) -> Result<(HashMap<String, String>, ResultInfo), AnyError> {
|
||||||
let mut config = TsConfig::new(json!({
|
let mut config = TsConfig::new(json!({
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
"checkJs": false,
|
||||||
// TODO(@kitsonk) consider enabling this by default
|
// TODO(@kitsonk) consider enabling this by default
|
||||||
// see: https://github.com/denoland/deno/issues/7732
|
// see: https://github.com/denoland/deno/issues/7732
|
||||||
"emitDecoratorMetadata": false,
|
"emitDecoratorMetadata": false,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"inlineSourceMap": false,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
|
"jsxFactory": "React.createElement",
|
||||||
|
"jsxFragmentFactory": "React.Fragment",
|
||||||
"lib": TypeLib::DenoWindow,
|
"lib": TypeLib::DenoWindow,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
@ -937,11 +954,7 @@ impl Graph {
|
||||||
}));
|
}));
|
||||||
let opts = match options.bundle_type {
|
let opts = match options.bundle_type {
|
||||||
BundleType::Esm => json!({
|
BundleType::Esm => json!({
|
||||||
"checkJs": false,
|
|
||||||
"inlineSourceMap": false,
|
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsxFactory": "React.createElement",
|
|
||||||
"jsxFragmentFactory": "React.Fragment",
|
|
||||||
}),
|
}),
|
||||||
BundleType::None => json!({
|
BundleType::None => json!({
|
||||||
"outDir": "deno://",
|
"outDir": "deno://",
|
||||||
|
@ -957,74 +970,138 @@ impl Graph {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_names = self.get_root_names(!config.get_check_js());
|
if !options.check && config.get_declaration() {
|
||||||
let hash_data =
|
return Err(anyhow!("The option of `check` is false, but the compiler option of `declaration` is true which is not currently supported."));
|
||||||
vec![config.as_bytes(), version::deno().as_bytes().to_owned()];
|
}
|
||||||
let graph = Arc::new(Mutex::new(self));
|
if options.bundle_type != BundleType::None && config.get_declaration() {
|
||||||
|
return Err(anyhow!("The bundle option is set, but the compiler option of `declaration` is true which is not currently supported."));
|
||||||
let response = tsc::exec(
|
}
|
||||||
js::compiler_isolate_init(),
|
|
||||||
tsc::Request {
|
|
||||||
config: config.clone(),
|
|
||||||
debug: options.debug,
|
|
||||||
graph: graph.clone(),
|
|
||||||
hash_data,
|
|
||||||
maybe_tsbuildinfo: None,
|
|
||||||
root_names,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut emitted_files = HashMap::new();
|
let mut emitted_files = HashMap::new();
|
||||||
let graph = graph.lock().unwrap();
|
if options.check {
|
||||||
match options.bundle_type {
|
let root_names = self.get_root_names(!config.get_check_js());
|
||||||
BundleType::Esm => {
|
let hash_data =
|
||||||
assert!(
|
vec![config.as_bytes(), version::deno().as_bytes().to_owned()];
|
||||||
response.emitted_files.is_empty(),
|
let graph = Arc::new(Mutex::new(self));
|
||||||
"No files should have been emitted from tsc."
|
let response = tsc::exec(
|
||||||
);
|
js::compiler_isolate_init(),
|
||||||
assert_eq!(
|
tsc::Request {
|
||||||
graph.roots.len(),
|
config: config.clone(),
|
||||||
1,
|
debug: options.debug,
|
||||||
"Only a single root module supported."
|
graph: graph.clone(),
|
||||||
);
|
hash_data,
|
||||||
let specifier = &graph.roots[0];
|
maybe_tsbuildinfo: None,
|
||||||
let s = graph.emit_bundle(specifier, &config.into())?;
|
root_names,
|
||||||
emitted_files.insert("deno:///bundle.js".to_string(), s);
|
},
|
||||||
}
|
)?;
|
||||||
BundleType::None => {
|
|
||||||
for emitted_file in &response.emitted_files {
|
let graph = graph.lock().unwrap();
|
||||||
|
match options.bundle_type {
|
||||||
|
BundleType::Esm => {
|
||||||
assert!(
|
assert!(
|
||||||
emitted_file.maybe_specifiers.is_some(),
|
response.emitted_files.is_empty(),
|
||||||
"Orphaned file emitted."
|
"No files should have been emitted from tsc."
|
||||||
);
|
);
|
||||||
let specifiers = emitted_file.maybe_specifiers.clone().unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
specifiers.len(),
|
graph.roots.len(),
|
||||||
1,
|
1,
|
||||||
"An unexpected number of specifiers associated with emitted file."
|
"Only a single root module supported."
|
||||||
);
|
);
|
||||||
let specifier = specifiers[0].clone();
|
let specifier = &graph.roots[0];
|
||||||
let extension = match emitted_file.media_type {
|
let s = graph.emit_bundle(specifier, &config.into())?;
|
||||||
MediaType::JavaScript => ".js",
|
emitted_files.insert("deno:///bundle.js".to_string(), s);
|
||||||
MediaType::SourceMap => ".js.map",
|
}
|
||||||
MediaType::Dts => ".d.ts",
|
BundleType::None => {
|
||||||
_ => unreachable!(),
|
for emitted_file in &response.emitted_files {
|
||||||
};
|
assert!(
|
||||||
let key = format!("{}{}", specifier, extension);
|
emitted_file.maybe_specifiers.is_some(),
|
||||||
emitted_files.insert(key, emitted_file.data.clone());
|
"Orphaned file emitted."
|
||||||
|
);
|
||||||
|
let specifiers = emitted_file.maybe_specifiers.clone().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
specifiers.len(),
|
||||||
|
1,
|
||||||
|
"An unexpected number of specifiers associated with emitted file."
|
||||||
|
);
|
||||||
|
let specifier = specifiers[0].clone();
|
||||||
|
let extension = match emitted_file.media_type {
|
||||||
|
MediaType::JavaScript => ".js",
|
||||||
|
MediaType::SourceMap => ".js.map",
|
||||||
|
MediaType::Dts => ".d.ts",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let key = format!("{}{}", specifier, extension);
|
||||||
|
emitted_files.insert(key, emitted_file.data.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
emitted_files,
|
||||||
|
ResultInfo {
|
||||||
|
diagnostics: response.diagnostics,
|
||||||
|
loadable_modules: graph.get_loadable_modules(),
|
||||||
|
maybe_ignored_options,
|
||||||
|
stats: response.stats,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut emit_count = 0_u32;
|
||||||
|
match options.bundle_type {
|
||||||
|
BundleType::Esm => {
|
||||||
|
assert_eq!(
|
||||||
|
self.roots.len(),
|
||||||
|
1,
|
||||||
|
"Only a single root module supported."
|
||||||
|
);
|
||||||
|
let specifier = &self.roots[0];
|
||||||
|
let s = self.emit_bundle(specifier, &config.into())?;
|
||||||
|
emit_count += 1;
|
||||||
|
emitted_files.insert("deno:///bundle.js".to_string(), s);
|
||||||
|
}
|
||||||
|
BundleType::None => {
|
||||||
|
let emit_options: ast::EmitOptions = config.into();
|
||||||
|
for (_, module_slot) in self.modules.iter_mut() {
|
||||||
|
if let ModuleSlot::Module(module) = module_slot {
|
||||||
|
if !(emit_options.check_js
|
||||||
|
|| module.media_type == MediaType::JSX
|
||||||
|
|| module.media_type == MediaType::TSX
|
||||||
|
|| module.media_type == MediaType::TypeScript)
|
||||||
|
{
|
||||||
|
emitted_files
|
||||||
|
.insert(module.specifier.to_string(), module.source.clone());
|
||||||
|
}
|
||||||
|
let parsed_module = module.parse()?;
|
||||||
|
let (code, maybe_map) = parsed_module.transpile(&emit_options)?;
|
||||||
|
emit_count += 1;
|
||||||
|
emitted_files.insert(format!("{}.js", module.specifier), code);
|
||||||
|
if let Some(map) = maybe_map {
|
||||||
|
emitted_files
|
||||||
|
.insert(format!("{}.js.map", module.specifier), map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.flush()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
Ok((
|
let stats = Stats(vec![
|
||||||
emitted_files,
|
("Files".to_string(), self.modules.len() as u32),
|
||||||
ResultInfo {
|
("Emitted".to_string(), emit_count),
|
||||||
diagnostics: response.diagnostics,
|
("Total time".to_string(), start.elapsed().as_millis() as u32),
|
||||||
loadable_modules: graph.get_loadable_modules(),
|
]);
|
||||||
maybe_ignored_options,
|
|
||||||
stats: response.stats,
|
Ok((
|
||||||
},
|
emitted_files,
|
||||||
))
|
ResultInfo {
|
||||||
|
diagnostics: Default::default(),
|
||||||
|
loadable_modules: self.get_loadable_modules(),
|
||||||
|
maybe_ignored_options,
|
||||||
|
stats,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shared between `bundle()` and `emit()`.
|
/// Shared between `bundle()` and `emit()`.
|
||||||
|
@ -1566,10 +1643,9 @@ impl Graph {
|
||||||
let maybe_ignored_options =
|
let maybe_ignored_options =
|
||||||
ts_config.merge_tsconfig(options.maybe_config_path)?;
|
ts_config.merge_tsconfig(options.maybe_config_path)?;
|
||||||
|
|
||||||
let emit_options: ast::EmitOptions = ts_config.clone().into();
|
|
||||||
|
|
||||||
let mut emit_count: u128 = 0;
|
|
||||||
let config = ts_config.as_bytes();
|
let config = ts_config.as_bytes();
|
||||||
|
let emit_options: ast::EmitOptions = ts_config.into();
|
||||||
|
let mut emit_count = 0_u32;
|
||||||
for (_, module_slot) in self.modules.iter_mut() {
|
for (_, module_slot) in self.modules.iter_mut() {
|
||||||
if let ModuleSlot::Module(module) = module_slot {
|
if let ModuleSlot::Module(module) = module_slot {
|
||||||
// TODO(kitsonk) a lot of this logic should be refactored into `Module` as
|
// TODO(kitsonk) a lot of this logic should be refactored into `Module` as
|
||||||
|
@ -1604,9 +1680,9 @@ impl Graph {
|
||||||
self.flush()?;
|
self.flush()?;
|
||||||
|
|
||||||
let stats = Stats(vec![
|
let stats = Stats(vec![
|
||||||
("Files".to_string(), self.modules.len() as u128),
|
("Files".to_string(), self.modules.len() as u32),
|
||||||
("Emitted".to_string(), emit_count),
|
("Emitted".to_string(), emit_count),
|
||||||
("Total time".to_string(), start.elapsed().as_millis()),
|
("Total time".to_string(), start.elapsed().as_millis() as u32),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(ResultInfo {
|
Ok(ResultInfo {
|
||||||
|
@ -2270,6 +2346,7 @@ pub mod tests {
|
||||||
.await;
|
.await;
|
||||||
let (emitted_files, result_info) = graph
|
let (emitted_files, result_info) = graph
|
||||||
.emit(EmitOptions {
|
.emit(EmitOptions {
|
||||||
|
check: true,
|
||||||
bundle_type: BundleType::None,
|
bundle_type: BundleType::None,
|
||||||
debug: false,
|
debug: false,
|
||||||
maybe_user_config: None,
|
maybe_user_config: None,
|
||||||
|
@ -2310,6 +2387,7 @@ pub mod tests {
|
||||||
.await;
|
.await;
|
||||||
let (emitted_files, result_info) = graph
|
let (emitted_files, result_info) = graph
|
||||||
.emit(EmitOptions {
|
.emit(EmitOptions {
|
||||||
|
check: true,
|
||||||
bundle_type: BundleType::Esm,
|
bundle_type: BundleType::Esm,
|
||||||
debug: false,
|
debug: false,
|
||||||
maybe_user_config: None,
|
maybe_user_config: None,
|
||||||
|
@ -2347,6 +2425,7 @@ pub mod tests {
|
||||||
user_config.insert("declaration".to_string(), json!(true));
|
user_config.insert("declaration".to_string(), json!(true));
|
||||||
let (emitted_files, result_info) = graph
|
let (emitted_files, result_info) = graph
|
||||||
.emit(EmitOptions {
|
.emit(EmitOptions {
|
||||||
|
check: true,
|
||||||
bundle_type: BundleType::None,
|
bundle_type: BundleType::None,
|
||||||
debug: false,
|
debug: false,
|
||||||
maybe_user_config: Some(user_config),
|
maybe_user_config: Some(user_config),
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::ast;
|
use crate::import_map::ImportMap;
|
||||||
use crate::colors;
|
|
||||||
use crate::media_type::MediaType;
|
|
||||||
use crate::module_graph::BundleType;
|
use crate::module_graph::BundleType;
|
||||||
use crate::module_graph::EmitOptions;
|
use crate::module_graph::EmitOptions;
|
||||||
use crate::module_graph::GraphBuilder;
|
use crate::module_graph::GraphBuilder;
|
||||||
|
@ -10,11 +8,10 @@ use crate::program_state::ProgramState;
|
||||||
use crate::specifier_handler::FetchHandler;
|
use crate::specifier_handler::FetchHandler;
|
||||||
use crate::specifier_handler::MemoryHandler;
|
use crate::specifier_handler::MemoryHandler;
|
||||||
use crate::specifier_handler::SpecifierHandler;
|
use crate::specifier_handler::SpecifierHandler;
|
||||||
use crate::tsc_config;
|
|
||||||
|
|
||||||
|
use deno_core::error::generic_error;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::error::Context;
|
use deno_core::error::Context;
|
||||||
use deno_core::serde::Serialize;
|
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::serde_json::json;
|
use deno_core::serde_json::json;
|
||||||
use deno_core::serde_json::Value;
|
use deno_core::serde_json::Value;
|
||||||
|
@ -30,37 +27,46 @@ use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
pub fn init(rt: &mut deno_core::JsRuntime) {
|
pub fn init(rt: &mut deno_core::JsRuntime) {
|
||||||
super::reg_json_async(rt, "op_compile", op_compile);
|
super::reg_json_async(rt, "op_emit", op_emit);
|
||||||
super::reg_json_async(rt, "op_transpile", op_transpile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
enum RuntimeBundleType {
|
||||||
|
#[serde(rename = "esm")]
|
||||||
|
Esm,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct CompileArgs {
|
struct EmitArgs {
|
||||||
root_name: String,
|
bundle: Option<RuntimeBundleType>,
|
||||||
|
check: Option<bool>,
|
||||||
|
compiler_options: Option<HashMap<String, Value>>,
|
||||||
|
import_map: Option<Value>,
|
||||||
|
import_map_path: Option<String>,
|
||||||
|
root_specifier: String,
|
||||||
sources: Option<HashMap<String, String>>,
|
sources: Option<HashMap<String, String>>,
|
||||||
bundle: bool,
|
|
||||||
options: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn op_compile(
|
async fn op_emit(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
args: Value,
|
args: Value,
|
||||||
_data: BufVec,
|
_data: BufVec,
|
||||||
) -> Result<Value, AnyError> {
|
) -> Result<Value, AnyError> {
|
||||||
let args: CompileArgs = serde_json::from_value(args)?;
|
deno_runtime::ops::check_unstable2(&state, "Deno.emit");
|
||||||
if args.bundle {
|
let args: EmitArgs = serde_json::from_value(args)?;
|
||||||
deno_runtime::ops::check_unstable2(&state, "Deno.bundle");
|
|
||||||
} else {
|
|
||||||
deno_runtime::ops::check_unstable2(&state, "Deno.compile");
|
|
||||||
}
|
|
||||||
let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone();
|
let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone();
|
||||||
let runtime_permissions = {
|
let runtime_permissions = {
|
||||||
let state = state.borrow();
|
let state = state.borrow();
|
||||||
state.borrow::<Permissions>().clone()
|
state.borrow::<Permissions>().clone()
|
||||||
};
|
};
|
||||||
|
// when we are actually resolving modules without provided sources, we should
|
||||||
|
// treat the root module as a dynamic import so that runtime permissions are
|
||||||
|
// applied.
|
||||||
|
let mut is_dynamic = false;
|
||||||
let handler: Arc<Mutex<dyn SpecifierHandler>> =
|
let handler: Arc<Mutex<dyn SpecifierHandler>> =
|
||||||
if let Some(sources) = args.sources {
|
if let Some(sources) = args.sources {
|
||||||
|
is_dynamic = true;
|
||||||
Arc::new(Mutex::new(MemoryHandler::new(sources)))
|
Arc::new(Mutex::new(MemoryHandler::new(sources)))
|
||||||
} else {
|
} else {
|
||||||
Arc::new(Mutex::new(FetchHandler::new(
|
Arc::new(Mutex::new(FetchHandler::new(
|
||||||
|
@ -68,93 +74,44 @@ async fn op_compile(
|
||||||
runtime_permissions,
|
runtime_permissions,
|
||||||
)?))
|
)?))
|
||||||
};
|
};
|
||||||
let mut builder = GraphBuilder::new(handler, None, None);
|
let maybe_import_map = if let Some(import_map_str) = args.import_map_path {
|
||||||
let specifier = ModuleSpecifier::resolve_url_or_path(&args.root_name)
|
let import_map_specifier =
|
||||||
.context("The root specifier is invalid.")?;
|
ModuleSpecifier::resolve_url_or_path(&import_map_str).context(
|
||||||
builder.add(&specifier, false).await?;
|
format!("Bad file path (\"{}\") for import map.", import_map_str),
|
||||||
let graph = builder.get_graph();
|
)?;
|
||||||
let bundle_type = if args.bundle {
|
let import_map_url = import_map_specifier.as_url();
|
||||||
BundleType::Esm
|
let import_map = if let Some(value) = args.import_map {
|
||||||
} else {
|
ImportMap::from_json(&import_map_url.to_string(), &value.to_string())?
|
||||||
BundleType::None
|
|
||||||
};
|
|
||||||
let debug = program_state.flags.log_level == Some(log::Level::Debug);
|
|
||||||
let maybe_user_config: Option<HashMap<String, Value>> =
|
|
||||||
if let Some(options) = args.options {
|
|
||||||
Some(serde_json::from_str(&options)?)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
ImportMap::load(&import_map_str)?
|
||||||
};
|
};
|
||||||
let (emitted_files, result_info) = graph.emit(EmitOptions {
|
Some(import_map)
|
||||||
|
} else if args.import_map.is_some() {
|
||||||
|
return Err(generic_error("An importMap was specified, but no importMapPath was provided, which is required."));
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let mut builder = GraphBuilder::new(handler, maybe_import_map, None);
|
||||||
|
let root_specifier =
|
||||||
|
ModuleSpecifier::resolve_url_or_path(&args.root_specifier)?;
|
||||||
|
builder.add(&root_specifier, is_dynamic).await?;
|
||||||
|
let bundle_type = match args.bundle {
|
||||||
|
Some(RuntimeBundleType::Esm) => BundleType::Esm,
|
||||||
|
_ => BundleType::None,
|
||||||
|
};
|
||||||
|
let graph = builder.get_graph();
|
||||||
|
let debug = program_state.flags.log_level == Some(log::Level::Debug);
|
||||||
|
let (files, result_info) = graph.emit(EmitOptions {
|
||||||
bundle_type,
|
bundle_type,
|
||||||
|
check: args.check.unwrap_or(true),
|
||||||
debug,
|
debug,
|
||||||
maybe_user_config,
|
maybe_user_config: args.compiler_options,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(json!({
|
Ok(json!({
|
||||||
"emittedFiles": emitted_files,
|
|
||||||
"diagnostics": result_info.diagnostics,
|
"diagnostics": result_info.diagnostics,
|
||||||
|
"files": files,
|
||||||
|
"ignoredOptions": result_info.maybe_ignored_options,
|
||||||
|
"stats": result_info.stats,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct TranspileArgs {
|
|
||||||
sources: HashMap<String, String>,
|
|
||||||
options: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct RuntimeTranspileEmit {
|
|
||||||
source: String,
|
|
||||||
map: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn op_transpile(
|
|
||||||
state: Rc<RefCell<OpState>>,
|
|
||||||
args: Value,
|
|
||||||
_data: BufVec,
|
|
||||||
) -> Result<Value, AnyError> {
|
|
||||||
deno_runtime::ops::check_unstable2(&state, "Deno.transpileOnly");
|
|
||||||
let args: TranspileArgs = serde_json::from_value(args)?;
|
|
||||||
|
|
||||||
let mut compiler_options = tsc_config::TsConfig::new(json!({
|
|
||||||
"checkJs": true,
|
|
||||||
"emitDecoratorMetadata": false,
|
|
||||||
"jsx": "react",
|
|
||||||
"jsxFactory": "React.createElement",
|
|
||||||
"jsxFragmentFactory": "React.Fragment",
|
|
||||||
"inlineSourceMap": false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
let user_options: HashMap<String, Value> = if let Some(options) = args.options
|
|
||||||
{
|
|
||||||
serde_json::from_str(&options)?
|
|
||||||
} else {
|
|
||||||
HashMap::new()
|
|
||||||
};
|
|
||||||
let maybe_ignored_options =
|
|
||||||
compiler_options.merge_user_config(&user_options)?;
|
|
||||||
// TODO(@kitsonk) these really should just be passed back to the caller
|
|
||||||
if let Some(ignored_options) = maybe_ignored_options {
|
|
||||||
info!("{}: {}", colors::yellow("warning"), ignored_options);
|
|
||||||
}
|
|
||||||
|
|
||||||
let emit_options: ast::EmitOptions = compiler_options.into();
|
|
||||||
let mut emit_map = HashMap::new();
|
|
||||||
|
|
||||||
for (specifier, source) in args.sources {
|
|
||||||
let media_type = MediaType::from(&specifier);
|
|
||||||
let parsed_module = ast::parse(&specifier, &source, &media_type)?;
|
|
||||||
let (source, maybe_source_map) = parsed_module.transpile(&emit_options)?;
|
|
||||||
|
|
||||||
emit_map.insert(
|
|
||||||
specifier.to_string(),
|
|
||||||
RuntimeTranspileEmit {
|
|
||||||
source,
|
|
||||||
map: maybe_source_map,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let result = serde_json::to_value(emit_map)?;
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,15 +6,21 @@ import {
|
||||||
} from "../../std/testing/asserts.ts";
|
} from "../../std/testing/asserts.ts";
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.compile() - sources provided",
|
name: "Deno.emit() - sources provided",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics, actual] = await Deno.compile("/foo.ts", {
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
"/foo.ts": `import * as bar from "./bar.ts";\n\nconsole.log(bar);\n`,
|
"/foo.ts",
|
||||||
"/bar.ts": `export const bar = "bar";\n`,
|
{
|
||||||
});
|
sources: {
|
||||||
assert(diagnostics == null);
|
"/foo.ts": `import * as bar from "./bar.ts";\n\nconsole.log(bar);\n`,
|
||||||
assert(actual);
|
"/bar.ts": `export const bar = "bar";\n`,
|
||||||
const keys = Object.keys(actual).sort();
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assertEquals(diagnostics.length, 0);
|
||||||
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 12);
|
||||||
|
const keys = Object.keys(files).sort();
|
||||||
assert(keys[0].endsWith("/bar.ts.js"));
|
assert(keys[0].endsWith("/bar.ts.js"));
|
||||||
assert(keys[1].endsWith("/bar.ts.js.map"));
|
assert(keys[1].endsWith("/bar.ts.js.map"));
|
||||||
assert(keys[2].endsWith("/foo.ts.js"));
|
assert(keys[2].endsWith("/foo.ts.js"));
|
||||||
|
@ -23,12 +29,15 @@ Deno.test({
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.compile() - no sources provided",
|
name: "Deno.emit() - no sources provided",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics, actual] = await Deno.compile("./subdir/mod1.ts");
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
assert(diagnostics == null);
|
"./subdir/mod1.ts",
|
||||||
assert(actual);
|
);
|
||||||
const keys = Object.keys(actual).sort();
|
assertEquals(diagnostics.length, 0);
|
||||||
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 12);
|
||||||
|
const keys = Object.keys(files).sort();
|
||||||
assertEquals(keys.length, 6);
|
assertEquals(keys.length, 6);
|
||||||
assert(keys[0].endsWith("cli/tests/subdir/mod1.ts.js"));
|
assert(keys[0].endsWith("cli/tests/subdir/mod1.ts.js"));
|
||||||
assert(keys[1].endsWith("cli/tests/subdir/mod1.ts.js.map"));
|
assert(keys[1].endsWith("cli/tests/subdir/mod1.ts.js.map"));
|
||||||
|
@ -36,183 +45,246 @@ Deno.test({
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.compile() - compiler options effects emit",
|
name: "Deno.emit() - compiler options effects emit",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics, actual] = await Deno.compile(
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
"/foo.ts",
|
"/foo.ts",
|
||||||
{
|
{
|
||||||
"/foo.ts": `export const foo = "foo";`,
|
compilerOptions: {
|
||||||
},
|
module: "amd",
|
||||||
{
|
sourceMap: false,
|
||||||
module: "amd",
|
},
|
||||||
sourceMap: false,
|
sources: { "/foo.ts": `export const foo = "foo";` },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert(diagnostics == null);
|
assertEquals(diagnostics.length, 0);
|
||||||
assert(actual);
|
assert(!ignoredOptions);
|
||||||
const keys = Object.keys(actual);
|
assertEquals(stats.length, 12);
|
||||||
|
const keys = Object.keys(files);
|
||||||
assertEquals(keys.length, 1);
|
assertEquals(keys.length, 1);
|
||||||
const key = keys[0];
|
const key = keys[0];
|
||||||
assert(key.endsWith("/foo.ts.js"));
|
assert(key.endsWith("/foo.ts.js"));
|
||||||
assert(actual[key].startsWith("define("));
|
assert(files[key].startsWith("define("));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.compile() - pass lib in compiler options",
|
name: "Deno.emit() - pass lib in compiler options",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics, actual] = await Deno.compile(
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
"file:///foo.ts",
|
"file:///foo.ts",
|
||||||
{
|
{
|
||||||
"file:///foo.ts": `console.log(document.getElementById("foo"));
|
compilerOptions: {
|
||||||
console.log(Deno.args);`,
|
lib: ["dom", "es2018", "deno.ns"],
|
||||||
},
|
},
|
||||||
{
|
sources: {
|
||||||
lib: ["dom", "es2018", "deno.ns"],
|
"file:///foo.ts": `console.log(document.getElementById("foo"));
|
||||||
|
console.log(Deno.args);`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert(diagnostics == null);
|
assertEquals(diagnostics.length, 0);
|
||||||
assert(actual);
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 12);
|
||||||
|
const keys = Object.keys(files).sort();
|
||||||
|
assertEquals(keys, ["file:///foo.ts.js", "file:///foo.ts.js.map"]);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test({
|
||||||
|
name: "Deno.emit() - import maps",
|
||||||
|
async fn() {
|
||||||
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
|
"file:///a.ts",
|
||||||
|
{
|
||||||
|
importMap: {
|
||||||
|
imports: {
|
||||||
|
"b": "./b.ts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
importMapPath: "file:///import-map.json",
|
||||||
|
sources: {
|
||||||
|
"file:///a.ts": `import * as b from "b"
|
||||||
|
console.log(b);`,
|
||||||
|
"file:///b.ts": `export const b = "b";`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assertEquals(diagnostics.length, 0);
|
||||||
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 12);
|
||||||
|
const keys = Object.keys(files).sort();
|
||||||
assertEquals(
|
assertEquals(
|
||||||
Object.keys(actual).sort(),
|
keys,
|
||||||
["file:///foo.ts.js", "file:///foo.ts.js.map"],
|
[
|
||||||
|
"file:///a.ts.js",
|
||||||
|
"file:///a.ts.js.map",
|
||||||
|
"file:///b.ts.js",
|
||||||
|
"file:///b.ts.js.map",
|
||||||
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO(@kitsonk) figure the "right way" to restore support for types
|
|
||||||
// Deno.test({
|
|
||||||
// name: "Deno.compile() - properly handles .d.ts files",
|
|
||||||
// async fn() {
|
|
||||||
// const [diagnostics, actual] = await Deno.compile(
|
|
||||||
// "/foo.ts",
|
|
||||||
// {
|
|
||||||
// "/foo.ts": `console.log(Foo.bar);`,
|
|
||||||
// "/foo_types.d.ts": `declare namespace Foo {
|
|
||||||
// const bar: string;
|
|
||||||
// }`,
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// types: ["/foo_types.d.ts"],
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// assert(diagnostics == null);
|
|
||||||
// assert(actual);
|
|
||||||
// assertEquals(
|
|
||||||
// Object.keys(actual).sort(),
|
|
||||||
// ["file:///foo.ts.js", "file:///file.ts.js.map"],
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.transpileOnly()",
|
name: "Deno.emit() - no check",
|
||||||
async fn() {
|
async fn() {
|
||||||
const actual = await Deno.transpileOnly({
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
"foo.ts": `export enum Foo { Foo, Bar, Baz };\n`,
|
"/foo.ts",
|
||||||
});
|
|
||||||
assert(actual);
|
|
||||||
assertEquals(Object.keys(actual), ["foo.ts"]);
|
|
||||||
assert(actual["foo.ts"].source.startsWith("export var Foo;"));
|
|
||||||
assert(actual["foo.ts"].map);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "Deno.transpileOnly() - config effects commit",
|
|
||||||
async fn() {
|
|
||||||
const actual = await Deno.transpileOnly(
|
|
||||||
{
|
{
|
||||||
"foo.ts": `/** This is JSDoc */\nexport enum Foo { Foo, Bar, Baz };\n`,
|
check: false,
|
||||||
},
|
sources: {
|
||||||
{
|
"/foo.ts": `export enum Foo { Foo, Bar, Baz };\n`,
|
||||||
removeComments: true,
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert(actual);
|
assertEquals(diagnostics.length, 0);
|
||||||
assertEquals(Object.keys(actual), ["foo.ts"]);
|
assert(!ignoredOptions);
|
||||||
assert(!actual["foo.ts"].source.includes("This is JSDoc"));
|
assertEquals(stats.length, 3);
|
||||||
assert(actual["foo.ts"].map);
|
const keys = Object.keys(files).sort();
|
||||||
|
assert(keys[0].endsWith("/foo.ts.js"));
|
||||||
|
assert(keys[1].endsWith("/foo.ts.js.map"));
|
||||||
|
assert(files[keys[0]].startsWith("export var Foo;"));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.bundle() - sources passed",
|
name: "Deno.emit() - no check - config effects emit",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics, actual] = await Deno.bundle("/foo.ts", {
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
"/foo.ts": `export * from "./bar.ts";\n`,
|
"/foo.ts",
|
||||||
"/bar.ts": `export const bar = "bar";\n`,
|
{
|
||||||
});
|
check: false,
|
||||||
assert(diagnostics == null);
|
compilerOptions: { removeComments: true },
|
||||||
assert(actual.includes(`const bar = "bar"`));
|
sources: {
|
||||||
|
"/foo.ts":
|
||||||
|
`/** This is JSDoc */\nexport enum Foo { Foo, Bar, Baz };\n`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assertEquals(diagnostics.length, 0);
|
||||||
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 3);
|
||||||
|
const keys = Object.keys(files).sort();
|
||||||
|
assert(keys[0].endsWith("/foo.ts.js"));
|
||||||
|
assert(keys[1].endsWith("/foo.ts.js.map"));
|
||||||
|
assert(!files[keys[0]].includes("This is JSDoc"));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.bundle() - no sources passed",
|
name: "Deno.emit() - bundle esm - with sources",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics, actual] = await Deno.bundle("./subdir/mod1.ts");
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
assert(diagnostics == null);
|
"/foo.ts",
|
||||||
assert(actual.length);
|
{
|
||||||
|
bundle: "esm",
|
||||||
|
sources: {
|
||||||
|
"/foo.ts": `export * from "./bar.ts";\n`,
|
||||||
|
"/bar.ts": `export const bar = "bar";\n`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assertEquals(diagnostics.length, 0);
|
||||||
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 12);
|
||||||
|
assertEquals(Object.keys(files), ["deno:///bundle.js"]);
|
||||||
|
assert(files["deno:///bundle.js"].includes(`const bar = "bar"`));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.bundle() - JS Modules included",
|
name: "Deno.emit() - bundle esm - no sources",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics, actual] = await Deno.bundle("/foo.js", {
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
"/foo.js": `export * from "./bar.js";\n`,
|
"./subdir/mod1.ts",
|
||||||
"/bar.js": `export const bar = "bar";\n`,
|
{
|
||||||
});
|
bundle: "esm",
|
||||||
assert(diagnostics == null);
|
},
|
||||||
assert(actual.includes(`const bar = "bar"`));
|
);
|
||||||
|
assertEquals(diagnostics.length, 0);
|
||||||
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 12);
|
||||||
|
assertEquals(Object.keys(files), ["deno:///bundle.js"]);
|
||||||
|
assert(files["deno:///bundle.js"].length);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "runtime compiler APIs diagnostics",
|
name: "Deno.emit() - bundle esm - include js modules",
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics] = await Deno.compile("/foo.ts", {
|
const { diagnostics, files, ignoredOptions, stats } = await Deno.emit(
|
||||||
"/foo.ts": `document.getElementById("foo");`,
|
"/foo.js",
|
||||||
});
|
{
|
||||||
assert(Array.isArray(diagnostics));
|
bundle: "esm",
|
||||||
assert(diagnostics.length === 1);
|
sources: {
|
||||||
|
"/foo.js": `export * from "./bar.js";\n`,
|
||||||
|
"/bar.js": `export const bar = "bar";\n`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assertEquals(diagnostics.length, 0);
|
||||||
|
assert(!ignoredOptions);
|
||||||
|
assertEquals(stats.length, 12);
|
||||||
|
assertEquals(Object.keys(files), ["deno:///bundle.js"]);
|
||||||
|
assert(files["deno:///bundle.js"].includes(`const bar = "bar"`));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test({
|
||||||
|
name: "Deno.emit() - generates diagnostics",
|
||||||
|
async fn() {
|
||||||
|
const { diagnostics, files } = await Deno.emit(
|
||||||
|
"/foo.ts",
|
||||||
|
{
|
||||||
|
sources: {
|
||||||
|
"/foo.ts": `document.getElementById("foo");`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assertEquals(diagnostics.length, 1);
|
||||||
|
const keys = Object.keys(files).sort();
|
||||||
|
assert(keys[0].endsWith("/foo.ts.js"));
|
||||||
|
assert(keys[1].endsWith("/foo.ts.js.map"));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// See https://github.com/denoland/deno/issues/6908
|
// See https://github.com/denoland/deno/issues/6908
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "Deno.compile() - SWC diagnostics",
|
name: "Deno.emit() - invalid syntax does not panic",
|
||||||
async fn() {
|
async fn() {
|
||||||
await assertThrowsAsync(async () => {
|
await assertThrowsAsync(async () => {
|
||||||
await Deno.compile("/main.js", {
|
await Deno.emit("/main.js", {
|
||||||
"/main.js": `
|
sources: {
|
||||||
export class Foo {
|
"/main.js": `
|
||||||
constructor() {
|
export class Foo {
|
||||||
console.log("foo");
|
constructor() {
|
||||||
}
|
console.log("foo");
|
||||||
export get() {
|
}
|
||||||
console.log("bar");
|
export get() {
|
||||||
}
|
console.log("bar");
|
||||||
}`,
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: `Deno.compile() - Allows setting of "importsNotUsedAsValues"`,
|
name: 'Deno.emit() - allows setting of "importsNotUsedAsValues"',
|
||||||
async fn() {
|
async fn() {
|
||||||
const [diagnostics] = await Deno.compile("/a.ts", {
|
const { diagnostics } = await Deno.emit("/a.ts", {
|
||||||
"/a.ts": `import { B } from "./b.ts";
|
sources: {
|
||||||
const b: B = { b: "b" };
|
"/a.ts": `import { B } from "./b.ts";
|
||||||
`,
|
const b: B = { b: "b" };`,
|
||||||
"/b.ts": `export interface B {
|
"/b.ts": `export interface B {
|
||||||
b: string;
|
b:string;
|
||||||
};
|
};`,
|
||||||
`,
|
},
|
||||||
}, {
|
compilerOptions: {
|
||||||
importsNotUsedAsValues: "error",
|
importsNotUsedAsValues: "error",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
assert(diagnostics);
|
assert(diagnostics);
|
||||||
assertEquals(diagnostics.length, 1);
|
assertEquals(diagnostics.length, 1);
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
const [errors, program] = await Deno.compile(
|
const { diagnostics, files } = await Deno.emit(
|
||||||
"/main.ts",
|
"/main.ts",
|
||||||
{
|
{
|
||||||
"/main.ts":
|
sources: {
|
||||||
`/// <reference lib="dom" />\n\ndocument.getElementById("foo");\nDeno.args;`,
|
"/main.ts":
|
||||||
},
|
`/// <reference lib="dom" />\n\ndocument.getElementById("foo");\nDeno.args;`,
|
||||||
{
|
},
|
||||||
target: "es2018",
|
compilerOptions: {
|
||||||
lib: ["es2018", "deno.ns"],
|
target: "es2018",
|
||||||
|
lib: ["es2018", "deno.ns"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(errors);
|
console.log(diagnostics);
|
||||||
console.log(Object.keys(program).sort());
|
console.log(Object.keys(files).sort());
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
undefined
|
[]
|
||||||
[ "file:///[WILDCARD]main.ts.js", "file:///[WILDCARD]main.ts.js.map" ]
|
[ "file:///[WILDCARD]main.ts.js", "file:///[WILDCARD]main.ts.js.map" ]
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
const [errors, program] = await Deno.compile(
|
const { diagnostics, files } = await Deno.emit(
|
||||||
"/main.ts",
|
"/main.ts",
|
||||||
{
|
{
|
||||||
"/main.ts": `document.getElementById("foo");`,
|
sources: {
|
||||||
},
|
"/main.ts": `document.getElementById("foo");`,
|
||||||
{
|
},
|
||||||
lib: ["dom", "esnext"],
|
compilerOptions: {
|
||||||
|
lib: ["dom", "esnext"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(errors);
|
console.log(diagnostics);
|
||||||
console.log(Object.keys(program).sort());
|
console.log(Object.keys(files).sort());
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
undefined
|
[]
|
||||||
[ "file:///[WILDCARD]main.ts.js", "file:///[WILDCARD]main.ts.js.map" ]
|
[ "file:///[WILDCARD]main.ts.js", "file:///[WILDCARD]main.ts.js.map" ]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
console.log(Deno.permissions.query);
|
console.log(Deno.permissions.query);
|
||||||
console.log(Deno.compile);
|
console.log(Deno.emit);
|
||||||
self.onmessage = () => {
|
self.onmessage = () => {
|
||||||
self.close();
|
self.close();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[Function: query]
|
[Function: query]
|
||||||
[AsyncFunction: compile]
|
[Function: emit]
|
||||||
|
|
|
@ -49,6 +49,15 @@ impl fmt::Display for IgnoredCompilerOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for IgnoredCompilerOptions {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
Serialize::serialize(&self.items, serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A static slice of all the compiler options that should be ignored that
|
/// A static slice of all the compiler options that should be ignored that
|
||||||
/// either have no effect on the compilation or would cause the emit to not work
|
/// either have no effect on the compilation or would cause the emit to not work
|
||||||
/// in Deno.
|
/// in Deno.
|
||||||
|
@ -64,7 +73,6 @@ pub const IGNORED_COMPILER_OPTIONS: &[&str] = &[
|
||||||
"importHelpers",
|
"importHelpers",
|
||||||
"inlineSourceMap",
|
"inlineSourceMap",
|
||||||
"inlineSources",
|
"inlineSources",
|
||||||
"isolatedModules",
|
|
||||||
"module",
|
"module",
|
||||||
"noEmitHelpers",
|
"noEmitHelpers",
|
||||||
"noLib",
|
"noLib",
|
||||||
|
@ -97,6 +105,7 @@ pub const IGNORED_RUNTIME_COMPILER_OPTIONS: &[&str] = &[
|
||||||
"help",
|
"help",
|
||||||
"incremental",
|
"incremental",
|
||||||
"init",
|
"init",
|
||||||
|
"isolatedModules",
|
||||||
"listEmittedFiles",
|
"listEmittedFiles",
|
||||||
"listFiles",
|
"listFiles",
|
||||||
"mapRoot",
|
"mapRoot",
|
||||||
|
@ -246,6 +255,14 @@ impl TsConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_declaration(&self) -> bool {
|
||||||
|
if let Some(declaration) = self.0.get("declaration") {
|
||||||
|
declaration.as_bool().unwrap_or(false)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Merge a serde_json value into the configuration.
|
/// Merge a serde_json value into the configuration.
|
||||||
pub fn merge(&mut self, value: &Value) {
|
pub fn merge(&mut self, value: &Value) {
|
||||||
json_merge(&mut self.0, value);
|
json_merge(&mut self.0, value);
|
||||||
|
|
|
@ -1,97 +1,88 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
// This file contains the runtime APIs which will dispatch work to the internal
|
// This file contains the runtime APIs which will dispatch work to the internal
|
||||||
// compiler within Deno.
|
// compiler within Deno.
|
||||||
((window) => {
|
((window) => {
|
||||||
const core = window.Deno.core;
|
const core = window.Deno.core;
|
||||||
const util = window.__bootstrap.util;
|
const util = window.__bootstrap.util;
|
||||||
|
|
||||||
function opCompile(request) {
|
/**
|
||||||
return core.jsonOpAsync("op_compile", request);
|
* @typedef {object} ImportMap
|
||||||
}
|
* @property {Record<string, string>} imports
|
||||||
|
* @property {Record<string, Record<string, string>>=} scopes
|
||||||
function opTranspile(
|
*/
|
||||||
request,
|
|
||||||
) {
|
/**
|
||||||
return core.jsonOpAsync("op_transpile", request);
|
* @typedef {object} OpEmitRequest
|
||||||
|
* @property {"esm"=} bundle
|
||||||
|
* @property {boolean=} check
|
||||||
|
* @property {Record<string, any>=} compilerOptions
|
||||||
|
* @property {ImportMap=} importMap
|
||||||
|
* @property {string=} importMapPath
|
||||||
|
* @property {string} rootSpecifier
|
||||||
|
* @property {Record<string, string>=} sources
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef OpEmitResponse
|
||||||
|
* @property {any[]} diagnostics
|
||||||
|
* @property {Record<string, string>} files
|
||||||
|
* @property {string[]=} ignoredOptions
|
||||||
|
* @property {Array<[string, number]>} stats
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {OpEmitRequest} request
|
||||||
|
* @returns {Promise<OpEmitResponse>}
|
||||||
|
*/
|
||||||
|
function opEmit(request) {
|
||||||
|
return core.jsonOpAsync("op_emit", request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} specifier
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
function checkRelative(specifier) {
|
function checkRelative(specifier) {
|
||||||
return specifier.match(/^([\.\/\\]|https?:\/{2}|file:\/{2})/)
|
return specifier.match(/^([\.\/\\]|https?:\/{2}|file:\/{2})/)
|
||||||
? specifier
|
? specifier
|
||||||
: `./${specifier}`;
|
: `./${specifier}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bartlomieju): change return type to interface?
|
/**
|
||||||
function transpileOnly(
|
* @typedef {object} EmitOptions
|
||||||
sources,
|
* @property {"esm"=} bundle
|
||||||
options = {},
|
* @property {boolean=} check
|
||||||
) {
|
* @property {Record<string, any>=} compilerOptions
|
||||||
util.log("Deno.transpileOnly", { sources: Object.keys(sources), options });
|
* @property {ImportMap=} importMap
|
||||||
const payload = {
|
* @property {string=} importMapPath
|
||||||
sources,
|
* @property {Record<string, string>=} sources
|
||||||
options: JSON.stringify(options),
|
*/
|
||||||
};
|
|
||||||
return opTranspile(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bartlomieju): change return type to interface?
|
/**
|
||||||
async function compile(
|
* @param {string | URL} rootSpecifier
|
||||||
rootName,
|
* @param {EmitOptions=} options
|
||||||
sources,
|
* @returns {Promise<OpEmitResponse>}
|
||||||
options = {},
|
*/
|
||||||
) {
|
function emit(rootSpecifier, options = {}) {
|
||||||
const payload = {
|
util.log(`Deno.emit`, { rootSpecifier });
|
||||||
rootName: sources ? rootName : checkRelative(rootName),
|
if (!rootSpecifier) {
|
||||||
sources,
|
return Promise.reject(
|
||||||
options: JSON.stringify(options),
|
new TypeError("A root specifier must be supplied."),
|
||||||
bundle: false,
|
);
|
||||||
};
|
}
|
||||||
util.log("Deno.compile", {
|
if (!(typeof rootSpecifier === "string")) {
|
||||||
rootName: payload.rootName,
|
rootSpecifier = rootSpecifier.toString();
|
||||||
sources: !!sources,
|
}
|
||||||
options,
|
if (!options.sources) {
|
||||||
});
|
rootSpecifier = checkRelative(rootSpecifier);
|
||||||
/** @type {{ emittedFiles: Record<string, string>, diagnostics: any[] }} */
|
}
|
||||||
const result = await opCompile(payload);
|
return opEmit({ rootSpecifier, ...options });
|
||||||
util.assert(result.emittedFiles);
|
|
||||||
const maybeDiagnostics = result.diagnostics.length === 0
|
|
||||||
? undefined
|
|
||||||
: result.diagnostics;
|
|
||||||
|
|
||||||
return [maybeDiagnostics, result.emittedFiles];
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bartlomieju): change return type to interface?
|
|
||||||
async function bundle(
|
|
||||||
rootName,
|
|
||||||
sources,
|
|
||||||
options = {},
|
|
||||||
) {
|
|
||||||
const payload = {
|
|
||||||
rootName: sources ? rootName : checkRelative(rootName),
|
|
||||||
sources,
|
|
||||||
options: JSON.stringify(options),
|
|
||||||
bundle: true,
|
|
||||||
};
|
|
||||||
util.log("Deno.bundle", {
|
|
||||||
rootName: payload.rootName,
|
|
||||||
sources: !!sources,
|
|
||||||
options,
|
|
||||||
});
|
|
||||||
/** @type {{ emittedFiles: Record<string, string>, diagnostics: any[] }} */
|
|
||||||
const result = await opCompile(payload);
|
|
||||||
const output = result.emittedFiles["deno:///bundle.js"];
|
|
||||||
util.assert(output);
|
|
||||||
const maybeDiagnostics = result.diagnostics.length === 0
|
|
||||||
? undefined
|
|
||||||
: result.diagnostics;
|
|
||||||
return [maybeDiagnostics, output];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.__bootstrap.compilerApi = {
|
window.__bootstrap.compilerApi = {
|
||||||
bundle,
|
emit,
|
||||||
compile,
|
|
||||||
transpileOnly,
|
|
||||||
};
|
};
|
||||||
})(this);
|
})(this);
|
||||||
|
|
|
@ -94,9 +94,7 @@
|
||||||
signals: __bootstrap.signals.signals,
|
signals: __bootstrap.signals.signals,
|
||||||
Signal: __bootstrap.signals.Signal,
|
Signal: __bootstrap.signals.Signal,
|
||||||
SignalStream: __bootstrap.signals.SignalStream,
|
SignalStream: __bootstrap.signals.SignalStream,
|
||||||
transpileOnly: __bootstrap.compilerApi.transpileOnly,
|
emit: __bootstrap.compilerApi.emit,
|
||||||
compile: __bootstrap.compilerApi.compile,
|
|
||||||
bundle: __bootstrap.compilerApi.bundle,
|
|
||||||
permissions: __bootstrap.permissions.permissions,
|
permissions: __bootstrap.permissions.permissions,
|
||||||
Permissions: __bootstrap.permissions.Permissions,
|
Permissions: __bootstrap.permissions.Permissions,
|
||||||
PermissionStatus: __bootstrap.permissions.PermissionStatus,
|
PermissionStatus: __bootstrap.permissions.PermissionStatus,
|
||||||
|
|
Loading…
Reference in a new issue