diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2019-06-04 23:03:56 +1000 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-06-04 09:03:56 -0400 |
commit | a71305b4febc3d8db95d3d144ae3a64c023718f0 (patch) | |
tree | f0dcc6017f62380b02a08d800503fbf7242fbe72 /js/compiler.ts | |
parent | 60d452264198adb3da4820236cf8ea35d33486cd (diff) |
Handle compiler diagnostics in Rust (#2445)
Diffstat (limited to 'js/compiler.ts')
-rw-r--r-- | js/compiler.ts | 128 |
1 files changed, 67 insertions, 61 deletions
diff --git a/js/compiler.ts b/js/compiler.ts index 15adba746..6b0881700 100644 --- a/js/compiler.ts +++ b/js/compiler.ts @@ -1,6 +1,7 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. import * as msg from "gen/cli/msg_generated"; import { core } from "./core"; +import { Diagnostic, fromTypeScriptDiagnostic } from "./diagnostics"; import * as flatbuffers from "./flatbuffers"; import { sendSync } from "./dispatch"; import { TextDecoder } from "./text_encoding"; @@ -37,6 +38,11 @@ interface CompilerReq { config?: string; } +interface ConfigureResponse { + ignoredOptions?: string[]; + diagnostics?: ts.Diagnostic[]; +} + /** Options that either do nothing in Deno, or would cause undesired behavior * if modified. */ const ignoredCompilerOptions: ReadonlyArray<string> = [ @@ -105,6 +111,11 @@ interface ModuleMetaData { sourceCode: string | undefined; } +interface EmitResult { + emitSkipped: boolean; + diagnostics?: Diagnostic; +} + function fetchModuleMetaData( specifier: string, referrer: string @@ -193,22 +204,19 @@ class Host implements ts.CompilerHost { * compiler's configuration options. The method returns an array of compiler * options which were ignored, or `undefined`. */ - configure(path: string, configurationText: string): string[] | undefined { + configure(path: string, configurationText: string): ConfigureResponse { util.log("compile.configure", path); const { config, error } = ts.parseConfigFileTextToJson( path, configurationText ); if (error) { - this._logDiagnostics([error]); + return { diagnostics: [error] }; } const { options, errors } = ts.convertCompilerOptionsFromJson( config.compilerOptions, cwd() ); - if (errors.length) { - this._logDiagnostics(errors); - } const ignoredOptions: string[] = []; for (const key of Object.keys(options)) { if ( @@ -220,7 +228,10 @@ class Host implements ts.CompilerHost { } } Object.assign(this._options, options); - return ignoredOptions.length ? ignoredOptions : undefined; + return { + ignoredOptions: ignoredOptions.length ? ignoredOptions : undefined, + diagnostics: errors.length ? errors : undefined + }; } getCompilationSettings(): ts.CompilerOptions { @@ -228,19 +239,6 @@ class Host implements ts.CompilerHost { return this._options; } - /** Log TypeScript diagnostics to the console and exit */ - _logDiagnostics(diagnostics: ReadonlyArray<ts.Diagnostic>): never { - const errMsg = os.noColor - ? ts.formatDiagnostics(diagnostics, this) - : ts.formatDiagnosticsWithColorAndContext(diagnostics, this); - - console.log(errMsg); - // TODO The compiler isolate shouldn't call os.exit(). (In fact, it - // shouldn't even have access to call that op.) Errors should be forwarded - // to to the caller and the caller exit. - return os.exit(1); - } - fileExists(_fileName: string): boolean { return notImplemented(); } @@ -362,10 +360,17 @@ class Host implements ts.CompilerHost { window.compilerMain = function compilerMain(): void { // workerMain should have already been called since a compiler is a worker. window.onmessage = ({ data }: { data: CompilerReq }): void => { + let emitSkipped = true; + let diagnostics: ts.Diagnostic[] | undefined; + const { rootNames, configPath, config } = data; const host = new Host(); - if (config && config.length) { - const ignoredOptions = host.configure(configPath!, config); + + // if there is a configuration supplied, we need to parse that + if (config && config.length && configPath) { + const configResult = host.configure(configPath, config); + const ignoredOptions = configResult.ignoredOptions; + diagnostics = configResult.diagnostics; if (ignoredOptions) { console.warn( yellow(`Unsupported compiler options in "${configPath}"\n`) + @@ -377,51 +382,52 @@ window.compilerMain = function compilerMain(): void { } } - const options = host.getCompilationSettings(); - const program = ts.createProgram(rootNames, options, host); - - const preEmitDiagnostics = ts.getPreEmitDiagnostics(program).filter( - ({ code }): boolean => { - // 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; - // TS5055: Cannot write file - // 'http://localhost:4545/tests/subdir/mt_application_x_javascript.j4.js' - // because it would overwrite input file. - if (code === 5055) return false; - // 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. - if (code === 5070) return false; - return true; + // if there was a configuration and no diagnostics with it, we will continue + // to generate the program and possibly emit it. + if (!diagnostics || (diagnostics && diagnostics.length === 0)) { + const options = host.getCompilationSettings(); + const program = ts.createProgram(rootNames, options, host); + + diagnostics = ts.getPreEmitDiagnostics(program).filter( + ({ code }): boolean => { + // 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; + // TS5055: Cannot write file + // 'http://localhost:4545/tests/subdir/mt_application_x_javascript.j4.js' + // because it would overwrite input file. + if (code === 5055) return false; + // 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. + if (code === 5070) return false; + return true; + } + ); + + // We will only proceed with the emit if there are no diagnostics. + if (diagnostics && diagnostics.length === 0) { + const emitResult = program.emit(); + emitSkipped = emitResult.emitSkipped; + // emitResult.diagnostics is `readonly` in TS3.5+ and can't be assigned + // without casting. + diagnostics = emitResult.diagnostics as ts.Diagnostic[]; } - ); - if (preEmitDiagnostics.length > 0) { - host._logDiagnostics(preEmitDiagnostics); - // The above _logDiagnostics calls os.exit(). The return is here just for - // clarity. - return; } - const emitResult = program!.emit(); - - // TODO(ry) Print diagnostics in Rust. - // https://github.com/denoland/deno/pull/2310 - - const { diagnostics } = emitResult; - if (diagnostics.length > 0) { - host._logDiagnostics(diagnostics); - // The above _logDiagnostics calls os.exit(). The return is here just for - // clarity. - return; - } + const result: EmitResult = { + emitSkipped, + diagnostics: diagnostics.length + ? fromTypeScriptDiagnostic(diagnostics) + : undefined + }; - postMessage(emitResult); + postMessage(result); - // The compiler isolate exits after a single messsage. + // The compiler isolate exits after a single message. workerClose(); }; }; |