diff --git a/cli/build.rs b/cli/build.rs index e75b09d74926fe..a94f3925b42f21 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -14,13 +14,12 @@ fn op_fetch_asset( ) -> impl Fn(&[u8], Option) -> CoreOp { move |control: &[u8], zero_copy_buf: Option| -> CoreOp { assert!(zero_copy_buf.is_none()); // zero_copy_buf unused in this op. - let custom_assets = custom_assets.clone(); let name = std::str::from_utf8(control).unwrap(); let asset_code = if let Some(source_code) = deno_typescript::get_asset(name) { source_code.to_string() - } else if let Some(asset_path) = custom_assets.get(name) { + } else if let Some(asset_path) = custom_assets.clone().get(name) { let source_code_vec = std::fs::read(&asset_path).expect("Asset not found"); let source_code = std::str::from_utf8(&source_code_vec).unwrap(); diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index 75774ed5b24883..41f31fb4934fd8 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -165,7 +165,7 @@ impl SourceFileFetcher { maybe_referrer: Option, ) -> Pin> { let module_url = specifier.as_url().to_owned(); - debug!("fetch_source_file. specifier {} ", &module_url); + debug!("fetch_source_file_async specifier: {} ", &module_url); // Check if this file was already fetched and can be retrieved from in-process cache. if let Some(source_file) = self.source_file_cache.get(specifier.to_string()) @@ -368,18 +368,13 @@ impl SourceFileFetcher { } Ok(c) => c, }; - let media_type = map_content_type( - &filepath, - source_code_headers.mime_type.as_ref().map(String::as_str), - ); + let media_type = + map_content_type(&filepath, source_code_headers.mime_type.as_deref()); let types_url = match media_type { msg::MediaType::JavaScript | msg::MediaType::JSX => get_types_url( &module_url, &source_code, - source_code_headers - .x_typescript_types - .as_ref() - .map(String::as_str), + source_code_headers.x_typescript_types.as_deref(), ), _ => None, }; @@ -515,17 +510,13 @@ impl SourceFileFetcher { .location .join(dir.deps_cache.get_cache_filename(&module_url)); - let media_type = map_content_type( - &filepath, - maybe_content_type.as_ref().map(String::as_str), - ); + let media_type = + map_content_type(&filepath, maybe_content_type.as_deref()); let types_url = match media_type { - msg::MediaType::JavaScript | msg::MediaType::JSX => get_types_url( - &module_url, - &source, - x_typescript_types.as_ref().map(String::as_str), - ), + msg::MediaType::JavaScript | msg::MediaType::JSX => { + get_types_url(&module_url, &source, x_typescript_types.as_deref()) + } _ => None, }; diff --git a/cli/js/compiler_api.ts b/cli/js/compiler_api.ts index 489f3693b2a39b..d397ca56855cf1 100644 --- a/cli/js/compiler_api.ts +++ b/cli/js/compiler_api.ts @@ -101,6 +101,10 @@ export interface CompilerOptions { * Does not apply to `"esnext"` target. */ useDefineForClassFields?: boolean; + /** List of library files to be included in the compilation. If omitted, + * then the Deno main runtime libs are used. */ + lib?: string[]; + /** The locale to use to show error messages. */ locale?: string; diff --git a/cli/js/compiler_api_test.ts b/cli/js/compiler_api_test.ts index eef12c8cc96a33..a6baecbf5946a0 100644 --- a/cli/js/compiler_api_test.ts +++ b/cli/js/compiler_api_test.ts @@ -46,6 +46,22 @@ test(async function compilerApiCompileOptions() { assert(actual["/foo.js"].startsWith("define(")); }); +test(async function compilerApiCompileLib() { + const [diagnostics, actual] = await compile( + "/foo.ts", + { + "/foo.ts": `console.log(document.getElementById("foo")); + console.log(Deno.args);` + }, + { + lib: ["dom", "es2018", "deno.ns"] + } + ); + assert(diagnostics == null); + assert(actual); + assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]); +}); + test(async function transpileOnlyApi() { const actual = await transpileOnly({ "foo.ts": `export enum Foo { Foo, Bar, Baz };\n` diff --git a/cli/js/compiler_bootstrap.ts b/cli/js/compiler_bootstrap.ts index 817486d121ce79..c502e2e0186108 100644 --- a/cli/js/compiler_bootstrap.ts +++ b/cli/js/compiler_bootstrap.ts @@ -1,6 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { ASSETS, CompilerHostTarget, Host } from "./compiler_host.ts"; +import { CompilerHostTarget, Host } from "./compiler_host.ts"; +import { ASSETS } from "./compiler_sourcefile.ts"; import { getAsset } from "./compiler_util.ts"; // NOTE: target doesn't really matter here, @@ -14,18 +15,11 @@ const options = host.getCompilationSettings(); // This is a hacky way of adding our libs to the libs available in TypeScript() // as these are internal APIs of TypeScript which maintain valid libs -/* eslint-disable @typescript-eslint/no-explicit-any */ -(ts as any).libs.push( - "deno_ns", - "deno_window", - "deno_worker", - "deno_shared_globals" -); -(ts as any).libMap.set("deno_ns", "lib.deno.ns.d.ts"); -(ts as any).libMap.set("deno_window", "lib.deno.window.d.ts"); -(ts as any).libMap.set("deno_worker", "lib.deno.worker.d.ts"); -(ts as any).libMap.set("deno_shared_globals", "lib.deno.shared_globals.d.ts"); -/* eslint-enable @typescript-eslint/no-explicit-any */ +ts.libs.push("deno.ns", "deno.window", "deno.worker", "deno.shared_globals"); +ts.libMap.set("deno.ns", "lib.deno.ns.d.ts"); +ts.libMap.set("deno.window", "lib.deno.window.d.ts"); +ts.libMap.set("deno.worker", "lib.deno.worker.d.ts"); +ts.libMap.set("deno.shared_globals", "lib.deno.shared_globals.d.ts"); // this pre-populates the cache at snapshot time of our library files, so they // are available in the future when needed. diff --git a/cli/js/compiler_host.ts b/cli/js/compiler_host.ts index 0f6aa4d089a131..8f19eb326b6d97 100644 --- a/cli/js/compiler_host.ts +++ b/cli/js/compiler_host.ts @@ -1,6 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { MediaType, SourceFile } from "./compiler_sourcefile.ts"; +import { ASSETS, MediaType, SourceFile } from "./compiler_sourcefile.ts"; import { OUT_DIR, WriteFileCallback, getAsset } from "./compiler_util.ts"; import { cwd } from "./dir.ts"; import { assert, notImplemented } from "./util.ts"; @@ -18,8 +18,14 @@ export enum CompilerHostTarget { } export interface CompilerHostOptions { + /** Flag determines if the host should assume a single bundle output. */ bundle?: boolean; + + /** Determines what the default library that should be used when type checking + * TS code. */ target: CompilerHostTarget; + + /** A function to be used when the program emit occurs to write out files. */ writeFile: WriteFileCallback; } @@ -28,8 +34,6 @@ export interface ConfigureResponse { diagnostics?: ts.Diagnostic[]; } -export const ASSETS = "$asset$"; - /** Options that need to be used when generating a bundle (either trusted or * runtime). */ export const defaultBundlerOptions: ts.CompilerOptions = { @@ -96,7 +100,6 @@ const ignoredCompilerOptions: readonly string[] = [ "inlineSources", "init", "isolatedModules", - "lib", "listEmittedFiles", "listFiles", "mapRoot", @@ -141,7 +144,10 @@ export class Host implements ts.CompilerHost { private _writeFile: WriteFileCallback; private _getAsset(filename: string): SourceFile { - const url = filename.split("/").pop()!; + const lastSegment = filename.split("/").pop()!; + const url = ts.libMap.has(lastSegment) + ? ts.libMap.get(lastSegment)! + : lastSegment; const sourceFile = SourceFile.get(url); if (sourceFile) { return sourceFile; @@ -150,7 +156,7 @@ export class Host implements ts.CompilerHost { const sourceCode = getAsset(name); return new SourceFile({ url, - filename, + filename: `${ASSETS}/${name}`, mediaType: MediaType.TypeScript, sourceCode }); @@ -230,6 +236,7 @@ export class Host implements ts.CompilerHost { } getDefaultLibFileName(_options: ts.CompilerOptions): string { + util.log("compiler::host.getDefaultLibFileName()"); switch (this._target) { case CompilerHostTarget.Main: case CompilerHostTarget.Runtime: @@ -259,7 +266,7 @@ export class Host implements ts.CompilerHost { if (!sourceFile.tsSourceFile) { assert(sourceFile.sourceCode != null); sourceFile.tsSourceFile = ts.createSourceFile( - fileName, + fileName.startsWith(ASSETS) ? sourceFile.filename : fileName, sourceFile.sourceCode, languageVersion ); diff --git a/cli/js/compiler_sourcefile.ts b/cli/js/compiler_sourcefile.ts index ca7cf27df019d0..faa096ba88379c 100644 --- a/cli/js/compiler_sourcefile.ts +++ b/cli/js/compiler_sourcefile.ts @@ -26,6 +26,8 @@ export interface SourceFileJson { sourceCode: string; } +export const ASSETS = "$asset$"; + /** Returns the TypeScript Extension enum for a given media type. */ function getExtension(fileName: string, mediaType: MediaType): ts.Extension { switch (mediaType) { @@ -109,7 +111,7 @@ export class SourceFile { this.processed = true; const files = (this.importedFiles = [] as Array<[string, string]>); - function process(references: ts.FileReference[]): void { + function process(references: Array<{ fileName: string }>): void { for (const { fileName } of references) { files.push([fileName, fileName]); } @@ -133,7 +135,15 @@ export class SourceFile { process(importedFiles); } process(referencedFiles); - process(libReferenceDirectives); + // built in libs comes across as `"dom"` for example, and should be filtered + // out during pre-processing as they are either already cached or they will + // be lazily fetched by the compiler host. Ones that contain full files are + // not filtered out and will be fetched as normal. + process( + libReferenceDirectives.filter( + ({ fileName }) => !ts.libMap.has(fileName.toLowerCase()) + ) + ); process(typeReferenceDirectives); return files; } diff --git a/cli/js/compiler_util.ts b/cli/js/compiler_util.ts index b58d8da43dbaa0..a28e2d109d6de6 100644 --- a/cli/js/compiler_util.ts +++ b/cli/js/compiler_util.ts @@ -92,15 +92,19 @@ function cache( } let OP_FETCH_ASSET: number; +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); -/** - * This op is called only during snapshotting. - * - * We really don't want to depend on JSON dispatch - * during snapshotting, so this op exchanges strings with Rust - * as raw byte arrays. - */ +/** Retrieve an asset from Rust. */ export function getAsset(name: string): string { + // this path should only be called for assets that are lazily loaded at + // runtime + if (dispatch.OP_FETCH_ASSET) { + util.log("compiler_util::getAsset", name); + return sendSync(dispatch.OP_FETCH_ASSET, { name }).sourceCode; + } + + // this path should only be taken during snapshotting if (!OP_FETCH_ASSET) { const ops = core.ops(); const opFetchAsset = ops["fetch_asset"]; @@ -108,8 +112,8 @@ export function getAsset(name: string): string { OP_FETCH_ASSET = opFetchAsset; } - const encoder = new TextEncoder(); - const decoder = new TextDecoder(); + // We really don't want to depend on JSON dispatch during snapshotting, so + // this op exchanges strings with Rust as raw byte arrays. const sourceCodeBytes = core.dispatch(OP_FETCH_ASSET, encoder.encode(name)); return decoder.decode(sourceCodeBytes!); } diff --git a/cli/js/dispatch.ts b/cli/js/dispatch.ts index b4677b219ccd9a..4322daa998cb42 100644 --- a/cli/js/dispatch.ts +++ b/cli/js/dispatch.ts @@ -19,6 +19,7 @@ export let OP_APPLY_SOURCE_MAP: number; export let OP_FORMAT_ERROR: number; export let OP_CACHE: number; export let OP_RESOLVE_MODULES: number; +export let OP_FETCH_ASSET: number; export let OP_FETCH_SOURCE_FILES: number; export let OP_OPEN: number; export let OP_CLOSE: number; @@ -76,10 +77,6 @@ export let OP_SIGNAL_BIND: number; export let OP_SIGNAL_UNBIND: number; export let OP_SIGNAL_POLL: number; -/** **WARNING:** This is only available during the snapshotting process and is - * unavailable at runtime. */ -export let OP_FETCH_ASSET: number; - const PLUGIN_ASYNC_HANDLER_MAP: Map = new Map(); export function setPluginAsyncHandler( diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index 12e8ae4ba9728f..b5a469f0b12590 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -248,7 +248,7 @@ declare namespace Deno { /** UNSTABLE: might move to Deno.symbols */ export const EOF: unique symbol; - /** UNSTABLE: might move to Deno.symbols */ + /** UNSTABLE: might move to Deno.symbols */ export type EOF = typeof EOF; /** UNSTABLE: maybe remove "SEEK_" prefix. Maybe capitalization wrong. */ @@ -1917,6 +1917,10 @@ declare namespace Deno { * Does not apply to `"esnext"` target. */ useDefineForClassFields?: boolean; + /** List of library files to be included in the compilation. If omitted, + * then the Deno main runtime libs are used. */ + lib?: string[]; + /** The locale to use to show error messages. */ locale?: string; diff --git a/cli/js/lib.deno.shared_globals.d.ts b/cli/js/lib.deno.shared_globals.d.ts index 722bc6a493bdfc..efbc89bd7e4eb3 100644 --- a/cli/js/lib.deno.shared_globals.d.ts +++ b/cli/js/lib.deno.shared_globals.d.ts @@ -3,7 +3,10 @@ /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */ /// -/// +// TODO: we need to remove this, but Fetch::Response::Body implements Reader +// which requires Deno.EOF, and we shouldn't be leaking that, but https_proxy +// at the least requires the Reader interface on Body, which it shouldn't +/// /// // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope diff --git a/cli/js/lib.deno.window.d.ts b/cli/js/lib.deno.window.d.ts index d4dc08acb0325a..7beb853b6a0e2c 100644 --- a/cli/js/lib.deno.window.d.ts +++ b/cli/js/lib.deno.window.d.ts @@ -3,8 +3,8 @@ /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */ /// -/// -/// +/// +/// /// declare interface Window extends WindowOrWorkerGlobalScope { diff --git a/cli/js/lib.deno.worker.d.ts b/cli/js/lib.deno.worker.d.ts index 3311d9457c6477..95a26924053d9f 100644 --- a/cli/js/lib.deno.worker.d.ts +++ b/cli/js/lib.deno.worker.d.ts @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */ /// -/// +/// /// declare interface DedicatedWorkerGlobalScope extends WindowOrWorkerGlobalScope { diff --git a/cli/js/ts_global.d.ts b/cli/js/ts_global.d.ts index f887d578e30111..7b9d84c7ad9236 100644 --- a/cli/js/ts_global.d.ts +++ b/cli/js/ts_global.d.ts @@ -16,4 +16,11 @@ declare global { namespace ts { export = ts_; } + + namespace ts { + // this are marked @internal in TypeScript, but we need to access them, + // there is a risk these could change in future versions of TypeScript + export const libs: string[]; + export const libMap: Map; + } } diff --git a/cli/ops/compiler.rs b/cli/ops/compiler.rs index cce2f4980017f3..f61bf68206fce1 100644 --- a/cli/ops/compiler.rs +++ b/cli/ops/compiler.rs @@ -1,5 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::Deserialize; +use super::dispatch_json::JsonOp; +use super::dispatch_json::Value; use crate::futures::future::try_join_all; use crate::msg; use crate::ops::json_op; @@ -17,6 +19,10 @@ pub fn init(i: &mut Isolate, s: &State) { "fetch_source_files", s.core_op(json_op(s.stateful_op(op_fetch_source_files))), ); + i.register_op( + "fetch_asset", + s.core_op(json_op(s.stateful_op(op_fetch_asset))), + ); } #[derive(Deserialize)] @@ -154,3 +160,26 @@ fn op_fetch_source_files( Ok(JsonOp::Async(future)) } + +#[derive(Deserialize, Debug)] +struct FetchRemoteAssetArgs { + name: String, +} + +fn op_fetch_asset( + _state: &State, + args: Value, + _data: Option, +) -> Result { + let args: FetchRemoteAssetArgs = serde_json::from_value(args)?; + debug!("args.name: {}", args.name); + + let source_code = + if let Some(source_code) = deno_typescript::get_asset(&args.name) { + source_code.to_string() + } else { + panic!("Asset not found: \"{}\"", args.name) + }; + + Ok(JsonOp::Sync(json!({ "sourceCode": source_code }))) +} diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index 38c870200dcd4f..ebb0349c55d419 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -833,6 +833,16 @@ itest!(import_meta { output: "import_meta.ts.out", }); +itest!(lib_ref { + args: "run --reload lib_ref.ts", + output: "lib_ref.ts.out", +}); + +itest!(lib_runtime_api { + args: "run --reload lib_runtime_api.ts", + output: "lib_runtime_api.ts.out", +}); + itest!(seed_random { args: "run --seed=100 seed_random.js", output: "seed_random.js.out", diff --git a/cli/tests/lib_ref.ts b/cli/tests/lib_ref.ts new file mode 100644 index 00000000000000..9fc84ea3e7cf81 --- /dev/null +++ b/cli/tests/lib_ref.ts @@ -0,0 +1,13 @@ +const [errors, program] = await Deno.compile( + "main.ts", + { + "main.ts": `/// \n\ndocument.getElementById("foo");\nDeno.args;` + }, + { + target: "es2018", + lib: ["es2018", "deno.ns"] + } +); + +console.log(errors); +console.log(Object.keys(program)); diff --git a/cli/tests/lib_ref.ts.out b/cli/tests/lib_ref.ts.out new file mode 100644 index 00000000000000..6ff3616b70a59f --- /dev/null +++ b/cli/tests/lib_ref.ts.out @@ -0,0 +1,2 @@ +null +[ "main.js.map", "main.js" ] diff --git a/cli/tests/lib_runtime_api.ts b/cli/tests/lib_runtime_api.ts new file mode 100644 index 00000000000000..848b523a10af52 --- /dev/null +++ b/cli/tests/lib_runtime_api.ts @@ -0,0 +1,12 @@ +const [errors, program] = await Deno.compile( + "main.ts", + { + "main.ts": `document.getElementById("foo");` + }, + { + lib: ["dom", "esnext"] + } +); + +console.log(errors); +console.log(Object.keys(program)); diff --git a/cli/tests/lib_runtime_api.ts.out b/cli/tests/lib_runtime_api.ts.out new file mode 100644 index 00000000000000..6ff3616b70a59f --- /dev/null +++ b/cli/tests/lib_runtime_api.ts.out @@ -0,0 +1,2 @@ +null +[ "main.js.map", "main.js" ] diff --git a/deno_typescript/lib.rs b/deno_typescript/lib.rs index 9056fd903a7e26..c825277e370588 100644 --- a/deno_typescript/lib.rs +++ b/deno_typescript/lib.rs @@ -248,36 +248,44 @@ pub fn get_asset(name: &str) -> Option<&'static str> { "system_loader.js" => Some(include_str!("system_loader.js")), "bootstrap.ts" => Some("console.log(\"hello deno\");"), "typescript.d.ts" => inc!("typescript.d.ts"), + "lib.dom.d.ts" => inc!("lib.dom.d.ts"), + "lib.dom.iterable.d.ts" => inc!("lib.dom.d.ts"), + "lib.es5.d.ts" => inc!("lib.es5.d.ts"), + "lib.es6.d.ts" => inc!("lib.es6.d.ts"), "lib.esnext.d.ts" => inc!("lib.esnext.d.ts"), "lib.es2020.d.ts" => inc!("lib.es2020.d.ts"), + "lib.es2020.full.d.ts" => inc!("lib.es2020.full.d.ts"), "lib.es2019.d.ts" => inc!("lib.es2019.d.ts"), + "lib.es2019.full.d.ts" => inc!("lib.es2019.full.d.ts"), "lib.es2018.d.ts" => inc!("lib.es2018.d.ts"), + "lib.es2018.full.d.ts" => inc!("lib.es2018.full.d.ts"), "lib.es2017.d.ts" => inc!("lib.es2017.d.ts"), + "lib.es2017.full.d.ts" => inc!("lib.es2017.full.d.ts"), "lib.es2016.d.ts" => inc!("lib.es2016.d.ts"), - "lib.es5.d.ts" => inc!("lib.es5.d.ts"), + "lib.es2016.full.d.ts" => inc!("lib.es2016.full.d.ts"), "lib.es2015.d.ts" => inc!("lib.es2015.d.ts"), - "lib.es2015.core.d.ts" => inc!("lib.es2015.core.d.ts"), "lib.es2015.collection.d.ts" => inc!("lib.es2015.collection.d.ts"), + "lib.es2015.core.d.ts" => inc!("lib.es2015.core.d.ts"), "lib.es2015.generator.d.ts" => inc!("lib.es2015.generator.d.ts"), "lib.es2015.iterable.d.ts" => inc!("lib.es2015.iterable.d.ts"), "lib.es2015.promise.d.ts" => inc!("lib.es2015.promise.d.ts"), - "lib.es2015.symbol.d.ts" => inc!("lib.es2015.symbol.d.ts"), "lib.es2015.proxy.d.ts" => inc!("lib.es2015.proxy.d.ts"), + "lib.es2015.reflect.d.ts" => inc!("lib.es2015.reflect.d.ts"), + "lib.es2015.symbol.d.ts" => inc!("lib.es2015.symbol.d.ts"), "lib.es2015.symbol.wellknown.d.ts" => { inc!("lib.es2015.symbol.wellknown.d.ts") } - "lib.es2015.reflect.d.ts" => inc!("lib.es2015.reflect.d.ts"), "lib.es2016.array.include.d.ts" => inc!("lib.es2016.array.include.d.ts"), + "lib.es2017.intl.d.ts" => inc!("lib.es2017.intl.d.ts"), "lib.es2017.object.d.ts" => inc!("lib.es2017.object.d.ts"), "lib.es2017.sharedmemory.d.ts" => inc!("lib.es2017.sharedmemory.d.ts"), "lib.es2017.string.d.ts" => inc!("lib.es2017.string.d.ts"), - "lib.es2017.intl.d.ts" => inc!("lib.es2017.intl.d.ts"), "lib.es2017.typedarrays.d.ts" => inc!("lib.es2017.typedarrays.d.ts"), "lib.es2018.asyncgenerator.d.ts" => inc!("lib.es2018.asyncgenerator.d.ts"), "lib.es2018.asynciterable.d.ts" => inc!("lib.es2018.asynciterable.d.ts"), + "lib.es2018.intl.d.ts" => inc!("lib.es2018.intl.d.ts"), "lib.es2018.promise.d.ts" => inc!("lib.es2018.promise.d.ts"), "lib.es2018.regexp.d.ts" => inc!("lib.es2018.regexp.d.ts"), - "lib.es2018.intl.d.ts" => inc!("lib.es2018.intl.d.ts"), "lib.es2019.array.d.ts" => inc!("lib.es2019.array.d.ts"), "lib.es2019.object.d.ts" => inc!("lib.es2019.object.d.ts"), "lib.es2019.string.d.ts" => inc!("lib.es2019.string.d.ts"), @@ -291,6 +299,11 @@ pub fn get_asset(name: &str) -> Option<&'static str> { "lib.esnext.bigint.d.ts" => inc!("lib.esnext.bigint.d.ts"), "lib.esnext.intl.d.ts" => inc!("lib.esnext.intl.d.ts"), "lib.esnext.symbol.d.ts" => inc!("lib.esnext.symbol.d.ts"), + "lib.scripthost.d.ts" => inc!("lib.scripthost.d.ts"), + "lib.webworker.d.ts" => inc!("lib.webworker.d.ts"), + "lib.webworker.importscripts.d.ts" => { + inc!("lib.webworker.importscripts.d.ts") + } _ => None, } } diff --git a/std/manual.md b/std/manual.md index e5bd6ef75c847c..78037ad1ece421 100644 --- a/std/manual.md +++ b/std/manual.md @@ -174,6 +174,12 @@ command line: $ deno types ``` +The output is the concatenation of three library files that are built into Deno: + +- [lib.deno.ns.d.ts](https://github.com/denoland/deno/blob/master/cli/js/lib.deno.ns.d.ts) +- [lib.deno.shared_globals.d.ts](https://github.com/denoland/deno/blob/master/cli/js/lib.deno.shared_globals.d.ts) +- [lib.deno.window.d.ts](https://github.com/denoland/deno/blob/master/cli/js/lib.deno.window.d.ts) + [This is what the output looks like.](https://github.com/denoland/deno/blob/master/cli/js/lib.deno_runtime.d.ts) ### Reference websites @@ -640,6 +646,100 @@ reference directive. If Deno used this, it would interfere with the behavior of the TypeScript compiler. Deno only looks for the directive in JavaScript (and JSX) files. +### Referencing TypeScript library files + +When you use `deno run`, or other Deno commands which type check TypeScript, +that code is evaluated against custom libraries which describe the environment +that Deno supports. By default, the compiler runtime APIs which type check +TypeScript also use these libraries (`Deno.compile()` and `Deno.bundle()`). + +But if you want to compile or bundle TypeScript for some other runtime, you may +want to override the default libraries. In order to do this, the runtime APIs +support the `lib` property in the compiler options. For example, if you had +TypeScript code that is destined for the browser, you would want to use the +TypeScript `"dom"` library: + +```ts +const [errors, emitted] = Deno.compile( + "main.ts", + { + "main.ts": `document.getElementById("foo");\n` + }, + { + lib: ["dom", "esnext"] + } +); +``` + +For a list of all the libraries that TypeScript supports, see the +[`lib` compiler option](https://www.typescriptlang.org/docs/handbook/compiler-options.html) +documentation. + +**Don't forget to include the JavaScript library** + +Just like `tsc`, when you supply a `lib` compiler option, it overrides the +default ones, which means that the basic JavaScript library won't be included +and you should include the one that best represents your target runtime (e.g. +`es5`, `es2015`, `es2016`, `es2017`, `es2018`, `es2019`, `es2020` or `esnext`). + +#### Including the `Deno` namespace + +In addition to the libraries that are provided by TypeScript, there are four +libraries that are built into Deno that can be referenced: + +- `deno.ns` - Provides the `Deno` namespace. +- `deno.shared_globals` - Provides global interfaces and variables which Deno + supports at runtime that are then exposed by the final runtime library. +- `deno.window` - Exposes the global variables plus the Deno namespace that are + available in the Deno main worker and is the default for the runtime compiler + APIs. +- `deno.worker` - Exposes the global variables that are available in workers + under Deno. + +So to add the Deno namespace to a compilation, you would include the `deno.ns` +lib in the array. For example: + +```ts +const [errors, emitted] = Deno.compile( + "main.ts", + { + "main.ts": `document.getElementById("foo");\n` + }, + { + lib: ["dom", "esnext", "deno.ns"] + } +); +``` + +**Note** that the Deno namespace expects a runtime environment that is at least +ES2018 or later. This means if you use a lib "lower" than ES2018 you will get +errors logged as part of the compilation. + +#### Using the triple slash reference + +You do not have to specify the `lib` in just the compiler options. Deno supports +[the triple-slash reference to a lib](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-lib-). +and could be embedded in the contents of the file. For example of you have a +`main.ts` like: + +```ts +/// + +document.getElementById("foo"); +``` + +It would compiler without errors like this: + +```ts +const [errors, emitted] = Deno.compile("./main.ts", undefined, { + lib: ["esnext"] +}); +``` + +**Note** that the `dom` library conflicts with some of the default globals that +are defined in the default type library for Deno. To avoid this, you need to +specify a `lib` option in the compiler options to the runtime compiler APIs. + ### Testing if current file is the main program To test if the current script has been executed as the main input to the program