1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

Support loading additional TS lib files (#3863)

Fixes #3726

This PR provides support for referencing other lib files (like lib.dom.d.ts that are not
used by default in Deno.
This commit is contained in:
Kitson Kelly 2020-02-19 16:34:11 +11:00 committed by GitHub
parent 3d5bed35e0
commit 046bbb2691
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 284 additions and 67 deletions

View file

@ -14,13 +14,12 @@ fn op_fetch_asset(
) -> impl Fn(&[u8], Option<ZeroCopyBuf>) -> CoreOp {
move |control: &[u8], zero_copy_buf: Option<ZeroCopyBuf>| -> 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();

View file

@ -165,7 +165,7 @@ impl SourceFileFetcher {
maybe_referrer: Option<ModuleSpecifier>,
) -> Pin<Box<SourceFileFuture>> {
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,
};

View file

@ -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;

View file

@ -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`

View file

@ -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.

View file

@ -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
);

View file

@ -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;
}

View file

@ -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!);
}

View file

@ -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<number, AsyncHandler> = new Map();
export function setPluginAsyncHandler(

View file

@ -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;

View file

@ -3,7 +3,10 @@
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */
/// <reference no-default-lib="true" />
/// <reference lib="deno_ns" />
// 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
/// <reference lib="deno.ns" />
/// <reference lib="esnext" />
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope

View file

@ -3,8 +3,8 @@
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */
/// <reference no-default-lib="true" />
/// <reference lib="deno_ns" />
/// <reference lib="deno_shared_globals" />
/// <reference lib="deno.ns" />
/// <reference lib="deno.shared_globals" />
/// <reference lib="esnext" />
declare interface Window extends WindowOrWorkerGlobalScope {

View file

@ -3,7 +3,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */
/// <reference no-default-lib="true" />
/// <reference lib="deno_shared_globals" />
/// <reference lib="deno.shared_globals" />
/// <reference lib="esnext" />
declare interface DedicatedWorkerGlobalScope extends WindowOrWorkerGlobalScope {

View file

@ -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<string, string>;
}
}

View file

@ -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<ZeroCopyBuf>,
) -> Result<JsonOp, ErrBox> {
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 })))
}

View file

@ -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",

13
cli/tests/lib_ref.ts Normal file
View file

@ -0,0 +1,13 @@
const [errors, program] = await Deno.compile(
"main.ts",
{
"main.ts": `/// <reference lib="dom" />\n\ndocument.getElementById("foo");\nDeno.args;`
},
{
target: "es2018",
lib: ["es2018", "deno.ns"]
}
);
console.log(errors);
console.log(Object.keys(program));

2
cli/tests/lib_ref.ts.out Normal file
View file

@ -0,0 +1,2 @@
null
[ "main.js.map", "main.js" ]

View file

@ -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));

View file

@ -0,0 +1,2 @@
null
[ "main.js.map", "main.js" ]

View file

@ -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,
}
}

View file

@ -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
/// <reference lib="dom" />
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