Skip to content

Commit 913ec0f

Browse files
nspaethvegarringdal
authored andcommitted
Improve formatting (#29)
* improve formatting by grouping files and truncating pathnames Instead of showing paths like: /home/myusername/projects/my-project-name/src/client/views/Login/index.ts: left-truncate them to ./src/client/views/Login/index.ts Instead of repeating the path for many errors in the same file, eg.. └── ./src/client/views/Login/index.ts (20,1): [SomeError:234233]: A long message └── ./src/client/views/Login/style.ts (21,1): [SomeError:234233]: A long message └── ./src/client/views/Login/style.ts (22,1): [SomeError:234233]: A long message └── ./src/client/views/Login/index.ts (23,1): [SomeError:234233]: A long message Group messages to └──./src/client/views/Login/index.ts | (20,1): [SomeError:234233]: A long message | (23,1): [SomeError:234233]: A long message └──./src/client/views/Login/style.ts | (21,1): [SomeError:234233]: A long message | (22,1): [SomeError:234233]: A long message * fix accidentally commented code * Move interfaces to interfaces.ts * fix tslint errors * make short filenames optional * document option to shorten filenames * use path.resolve on paths in order to ensure cross-platform compatibility * change grouping filename color to white
1 parent 4593853 commit 913ec0f

File tree

4 files changed

+123
-116
lines changed

4 files changed

+123
-116
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ var buildFuse = (production) => {
126126
fuse.bundle("vendor")
127127
.cache(true)
128128
.target('browser')
129-
.instructions(`
129+
.instructions(`
130130
+ whatwg-fetch
131131
+ something-else-u-need
132132
`)
@@ -142,7 +142,7 @@ var buildFuse = (production) => {
142142
.target('browser')
143143

144144

145-
// is production build
145+
// is production build
146146
production ? null : app.watch()
147147
.cache(false)
148148
.sourceMaps(true)
@@ -166,7 +166,7 @@ var buildFuse = (production) => {
166166

167167

168168
```typescript
169-
interface IOptionsInterface {
169+
interface ITypeCheckerOptionsInterface {
170170
tsConfig: string; //config file (compared to basepath './tsconfig.json')
171171
throwOnSyntactic?: boolean; // if you want it to throwe error
172172
throwOnSemantic?: boolean; // if you want it to throwe error
@@ -182,6 +182,7 @@ interface IOptionsInterface {
182182
yellowOnGlobal?: boolean; // use yellow color instead of red on Global errors
183183
yellowOnSemantic?: boolean; // use yellow color instead of red on Semantic errors
184184
yellowOnSyntactic?: boolean; // use yellow color instead of red on Syntactic errors
185+
shortenFilenames?: boolean; // use shortened filenames in order to make output less noisy
185186
}
186187

187188

src/checker.ts

Lines changed: 93 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import * as ts from 'typescript';
22
import * as chalk from 'chalk';
33
import * as tslint from 'tslint';
44
import * as path from 'path';
5-
import { IInternalTypeCheckerOptions, END_LINE } from './interfaces';
5+
import { IInternalTypeCheckerOptions, END_LINE, ITSLintError, ITSError } from './interfaces';
66

7+
type TypeCheckError = ITSLintError | ITSError;
8+
function isTSError(error: TypeCheckError) {
9+
return (<ITSError>error).code !== undefined;
10+
}
711

812
export class Checker {
913

@@ -146,22 +150,52 @@ export class Checker {
146150
);
147151

148152
// get the lint errors messages
149-
let lintErrorMessages = this.processLintFiles();
153+
let lintErrorMessages: TypeCheckError[] = this.processLintFiles();
150154

151155
// loop diagnostics and get the errors messages
152-
let tsErrorMessages = this.processTsDiagnostics();
156+
let tsErrorMessages: TypeCheckError[] = this.processTsDiagnostics();
153157

154158
// combine errors and print if any
155-
let allErrors = tsErrorMessages.concat(lintErrorMessages);
159+
let combinedErrors: TypeCheckError[] = tsErrorMessages.concat(lintErrorMessages);
160+
161+
// group by filename
162+
let groupedErrors: {[k: string]: TypeCheckError[]} = {};
163+
combinedErrors.forEach((error: TypeCheckError) => {
164+
if (!groupedErrors[error.fileName]) {
165+
groupedErrors[error.fileName] = [] as TypeCheckError[];
166+
}
167+
168+
groupedErrors[error.fileName].push(error);
169+
});
170+
171+
let allErrors = Object.entries(groupedErrors)
172+
.map(([fileName, errors]) => {
173+
const short = this.options.shortenFilenames;
174+
const fullFileName = path.resolve(fileName);
175+
const shortFileName = fullFileName.split(options.basePath).join('.');
176+
return chalk.white(`└── ${shortFileName}`) + END_LINE + errors.map((err: TypeCheckError) => {
177+
let text = chalk.red(' |');
178+
text += chalk[err.color](` ${short ? shortFileName : fullFileName} (${err.line + 1},${err.char + 1}) `);
179+
if (isTSError(err)) {
180+
text += chalk.white(`(${(<ITSError>err).category}:`);
181+
text += chalk.white(`${(<ITSError>err).code})`);
182+
text += ' ' + (<ITSError>err).message;
183+
} else {
184+
text += chalk.white(`(${(<ITSLintError>err).ruleSeverity}:`);
185+
text += chalk.white(`${(<ITSLintError>err).ruleName})`);
186+
text += ' ' + (<ITSLintError>err).failure;
187+
}
188+
189+
return text;
190+
}).join(END_LINE);
191+
});
156192

157193
// print if any
158194
if (allErrors.length > 0) {
159-
160195
// insert header
161196
allErrors.unshift(
162197
chalk.underline(`${END_LINE}File errors`) + chalk.white(':') // fix windows
163198
);
164-
165199
print(allErrors.join(END_LINE));
166200
}
167201

@@ -280,118 +314,65 @@ export class Checker {
280314
* loops lint failures and return pretty failure string ready to be printed
281315
*
282316
*/
283-
private processLintFiles(): string[] {
284-
285-
const options = this.options;
286-
287-
// loop lint results
288-
let lintResultsFilesMessages =
289-
this.lintFileResult.map((fileResult: tslint.LintResult) => {
290-
let messages: string[] = [];
291-
if (fileResult.failures) {
292-
// we have a failure, lets check its failures
293-
messages = fileResult.failures.map((failure: any) => {
294-
295-
// simplify it so its more readable later
296-
let r = {
297-
fileName: failure.fileName,
298-
line: failure.startPosition.lineAndCharacter.line,
299-
char: failure.startPosition.lineAndCharacter.character,
300-
ruleSeverity: failure.ruleSeverity.charAt(0).toUpperCase() + failure.ruleSeverity.slice(1),
301-
ruleName: failure.ruleName,
302-
failure: failure.failure
303-
};
304-
305-
// make error pretty and return it
306-
let message = chalk.red('└── ');
307-
message += chalk[options.yellowOnLint ? 'yellow' : 'red'](`${r.fileName} (${r.line + 1},${r.char + 1}) `);
308-
message += chalk.white(`(${r.ruleSeverity}:`);
309-
message += chalk.white(`${r.ruleName})`);
310-
message += ' ' + r.failure;
311-
return message;
312-
});
313-
}
314-
// return messages
315-
return messages;
316-
317-
}).filter((res: string[]) => {
318-
// filter our only messages with content
319-
return res.length === 0 ? false : true;
320-
});
321-
322-
// flatten/concatenate lint files - > failures
323-
let lintErrorMessages: string[] = [];
324-
try {
325-
if (lintResultsFilesMessages.length) {
326-
lintErrorMessages = lintResultsFilesMessages.reduce((a: string[], b: string[]) => {
327-
return a.concat(b);
328-
});
329-
}
330-
} catch (err) {
331-
console.log(err);
332-
}
333-
334-
return lintErrorMessages;
317+
private processLintFiles(): ITSLintError[] {
318+
const options = this.options;
319+
const erroredLintFiles = this.lintFileResult
320+
.filter((fileResult: tslint.LintResult) => fileResult.failures);
321+
const errors = erroredLintFiles
322+
.map(
323+
(fileResult: tslint.LintResult) =>
324+
fileResult.failures.map((failure: any) => ({
325+
fileName: failure.fileName,
326+
line: failure.startPosition.lineAndCharacter.line,
327+
char: failure.startPosition.lineAndCharacter.character,
328+
ruleSeverity: failure.ruleSeverity.charAt(0).toUpperCase() + failure.ruleSeverity.slice(1),
329+
ruleName: failure.ruleName,
330+
color: options.yellowOnLint ? 'yellow' : 'red',
331+
failure: failure.failure
332+
}))).reduce((acc, curr) => acc.concat(curr), []);
333+
return errors;
335334
}
336335

337-
338-
339336
/**
340337
* loops ts failures and return pretty failure string ready to be printed
341338
*
342339
*/
343-
private processTsDiagnostics(): string[] {
344-
345-
const options = this.options;
346-
let tsErrorMessages: string[] = [];
347-
348-
if (this.tsDiagnostics.length > 0) {
349-
tsErrorMessages = this.tsDiagnostics.map((diag: any) => {
350-
351-
// get message type error, warn, info
352-
let message = chalk.red('└── ');
353-
354-
// set color from options
355-
let color: string;
356-
switch (diag._type) {
357-
case 'options':
358-
color = options.yellowOnOptions ? 'yellow' : 'red';
359-
break;
360-
case 'global':
361-
color = options.yellowOnGlobal ? 'yellow' : 'red';
362-
break;
363-
case 'syntactic':
364-
color = options.yellowOnSyntactic ? 'yellow' : 'red';
365-
break;
366-
case 'semantic':
367-
color = options.yellowOnSemantic ? 'yellow' : 'red';
368-
break;
369-
default:
370-
color = 'red';
371-
}
372-
373-
// if file
374-
if (diag.file) {
375-
const {
376-
line,
377-
character
378-
} = diag.file.getLineAndCharacterOfPosition(diag.start);
379-
380-
message += chalk[color](`${diag.file.fileName} (${line + 1},${character + 1}) `);
381-
message += chalk.white(`(${ts.DiagnosticCategory[diag.category]}:`);
382-
message += chalk.white(`TS${diag.code})`);
383-
}
384-
385-
// flatten error message
386-
message += ' ' + ts.flattenDiagnosticMessageText(diag.messageText, END_LINE);
387-
388-
// return message
389-
return message;
390-
});
340+
private processTsDiagnostics(): ITSError[] {
341+
const options = this.options;
342+
return this.tsDiagnostics
343+
.filter((diag: any) => diag.file)
344+
.map((diag: any) => {
345+
// set color from options
346+
let color: string;
347+
switch (diag._type) {
348+
case 'options':
349+
color = options.yellowOnOptions ? 'yellow' : 'red';
350+
break;
351+
case 'global':
352+
color = options.yellowOnGlobal ? 'yellow' : 'red';
353+
break;
354+
case 'syntactic':
355+
color = options.yellowOnSyntactic ? 'yellow' : 'red';
356+
break;
357+
case 'semantic':
358+
color = options.yellowOnSemantic ? 'yellow' : 'red';
359+
break;
360+
default:
361+
color = 'red';
391362
}
392-
393-
return tsErrorMessages;
363+
const {
364+
line,
365+
character
366+
} = diag.file.getLineAndCharacterOfPosition(diag.start);
367+
return {
368+
fileName: diag.file.fileName,
369+
line: line + 1, // `(${line + 1},${character + 1})`,
370+
message: ts.flattenDiagnosticMessageText(diag.messageText, END_LINE),
371+
char: character + 1,
372+
color: color,
373+
category: `${ts.DiagnosticCategory[diag.category]}:`,
374+
code: `TS${diag.code}`
375+
};
376+
});
394377
}
395-
396-
397378
}

src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ export class TypeHelperClass {
3232
// get name
3333
this.options.name = this.options.name ? ':' + this.options.name : '';
3434

35+
// shorten filenames to de-clutter output?
36+
this.options.shortenFilenames = !!this.options.shortenFilenames;
37+
3538
// tslint options
3639
let lintOp = this.options.lintoptions;
3740
this.options.lintoptions = lintOp ? lintOp : ({} as ILintOptions);
@@ -312,4 +315,3 @@ export class TypeHelperClass {
312315
export const TypeHelper = (options: ITypeCheckerOptions): TypeHelperClass => {
313316
return new TypeHelperClass(options);
314317
};
315-

src/interfaces.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ export interface ITypeCheckerOptions {
3030
// lint options that can be passed in
3131
// todo: rename to lintOptions, but thats a breaking change, so will do that later
3232
lintoptions?: ILintOptions;
33+
34+
// use shortened filenames in order to make output less cluttered
35+
shortenFilenames?: boolean;
3336
}
3437

3538
// lint options,this is the same as tsLint uses all paths will be from basepath
@@ -70,4 +73,24 @@ export enum TypecheckerRunType {
7073
promiseAsync = 'promisesync' as any
7174
}
7275

76+
export interface ITSLintError {
77+
fileName: string;
78+
line: number;
79+
char: number;
80+
failure: string;
81+
color: string;
82+
ruleSeverity: string;
83+
ruleName: string;
84+
}
85+
86+
export interface ITSError {
87+
fileName: string;
88+
line: number;
89+
char: number;
90+
message: string;
91+
color: string;
92+
category: string;
93+
code: string;
94+
}
95+
7396
export const END_LINE = '\n';

0 commit comments

Comments
 (0)