Skip to content

Commit d083fc8

Browse files
authored
fix: properly output chained Typescript errors (#390)
* fix: properly output chained TypeScript errors
1 parent df98e98 commit d083fc8

File tree

5 files changed

+91
-66
lines changed

5 files changed

+91
-66
lines changed

src/ApiIncrementalChecker.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as ts from 'typescript'; // used for types only
12
import {
23
IncrementalCheckerInterface,
34
IncrementalCheckerParams
@@ -13,6 +14,7 @@ import { LintReport } from './types/eslint';
1314

1415
export class ApiIncrementalChecker implements IncrementalCheckerInterface {
1516
protected readonly tsIncrementalCompiler: CompilerHost;
17+
protected readonly typescript: typeof ts;
1618

1719
private currentEsLintErrors = new Map<string, LintReport>();
1820
private lastUpdatedFiles: string[] = [];
@@ -41,6 +43,8 @@ export class ApiIncrementalChecker implements IncrementalCheckerInterface {
4143
resolveModuleName,
4244
resolveTypeReferenceDirective
4345
);
46+
47+
this.typescript = typescript;
4448
}
4549

4650
public hasEsLinter(): boolean {
@@ -60,7 +64,10 @@ export class ApiIncrementalChecker implements IncrementalCheckerInterface {
6064
this.lastUpdatedFiles = tsDiagnostics.updatedFiles;
6165
this.lastRemovedFiles = tsDiagnostics.removedFiles;
6266

63-
return createIssuesFromTsDiagnostics(tsDiagnostics.results);
67+
return createIssuesFromTsDiagnostics(
68+
tsDiagnostics.results,
69+
this.typescript
70+
);
6471
}
6572

6673
public async getEsLintIssues(cancellationToken: CancellationToken) {

src/IncrementalChecker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export class IncrementalChecker implements IncrementalCheckerInterface {
246246
tsDiagnostics.push(...tsDiagnosticsToRegister);
247247
});
248248

249-
return createIssuesFromTsDiagnostics(tsDiagnostics);
249+
return createIssuesFromTsDiagnostics(tsDiagnostics, this.typescript);
250250
}
251251

252252
public async getEsLintIssues(

src/issue/typescript/TypeScriptIssueFactory.ts

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,10 @@ import { deduplicateAndSortIssues, Issue } from '../Issue';
33
import { IssueOrigin } from '../IssueOrigin';
44
import { IssueSeverity } from '../IssueSeverity';
55

6-
/**
7-
* Based on the TypeScript source - not used directly from the `typescript`
8-
* package as there is an option to pass a custom TypeScript instance.
9-
*/
10-
function flattenDiagnosticMessageText(
11-
messageText: string | ts.DiagnosticMessageChain
12-
) {
13-
if (typeof messageText === 'string') {
14-
return messageText;
15-
} else {
16-
let diagnosticChain: ts.DiagnosticMessageChain | undefined = messageText;
17-
let flattenMessageText = '';
18-
let indent = 0;
19-
20-
while (diagnosticChain) {
21-
if (indent) {
22-
flattenMessageText += '\n';
23-
for (let i = 0; i < indent; i++) {
24-
flattenMessageText += ' ';
25-
}
26-
}
27-
28-
flattenMessageText += diagnosticChain.messageText;
29-
indent++;
30-
diagnosticChain = diagnosticChain.next;
31-
}
32-
33-
return flattenMessageText;
34-
}
35-
}
36-
37-
function createIssueFromTsDiagnostic(diagnostic: ts.Diagnostic): Issue {
6+
function createIssueFromTsDiagnostic(
7+
diagnostic: ts.Diagnostic,
8+
typescript: typeof ts
9+
): Issue {
3810
let file: string | undefined;
3911
let line: number | undefined;
4012
let character: number | undefined;
@@ -57,15 +29,26 @@ function createIssueFromTsDiagnostic(diagnostic: ts.Diagnostic): Issue {
5729
// we don't handle Suggestion and Message diagnostics
5830
severity:
5931
diagnostic.category === 0 ? IssueSeverity.WARNING : IssueSeverity.ERROR,
60-
message: flattenDiagnosticMessageText(diagnostic.messageText),
32+
message: typescript.flattenDiagnosticMessageText(
33+
diagnostic.messageText,
34+
'\n'
35+
),
6136
file,
6237
line,
6338
character
6439
};
6540
}
6641

67-
function createIssuesFromTsDiagnostics(diagnostic: ts.Diagnostic[]): Issue[] {
68-
return deduplicateAndSortIssues(diagnostic.map(createIssueFromTsDiagnostic));
42+
function createIssuesFromTsDiagnostics(
43+
diagnostics: ts.Diagnostic[],
44+
typescript: typeof ts
45+
): Issue[] {
46+
function createIssueFromTsDiagnosticWithFormatter(diagnostic: ts.Diagnostic) {
47+
return createIssueFromTsDiagnostic(diagnostic, typescript);
48+
}
49+
return deduplicateAndSortIssues(
50+
diagnostics.map(createIssueFromTsDiagnosticWithFormatter)
51+
);
6952
}
7053

7154
export { createIssueFromTsDiagnostic, createIssuesFromTsDiagnostics };

test/unit/issue/typescript/TypeScriptIssueFactory.spec.ts

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,66 @@ import {
22
createIssueFromTsDiagnostic,
33
createIssuesFromTsDiagnostics
44
} from '../../../../lib/issue';
5-
import { Diagnostic } from 'typescript';
5+
import * as ts from 'typescript';
6+
7+
function makeDiagnosticMessageChainTestCase(): ts.Diagnostic {
8+
const version: number = Number.parseFloat(ts.versionMajorMinor);
9+
if (version <= 3.5) {
10+
return ({
11+
start: 12,
12+
code: 1221,
13+
category: 0,
14+
length: 3,
15+
file: undefined,
16+
messageText: {
17+
messageText: 'Cannot assign object to the string type',
18+
category: 0,
19+
code: 1221,
20+
next: {
21+
messageText: 'Another ident message',
22+
category: 0,
23+
code: 1221,
24+
next: {
25+
messageText: 'The most ident message',
26+
category: 0,
27+
code: 1221
28+
}
29+
}
30+
}
31+
} as unknown) as ts.Diagnostic;
32+
} else {
33+
// newer versions of typescript have the |next| property as an array
34+
return ({
35+
start: 12,
36+
code: 1221,
37+
category: 0,
38+
length: 3,
39+
file: undefined,
40+
messageText: {
41+
messageText: 'Cannot assign object to the string type',
42+
category: 0,
43+
code: 1221,
44+
next: [
45+
{
46+
messageText: 'Another ident message',
47+
category: 0,
48+
code: 1221,
49+
next: [
50+
{
51+
messageText: 'The most ident message',
52+
category: 0,
53+
code: 1221
54+
}
55+
]
56+
}
57+
]
58+
}
59+
} as unknown) as ts.Diagnostic;
60+
}
61+
}
662

763
describe('[UNIT] issue/typescript/TypeScriptIssueFactory', () => {
8-
const TS_DIAGNOSTIC_WARNING: Diagnostic = {
64+
const TS_DIAGNOSTIC_WARNING: ts.Diagnostic = {
965
start: 100,
1066
code: 4221,
1167
category: 1,
@@ -20,7 +76,7 @@ describe('[UNIT] issue/typescript/TypeScriptIssueFactory', () => {
2076
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2177
} as any
2278
};
23-
const TS_DIAGNOSTIC_ERROR: Diagnostic = {
79+
const TS_DIAGNOSTIC_ERROR: ts.Diagnostic = {
2480
start: 12,
2581
code: 1221,
2682
category: 0,
@@ -35,44 +91,23 @@ describe('[UNIT] issue/typescript/TypeScriptIssueFactory', () => {
3591
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3692
} as any
3793
};
38-
const TS_DIAGNOSTIC_WITHOUT_FILE: Diagnostic = {
94+
const TS_DIAGNOSTIC_WITHOUT_FILE: ts.Diagnostic = {
3995
start: 12,
4096
code: 1221,
4197
category: 0,
4298
length: 1,
4399
messageText: 'Cannot assign object to the string type',
44100
file: undefined
45101
};
46-
const TS_DIAGNOSTIC_MESSAGE_CHAIN: Diagnostic = {
47-
start: 12,
48-
code: 1221,
49-
category: 0,
50-
length: 3,
51-
file: undefined,
52-
messageText: {
53-
messageText: 'Cannot assign object to the string type',
54-
category: 0,
55-
code: 1221,
56-
next: {
57-
messageText: 'Another ident message',
58-
category: 0,
59-
code: 1221,
60-
next: {
61-
messageText: 'The most ident message',
62-
category: 0,
63-
code: 1221
64-
}
65-
}
66-
}
67-
};
102+
const TS_DIAGNOSTIC_MESSAGE_CHAIN: ts.Diagnostic = makeDiagnosticMessageChainTestCase();
68103

69104
it.each([
70105
[TS_DIAGNOSTIC_WARNING],
71106
[TS_DIAGNOSTIC_ERROR],
72107
[TS_DIAGNOSTIC_WITHOUT_FILE],
73108
[TS_DIAGNOSTIC_MESSAGE_CHAIN]
74109
])('creates Issue from TsDiagnostic: %p', tsDiagnostic => {
75-
const issue = createIssueFromTsDiagnostic(tsDiagnostic);
110+
const issue = createIssueFromTsDiagnostic(tsDiagnostic, ts);
76111

77112
expect(issue).toMatchSnapshot();
78113
});
@@ -87,7 +122,7 @@ describe('[UNIT] issue/typescript/TypeScriptIssueFactory', () => {
87122
]
88123
]
89124
])('creates Issues from TsDiagnostics: %p', tsDiagnostics => {
90-
const issues = createIssuesFromTsDiagnostics(tsDiagnostics);
125+
const issues = createIssuesFromTsDiagnostics(tsDiagnostics, ts);
91126

92127
expect(issues).toMatchSnapshot();
93128
});

test/unit/issue/typescript/__snapshots__/TypeScriptIssueFactory.spec.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,4 @@ Array [
9191
"severity": "error",
9292
},
9393
]
94-
`;
94+
`;

0 commit comments

Comments
 (0)