diff options
Diffstat (limited to 'cli/js2/99_main_compiler.js')
-rw-r--r-- | cli/js2/99_main_compiler.js | 1867 |
1 files changed, 0 insertions, 1867 deletions
diff --git a/cli/js2/99_main_compiler.js b/cli/js2/99_main_compiler.js deleted file mode 100644 index d64896862..000000000 --- a/cli/js2/99_main_compiler.js +++ /dev/null @@ -1,1867 +0,0 @@ -// 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 a single functions that should be called by Rust: -// - `bootstrapTsCompilerRuntime` -// This functions must be called when creating isolate -// to properly setup runtime. - -// Removes the `__proto__` for security reasons. This intentionally makes -// Deno non compliant with ECMA-262 Annex B.2.2.1 -// -// eslint-disable-next-line @typescript-eslint/no-explicit-any -delete Object.prototype.__proto__; - -((window) => { - const core = Deno.core; - const { bold, cyan, yellow } = window.__bootstrap.colors; - const { assert, log, notImplemented } = window.__bootstrap.util; - const { DiagnosticCategory } = window.__bootstrap.diagnostics; - - const unstableDenoGlobalProperties = [ - "umask", - "linkSync", - "link", - "symlinkSync", - "symlink", - "loadavg", - "osRelease", - "openPlugin", - "DiagnosticCategory", - "DiagnosticMessageChain", - "DiagnosticItem", - "Diagnostic", - "formatDiagnostics", - "CompilerOptions", - "TranspileOnlyResult", - "transpileOnly", - "compile", - "bundle", - "Location", - "applySourceMap", - "LinuxSignal", - "MacOSSignal", - "Signal", - "SignalStream", - "signal", - "signals", - "setRaw", - "utimeSync", - "utime", - "ShutdownMode", - "shutdown", - "DatagramConn", - "UnixListenOptions", - "listen", - "listenDatagram", - "UnixConnectOptions", - "connect", - "StartTlsOptions", - "startTls", - "kill", - "PermissionName", - "PermissionState", - "RunPermissionDescriptor", - "ReadPermissionDescriptor", - "WritePermissionDescriptor", - "NetPermissionDescriptor", - "EnvPermissionDescriptor", - "PluginPermissionDescriptor", - "HrtimePermissionDescriptor", - "PermissionDescriptor", - "Permissions", - "PermissionStatus", - "hostname", - "ppid", - ]; - - function transformMessageText(messageText, code) { - switch (code) { - case 2339: { - const property = messageText - .replace(/^Property '/, "") - .replace(/' does not exist on type 'typeof Deno'\./, ""); - - if ( - messageText.endsWith("on type 'typeof Deno'.") && - unstableDenoGlobalProperties.includes(property) - ) { - return `${messageText} 'Deno.${property}' is an unstable API. Did you forget to run with the '--unstable' flag?`; - } - break; - } - case 2551: { - const suggestionMessagePattern = / Did you mean '(.+)'\?$/; - const property = messageText - .replace(/^Property '/, "") - .replace(/' does not exist on type 'typeof Deno'\./, "") - .replace(suggestionMessagePattern, ""); - const suggestion = messageText.match(suggestionMessagePattern); - const replacedMessageText = messageText.replace( - suggestionMessagePattern, - "", - ); - if (suggestion && unstableDenoGlobalProperties.includes(property)) { - const suggestedProperty = suggestion[1]; - return `${replacedMessageText} 'Deno.${property}' is an unstable API. Did you forget to run with the '--unstable' flag, or did you mean '${suggestedProperty}'?`; - } - break; - } - } - - return messageText; - } - - function fromDiagnosticCategory( - category, - ) { - switch (category) { - case ts.DiagnosticCategory.Error: - return DiagnosticCategory.Error; - case ts.DiagnosticCategory.Message: - return DiagnosticCategory.Info; - case ts.DiagnosticCategory.Suggestion: - return DiagnosticCategory.Suggestion; - case ts.DiagnosticCategory.Warning: - return DiagnosticCategory.Warning; - default: - throw new Error( - `Unexpected DiagnosticCategory: "${category}"/"${ - ts.DiagnosticCategory[category] - }"`, - ); - } - } - - function getSourceInformation( - sourceFile, - start, - length, - ) { - const scriptResourceName = sourceFile.fileName; - const { - line: lineNumber, - character: startColumn, - } = sourceFile.getLineAndCharacterOfPosition(start); - const endPosition = sourceFile.getLineAndCharacterOfPosition( - start + length, - ); - const endColumn = lineNumber === endPosition.line - ? endPosition.character - : startColumn; - const lastLineInFile = sourceFile.getLineAndCharacterOfPosition( - sourceFile.text.length, - ).line; - const lineStart = sourceFile.getPositionOfLineAndCharacter(lineNumber, 0); - const lineEnd = lineNumber < lastLineInFile - ? sourceFile.getPositionOfLineAndCharacter(lineNumber + 1, 0) - : sourceFile.text.length; - const sourceLine = sourceFile.text - .slice(lineStart, lineEnd) - .replace(/\s+$/g, "") - .replace("\t", " "); - return { - sourceLine, - lineNumber, - scriptResourceName, - startColumn, - endColumn, - }; - } - - function fromDiagnosticMessageChain( - messageChain, - ) { - if (!messageChain) { - return undefined; - } - - return messageChain.map(({ messageText, code, category, next }) => { - const message = transformMessageText(messageText, code); - return { - message, - code, - category: fromDiagnosticCategory(category), - next: fromDiagnosticMessageChain(next), - }; - }); - } - - function parseDiagnostic( - item, - ) { - const { - messageText, - category: sourceCategory, - code, - file, - start: startPosition, - length, - } = item; - const sourceInfo = file && startPosition && length - ? getSourceInformation(file, startPosition, length) - : undefined; - const endPosition = startPosition && length - ? startPosition + length - : undefined; - const category = fromDiagnosticCategory(sourceCategory); - - let message; - let messageChain; - if (typeof messageText === "string") { - message = transformMessageText(messageText, code); - } else { - message = transformMessageText(messageText.messageText, messageText.code); - messageChain = fromDiagnosticMessageChain([messageText])[0]; - } - - const base = { - message, - messageChain, - code, - category, - startPosition, - endPosition, - }; - - return sourceInfo ? { ...base, ...sourceInfo } : base; - } - - function parseRelatedInformation( - relatedInformation, - ) { - const result = []; - for (const item of relatedInformation) { - result.push(parseDiagnostic(item)); - } - return result; - } - - function fromTypeScriptDiagnostic( - diagnostics, - ) { - const items = []; - for (const sourceDiagnostic of diagnostics) { - const item = parseDiagnostic(sourceDiagnostic); - if (sourceDiagnostic.relatedInformation) { - item.relatedInformation = parseRelatedInformation( - sourceDiagnostic.relatedInformation, - ); - } - items.push(item); - } - return { items }; - } - - // 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); - } - - // Constants used by `normalizeString` and `resolvePath` - const CHAR_DOT = 46; /* . */ - const CHAR_FORWARD_SLASH = 47; /* / */ - // 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://"; - // 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"; - - // TODO(Bartlomieju): this check should be done in Rust - const IGNORED_COMPILER_OPTIONS = [ - "allowSyntheticDefaultImports", - "allowUmdGlobalAccess", - "assumeChangesOnlyAffectDirectDependencies", - "baseUrl", - "build", - "composite", - "declaration", - "declarationDir", - "declarationMap", - "diagnostics", - "downlevelIteration", - "emitBOM", - "emitDeclarationOnly", - "esModuleInterop", - "extendedDiagnostics", - "forceConsistentCasingInFileNames", - "generateCpuProfile", - "help", - "importHelpers", - "incremental", - "inlineSourceMap", - "inlineSources", - "init", - "listEmittedFiles", - "listFiles", - "mapRoot", - "maxNodeModuleJsDepth", - "module", - "moduleResolution", - "newLine", - "noEmit", - "noEmitHelpers", - "noEmitOnError", - "noLib", - "noResolve", - "out", - "outDir", - "outFile", - "paths", - "preserveSymlinks", - "preserveWatchOutput", - "pretty", - "rootDir", - "rootDirs", - "showConfig", - "skipDefaultLibCheck", - "skipLibCheck", - "sourceMap", - "sourceRoot", - "stripInternal", - "target", - "traceResolution", - "tsBuildInfoFile", - "types", - "typeRoots", - "version", - "watch", - ]; - - const DEFAULT_BUNDLER_OPTIONS = { - allowJs: true, - inlineSourceMap: false, - module: ts.ModuleKind.System, - outDir: undefined, - outFile: `${OUT_DIR}/bundle.js`, - // disabled until we have effective way to modify source maps - sourceMap: false, - }; - - const DEFAULT_INCREMENTAL_COMPILE_OPTIONS = { - allowJs: false, - allowNonTsExtensions: true, - checkJs: false, - esModuleInterop: true, - incremental: true, - inlineSourceMap: true, - jsx: ts.JsxEmit.React, - module: ts.ModuleKind.ESNext, - outDir: OUT_DIR, - resolveJsonModule: true, - sourceMap: false, - strict: true, - stripComments: true, - target: ts.ScriptTarget.ESNext, - tsBuildInfoFile: TS_BUILD_INFO, - }; - - const DEFAULT_COMPILE_OPTIONS = { - allowJs: false, - allowNonTsExtensions: true, - checkJs: false, - esModuleInterop: true, - jsx: ts.JsxEmit.React, - module: ts.ModuleKind.ESNext, - outDir: OUT_DIR, - sourceMap: true, - strict: true, - removeComments: true, - target: ts.ScriptTarget.ESNext, - }; - - const DEFAULT_TRANSPILE_OPTIONS = { - esModuleInterop: true, - inlineSourceMap: true, - jsx: ts.JsxEmit.React, - module: ts.ModuleKind.ESNext, - removeComments: true, - target: ts.ScriptTarget.ESNext, - }; - - const DEFAULT_RUNTIME_COMPILE_OPTIONS = { - outDir: undefined, - }; - - const DEFAULT_RUNTIME_TRANSPILE_OPTIONS = { - esModuleInterop: true, - module: ts.ModuleKind.ESNext, - sourceMap: true, - scriptComments: 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: "TSX", - 4: "Json", - 5: "Wasm", - 6: "Unknown", - JavaScript: 0, - JSX: 1, - TypeScript: 2, - TSX: 3, - Json: 4, - Wasm: 5, - Unknown: 6, - }; - - function getExtension(fileName, mediaType) { - switch (mediaType) { - case MediaType.JavaScript: - return ts.Extension.Js; - case MediaType.JSX: - return ts.Extension.Jsx; - case MediaType.TypeScript: - return fileName.endsWith(".d.ts") ? ts.Extension.Dts : ts.Extension.Ts; - 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(); - - function configure( - defaultOptions, - source, - path, - cwd, - ) { - const { config, error } = ts.parseConfigFileTextToJson(path, source); - if (error) { - return { diagnostics: [error], options: defaultOptions }; - } - const { options, errors } = ts.convertCompilerOptionsFromJson( - config.compilerOptions, - cwd, - ); - const ignoredOptions = []; - for (const key of Object.keys(options)) { - if ( - IGNORED_COMPILER_OPTIONS.includes(key) && - (!(key in defaultOptions) || options[key] !== defaultOptions[key]) - ) { - ignoredOptions.push(key); - delete options[key]; - } - } - return { - options: Object.assign({}, defaultOptions, options), - ignoredOptions: ignoredOptions.length ? ignoredOptions : undefined, - diagnostics: errors.length ? errors : undefined, - }; - } - - 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, - }); - } - - class Host { - #options = DEFAULT_COMPILE_OPTIONS; - #target = ""; - #writeFile = null; - /* Deno specific APIs */ - - constructor({ - bundle = false, - incremental = false, - target, - unstable, - writeFile, - }) { - this.#target = target; - this.#writeFile = writeFile; - if (bundle) { - // options we need to change when we are generating a bundle - Object.assign(this.#options, DEFAULT_BUNDLER_OPTIONS); - } else if (incremental) { - Object.assign(this.#options, DEFAULT_INCREMENTAL_COMPILE_OPTIONS); - } - if (unstable) { - this.#options.lib = [ - target === CompilerHostTarget.Worker - ? "lib.deno.worker.d.ts" - : "lib.deno.window.d.ts", - "lib.deno.unstable.d.ts", - ]; - } - } - - get options() { - return this.#options; - } - - configure( - cwd, - path, - configurationText, - ) { - log("compiler::host.configure", path); - const { options, ...result } = configure( - this.#options, - configurationText, - path, - cwd, - ); - this.#options = options; - return result; - } - - mergeOptions(...options) { - Object.assign(this.#options, ...options); - return Object.assign({}, this.#options); - } - - /* TypeScript CompilerHost APIs */ - - fileExists(_fileName) { - return notImplemented(); - } - - getCanonicalFileName(fileName) { - return fileName; - } - - getCompilationSettings() { - log("compiler::host.getCompilationSettings()"); - return this.#options; - } - - getCurrentDirectory() { - return ""; - } - - getDefaultLibFileName(_options) { - log("compiler::host.getDefaultLibFileName()"); - switch (this.#target) { - case CompilerHostTarget.Main: - case CompilerHostTarget.Runtime: - return `${ASSETS}/lib.deno.window.d.ts`; - case CompilerHostTarget.Worker: - return `${ASSETS}/lib.deno.worker.d.ts`; - } - } - - getNewLine() { - return "\n"; - } - - getSourceFile( - fileName, - languageVersion, - onError, - shouldCreateNewSourceFile, - ) { - log("compiler::host.getSourceFile", fileName); - try { - assert(!shouldCreateNewSourceFile); - const sourceFile = fileName.startsWith(ASSETS) - ? getAssetInternal(fileName) - : SourceFile.getCached(fileName); - assert(sourceFile != null); - if (!sourceFile.tsSourceFile) { - assert(sourceFile.sourceCode != null); - const tsSourceFileName = fileName.startsWith(ASSETS) - ? sourceFile.filename - : fileName; - - sourceFile.tsSourceFile = ts.createSourceFile( - tsSourceFileName, - sourceFile.sourceCode, - languageVersion, - ); - sourceFile.tsSourceFile.version = sourceFile.versionHash; - delete sourceFile.sourceCode; - } - return sourceFile.tsSourceFile; - } catch (e) { - if (onError) { - onError(String(e)); - } else { - throw e; - } - return undefined; - } - } - - readFile(_fileName) { - return notImplemented(); - } - - resolveModuleNames( - moduleNames, - containingFile, - ) { - log("compiler::host.resolveModuleNames", { - moduleNames, - containingFile, - }); - const resolved = moduleNames.map((specifier) => { - const maybeUrl = SourceFile.getResolvedUrl(specifier, containingFile); - - log("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, - }; - }); - log(resolved); - return resolved; - } - - useCaseSensitiveFileNames() { - return true; - } - - writeFile( - fileName, - data, - _writeByteOrderMark, - _onError, - sourceFiles, - ) { - log("compiler::host.writeFile", fileName); - this.#writeFile(fileName, data, sourceFiles); - } - } - - class IncrementalCompileHost extends Host { - #buildInfo = ""; - - constructor(options) { - super({ ...options, incremental: true }); - const { buildInfo } = options; - if (buildInfo) { - this.#buildInfo = buildInfo; - } - } - - readFile(fileName) { - if (fileName == TS_BUILD_INFO) { - return this.#buildInfo; - } - throw new Error("unreachable"); - } - } - - // NOTE: target doesn't really matter here, - // this is in fact a mock host created just to - // load all type definitions and snapshot them. - let SNAPSHOT_HOST = new Host({ - target: CompilerHostTarget.Main, - writeFile() {}, - }); - const SNAPSHOT_COMPILER_OPTIONS = SNAPSHOT_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 - 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"); - ts.libMap.set("deno.unstable", "lib.deno.unstable.d.ts"); - - // this pre-populates the cache at snapshot time of our library files, so they - // are available in the future when needed. - SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.ns.d.ts`, - ts.ScriptTarget.ESNext, - ); - SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.window.d.ts`, - ts.ScriptTarget.ESNext, - ); - SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.worker.d.ts`, - ts.ScriptTarget.ESNext, - ); - SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.shared_globals.d.ts`, - ts.ScriptTarget.ESNext, - ); - SNAPSHOT_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: SNAPSHOT_COMPILER_OPTIONS, - host: SNAPSHOT_HOST, - }); - - // Derference the snapshot host so it can be GCed - SNAPSHOT_HOST = undefined; - - // This function is called only during snapshotting process - const SYSTEM_LOADER = getAsset("system_loader.js"); - const SYSTEM_LOADER_ES5 = getAsset("system_loader_es5.js"); - - function buildLocalSourceFileCache( - sourceFileMap, - ) { - for (const entry of Object.values(sourceFileMap)) { - assert(entry.sourceCode.length > 0); - SourceFile.addToCache({ - url: entry.url, - filename: entry.url, - mediaType: entry.mediaType, - sourceCode: entry.sourceCode, - versionHash: entry.versionHash, - }); - - for (const importDesc of entry.imports) { - let mappedUrl = importDesc.resolvedSpecifier; - const importedFile = sourceFileMap[importDesc.resolvedSpecifier]; - assert(importedFile); - const isJsOrJsx = importedFile.mediaType === MediaType.JavaScript || - importedFile.mediaType === MediaType.JSX; - // If JS or JSX perform substitution for types if available - if (isJsOrJsx) { - if (importedFile.typeHeaders.length > 0) { - const typeHeaders = importedFile.typeHeaders[0]; - mappedUrl = typeHeaders.resolvedSpecifier; - } else if (importDesc.resolvedTypeDirective) { - mappedUrl = importDesc.resolvedTypeDirective; - } else if (importedFile.typesDirectives.length > 0) { - const typeDirective = importedFile.typesDirectives[0]; - mappedUrl = typeDirective.resolvedSpecifier; - } - } - - mappedUrl = mappedUrl.replace("memory://", ""); - SourceFile.cacheResolvedUrl(mappedUrl, importDesc.specifier, entry.url); - } - for (const fileRef of entry.referencedFiles) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier.replace("memory://", ""), - fileRef.specifier, - entry.url, - ); - } - for (const fileRef of entry.libDirectives) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier.replace("memory://", ""), - fileRef.specifier, - entry.url, - ); - } - } - } - - function buildSourceFileCache( - sourceFileMap, - ) { - for (const entry of Object.values(sourceFileMap)) { - SourceFile.addToCache({ - url: entry.url, - filename: entry.url, - mediaType: entry.mediaType, - sourceCode: entry.sourceCode, - versionHash: entry.versionHash, - }); - - for (const importDesc of entry.imports) { - let mappedUrl = importDesc.resolvedSpecifier; - const importedFile = sourceFileMap[importDesc.resolvedSpecifier]; - // IMPORTANT: due to HTTP redirects we might end up in situation - // where URL points to a file with completely different URL. - // In that case we take value of `redirect` field and cache - // resolved specifier pointing to the value of the redirect. - // It's not very elegant solution and should be rethinked. - assert(importedFile); - if (importedFile.redirect) { - mappedUrl = importedFile.redirect; - } - const isJsOrJsx = importedFile.mediaType === MediaType.JavaScript || - importedFile.mediaType === MediaType.JSX; - // If JS or JSX perform substitution for types if available - if (isJsOrJsx) { - if (importedFile.typeHeaders.length > 0) { - const typeHeaders = importedFile.typeHeaders[0]; - mappedUrl = typeHeaders.resolvedSpecifier; - } else if (importDesc.resolvedTypeDirective) { - mappedUrl = importDesc.resolvedTypeDirective; - } else if (importedFile.typesDirectives.length > 0) { - const typeDirective = importedFile.typesDirectives[0]; - mappedUrl = typeDirective.resolvedSpecifier; - } - } - - SourceFile.cacheResolvedUrl(mappedUrl, importDesc.specifier, entry.url); - } - for (const fileRef of entry.referencedFiles) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier, - fileRef.specifier, - entry.url, - ); - } - for (const fileRef of entry.libDirectives) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier, - fileRef.specifier, - entry.url, - ); - } - } - } - - // Warning! The values in this enum are duplicated in `cli/msg.rs` - // Update carefully! - const CompilerRequestType = { - Compile: 0, - Transpile: 1, - Bundle: 2, - RuntimeCompile: 3, - RuntimeBundle: 4, - RuntimeTranspile: 5, - }; - - function createBundleWriteFile(state) { - return function writeFile( - _fileName, - data, - sourceFiles, - ) { - assert(sourceFiles != null); - assert(state.host); - // we only support single root names for bundles - assert(state.rootNames.length === 1); - state.bundleOutput = buildBundle( - state.rootNames[0], - data, - sourceFiles, - state.host.options.target ?? ts.ScriptTarget.ESNext, - ); - }; - } - - function createCompileWriteFile( - state, - ) { - return function writeFile( - fileName, - data, - sourceFiles, - ) { - const isBuildInfo = fileName === TS_BUILD_INFO; - - if (isBuildInfo) { - assert(isBuildInfo); - state.buildInfo = data; - return; - } - - assert(sourceFiles); - assert(sourceFiles.length === 1); - state.emitMap[fileName] = { - filename: sourceFiles[0].fileName, - contents: data, - }; - }; - } - - function createRuntimeCompileWriteFile( - state, - ) { - return function writeFile( - fileName, - data, - sourceFiles, - ) { - assert(sourceFiles); - assert(sourceFiles.length === 1); - state.emitMap[fileName] = { - filename: sourceFiles[0].fileName, - contents: data, - }; - }; - } - - function convertCompilerOptions(str) { - const options = JSON.parse(str); - const out = {}; - const keys = Object.keys(options); - const files = []; - for (const key of keys) { - switch (key) { - case "jsx": - const value = options[key]; - if (value === "preserve") { - out[key] = ts.JsxEmit.Preserve; - } else if (value === "react") { - out[key] = ts.JsxEmit.React; - } else { - out[key] = ts.JsxEmit.ReactNative; - } - break; - case "module": - switch (options[key]) { - case "amd": - out[key] = ts.ModuleKind.AMD; - break; - case "commonjs": - out[key] = ts.ModuleKind.CommonJS; - break; - case "es2015": - case "es6": - out[key] = ts.ModuleKind.ES2015; - break; - case "esnext": - out[key] = ts.ModuleKind.ESNext; - break; - case "none": - out[key] = ts.ModuleKind.None; - break; - case "system": - out[key] = ts.ModuleKind.System; - break; - case "umd": - out[key] = ts.ModuleKind.UMD; - break; - default: - throw new TypeError("Unexpected module type"); - } - break; - case "target": - switch (options[key]) { - case "es3": - out[key] = ts.ScriptTarget.ES3; - break; - case "es5": - out[key] = ts.ScriptTarget.ES5; - break; - case "es6": - case "es2015": - out[key] = ts.ScriptTarget.ES2015; - break; - case "es2016": - out[key] = ts.ScriptTarget.ES2016; - break; - case "es2017": - out[key] = ts.ScriptTarget.ES2017; - break; - case "es2018": - out[key] = ts.ScriptTarget.ES2018; - break; - case "es2019": - out[key] = ts.ScriptTarget.ES2019; - break; - case "es2020": - out[key] = ts.ScriptTarget.ES2020; - break; - case "esnext": - out[key] = ts.ScriptTarget.ESNext; - break; - default: - throw new TypeError("Unexpected emit target."); - } - break; - case "types": - const types = options[key]; - assert(types); - files.push(...types); - break; - default: - out[key] = options[key]; - } - } - return { - options: out, - files: files.length ? files : undefined, - }; - } - - const ignoredDiagnostics = [ - // 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 stats = []; - let statsStart = 0; - - function performanceStart() { - stats.length = 0; - // TODO(kitsonk) replace with performance.mark() when landed - statsStart = performance.now(); - ts.performance.enable(); - } - - function performanceProgram({ - program, - fileCount, - }) { - if (program) { - 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(), - }); - } else if (fileCount != null) { - stats.push({ key: "Files", value: 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, - }); - } - - function performanceEnd() { - // TODO(kitsonk) replace with performance.measure() when landed - const duration = performance.now() - statsStart; - stats.push({ key: "Compile time", value: duration }); - return stats; - } - - // TODO(Bartlomieju): this check should be done in Rust; there should be no - function processConfigureResponse( - configResult, - configPath, - ) { - const { ignoredOptions, diagnostics } = configResult; - if (ignoredOptions) { - console.warn( - yellow(`Unsupported compiler options in "${configPath}"\n`) + - cyan(` The following options were ignored:\n`) + - ` ${ignoredOptions.map((value) => bold(value)).join(", ")}`, - ); - } - return diagnostics; - } - - function normalizeString(path) { - let res = ""; - let lastSegmentLength = 0; - let lastSlash = -1; - let dots = 0; - let code; - for (let i = 0, len = path.length; i <= len; ++i) { - if (i < len) code = path.charCodeAt(i); - else if (code === CHAR_FORWARD_SLASH) break; - else code = CHAR_FORWARD_SLASH; - - if (code === CHAR_FORWARD_SLASH) { - if (lastSlash === i - 1 || dots === 1) { - // NOOP - } else if (lastSlash !== i - 1 && dots === 2) { - if ( - res.length < 2 || - lastSegmentLength !== 2 || - res.charCodeAt(res.length - 1) !== CHAR_DOT || - res.charCodeAt(res.length - 2) !== CHAR_DOT - ) { - if (res.length > 2) { - const lastSlashIndex = res.lastIndexOf("/"); - if (lastSlashIndex === -1) { - res = ""; - lastSegmentLength = 0; - } else { - res = res.slice(0, lastSlashIndex); - lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); - } - lastSlash = i; - dots = 0; - continue; - } else if (res.length === 2 || res.length === 1) { - res = ""; - lastSegmentLength = 0; - lastSlash = i; - dots = 0; - continue; - } - } - } else { - if (res.length > 0) res += "/" + path.slice(lastSlash + 1, i); - else res = path.slice(lastSlash + 1, i); - lastSegmentLength = i - lastSlash - 1; - } - lastSlash = i; - dots = 0; - } else if (code === CHAR_DOT && dots !== -1) { - ++dots; - } else { - dots = -1; - } - } - return res; - } - - function commonPath(paths, sep = "/") { - const [first = "", ...remaining] = paths; - if (first === "" || remaining.length === 0) { - return first.substring(0, first.lastIndexOf(sep) + 1); - } - const parts = first.split(sep); - - let endOfPrefix = parts.length; - for (const path of remaining) { - const compare = path.split(sep); - for (let i = 0; i < endOfPrefix; i++) { - if (compare[i] !== parts[i]) { - endOfPrefix = i; - } - } - - if (endOfPrefix === 0) { - return ""; - } - } - const prefix = parts.slice(0, endOfPrefix).join(sep); - return prefix.endsWith(sep) ? prefix : `${prefix}${sep}`; - } - - let rootExports; - - function normalizeUrl(rootName) { - const match = /^(\S+:\/{2,3})(.+)$/.exec(rootName); - if (match) { - const [, protocol, path] = match; - return `${protocol}${normalizeString(path)}`; - } else { - return rootName; - } - } - - function buildBundle( - rootName, - data, - sourceFiles, - target, - ) { - // when outputting to AMD and a single outfile, TypeScript makes up the module - // specifiers which are used to define the modules, and doesn't expose them - // publicly, so we have to try to replicate - const sources = sourceFiles.map((sf) => sf.fileName); - const sharedPath = commonPath(sources); - rootName = normalizeUrl(rootName) - .replace(sharedPath, "") - .replace(/\.\w+$/i, ""); - // If one of the modules requires support for top-level-await, TypeScript will - // emit the execute function as an async function. When this is the case we - // need to bubble up the TLA to the instantiation, otherwise we instantiate - // synchronously. - const hasTla = data.match(/execute:\sasync\sfunction\s/); - let instantiate; - if (rootExports && rootExports.length) { - instantiate = hasTla - ? `const __exp = await __instantiate("${rootName}", true);\n` - : `const __exp = __instantiate("${rootName}", false);\n`; - for (const rootExport of rootExports) { - if (rootExport === "default") { - instantiate += `export default __exp["${rootExport}"];\n`; - } else { - instantiate += - `export const ${rootExport} = __exp["${rootExport}"];\n`; - } - } - } else { - instantiate = hasTla - ? `await __instantiate("${rootName}", true);\n` - : `__instantiate("${rootName}", false);\n`; - } - const es5Bundle = target === ts.ScriptTarget.ES3 || - target === ts.ScriptTarget.ES5 || - target === ts.ScriptTarget.ES2015 || - target === ts.ScriptTarget.ES2016; - return `${ - es5Bundle ? SYSTEM_LOADER_ES5 : SYSTEM_LOADER - }\n${data}\n${instantiate}`; - } - - function setRootExports(program, rootModule) { - // get a reference to the type checker, this will let us find symbols from - // the AST. - const checker = program.getTypeChecker(); - // get a reference to the main source file for the bundle - const mainSourceFile = program.getSourceFile(rootModule); - assert(mainSourceFile); - // retrieve the internal TypeScript symbol for this AST node - const mainSymbol = checker.getSymbolAtLocation(mainSourceFile); - if (!mainSymbol) { - return; - } - rootExports = checker - .getExportsOfModule(mainSymbol) - // .getExportsOfModule includes type only symbols which are exported from - // the module, so we need to try to filter those out. While not critical - // someone looking at the bundle would think there is runtime code behind - // that when there isn't. There appears to be no clean way of figuring that - // out, so inspecting SymbolFlags that might be present that are type only - .filter( - (sym) => - sym.flags & ts.SymbolFlags.Class || - !( - sym.flags & ts.SymbolFlags.Interface || - sym.flags & ts.SymbolFlags.TypeLiteral || - sym.flags & ts.SymbolFlags.Signature || - sym.flags & ts.SymbolFlags.TypeParameter || - sym.flags & ts.SymbolFlags.TypeAlias || - sym.flags & ts.SymbolFlags.Type || - sym.flags & ts.SymbolFlags.Namespace || - sym.flags & ts.SymbolFlags.InterfaceExcludes || - sym.flags & ts.SymbolFlags.TypeParameterExcludes || - sym.flags & ts.SymbolFlags.TypeAliasExcludes - ), - ) - .map((sym) => sym.getName()); - } - - function compile({ - allowJs, - buildInfo, - config, - configPath, - rootNames, - target, - unstable, - cwd, - sourceFileMap, - type, - performance, - }) { - if (performance) { - performanceStart(); - } - log(">>> compile start", { rootNames, type: CompilerRequestType[type] }); - - // When a programme is emitted, TypeScript will call `writeFile` with - // each file that needs to be emitted. The Deno compiler host delegates - // this, to make it easier to perform the right actions, which vary - // based a lot on the request. - const state = { - rootNames, - emitMap: {}, - }; - const host = new IncrementalCompileHost({ - bundle: false, - target, - unstable, - writeFile: createCompileWriteFile(state), - rootNames, - buildInfo, - }); - let diagnostics = []; - - host.mergeOptions({ allowJs }); - - // if there is a configuration supplied, we need to parse that - if (config && config.length && configPath) { - const configResult = host.configure(cwd, configPath, config); - diagnostics = processConfigureResponse(configResult, configPath) || []; - } - - buildSourceFileCache(sourceFileMap); - // if there was a configuration and no diagnostics with it, we will continue - // to generate the program and possibly emit it. - if (diagnostics.length === 0) { - const options = host.getCompilationSettings(); - const program = ts.createIncrementalProgram({ - rootNames, - options, - host, - }); - - // TODO(bartlomieju): check if this is ok - diagnostics = [ - ...program.getConfigFileParsingDiagnostics(), - ...program.getSyntacticDiagnostics(), - ...program.getOptionsDiagnostics(), - ...program.getGlobalDiagnostics(), - ...program.getSemanticDiagnostics(), - ]; - diagnostics = diagnostics.filter( - ({ code }) => !ignoredDiagnostics.includes(code), - ); - - // We will only proceed with the emit if there are no diagnostics. - if (diagnostics.length === 0) { - const emitResult = program.emit(); - // If `checkJs` is off we still might be compiling entry point JavaScript file - // (if it has `.ts` imports), but it won't be emitted. In that case we skip - // assertion. - if (options.checkJs) { - assert( - emitResult.emitSkipped === false, - "Unexpected skip of the emit.", - ); - } - // emitResult.diagnostics is `readonly` in TS3.5+ and can't be assigned - // without casting. - diagnostics = emitResult.diagnostics; - } - performanceProgram({ program }); - } - - log("<<< compile end", { rootNames, type: CompilerRequestType[type] }); - const stats = performance ? performanceEnd() : undefined; - - return { - emitMap: state.emitMap, - buildInfo: state.buildInfo, - diagnostics: fromTypeScriptDiagnostic(diagnostics), - stats, - }; - } - - function transpile({ - config: configText, - configPath, - cwd, - performance, - sourceFiles, - }) { - if (performance) { - performanceStart(); - } - log(">>> transpile start"); - let compilerOptions; - if (configText && configPath && cwd) { - const { options, ...response } = configure( - DEFAULT_TRANSPILE_OPTIONS, - configText, - configPath, - cwd, - ); - const diagnostics = processConfigureResponse(response, configPath); - if (diagnostics && diagnostics.length) { - return { - diagnostics: fromTypeScriptDiagnostic(diagnostics), - emitMap: {}, - }; - } - compilerOptions = options; - } else { - compilerOptions = Object.assign({}, DEFAULT_TRANSPILE_OPTIONS); - } - const emitMap = {}; - let diagnostics = []; - for (const { sourceCode, fileName } of sourceFiles) { - const { - outputText, - sourceMapText, - diagnostics: diags, - } = ts.transpileModule(sourceCode, { - fileName, - compilerOptions, - reportDiagnostics: true, - }); - if (diags) { - diagnostics = diagnostics.concat(...diags); - } - emitMap[`${fileName}.js`] = { filename: fileName, contents: outputText }; - // currently we inline source maps, but this is good logic to have if this - // ever changes - if (sourceMapText) { - emitMap[`${fileName}.map`] = { - filename: fileName, - contents: sourceMapText, - }; - } - } - performanceProgram({ fileCount: sourceFiles.length }); - const stats = performance ? performanceEnd() : undefined; - log("<<< transpile end"); - return { - diagnostics: fromTypeScriptDiagnostic(diagnostics), - emitMap, - stats, - }; - } - - function bundle({ - config, - configPath, - rootNames, - target, - unstable, - cwd, - sourceFileMap, - type, - }) { - if (performance) { - performanceStart(); - } - log(">>> bundle start", { - rootNames, - type: CompilerRequestType[type], - }); - - // When a programme is emitted, TypeScript will call `writeFile` with - // each file that needs to be emitted. The Deno compiler host delegates - // this, to make it easier to perform the right actions, which vary - // based a lot on the request. - const state = { - rootNames, - bundleOutput: undefined, - }; - const host = new Host({ - bundle: true, - target, - unstable, - writeFile: createBundleWriteFile(state), - }); - state.host = host; - let diagnostics = []; - - // if there is a configuration supplied, we need to parse that - if (config && config.length && configPath) { - const configResult = host.configure(cwd, configPath, config); - diagnostics = processConfigureResponse(configResult, configPath) || []; - } - - buildSourceFileCache(sourceFileMap); - // if there was a configuration and no diagnostics with it, we will continue - // to generate the program and possibly emit it. - if (diagnostics.length === 0) { - const options = host.getCompilationSettings(); - const program = ts.createProgram({ - rootNames, - options, - host, - }); - - diagnostics = ts - .getPreEmitDiagnostics(program) - .filter(({ code }) => !ignoredDiagnostics.includes(code)); - - // We will only proceed with the emit if there are no diagnostics. - if (diagnostics.length === 0) { - // we only support a single root module when bundling - assert(rootNames.length === 1); - setRootExports(program, rootNames[0]); - const emitResult = program.emit(); - assert( - emitResult.emitSkipped === false, - "Unexpected skip of the emit.", - ); - // emitResult.diagnostics is `readonly` in TS3.5+ and can't be assigned - // without casting. - diagnostics = emitResult.diagnostics; - } - if (performance) { - performanceProgram({ program }); - } - } - - let bundleOutput; - - if (diagnostics.length === 0) { - assert(state.bundleOutput); - bundleOutput = state.bundleOutput; - } - - const stats = performance ? performanceEnd() : undefined; - - const result = { - bundleOutput, - diagnostics: fromTypeScriptDiagnostic(diagnostics), - stats, - }; - - log("<<< bundle end", { - rootNames, - type: CompilerRequestType[type], - }); - - return result; - } - - function runtimeCompile( - request, - ) { - const { options, rootNames, target, unstable, sourceFileMap } = request; - - log(">>> runtime compile start", { - rootNames, - }); - - // if there are options, convert them into TypeScript compiler options, - // and resolve any external file references - let convertedOptions; - if (options) { - const result = convertCompilerOptions(options); - convertedOptions = result.options; - } - - buildLocalSourceFileCache(sourceFileMap); - - const state = { - rootNames, - emitMap: {}, - }; - const host = new Host({ - bundle: false, - target, - writeFile: createRuntimeCompileWriteFile(state), - }); - const compilerOptions = [DEFAULT_RUNTIME_COMPILE_OPTIONS]; - if (convertedOptions) { - compilerOptions.push(convertedOptions); - } - if (unstable) { - compilerOptions.push({ - lib: [ - "deno.unstable", - ...((convertedOptions && convertedOptions.lib) || ["deno.window"]), - ], - }); - } - - host.mergeOptions(...compilerOptions); - - const program = ts.createProgram({ - rootNames, - options: host.getCompilationSettings(), - host, - }); - - const diagnostics = ts - .getPreEmitDiagnostics(program) - .filter(({ code }) => !ignoredDiagnostics.includes(code)); - - const emitResult = program.emit(); - - assert(emitResult.emitSkipped === false, "Unexpected skip of the emit."); - - log("<<< runtime compile finish", { - rootNames, - emitMap: Object.keys(state.emitMap), - }); - - const maybeDiagnostics = diagnostics.length - ? fromTypeScriptDiagnostic(diagnostics).items - : []; - - return { - diagnostics: maybeDiagnostics, - emitMap: state.emitMap, - }; - } - - function runtimeBundle(request) { - const { options, rootNames, target, unstable, sourceFileMap } = request; - - log(">>> runtime bundle start", { - rootNames, - }); - - // if there are options, convert them into TypeScript compiler options, - // and resolve any external file references - let convertedOptions; - if (options) { - const result = convertCompilerOptions(options); - convertedOptions = result.options; - } - - buildLocalSourceFileCache(sourceFileMap); - - const state = { - rootNames, - bundleOutput: undefined, - }; - const host = new Host({ - bundle: true, - target, - writeFile: createBundleWriteFile(state), - }); - state.host = host; - - const compilerOptions = [DEFAULT_RUNTIME_COMPILE_OPTIONS]; - if (convertedOptions) { - compilerOptions.push(convertedOptions); - } - if (unstable) { - compilerOptions.push({ - lib: [ - "deno.unstable", - ...((convertedOptions && convertedOptions.lib) || ["deno.window"]), - ], - }); - } - compilerOptions.push(DEFAULT_BUNDLER_OPTIONS); - host.mergeOptions(...compilerOptions); - - const program = ts.createProgram({ - rootNames, - options: host.getCompilationSettings(), - host, - }); - - setRootExports(program, rootNames[0]); - const diagnostics = ts - .getPreEmitDiagnostics(program) - .filter(({ code }) => !ignoredDiagnostics.includes(code)); - - const emitResult = program.emit(); - - assert(emitResult.emitSkipped === false, "Unexpected skip of the emit."); - - log("<<< runtime bundle finish", { - rootNames, - }); - - const maybeDiagnostics = diagnostics.length - ? fromTypeScriptDiagnostic(diagnostics).items - : []; - - return { - diagnostics: maybeDiagnostics, - output: state.bundleOutput, - }; - } - - function runtimeTranspile( - request, - ) { - const result = {}; - const { sources, options } = request; - const compilerOptions = options - ? Object.assign( - {}, - DEFAULT_RUNTIME_TRANSPILE_OPTIONS, - convertCompilerOptions(options).options, - ) - : DEFAULT_RUNTIME_TRANSPILE_OPTIONS; - - for (const [fileName, inputText] of Object.entries(sources)) { - const { outputText: source, sourceMapText: map } = ts.transpileModule( - inputText, - { - fileName, - compilerOptions, - }, - ); - result[fileName] = { source, map }; - } - return Promise.resolve(result); - } - - async function tsCompilerOnMessage({ - data: request, - }) { - switch (request.type) { - case CompilerRequestType.Compile: { - const result = compile(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.Transpile: { - const result = transpile(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.Bundle: { - const result = bundle(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.RuntimeCompile: { - const result = runtimeCompile(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.RuntimeBundle: { - const result = runtimeBundle(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.RuntimeTranspile: { - const result = await runtimeTranspile(request); - globalThis.postMessage(result); - break; - } - default: - log( - `!!! unhandled CompilerRequestType: ${request.type} (${ - CompilerRequestType[request.type] - })`, - ); - } - // Shutdown after single request - globalThis.close(); - } - - function bootstrapTsCompilerRuntime() { - globalThis.bootstrap.workerRuntime("TS", false); - globalThis.onmessage = tsCompilerOnMessage; - } - - Object.defineProperties(globalThis, { - bootstrap: { - value: { - ...globalThis.bootstrap, - tsCompilerRuntime: bootstrapTsCompilerRuntime, - }, - configurable: true, - writable: true, - }, - }); -})(this); |