summaryrefslogtreecommitdiff
path: root/cli/tsc/99_main_compiler.js
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tsc/99_main_compiler.js')
-rw-r--r--cli/tsc/99_main_compiler.js584
1 files changed, 145 insertions, 439 deletions
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js
index e2a481d0f..33f34b806 100644
--- a/cli/tsc/99_main_compiler.js
+++ b/cli/tsc/99_main_compiler.js
@@ -1,19 +1,11 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module is the entry point for "compiler" isolate, ie. the one
-// that is created when Deno needs to compile TS/WASM to JS.
-//
-// It provides two functions that should be called by Rust:
-// - `startup`
-// This functions must be called when creating isolate
-// to properly setup runtime.
-// - `tsCompilerOnMessage`
-// This function must be called when sending a request
-// to the compiler.
+// that is created when Deno needs to type check TypeScript, and in some
+// instances convert TypeScript to JavaScript.
// Removes the `__proto__` for security reasons. This intentionally makes
// Deno non compliant with ECMA-262 Annex B.2.2.1
-//
delete Object.prototype.__proto__;
((window) => {
@@ -22,11 +14,6 @@ delete Object.prototype.__proto__;
let logDebug = false;
let logSource = "JS";
- /** Instructs the host to behave in a legacy fashion, with the legacy
- * pipeline for handling code. Setting the value to `true` will cause the
- * host to behave in the modern way. */
- let legacy = true;
-
function setLogDebug(debug, source) {
logDebug = debug;
if (source) {
@@ -57,9 +44,7 @@ delete Object.prototype.__proto__;
/** @type {Map<string, ts.SourceFile>} */
const sourceFileCache = new Map();
- /**
- * @param {import("../dts/typescript").DiagnosticRelatedInformation} diagnostic
- */
+ /** @param {ts.DiagnosticRelatedInformation} diagnostic */
function fromRelatedInformation({
start,
length,
@@ -96,9 +81,7 @@ delete Object.prototype.__proto__;
}
}
- /**
- * @param {import("../dts/typescript").Diagnostic[]} diagnostics
- */
+ /** @param {ts.Diagnostic[]} diagnostics */
function fromTypeScriptDiagnostic(diagnostics) {
return diagnostics.map(({ relatedInformation: ri, source, ...diag }) => {
const value = fromRelatedInformation(diag);
@@ -110,179 +93,63 @@ delete Object.prototype.__proto__;
});
}
- // We really don't want to depend on JSON dispatch during snapshotting, so
- // this op exchanges strings with Rust as raw byte arrays.
- function getAsset(name) {
- const opId = core.ops()["op_fetch_asset"];
- const sourceCodeBytes = core.dispatch(opId, core.encode(name));
- return core.decode(sourceCodeBytes);
- }
-
// Using incremental compile APIs requires that all
// paths must be either relative or absolute. Since
// analysis in Rust operates on fully resolved URLs,
// it makes sense to use the same scheme here.
const ASSETS = "asset:///";
- const OUT_DIR = "deno://";
const CACHE = "cache:///";
- // This constant is passed to compiler settings when
- // doing incremental compiles. Contents of this
- // file are passed back to Rust and saved to $DENO_DIR.
- const TS_BUILD_INFO = "cache:///tsbuildinfo.json";
- const DEFAULT_COMPILE_OPTIONS = {
- allowJs: false,
- allowNonTsExtensions: true,
- checkJs: false,
+ /** Diagnostics that are intentionally ignored when compiling TypeScript in
+ * Deno, as they provide misleading or incorrect information. */
+ const IGNORED_DIAGNOSTICS = [
+ // TS1208: All files must be modules when the '--isolatedModules' flag is
+ // provided. We can ignore because we guarantuee that all files are
+ // modules.
+ 1208,
+ // TS1375: 'await' expressions are only allowed at the top level of a file
+ // when that file is a module, but this file has no imports or exports.
+ // Consider adding an empty 'export {}' to make this file a module.
+ 1375,
+ // TS1103: 'for-await-of' statement is only allowed within an async function
+ // or async generator.
+ 1103,
+ // TS2306: File 'file:///Users/rld/src/deno/cli/tests/subdir/amd_like.js' is
+ // not a module.
+ 2306,
+ // TS2691: An import path cannot end with a '.ts' extension. Consider
+ // importing 'bad-module' instead.
+ 2691,
+ // TS5009: Cannot find the common subdirectory path for the input files.
+ 5009,
+ // TS5055: Cannot write file
+ // 'http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js'
+ // because it would overwrite input file.
+ 5055,
+ // TypeScript is overly opinionated that only CommonJS modules kinds can
+ // support JSON imports. Allegedly this was fixed in
+ // Microsoft/TypeScript#26825 but that doesn't seem to be working here,
+ // so we will ignore complaints about this compiler setting.
+ 5070,
+ // TS7016: Could not find a declaration file for module '...'. '...'
+ // implicitly has an 'any' type. This is due to `allowJs` being off by
+ // default but importing of a JavaScript module.
+ 7016,
+ ];
+
+ const SNAPSHOT_COMPILE_OPTIONS = {
esModuleInterop: true,
jsx: ts.JsxEmit.React,
module: ts.ModuleKind.ESNext,
- outDir: OUT_DIR,
- sourceMap: true,
+ noEmit: true,
strict: true,
- removeComments: true,
target: ts.ScriptTarget.ESNext,
};
- const CompilerHostTarget = {
- Main: "main",
- Runtime: "runtime",
- Worker: "worker",
- };
-
- // Warning! The values in this enum are duplicated in `cli/msg.rs`
- // Update carefully!
- const MediaType = {
- 0: "JavaScript",
- 1: "JSX",
- 2: "TypeScript",
- 3: "Dts",
- 4: "TSX",
- 5: "Json",
- 6: "Wasm",
- 7: "TsBuildInfo",
- 8: "SourceMap",
- 9: "Unknown",
- JavaScript: 0,
- JSX: 1,
- TypeScript: 2,
- Dts: 3,
- TSX: 4,
- Json: 5,
- Wasm: 6,
- TsBuildInfo: 7,
- SourceMap: 8,
- Unknown: 9,
- };
-
- function getExtension(fileName, mediaType) {
- switch (mediaType) {
- case MediaType.JavaScript:
- return ts.Extension.Js;
- case MediaType.JSX:
- return ts.Extension.Jsx;
- case MediaType.TypeScript:
- return ts.Extension.Ts;
- case MediaType.Dts:
- return ts.Extension.Dts;
- case MediaType.TSX:
- return ts.Extension.Tsx;
- case MediaType.Wasm:
- // Custom marker for Wasm type.
- return ts.Extension.Js;
- case MediaType.Unknown:
- default:
- throw TypeError(
- `Cannot resolve extension for "${fileName}" with mediaType "${
- MediaType[mediaType]
- }".`,
- );
- }
- }
-
- /** A global cache of module source files that have been loaded.
- * This cache will be rewritten to be populated on compiler startup
- * with files provided from Rust in request message.
- */
- const SOURCE_FILE_CACHE = new Map();
- /** A map of maps which cache resolved specifier for each import in a file.
- * This cache is used so `resolveModuleNames` ops is called as few times
- * as possible.
- *
- * First map's key is "referrer" URL ("file://a/b/c/mod.ts")
- * Second map's key is "raw" import specifier ("./foo.ts")
- * Second map's value is resolved import URL ("file:///a/b/c/foo.ts")
- */
- const RESOLVED_SPECIFIER_CACHE = new Map();
-
- class SourceFile {
- constructor(json) {
- this.processed = false;
- Object.assign(this, json);
- this.extension = getExtension(this.url, this.mediaType);
- }
-
- static addToCache(json) {
- if (SOURCE_FILE_CACHE.has(json.url)) {
- throw new TypeError("SourceFile already exists");
- }
- const sf = new SourceFile(json);
- SOURCE_FILE_CACHE.set(sf.url, sf);
- return sf;
- }
-
- static getCached(url) {
- return SOURCE_FILE_CACHE.get(url);
- }
-
- static cacheResolvedUrl(resolvedUrl, rawModuleSpecifier, containingFile) {
- containingFile = containingFile || "";
- let innerCache = RESOLVED_SPECIFIER_CACHE.get(containingFile);
- if (!innerCache) {
- innerCache = new Map();
- RESOLVED_SPECIFIER_CACHE.set(containingFile, innerCache);
- }
- innerCache.set(rawModuleSpecifier, resolvedUrl);
- }
-
- static getResolvedUrl(moduleSpecifier, containingFile) {
- const containingCache = RESOLVED_SPECIFIER_CACHE.get(containingFile);
- if (containingCache) {
- return containingCache.get(moduleSpecifier);
- }
- return undefined;
- }
- }
-
- function getAssetInternal(filename) {
- const lastSegment = filename.split("/").pop();
- const url = ts.libMap.has(lastSegment)
- ? ts.libMap.get(lastSegment)
- : lastSegment;
- const sourceFile = SourceFile.getCached(url);
- if (sourceFile) {
- return sourceFile;
- }
- const name = url.includes(".") ? url : `${url}.d.ts`;
- const sourceCode = getAsset(name);
- return SourceFile.addToCache({
- url,
- filename: `${ASSETS}/${name}`,
- mediaType: MediaType.TypeScript,
- versionHash: "1",
- sourceCode,
- });
- }
-
- /** There was some private state in the legacy host, that is moved out to
- * here which can then be refactored out later. */
- const legacyHostState = {
- buildInfo: "",
- target: CompilerHostTarget.Main,
- writeFile: (_fileName, _data, _sourceFiles) => {},
- };
-
- /** @type {import("../dts/typescript").CompilerHost} */
+ /** An object literal of the incremental compiler host, which provides the
+ * specific "bindings" to the Deno environment that tsc needs to work.
+ *
+ * @type {ts.CompilerHost} */
const host = {
fileExists(fileName) {
debug(`host.fileExists("${fileName}")`);
@@ -290,122 +157,61 @@ delete Object.prototype.__proto__;
},
readFile(specifier) {
debug(`host.readFile("${specifier}")`);
- if (legacy) {
- if (specifier == TS_BUILD_INFO) {
- return legacyHostState.buildInfo;
- }
- return unreachable();
- } else {
- return core.jsonOpSync("op_load", { specifier }).data;
- }
+ return core.jsonOpSync("op_load", { specifier }).data;
},
getSourceFile(
specifier,
languageVersion,
- onError,
- shouldCreateNewSourceFile,
+ _onError,
+ _shouldCreateNewSourceFile,
) {
debug(
`host.getSourceFile("${specifier}", ${
ts.ScriptTarget[languageVersion]
})`,
);
- if (legacy) {
- try {
- assert(!shouldCreateNewSourceFile);
- const sourceFile = specifier.startsWith(ASSETS)
- ? getAssetInternal(specifier)
- : SourceFile.getCached(specifier);
- assert(sourceFile != null);
- if (!sourceFile.tsSourceFile) {
- assert(sourceFile.sourceCode != null);
- const tsSourceFileName = specifier.startsWith(ASSETS)
- ? sourceFile.filename
- : specifier;
-
- sourceFile.tsSourceFile = ts.createSourceFile(
- tsSourceFileName,
- sourceFile.sourceCode,
- languageVersion,
- );
- sourceFile.tsSourceFile.version = sourceFile.versionHash;
- delete sourceFile.sourceCode;
-
- // This code is to support transition from the "legacy" compiler
- // to the new one, by populating the new source file cache.
- if (
- !sourceFileCache.has(specifier) && specifier.startsWith(ASSETS)
- ) {
- sourceFileCache.set(specifier, sourceFile.tsSourceFile);
- }
- }
- return sourceFile.tsSourceFile;
- } catch (e) {
- if (onError) {
- onError(String(e));
- } else {
- throw e;
- }
- return undefined;
- }
- } else {
- let sourceFile = sourceFileCache.get(specifier);
- if (sourceFile) {
- return sourceFile;
- }
-
- /** @type {{ data: string; hash?: string; scriptKind: ts.ScriptKind }} */
- const { data, hash, scriptKind } = core.jsonOpSync(
- "op_load",
- { specifier },
- );
- assert(
- data != null,
- `"data" is unexpectedly null for "${specifier}".`,
- );
- sourceFile = ts.createSourceFile(
- specifier,
- data,
- languageVersion,
- false,
- scriptKind,
- );
- sourceFile.moduleName = specifier;
- sourceFile.version = hash;
- sourceFileCache.set(specifier, sourceFile);
+ let sourceFile = sourceFileCache.get(specifier);
+ if (sourceFile) {
return sourceFile;
}
+
+ /** @type {{ data: string; hash?: string; scriptKind: ts.ScriptKind }} */
+ const { data, hash, scriptKind } = core.jsonOpSync(
+ "op_load",
+ { specifier },
+ );
+ assert(
+ data != null,
+ `"data" is unexpectedly null for "${specifier}".`,
+ );
+ sourceFile = ts.createSourceFile(
+ specifier,
+ data,
+ languageVersion,
+ false,
+ scriptKind,
+ );
+ sourceFile.moduleName = specifier;
+ sourceFile.version = hash;
+ sourceFileCache.set(specifier, sourceFile);
+ return sourceFile;
},
getDefaultLibFileName() {
- if (legacy) {
- switch (legacyHostState.target) {
- case CompilerHostTarget.Main:
- case CompilerHostTarget.Runtime:
- return `${ASSETS}/lib.deno.window.d.ts`;
- case CompilerHostTarget.Worker:
- return `${ASSETS}/lib.deno.worker.d.ts`;
- }
- } else {
- return `${ASSETS}/lib.esnext.d.ts`;
- }
+ return `${ASSETS}/lib.esnext.d.ts`;
},
getDefaultLibLocation() {
return ASSETS;
},
writeFile(fileName, data, _writeByteOrderMark, _onError, sourceFiles) {
debug(`host.writeFile("${fileName}")`);
- if (legacy) {
- legacyHostState.writeFile(fileName, data, sourceFiles);
- } else {
- let maybeSpecifiers;
- if (sourceFiles) {
- maybeSpecifiers = sourceFiles.map((sf) => sf.moduleName);
- }
- return core.jsonOpSync(
- "op_emit",
- { maybeSpecifiers, fileName, data },
- );
+ let maybeSpecifiers;
+ if (sourceFiles) {
+ maybeSpecifiers = sourceFiles.map((sf) => sf.moduleName);
}
+ return core.jsonOpSync(
+ "op_emit",
+ { maybeSpecifiers, fileName, data },
+ );
},
getCurrentDirectory() {
return CACHE;
@@ -423,148 +229,24 @@ delete Object.prototype.__proto__;
debug(`host.resolveModuleNames()`);
debug(` base: ${base}`);
debug(` specifiers: ${specifiers.join(", ")}`);
- if (legacy) {
- const resolved = specifiers.map((specifier) => {
- const maybeUrl = SourceFile.getResolvedUrl(specifier, base);
-
- debug("compiler::host.resolveModuleNames maybeUrl", {
- specifier,
- maybeUrl,
- });
-
- let sourceFile = undefined;
-
- if (specifier.startsWith(ASSETS)) {
- sourceFile = getAssetInternal(specifier);
- } else if (typeof maybeUrl !== "undefined") {
- sourceFile = SourceFile.getCached(maybeUrl);
- }
-
- if (!sourceFile) {
- return undefined;
- }
-
- return {
- resolvedFileName: sourceFile.url,
- isExternalLibraryImport: specifier.startsWith(ASSETS),
- extension: sourceFile.extension,
- };
- });
- debug(resolved);
- return resolved;
- } else {
- /** @type {Array<[string, import("../dts/typescript").Extension]>} */
- const resolved = core.jsonOpSync("op_resolve", {
- specifiers,
- base,
- });
- let r = resolved.map(([resolvedFileName, extension]) => ({
- resolvedFileName,
- extension,
- isExternalLibraryImport: false,
- }));
- return r;
- }
+ /** @type {Array<[string, ts.Extension]>} */
+ const resolved = core.jsonOpSync("op_resolve", {
+ specifiers,
+ base,
+ });
+ let r = resolved.map(([resolvedFileName, extension]) => ({
+ resolvedFileName,
+ extension,
+ isExternalLibraryImport: false,
+ }));
+ return r;
},
createHash(data) {
return core.jsonOpSync("op_create_hash", { data }).hash;
},
};
- // 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
- 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.web", "lib.deno.web.d.ts");
- ts.libMap.set("deno.fetch", "lib.deno.fetch.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");
- ts.libMap.set("deno.unstable", "lib.deno.unstable.d.ts");
-
- // TODO(@kitsonk) remove once added to TypeScript
- ts.libs.push("esnext.weakref");
- ts.libMap.set("esnext.weakref", "lib.esnext.weakref.d.ts");
-
- // this pre-populates the cache at snapshot time of our library files, so they
- // are available in the future when needed.
- host.getSourceFile(
- `${ASSETS}lib.deno.ns.d.ts`,
- ts.ScriptTarget.ESNext,
- );
- host.getSourceFile(
- `${ASSETS}lib.deno.web.d.ts`,
- ts.ScriptTarget.ESNext,
- );
- host.getSourceFile(
- `${ASSETS}lib.deno.fetch.d.ts`,
- ts.ScriptTarget.ESNext,
- );
- host.getSourceFile(
- `${ASSETS}lib.deno.window.d.ts`,
- ts.ScriptTarget.ESNext,
- );
- host.getSourceFile(
- `${ASSETS}lib.deno.worker.d.ts`,
- ts.ScriptTarget.ESNext,
- );
- host.getSourceFile(
- `${ASSETS}lib.deno.shared_globals.d.ts`,
- ts.ScriptTarget.ESNext,
- );
- host.getSourceFile(
- `${ASSETS}lib.deno.unstable.d.ts`,
- ts.ScriptTarget.ESNext,
- );
-
- // We never use this program; it's only created
- // during snapshotting to hydrate and populate
- // source file cache with lib declaration files.
- const _TS_SNAPSHOT_PROGRAM = ts.createProgram({
- rootNames: [`${ASSETS}bootstrap.ts`],
- options: DEFAULT_COMPILE_OPTIONS,
- host,
- });
-
- const IGNORED_DIAGNOSTICS = [
- // TS2306: File 'file:///Users/rld/src/deno/cli/tests/subdir/amd_like.js' is
- // not a module.
- 2306,
- // TS1375: 'await' expressions are only allowed at the top level of a file
- // when that file is a module, but this file has no imports or exports.
- // Consider adding an empty 'export {}' to make this file a module.
- 1375,
- // TS1103: 'for-await-of' statement is only allowed within an async function
- // or async generator.
- 1103,
- // TS2691: An import path cannot end with a '.ts' extension. Consider
- // importing 'bad-module' instead.
- 2691,
- // TS5009: Cannot find the common subdirectory path for the input files.
- 5009,
- // TS5055: Cannot write file
- // 'http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js'
- // because it would overwrite input file.
- 5055,
- // TypeScript is overly opinionated that only CommonJS modules kinds can
- // support JSON imports. Allegedly this was fixed in
- // Microsoft/TypeScript#26825 but that doesn't seem to be working here,
- // so we will ignore complaints about this compiler setting.
- 5070,
- // TS7016: Could not find a declaration file for module '...'. '...'
- // implicitly has an 'any' type. This is due to `allowJs` being off by
- // default but importing of a JavaScript module.
- 7016,
- ];
-
- const IGNORED_COMPILE_DIAGNOSTICS = [
- // TS1208: All files must be modules when the '--isolatedModules' flag is
- // provided. We can ignore because we guarantuee that all files are
- // modules.
- 1208,
- ];
-
- /** @type {Array<{ key: string, value: number }>} */
+ /** @type {Array<[string, number]>} */
const stats = [];
let statsStart = 0;
@@ -579,35 +261,31 @@ delete Object.prototype.__proto__;
if ("getProgram" in program) {
program = program.getProgram();
}
- stats.push({ key: "Files", value: program.getSourceFiles().length });
- stats.push({ key: "Nodes", value: program.getNodeCount() });
- stats.push({ key: "Identifiers", value: program.getIdentifierCount() });
- stats.push({ key: "Symbols", value: program.getSymbolCount() });
- stats.push({ key: "Types", value: program.getTypeCount() });
- stats.push({
- key: "Instantiations",
- value: program.getInstantiationCount(),
- });
+ stats.push(["Files", program.getSourceFiles().length]);
+ stats.push(["Nodes", program.getNodeCount()]);
+ stats.push(["Identifiers", program.getIdentifierCount()]);
+ stats.push(["Symbols", program.getSymbolCount()]);
+ stats.push(["Types", program.getTypeCount()]);
+ stats.push(["Instantiations", program.getInstantiationCount()]);
} else if (fileCount != null) {
- stats.push({ key: "Files", value: fileCount });
+ stats.push(["Files", fileCount]);
}
const programTime = ts.performance.getDuration("Program");
const bindTime = ts.performance.getDuration("Bind");
const checkTime = ts.performance.getDuration("Check");
const emitTime = ts.performance.getDuration("Emit");
- stats.push({ key: "Parse time", value: programTime });
- stats.push({ key: "Bind time", value: bindTime });
- stats.push({ key: "Check time", value: checkTime });
- stats.push({ key: "Emit time", value: emitTime });
- stats.push({
- key: "Total TS time",
- value: programTime + bindTime + checkTime + emitTime,
- });
+ stats.push(["Parse time", programTime]);
+ stats.push(["Bind time", bindTime]);
+ stats.push(["Check time", checkTime]);
+ stats.push(["Emit time", emitTime]);
+ stats.push(
+ ["Total TS time", programTime + bindTime + checkTime + emitTime],
+ );
}
function performanceEnd() {
const duration = new Date() - statsStart;
- stats.push({ key: "Compile time", value: duration });
+ stats.push(["Compile time", duration]);
return stats;
}
@@ -645,17 +323,12 @@ delete Object.prototype.__proto__;
...program.getGlobalDiagnostics(),
...program.getSemanticDiagnostics(),
...emitDiagnostics,
- ].filter(({ code }) =>
- !IGNORED_DIAGNOSTICS.includes(code) &&
- !IGNORED_COMPILE_DIAGNOSTICS.includes(code)
- );
+ ].filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code));
performanceProgram({ program });
- // TODO(@kitsonk) when legacy stats are removed, convert to just tuples
- let stats = performanceEnd().map(({ key, value }) => [key, value]);
core.jsonOpSync("op_respond", {
diagnostics: fromTypeScriptDiagnostic(diagnostics),
- stats,
+ stats: performanceEnd(),
});
debug("<<< exec stop");
}
@@ -665,7 +338,7 @@ delete Object.prototype.__proto__;
/** Startup the runtime environment, setting various flags.
* @param {{ debugFlag?: boolean; legacyFlag?: boolean; }} msg
*/
- function startup({ debugFlag = false, legacyFlag = true }) {
+ function startup({ debugFlag = false }) {
if (hasStarted) {
throw new Error("The compiler runtime already started.");
}
@@ -673,9 +346,42 @@ delete Object.prototype.__proto__;
core.ops();
core.registerErrorClass("Error", Error);
setLogDebug(!!debugFlag, "TS");
- legacy = legacyFlag;
}
+ // Setup the compiler runtime during the build process.
+ core.ops();
+ core.registerErrorClass("Error", Error);
+
+ // A build time only op that provides some setup information that is used to
+ // ensure the snapshot is setup properly.
+ /** @type {{ buildSpecifier: string; libs: string[] }} */
+ const { buildSpecifier, libs } = core.jsonOpSync("op_build_info", {});
+ for (const lib of libs) {
+ let specifier = `lib.${lib}.d.ts`;
+ // we are using internal APIs here to "inject" our custom libraries into
+ // tsc, so things like `"lib": [ "deno.ns" ]` are supported.
+ if (!ts.libs.includes(lib)) {
+ ts.libs.push(lib);
+ ts.libMap.set(lib, `lib.${lib}.d.ts`);
+ }
+ // we are caching in memory common type libraries that will be re-used by
+ // tsc on when the snapshot is restored
+ assert(
+ host.getSourceFile(`${ASSETS}${specifier}`, ts.ScriptTarget.ESNext),
+ );
+ }
+ // this helps ensure as much as possible is in memory that is re-usable
+ // before the snapshotting is done, which helps unsure fast "startup" for
+ // subsequent uses of tsc in Deno.
+ const TS_SNAPSHOT_PROGRAM = ts.createProgram({
+ rootNames: [buildSpecifier],
+ options: SNAPSHOT_COMPILE_OPTIONS,
+ host,
+ });
+ ts.getPreEmitDiagnostics(TS_SNAPSHOT_PROGRAM);
+
+ // exposes the two functions that are called by `tsc::exec()` when type
+ // checking TypeScript.
globalThis.startup = startup;
globalThis.exec = exec;
})(this);