Skip to content

Commit eafb8ba

Browse files
committed
Improve error messages using formatting and chalk
1 parent 170d8e0 commit eafb8ba

File tree

7 files changed

+148
-22
lines changed

7 files changed

+148
-22
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
},
6161
"dependencies": {
6262
"arrify": "^1.0.0",
63+
"chalk": "^1.1.1",
6364
"make-error": "^1.0.2",
6465
"minimist": "^1.2.0",
6566
"source-map-support": "^0.3.2",

src/bin/ts-node.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { readFileSync } from 'fs'
55
import Module = require('module')
66
import extend = require('xtend')
77
import minimist = require('minimist')
8-
import { register, VERSION } from '../typescript-node'
8+
import { register, VERSION, TypeScriptError } from '../typescript-node'
99

1010
interface Argv {
1111
eval?: string
@@ -52,15 +52,17 @@ if (argv.help) {
5252
process.exit(0)
5353
}
5454

55+
const cwd = process.cwd()
56+
const code = argv.eval == null ? argv.print : argv.eval
57+
58+
// Register the TypeScript compiler instance.
5559
const compiler = register({
5660
compiler: argv.compiler,
5761
ignoreWarnings: list(argv.ignoreWarnings),
58-
configFile: argv.compiler
62+
configFile: argv.compiler,
63+
isRepl: typeof code === 'string' || argv._.length === 0
5964
})
6065

61-
const cwd = process.cwd()
62-
const code = argv.eval == null ? argv.print : argv.eval
63-
6466
// TypeScript files must always end with `.ts`.
6567
const EVAL_FILENAME = '[eval].ts'
6668
const EVAL_PATH = join(cwd, EVAL_FILENAME)
@@ -77,11 +79,21 @@ if (typeof code === 'string') {
7779
global.module = module
7880
global.require = module.require.bind(module)
7981

80-
var result = _eval(code, EVAL_PATH)
82+
let result: any
83+
84+
try {
85+
result = _eval(code, EVAL_PATH)
86+
} catch (err) {
87+
if (err instanceof TypeScriptError) {
88+
console.error(err.message)
89+
process.exit(1)
90+
}
91+
92+
throw err
93+
}
8194

8295
if (argv.print != null) {
83-
var output = typeof result === 'string' ? result : inspect(result)
84-
process.stdout.write(output + '\n')
96+
console.log(typeof result === 'string' ? result : inspect(result))
8597
}
8698
} else {
8799
if (argv._.length) {
@@ -129,7 +141,11 @@ function replEval (code: string, context: any, filename: string, callback: (err:
129141
try {
130142
result = _eval(code, EVAL_PATH)
131143
} catch (e) {
132-
err = e
144+
if (e instanceof TypeScriptError) {
145+
err = e.message
146+
} else {
147+
err = e
148+
}
133149
}
134150

135151
callback(err, result)

src/typescript-node.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { BaseError } from 'make-error'
77
import sourceMapSupport = require('source-map-support')
88
import extend = require('xtend')
99
import arrify = require('arrify')
10+
import chalk = require('chalk')
1011

1112
/**
1213
* Export the current version.
@@ -25,6 +26,7 @@ export interface Options {
2526
compiler?: string
2627
configFile?: string
2728
ignoreWarnings?: string[]
29+
isRepl?: boolean
2830
}
2931

3032
/**
@@ -74,8 +76,10 @@ export function register (opts?: Options) {
7476
const ts: typeof TS = require(options.compiler)
7577
const config = readConfig(options.configFile, ts)
7678

79+
// Render the configuration errors and exit the script.
7780
if (config.errors.length) {
78-
throw new TypeScriptError(config.errors, ts)
81+
console.error(formatDiagnostics(config.errors, ts))
82+
process.exit(1)
7983
}
8084

8185
const serviceHost: TS.LanguageServiceHost = {
@@ -133,7 +137,14 @@ export function register (opts?: Options) {
133137
const diagnostics = getDiagnostics(service, fileName, options)
134138

135139
if (diagnostics.length) {
136-
throw new TypeScriptError(diagnostics, ts)
140+
const message = formatDiagnostics(diagnostics, ts)
141+
142+
if (opts.isRepl) {
143+
throw new TypeScriptError(message)
144+
}
145+
146+
console.error(message)
147+
process.exit(1)
137148
}
138149

139150
return contents
@@ -181,14 +192,23 @@ export function formatDiagnostic (diagnostic: TS.Diagnostic, ts: typeof TS, cwd:
181192
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')
182193

183194
if (diagnostic.file) {
195+
const path = relative(cwd, diagnostic.file.fileName)
184196
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start)
185197

186-
return `${relative(cwd, diagnostic.file.fileName)} (${line + 1},${character + 1}): ${message} (${diagnostic.code})`
198+
return `${chalk.gray(`${path} (${line + 1},${character + 1}):`)} ${message} (${diagnostic.code})`
187199
}
188200

189201
return `${message} (${diagnostic.code})`
190202
}
191203

204+
/**
205+
* Format diagnostics into friendlier errors.
206+
*/
207+
function formatDiagnostics (diagnostics: TS.Diagnostic[], ts: typeof TS) {
208+
return chalk.red('⨯ Unable to compile TypeScript') +
209+
EOL + EOL + diagnostics.map(d => formatDiagnostic(d, ts)).join(EOL)
210+
}
211+
192212
/**
193213
* Sanitize the source map content.
194214
*/
@@ -208,14 +228,4 @@ export class TypeScriptError extends BaseError {
208228

209229
name = 'TypeScriptError'
210230

211-
message: string
212-
diagnosticMessages: string[]
213-
214-
constructor (public diagnostics: TS.Diagnostic[], ts: typeof TS) {
215-
super()
216-
217-
this.diagnosticMessages = diagnostics.map(d => formatDiagnostic(d, ts))
218-
this.message = ['Unable to compile TypeScript'].concat(this.diagnosticMessages).join(EOL)
219-
}
220-
221231
}

src/typings/make-error.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ declare module 'make-error' {
33
message: string
44
name: string
55
stack: string
6+
7+
constructor (message: string)
68
}
79
}

tsd.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
},
2020
"minimist/minimist.d.ts": {
2121
"commit": "b3aeee64552e324581fdbe0926f4a96e981e451b"
22+
},
23+
"chalk/chalk.d.ts": {
24+
"commit": "a461a243e2e09b213bc49d12650f80d81047576d"
2225
}
2326
}
2427
}

typings/chalk/chalk.d.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Type definitions for chalk v0.4.0
2+
// Project: https://github.com/sindresorhus/chalk
3+
// Definitions by: Diullei Gomes <https://github.com/Diullei>, Bart van der Schoor <https://github.com/Bartvds>
4+
// Definitions: https://github.com/borisyankov/DefinitelyTyped
5+
6+
declare module Chalk {
7+
export interface ChalkModule extends ChalkStyle {
8+
enabled: boolean;
9+
supportsColor: boolean;
10+
styles: ChalkStyleMap;
11+
12+
stripColor(value: string): any;
13+
hasColor(str: string): boolean;
14+
}
15+
16+
export interface ChalkChain extends ChalkStyle {
17+
(...text: string[]): ChalkChain;
18+
}
19+
20+
export interface ChalkStyleElement {
21+
open: string;
22+
close: string;
23+
}
24+
25+
export interface ChalkStyle {
26+
// General
27+
reset: ChalkChain;
28+
bold: ChalkChain;
29+
italic: ChalkChain;
30+
underline: ChalkChain;
31+
inverse: ChalkChain;
32+
strikethrough: ChalkChain;
33+
34+
// Text colors
35+
black: ChalkChain;
36+
red: ChalkChain;
37+
green: ChalkChain;
38+
yellow: ChalkChain;
39+
blue: ChalkChain;
40+
magenta: ChalkChain;
41+
cyan: ChalkChain;
42+
white: ChalkChain;
43+
gray: ChalkChain;
44+
grey: ChalkChain;
45+
46+
// Background colors
47+
bgBlack: ChalkChain;
48+
bgRed: ChalkChain;
49+
bgGreen: ChalkChain;
50+
bgYellow: ChalkChain;
51+
bgBlue: ChalkChain;
52+
bgMagenta: ChalkChain;
53+
bgCyan: ChalkChain;
54+
bgWhite: ChalkChain;
55+
}
56+
57+
export interface ChalkStyleMap {
58+
// General
59+
reset: ChalkStyleElement;
60+
bold: ChalkStyleElement;
61+
italic: ChalkStyleElement;
62+
underline: ChalkStyleElement;
63+
inverse: ChalkStyleElement;
64+
strikethrough: ChalkStyleElement;
65+
66+
// Text colors
67+
black: ChalkStyleElement;
68+
red: ChalkStyleElement;
69+
green: ChalkStyleElement;
70+
yellow: ChalkStyleElement;
71+
blue: ChalkStyleElement;
72+
magenta: ChalkStyleElement;
73+
cyan: ChalkStyleElement;
74+
white: ChalkStyleElement;
75+
gray: ChalkStyleElement;
76+
77+
// Background colors
78+
bgBlack: ChalkStyleElement;
79+
bgRed: ChalkStyleElement;
80+
bgGreen: ChalkStyleElement;
81+
bgYellow: ChalkStyleElement;
82+
bgBlue: ChalkStyleElement;
83+
bgMagenta: ChalkStyleElement;
84+
bgCyan: ChalkStyleElement;
85+
bgWhite: ChalkStyleElement;
86+
}
87+
}
88+
89+
declare module "chalk" {
90+
var ch: Chalk.ChalkModule;
91+
export = ch;
92+
}
93+

typings/tsd.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/// <reference path="node/node.d.ts" />
44
/// <reference path="source-map-support/source-map-support.d.ts" />
55
/// <reference path="minimist/minimist.d.ts" />
6+
/// <reference path="chalk/chalk.d.ts" />

0 commit comments

Comments
 (0)