summaryrefslogtreecommitdiff
path: root/deno_typescript/compiler_main.js
diff options
context:
space:
mode:
Diffstat (limited to 'deno_typescript/compiler_main.js')
-rw-r--r--deno_typescript/compiler_main.js386
1 files changed, 0 insertions, 386 deletions
diff --git a/deno_typescript/compiler_main.js b/deno_typescript/compiler_main.js
deleted file mode 100644
index a42f96860..000000000
--- a/deno_typescript/compiler_main.js
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// Because we're bootstrapping the TypeScript compiler without dependencies on
-// Node, this is written in JavaScript, but leverages JSDoc that can be
-// understood by the TypeScript language service, so it allows type safety
-// checking in VSCode.
-
-"use strict";
-
-const ASSETS = "$asset$";
-
-/**
- * @param {string} configText
- * @param {Array<string>} rootNames
- */
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function main(configText, rootNames) {
- ops = Deno.core.ops();
- println(`>>> ts version ${ts.version}`);
- println(`>>> rootNames ${rootNames}`);
-
- const host = new Host();
-
- assert(rootNames.length === 1);
- // If root file is external file, ie. URL with "file://"
- // then create an internal name - in case of bundling
- // cli runtime this is always true.
- const rootFile = rootNames[0];
- const result = externalSpecifierRegEx.exec(rootFile);
- let rootSpecifier = rootFile;
- if (result) {
- const [, specifier] = result;
- const internalSpecifier = `$deno$${specifier}`;
- moduleMap.set(internalSpecifier, rootFile);
- rootSpecifier = internalSpecifier;
- }
- const { options, diagnostics } = configure(configText);
- handleDiagnostics(host, diagnostics);
-
- println(`>>> TS config: ${JSON.stringify(options)}`);
-
- const program = ts.createProgram([rootSpecifier], options, host);
-
- handleDiagnostics(
- host,
- ts.getPreEmitDiagnostics(program).filter(({ code }) => {
- // TS1063: An export assignment cannot be used in a namespace.
- if (code === 1063) return false;
- // TS2691: An import path cannot end with a '.ts' extension. Consider
- // importing 'bad-module' instead.
- if (code === 2691) return false;
- // TS5009: Cannot find the common subdirectory path for the input files.
- if (code === 5009) return false;
- return true;
- }),
- );
-
- const emitResult = program.emit();
- handleDiagnostics(host, emitResult.diagnostics);
-
- dispatch(
- "op_set_emit_result",
- Object.assign(emitResult, { tsVersion: ts.version }),
- );
-}
-
-/**
- * @param {...string} s
- */
-function println(...s) {
- Deno.core.print(s.join(" ") + "\n");
-}
-
-/**
- * @returns {never}
- */
-function unreachable() {
- throw Error("unreachable");
-}
-
-/**
- * @param {unknown} cond
- * @returns {asserts cond}
- */
-function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
-}
-
-/**
- * @param {Uint8Array | null} ui8
- */
-function decodeAscii(ui8) {
- let out = "";
- if (!ui8) {
- return out;
- }
- for (let i = 0; i < ui8.length; i++) {
- out += String.fromCharCode(ui8[i]);
- }
- return out;
-}
-
-/**
- * @param {string} str
- */
-function encode(str) {
- const charCodes = str.split("").map((c) => c.charCodeAt(0));
- const ui8 = new Uint8Array(charCodes);
- return ui8;
-}
-
-/** **Warning!** Op ids must be acquired from Rust using `Deno.core.ops()`
- * before dispatching any action.
- * @type {Record<string, number>}
- */
-let ops;
-
-/**
- * @type {Map<string, string>}
- */
-const moduleMap = new Map();
-
-const externalSpecifierRegEx = /^file:\/{3}\S+\/js(\/\S+\.ts)$/;
-
-/**
- * This is a minimal implementation of a compiler host to be able to allow the
- * creation of runtime bundles. Some of the methods are implemented in a way
- * to just appease the TypeScript compiler, not to necessarily be a general
- * purpose implementation.
- *
- * @implements {ts.CompilerHost}
- */
-class Host {
- /**
- * @param {string} _fileName
- */
- fileExists(_fileName) {
- return true;
- }
-
- /**
- * @param {string} _fileName
- */
- readFile(_fileName) {
- unreachable();
- }
-
- useCaseSensitiveFileNames() {
- return false;
- }
-
- /**
- * @param {ts.CompilerOptions} _options
- */
- getDefaultLibFileName(_options) {
- return "lib.esnext.d.ts";
- }
-
- getDefaultLibLocation() {
- return ASSETS;
- }
-
- getCurrentDirectory() {
- return ".";
- }
-
- /**
- * @param {string} fileName
- * @param {ts.ScriptTarget} languageVersion
- * @param {(message: string) => void} _onError
- * @param {boolean} shouldCreateNewSourceFile
- */
- getSourceFile(
- fileName,
- languageVersion,
- _onError,
- shouldCreateNewSourceFile,
- ) {
- assert(!shouldCreateNewSourceFile); // We haven't yet encountered this.
-
- // This hacks around the fact that TypeScript tries to magically guess the
- // d.ts filename.
- if (fileName.startsWith("$typeRoots$")) {
- assert(fileName.startsWith("$typeRoots$/"));
- assert(fileName.endsWith("/index.d.ts"));
- fileName = fileName
- .replace("$typeRoots$/", "")
- .replace("/index.d.ts", "");
- }
-
- // This looks up any modules that have been mapped to internal names
- const moduleUrl = moduleMap.has(fileName)
- ? moduleMap.get(fileName)
- : fileName;
-
- const { sourceCode } = dispatch("op_load_module", {
- moduleUrl,
- languageVersion,
- shouldCreateNewSourceFile,
- });
-
- const sourceFile = ts.createSourceFile(
- fileName,
- sourceCode,
- languageVersion,
- );
- sourceFile.moduleName = fileName;
- return sourceFile;
- }
-
- /**
- * @param {string} fileName
- * @param {string} data
- * @param {boolean} _writeByteOrderMark
- * @param {((message: string) => void)?} _onError
- * @param {ReadonlyArray<ts.SourceFile>?} sourceFiles
- */
- writeFile(
- fileName,
- data,
- _writeByteOrderMark,
- _onError = null,
- sourceFiles = null,
- ) {
- if (sourceFiles == null) {
- return;
- }
- const moduleName = sourceFiles[sourceFiles.length - 1].moduleName;
- return dispatch("op_write_file", { fileName, moduleName, data });
- }
-
- /**
- * @param {string} _fileName
- * @param {ts.Path} _path
- * @param {ts.ScriptTarget} _languageVersion
- * @param {*} _onError
- * @param {boolean} _shouldCreateNewSourceFile
- */
- getSourceFileByPath(
- _fileName,
- _path,
- _languageVersion,
- _onError,
- _shouldCreateNewSourceFile,
- ) {
- unreachable();
- }
-
- /**
- * @param {string} fileName
- */
- getCanonicalFileName(fileName) {
- return fileName;
- }
-
- getNewLine() {
- return "\n";
- }
-
- /**
- * @param {string[]} moduleNames
- * @param {string} containingFile
- * @return {Array<ts.ResolvedModule | undefined>}
- */
- resolveModuleNames(moduleNames, containingFile) {
- // If the containing file is an internal specifier, map it back to the
- // external specifier
- containingFile = moduleMap.has(containingFile)
- ? moduleMap.get(containingFile)
- : containingFile;
- /** @type {string[]} */
- const resolvedNames = dispatch("op_resolve_module_names", {
- moduleNames,
- containingFile,
- });
- /** @type {ts.ResolvedModule[]} */
- const r = resolvedNames.map((resolvedFileName) => {
- const extension = getExtension(resolvedFileName);
- if (!moduleMap.has(resolvedFileName)) {
- // If we match the external specifier regex, we will then create an internal
- // specifier and then use that when creating the source file
- const result = externalSpecifierRegEx.exec(resolvedFileName);
- if (result) {
- const [, specifier] = result;
- const internalSpecifier = `$deno$${specifier}`;
- moduleMap.set(internalSpecifier, resolvedFileName);
- resolvedFileName = internalSpecifier;
- }
- }
- return { resolvedFileName, extension };
- });
- return r;
- }
-}
-
-/**
- * @param {string} configurationText
- */
-function configure(configurationText) {
- const { config, error } = ts.parseConfigFileTextToJson(
- "tsconfig.json",
- configurationText,
- );
- if (error) {
- return { options: {}, diagnostics: [error] };
- }
- const { options, errors } = ts.convertCompilerOptionsFromJson(
- config.compilerOptions,
- "",
- );
- return {
- options,
- diagnostics: errors.length ? errors : undefined,
- };
-}
-
-/**
- * @param {string} opName
- * @param {Record<string,any>} obj
- */
-function dispatch(opName, obj) {
- const opId = ops[opName];
-
- if (!opId) {
- throw new Error(`Unknown op: ${opName}`);
- }
-
- const s = JSON.stringify(obj);
- const msg = encode(s);
- const resUi8 = Deno.core.dispatch(opId, msg);
- const resStr = decodeAscii(resUi8);
- const res = JSON.parse(resStr);
- if (!res["ok"]) {
- throw Error(`${opName} failed ${res["err"]}. Args: ${JSON.stringify(obj)}`);
- }
- return res["ok"];
-}
-
-/**
- * @param {number} code
- */
-function exit(code) {
- dispatch("op_exit2", { code });
- return unreachable();
-}
-
-// Maximum number of diagnostics to display.
-const MAX_ERRORS = 5;
-
-/**
- * @param {ts.CompilerHost} host
- * @param {ReadonlyArray<ts.Diagnostic> | undefined} diagnostics
- */
-function handleDiagnostics(host, diagnostics) {
- if (diagnostics && diagnostics.length) {
- let rest = 0;
- if (diagnostics.length > MAX_ERRORS) {
- rest = diagnostics.length - MAX_ERRORS;
- diagnostics = diagnostics.slice(0, MAX_ERRORS);
- }
- const msg = ts.formatDiagnosticsWithColorAndContext(diagnostics, host);
- println(msg);
- if (rest) {
- println(`And ${rest} other errors.`);
- }
- exit(1);
- }
-}
-
-/** Returns the TypeScript Extension enum for a given media type.
- * @param {string} fileName
- * @returns {ts.Extension}
- */
-function getExtension(fileName) {
- if (fileName.endsWith(".d.ts")) {
- return ts.Extension.Dts;
- } else if (fileName.endsWith(".ts")) {
- return ts.Extension.Ts;
- } else if (fileName.endsWith(".js")) {
- return ts.Extension.Js;
- } else {
- throw TypeError(`Cannot resolve extension for ${fileName}`);
- }
-}