summaryrefslogtreecommitdiff
path: root/js/compiler.ts
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2019-04-29 15:58:31 +0100
committerRyan Dahl <ry@tinyclouds.org>2019-04-29 07:58:31 -0700
commit1a0f53a807abad0e9ebfcf437f3dade6b01d7f84 (patch)
tree013eb8d15383a22a4e2c4c5502ba37035b397903 /js/compiler.ts
parent73be183864d0983821e683198d9a6ea9008f070a (diff)
Add support for custom tsconfig.json (#2089)
Use `--config`
Diffstat (limited to 'js/compiler.ts')
-rw-r--r--js/compiler.ts162
1 files changed, 155 insertions, 7 deletions
diff --git a/js/compiler.ts b/js/compiler.ts
index fffb9e852..5711e103a 100644
--- a/js/compiler.ts
+++ b/js/compiler.ts
@@ -3,8 +3,12 @@ import * as ts from "typescript";
import * as msg from "gen/cli/msg_generated";
import { window } from "./window";
import { assetSourceCode } from "./assets";
+import { bold, cyan, yellow } from "./colors";
import { Console } from "./console";
import { core } from "./core";
+import { cwd } from "./dir";
+import { sendSync } from "./dispatch";
+import * as flatbuffers from "./flatbuffers";
import * as os from "./os";
import { TextDecoder, TextEncoder } from "./text_encoding";
import { clearTimer, setTimeout } from "./timers";
@@ -55,17 +59,81 @@ interface CompilerLookup {
interface Os {
fetchModuleMetaData: typeof os.fetchModuleMetaData;
exit: typeof os.exit;
+ noColor: typeof os.noColor;
}
/** Abstraction of the APIs required from the `typescript` module so they can
* be easily mocked.
*/
interface Ts {
+ convertCompilerOptionsFromJson: typeof ts.convertCompilerOptionsFromJson;
createLanguageService: typeof ts.createLanguageService;
formatDiagnosticsWithColorAndContext: typeof ts.formatDiagnosticsWithColorAndContext;
formatDiagnostics: typeof ts.formatDiagnostics;
+ parseConfigFileTextToJson: typeof ts.parseConfigFileTextToJson;
}
+/** Options that either do nothing in Deno, or would cause undesired behavior
+ * if modified. */
+const ignoredCompilerOptions: ReadonlyArray<string> = [
+ "allowSyntheticDefaultImports",
+ "baseUrl",
+ "build",
+ "composite",
+ "declaration",
+ "declarationDir",
+ "declarationMap",
+ "diagnostics",
+ "downlevelIteration",
+ "emitBOM",
+ "emitDeclarationOnly",
+ "esModuleInterop",
+ "extendedDiagnostics",
+ "forceConsistentCasingInFileNames",
+ "help",
+ "importHelpers",
+ "incremental",
+ "inlineSourceMap",
+ "inlineSources",
+ "init",
+ "isolatedModules",
+ "lib",
+ "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"
+];
+
/** A simple object structure for caching resolved modules and their contents.
*
* Named `ModuleMetaData` to clarify it is just a representation of meta data of
@@ -201,6 +269,18 @@ class Compiler implements ts.LanguageServiceHost, ts.FormatDiagnosticsHost {
);
}
+ /** Log TypeScript diagnostics to the console and exit */
+ private _logDiagnostics(diagnostics: ts.Diagnostic[]): never {
+ const errMsg = this._os.noColor
+ ? this._ts.formatDiagnostics(diagnostics, this)
+ : this._ts.formatDiagnosticsWithColorAndContext(diagnostics, this);
+
+ console.log(errMsg);
+ // TODO The compiler isolate shouldn't exit. Errors should be forwarded to
+ // to the caller and the caller exit.
+ return this._os.exit(1);
+ }
+
/** Given a `moduleSpecifier` and `containingFile` retrieve the cached
* `fileName` for a given module. If the module has yet to be resolved
* this will return `undefined`.
@@ -354,13 +434,7 @@ class Compiler implements ts.LanguageServiceHost, ts.FormatDiagnosticsHost {
...service.getSemanticDiagnostics(fileName)
];
if (diagnostics.length > 0) {
- const errMsg = os.noColor
- ? this._ts.formatDiagnostics(diagnostics, this)
- : this._ts.formatDiagnosticsWithColorAndContext(diagnostics, this);
-
- console.log(errMsg);
- // All TypeScript errors are terminal for deno
- this._os.exit(1);
+ this._logDiagnostics(diagnostics);
}
assert(
@@ -392,6 +466,40 @@ class Compiler implements ts.LanguageServiceHost, ts.FormatDiagnosticsHost {
return { outputCode, sourceMap };
}
+ /** Take a configuration string, parse it, and use it to merge with the
+ * compiler's configuration options. The method returns an array of compiler
+ * options which were ignored, or `undefined`.
+ */
+ configure(path: string, configurationText: string): string[] | undefined {
+ this._log("compile.configure", path);
+ const { config, error } = this._ts.parseConfigFileTextToJson(
+ path,
+ configurationText
+ );
+ if (error) {
+ this._logDiagnostics([error]);
+ }
+ const { options, errors } = this._ts.convertCompilerOptionsFromJson(
+ config.compilerOptions,
+ cwd()
+ );
+ if (errors.length) {
+ this._logDiagnostics(errors);
+ }
+ const ignoredOptions: string[] = [];
+ for (const key of Object.keys(options)) {
+ if (
+ ignoredCompilerOptions.includes(key) &&
+ (!(key in this._options) || options[key] !== this._options[key])
+ ) {
+ ignoredOptions.push(key);
+ delete options[key];
+ }
+ }
+ Object.assign(this._options, options);
+ return ignoredOptions.length ? ignoredOptions : undefined;
+ }
+
// TypeScript Language Service and Format Diagnostic Host API
getCanonicalFileName(fileName: string): string {
@@ -541,6 +649,46 @@ window.compilerMain = function compilerMain(): void {
};
};
+const decoder = new TextDecoder();
+
+// Perform the op to retrieve the compiler configuration if there was any
+// provided on startup.
+function getCompilerConfig(
+ compilerType: string
+): { path: string; data: string } {
+ const builder = flatbuffers.createBuilder();
+ const compilerType_ = builder.createString(compilerType);
+ msg.CompilerConfig.startCompilerConfig(builder);
+ msg.CompilerConfig.addCompilerType(builder, compilerType_);
+ const inner = msg.CompilerConfig.endCompilerConfig(builder);
+ const baseRes = sendSync(builder, msg.Any.CompilerConfig, inner);
+ assert(baseRes != null);
+ assert(msg.Any.CompilerConfigRes === baseRes!.innerType());
+ const res = new msg.CompilerConfigRes();
+ assert(baseRes!.inner(res) != null);
+
+ // the privileged side does not normalize path separators in windows, so we
+ // will normalize them here
+ const path = res.path()!.replace(/\\/g, "/");
+ assert(path != null);
+ const dataArray = res.dataArray()!;
+ assert(dataArray != null);
+ const data = decoder.decode(dataArray);
+ return { path, data };
+}
+
export default function denoMain(): void {
os.start("TS");
+
+ const { path, data } = getCompilerConfig("typescript");
+ if (data.length) {
+ const ignoredOptions = compiler.configure(path, data);
+ if (ignoredOptions) {
+ console.warn(
+ yellow(`Unsupported compiler options in "${path}"\n`) +
+ cyan(` The following options were ignored:\n`) +
+ ` ${ignoredOptions.map((value): string => bold(value)).join(", ")}`
+ );
+ }
+ }
}