From 0275944a1fc88b6dce5a9f34f94fb9189439fcb5 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Wed, 13 Mar 2019 15:55:23 +0200 Subject: [PATCH] fix(jsii): show jsii diagnostics in watch mode and support $tsc problem matcher (#383) Emit jsii diagnostics error when in watch mode, and also format the errors with a "TS9999" error code so that VSCode's $tsc problem matcher will show them as "Problems". Prefix "JSII" in the message to distinguish that these are jsii errors. Fixes #382 --- packages/jsii/bin/jsii.ts | 23 +---------------------- packages/jsii/lib/assembler.ts | 6 ++++-- packages/jsii/lib/compiler.ts | 14 ++++++++++++-- packages/jsii/lib/utils.ts | 15 +++++++++++++++ 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/jsii/bin/jsii.ts b/packages/jsii/bin/jsii.ts index 64e9c0dbfe..efb6a28779 100644 --- a/packages/jsii/bin/jsii.ts +++ b/packages/jsii/bin/jsii.ts @@ -1,10 +1,8 @@ import log4js = require('log4js'); import path = require('path'); import process = require('process'); -import ts = require('typescript'); import yargs = require('yargs'); import { Compiler, DIAGNOSTICS } from '../lib/compiler'; -import { hasDomain } from '../lib/emitter'; import { loadProjectInfo } from '../lib/project-info'; import utils = require('../lib/utils'); import { VERSION } from '../lib/version'; @@ -33,7 +31,7 @@ import { VERSION } from '../lib/version'; return { projectRoot, emitResult: await compiler.emit() }; })().then(({ projectRoot, emitResult }) => { for (const diagnostic of emitResult.diagnostics) { - _logDiagnostic(diagnostic, projectRoot); + utils.logDiagnostic(diagnostic, projectRoot); } if (emitResult.emitSkipped) { process.exit(1); @@ -72,22 +70,3 @@ function _configureLog4js(verbosity: number) { } } } - -function _logDiagnostic(diagnostic: ts.Diagnostic, projectRoot: string) { - const formatDiagnosticsHost = { - getCurrentDirectory: () => projectRoot, - getCanonicalFileName(fileName: string) { return fileName; }, - getNewLine() { return '\n'; } - }; - - let message = diagnostic.file - ? ts.formatDiagnosticsWithColorAndContext([diagnostic], formatDiagnosticsHost) - : ts.formatDiagnostics([diagnostic], formatDiagnosticsHost); - if (hasDomain(diagnostic)) { - // Make sure error codes don't render as ``TS123``, instead e.g: ``JSII123``. - message = message.replace(/([^\w])TS(\d+)([^\w])/, `$1${diagnostic.domain}$2$3`); - } - const logFunc = utils.diagnosticsLogger(log4js.getLogger(DIAGNOSTICS), diagnostic); - if (!logFunc) { return; } - logFunc(message.trim()); -} diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index 58fdb81c03..860df41f21 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -6,6 +6,7 @@ import spec = require('jsii-spec'); import log4js = require('log4js'); import path = require('path'); import ts = require('typescript'); +import { JSII_DIAGNOSTICS_CODE } from './compiler'; import { Diagnostic, Emitter } from './emitter'; import literate = require('./literate'); import { ProjectInfo } from './project-info'; @@ -223,8 +224,9 @@ export class Assembler implements Emitter { private _diagnostic(node: ts.Node | null, category: ts.DiagnosticCategory, messageText: string) { this._diagnostics.push({ domain: 'JSII', - category, code: 0, - messageText, + category, + code: JSII_DIAGNOSTICS_CODE, + messageText: `JSII: ${messageText}`, file: node != null ? node.getSourceFile() : undefined, start: node != null ? node.getStart() : undefined, length: node != null ? node.getEnd() - node.getStart() : undefined diff --git a/packages/jsii/lib/compiler.ts b/packages/jsii/lib/compiler.ts index 842d7774a4..ce0a409115 100644 --- a/packages/jsii/lib/compiler.ts +++ b/packages/jsii/lib/compiler.ts @@ -34,6 +34,7 @@ const COMPILER_OPTIONS: ts.CompilerOptions = { const LOG = log4js.getLogger('jsii/compiler'); export const DIAGNOSTICS = 'diagnostics'; +export const JSII_DIAGNOSTICS_CODE = 9999; export interface CompilerOptions { /** The information about the project to be built */ @@ -102,6 +103,7 @@ export class Compiler implements Emitter { projectReferences: this.typescriptConfig.references && this.typescriptConfig.references.map(ref => ({ path: path.resolve(ref.path) })), host: this.compilerHost }); + return await this._consumeProgram(prog, this.compilerHost.getDefaultLibLocation()); } @@ -121,7 +123,12 @@ export class Compiler implements Emitter { } const orig = host.afterProgramCreate; host.afterProgramCreate = async builderProgram => { - await this._consumeProgram(builderProgram.getProgram(), host.getDefaultLibLocation!()); + const emitResult = await this._consumeProgram(builderProgram.getProgram(), host.getDefaultLibLocation!()); + + for (const diag of emitResult.diagnostics.filter(d => d.code === JSII_DIAGNOSTICS_CODE)) { + utils.logDiagnostic(diag, projectRoot); + } + if (orig) { orig.call(host, builderProgram); } }; ts.createWatchProgram(host); @@ -133,13 +140,16 @@ export class Compiler implements Emitter { const emit = program.emit(); if (emit.emitSkipped) { LOG.error('Compilation errors prevented the JSII assembly from being created'); - return emit; } + + // we continue to do jsii checker even if there are compilation errors so that + // jsii warnings will appear. const assembler = new Assembler(this.options.projectInfo, program, stdlib); const assmEmit = await assembler.emit(); if (assmEmit.emitSkipped) { LOG.error('Type model errors prevented the JSII assembly from being created'); } + return { emitSkipped: assmEmit.emitSkipped, diagnostics: [...emit.diagnostics, ...assmEmit.diagnostics] diff --git a/packages/jsii/lib/utils.ts b/packages/jsii/lib/utils.ts index cebff1a757..eb28973d03 100644 --- a/packages/jsii/lib/utils.ts +++ b/packages/jsii/lib/utils.ts @@ -1,5 +1,6 @@ import log4js = require('log4js'); import ts = require('typescript'); +import { DIAGNOSTICS } from './compiler'; /** * Obtains the relevant logger to be used for a given diagnostic message. @@ -24,6 +25,20 @@ export function diagnosticsLogger(logger: log4js.Logger, diagnostic: ts.Diagnost return logger.debug.bind(logger); } } +export function logDiagnostic(diagnostic: ts.Diagnostic, projectRoot: string) { + const formatDiagnosticsHost = { + getCurrentDirectory: () => projectRoot, + getCanonicalFileName(fileName: string) { return fileName; }, + getNewLine() { return '\n'; } + }; + + const message = diagnostic.file + ? ts.formatDiagnosticsWithColorAndContext([diagnostic], formatDiagnosticsHost) + : ts.formatDiagnostics([diagnostic], formatDiagnosticsHost); + const logFunc = diagnosticsLogger(log4js.getLogger(DIAGNOSTICS), diagnostic); + if (!logFunc) { return; } + logFunc(message.trim()); +} /** * A filter function for ``JSON.stringify`` that removes: