diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2019-04-29 15:58:31 +0100 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-04-29 07:58:31 -0700 |
commit | 1a0f53a807abad0e9ebfcf437f3dade6b01d7f84 (patch) | |
tree | 013eb8d15383a22a4e2c4c5502ba37035b397903 /js/compiler.ts | |
parent | 73be183864d0983821e683198d9a6ea9008f070a (diff) |
Add support for custom tsconfig.json (#2089)
Use `--config`
Diffstat (limited to 'js/compiler.ts')
-rw-r--r-- | js/compiler.ts | 162 |
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(", ")}` + ); + } + } } |