diff --git a/std/manual.md b/std/manual.md index 49d0526959b40e..aa811cc7d487d4 100644 --- a/std/manual.md +++ b/std/manual.md @@ -897,6 +897,132 @@ import { fib } from "./fib.wasm"; console.log(fib(20)); ``` +## Compiler API + +Deno supports runtime access to the built in TypeScript compiler. There are +three methods in the `Deno` namespace that provide this access. + +### `Deno.compile()` + +This works similar to `deno run` on the command line, except that it doesn't +execute any code. It takes up to three arguments, the `rootName`, optionally +`sources`, and optionally `options`. The `rootName` is the root module which +will be used to generate the resulting program. This is like module name you +would pass on the command line in `deno --reload run example.ts`. The `sources` +is a hash where the key is the fully qualified module name, and the value is the +text source of the module. If `sources` is passed, Deno will resolve all the +modules from within that hash and not attempt to resolve them outside of Deno. +If `sources` are not provided, Deno will resolve modules as if the root module +had been passed on the command line. Deno will also cache any of these +resources. The `options` argument is a set of options of type +`Deno.CompilerOptions`, which is a subset of the TypeScript compiler options +which can be supported by Deno. + +The method resolves with a tuple where the first argument is any diagnostics +(syntax or type errors) related to the code, and a map of the code, where the +key would be the output filename and the value would be the content. + +An example of providing sources: + +```ts +const [diagnostics, emitMap] = await Deno.compile("/foo.ts", { + "/foo.ts": `import * as bar from "./bar.ts";\nconsole.log(bar);\n`, + "/bar.ts": `export const bar = "bar";\n` +}); + +assert(diagnostics == null); // ensuring no diagnostics are returned +console.log(emitMap); +``` + +We would expect map to contain 4 "files", named `/foo.js.map`, `/foo.js`, +`/bar.js.map`, and `/bar.js`. + +When not supplying resources, you can use local or remote modules, just like you +could do on the command line. So you could do something like this: + +```ts +const [diagnostics, emitMap] = await Deno.compile( + "https://deno.land/std/examples/welcome.ts" +); +``` + +We should get back in the `emitMap` a simple `console.log()` statement. + +### `Deno.bundle()` + +This works a lot like `deno bundle` does on the command line. It is also like +`Deno.compile()`, except instead of returning a map of files, it returns a +single string, which is a self-contained JavaScript ES module which will include +all of the code that was provided or resolved as well as exports of all the +exports of the root module that was provided. It takes up to three arguments, +the `rootName`, optionally `sources`, and optionally `options`. The `rootName` +is the root module which will be used to generate the resulting program. This is +like module name you would pass on the command line in `deno bundle example.ts`. +The `sources` is a hash where the key is the fully qualified module name, and +the value is the text source of the module. If `sources` is passed, Deno will +resolve all the modules from within that hash and not attempt to resolve them +outside of Deno. If `sources` are not provided, Deno will resolve modules as if +the root module had been passed on the command line. Deno will also cache any of +these resources. The `options` argument is a set of options of type +`Deno.CompilerOptions`, which is a subset of the TypeScript compiler options +which can be supported by Deno. + +An example of providing sources: + +```ts +const [diagnostics, emit] = await Deno.compile("/foo.ts", { + "/foo.ts": `import * as bar from "./bar.ts";\nconsole.log(bar);\n`, + "/bar.ts": `export const bar = "bar";\n` +}); + +assert(diagnostics == null); // ensuring no diagnostics are returned +console.log(emit); +``` + +We would expect `emit` to be the text for an ES module, which would contain the +output sources for both modules. + +When not supplying resources, you can use local or remote modules, just like you +could do on the command line. So you could do something like this: + +```ts +const [diagnostics, emit] = await Deno.compile( + "https://deno.land/std/http/server.ts" +); +``` + +We should get back in `emit` a self contained JavaScript ES module with all of +its dependencies resolved and exporting the same exports as the source module. + +### `Deno.transpileOnly()` + +This is based off of the TypeScript function `transpileModule()`. All this does +is "erase" any types from the modules and emit JavaScript. There is no type +checking and no resolution of dependencies. It accepts up to two arguments, the +first is a hash where the key is the module name and the value is the contents. +The only purpose of the module name is when putting information into a source +map, of what the source file name was. The second is optionally `options` which +is of type `Deno.CompilerOptions`. This is a subset of options which can be +supported by Deno. It resolves with a map where the key is the source module +name supplied, and the value is an object with a property of `source` which is +the output contents of the module, and optionally `map` which would be the +source map. By default, source maps are output, but can be turned off via the +`options` argument. + +An example: + +```ts +const result = await Deno.transpileOnly({ + "/foo.ts": `enum Foo { Foo, Bar, Baz };\n` +}); + +console.log(result["/foo.ts"].source); +console.log(result["/foo.ts"].map); +``` + +We would expect the `enum` would be rewritten to an IIFE which constructs the +enumerable, and the map to be defined. + ## Program lifecycle Deno supports browser compatible lifecycle events: `load` and `unload`. You can