Skip to content

Commit f3a0c98

Browse files
authored
fix: use :line:col format in webpack errors (#489)
As discussed in #481, changes the format of TypeScript error file locations to use file:line:col. This means files can be opened from the terminal at the location the error occurred (e.g. cmd+click on Mac). Closes: #481
1 parent cf52452 commit f3a0c98

12 files changed

+39
-44
lines changed

src/formatter/WebpackFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function createWebpackFormatter(formatter: Formatter, context: string): Formatte
1515
if (issue.file) {
1616
let location = forwardSlash(path.relative(context, issue.file));
1717
if (issue.location) {
18-
location += ` ${formatIssueLocation(issue.location)}`;
18+
location += `:${formatIssueLocation(issue.location)}`;
1919
}
2020

2121
return [color(`${severity} in ${location}`), formatter(issue), ''].join(os.EOL);

src/issue/IssueLocation.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,7 @@ function compareIssueLocations(locationA?: IssueLocation, locationB?: IssueLocat
2525
}
2626

2727
function formatIssueLocation(location: IssueLocation) {
28-
return [
29-
`${location.start.line}:${location.start.column}`,
30-
location.start.line !== location.end.line
31-
? `${location.end.line}:${location.end.column}`
32-
: `${location.end.column}`,
33-
].join('-');
28+
return `${location.start.line}:${location.start.column}`;
3429
}
3530

3631
export { IssueLocation, compareIssueLocations, formatIssueLocation };

src/issue/IssueWebpackError.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class IssueWebpackError extends Error {
1717
this.file = forwardSlash(relative(context, issue.file));
1818

1919
if (issue.location) {
20-
this.file += ` ${formatIssueLocation(issue.location)}`;
20+
this.file += `:${formatIssueLocation(issue.location)}`;
2121
}
2222
}
2323

test/e2e/EsLint.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ describe('EsLint', () => {
5959
errors = await driver.waitForErrors();
6060
expect(errors).toEqual([
6161
[
62-
'WARNING in src/authenticate.ts 14:34-37',
62+
'WARNING in src/authenticate.ts:14:34',
6363
'@typescript-eslint/no-explicit-any: Unexpected any. Specify a different type.',
6464
' 12 | }',
6565
' 13 | ',
@@ -70,7 +70,7 @@ describe('EsLint', () => {
7070
' 17 | {',
7171
].join('\n'),
7272
[
73-
'WARNING in src/index.ts 31:44-49',
73+
'WARNING in src/index.ts:31:44',
7474
"@typescript-eslint/no-unused-vars: 'event' is defined but never used.",
7575
' 29 | }',
7676
' 30 | });',
@@ -126,7 +126,7 @@ describe('EsLint', () => {
126126
errors = await driver.waitForErrors();
127127
expect(errors).toEqual([
128128
[
129-
'WARNING in src/model/User.ts 11:5-19',
129+
'WARNING in src/model/User.ts:11:5',
130130
"@typescript-eslint/no-unused-vars: 'temporary' is defined but never used.",
131131
' 9 | }',
132132
' 10 | ',
@@ -137,7 +137,7 @@ describe('EsLint', () => {
137137
' 14 | function getUserName(user: User): string {',
138138
].join('\n'),
139139
[
140-
'WARNING in src/model/User.ts 11:16-19',
140+
'WARNING in src/model/User.ts:11:16',
141141
'@typescript-eslint/no-explicit-any: Unexpected any. Specify a different type.',
142142
' 9 | }',
143143
' 10 | ',

test/e2e/TypeScriptContextOption.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ describe('TypeScript Context Option', () => {
102102
const errors = await driver.waitForErrors();
103103
expect(errors).toEqual([
104104
[
105-
'ERROR in src/model/User.ts 11:16-25',
105+
'ERROR in src/model/User.ts:11:16',
106106
"TS2339: Property 'firstName' does not exist on type 'User'.",
107107
' 9 | ',
108108
' 10 | function getUserName(user: User): string {',
@@ -113,7 +113,7 @@ describe('TypeScript Context Option', () => {
113113
' 14 | }',
114114
].join('\n'),
115115
[
116-
'ERROR in src/model/User.ts 11:32-40',
116+
'ERROR in src/model/User.ts:11:32',
117117
"TS2339: Property 'lastName' does not exist on type 'User'.",
118118
' 9 | ',
119119
' 10 | function getUserName(user: User): string {',

test/e2e/TypeScriptPnpSupport.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe('TypeScript PnP Support', () => {
6767
errors = await driver.waitForErrors();
6868
expect(errors).toEqual([
6969
[
70-
'ERROR in src/model/User.ts 11:16-25',
70+
'ERROR in src/model/User.ts:11:16',
7171
"TS2339: Property 'firstName' does not exist on type 'User'.",
7272
' 9 | ',
7373
' 10 | function getUserName(user: User): string {',
@@ -78,7 +78,7 @@ describe('TypeScript PnP Support', () => {
7878
' 14 | }',
7979
].join('\n'),
8080
[
81-
'ERROR in src/model/User.ts 11:32-40',
81+
'ERROR in src/model/User.ts:11:32',
8282
"TS2339: Property 'lastName' does not exist on type 'User'.",
8383
' 9 | ',
8484
' 10 | function getUserName(user: User): string {',
@@ -109,7 +109,7 @@ describe('TypeScript PnP Support', () => {
109109
errors = await driver.waitForErrors();
110110
expect(errors).toEqual([
111111
[
112-
'ERROR in src/index.ts 1:23-39',
112+
'ERROR in src/index.ts:1:23',
113113
"TS2307: Cannot find module './authenticate'.",
114114
" > 1 | import { login } from './authenticate';",
115115
' | ^^^^^^^^^^^^^^^^',
@@ -153,7 +153,7 @@ describe('TypeScript PnP Support', () => {
153153
errors = await driver.waitForErrors();
154154
expect(errors).toEqual([
155155
[
156-
'ERROR in src/index.ts 34:12-16',
156+
'ERROR in src/index.ts:34:12',
157157
"TS2339: Property 'role' does not exist on type 'void'.",
158158
' 32 | const user = await login(email, password);',
159159
' 33 | ',
@@ -164,7 +164,7 @@ describe('TypeScript PnP Support', () => {
164164
' 37 | console.log(`Logged in as ${getUserName(user)}`);',
165165
].join('\n'),
166166
[
167-
'ERROR in src/index.ts 35:45-49',
167+
'ERROR in src/index.ts:35:45',
168168
"TS2345: Argument of type 'void' is not assignable to parameter of type 'User'.",
169169
' 33 | ',
170170
" 34 | if (user.role === 'admin') {",
@@ -175,7 +175,7 @@ describe('TypeScript PnP Support', () => {
175175
' 38 | }',
176176
].join('\n'),
177177
[
178-
'ERROR in src/index.ts 37:45-49',
178+
'ERROR in src/index.ts:37:45',
179179
"TS2345: Argument of type 'void' is not assignable to parameter of type 'User'.",
180180
' 35 | console.log(`Logged in as ${getUserName(user)} [admin].`);',
181181
' 36 | } else {',

test/e2e/TypeScriptSolutionBuilderApi.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ describe('TypeScript SolutionBuilder API', () => {
5656
errors = await driver.waitForErrors();
5757
expect(errors).toEqual([
5858
[
59-
'ERROR in packages/shared/src/intersect.ts 2:41-49',
59+
'ERROR in packages/shared/src/intersect.ts:2:41',
6060
"TS2339: Property 'includes' does not exist on type 'T'.",
6161
' 1 | function intersect<T>(arrayA: T[] = [], arrayB: T): T[] {',
6262
' > 2 | return arrayA.filter((item) => arrayB.includes(item));',
@@ -78,7 +78,7 @@ describe('TypeScript SolutionBuilder API', () => {
7878
errors = await driver.waitForErrors();
7979
expect(errors).toEqual([
8080
[
81-
'ERROR in packages/client/src/index.ts 4:42-48',
81+
'ERROR in packages/client/src/index.ts:4:42',
8282
"TS2345: Argument of type 'T[]' is not assignable to parameter of type 'T'.",
8383
" 'T[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.",
8484
' 2 | ',

test/e2e/TypeScriptVueExtension.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ describe('TypeScript Vue Extension', () => {
9494
errors = await driver.waitForErrors();
9595
expect(errors).toEqual([
9696
[
97-
'ERROR in src/component/LoggedIn.vue 27:21-32',
97+
'ERROR in src/component/LoggedIn.vue:27:21',
9898
"TS2304: Cannot find name 'getUserName'.",
9999
' 25 | const user: User = this.user;',
100100
' 26 | ',
@@ -122,7 +122,7 @@ describe('TypeScript Vue Extension', () => {
122122
errors = await driver.waitForErrors();
123123
expect(errors).toEqual([
124124
[
125-
'ERROR in src/component/LoggedIn.vue 27:29-38',
125+
'ERROR in src/component/LoggedIn.vue:27:29',
126126
"TS2339: Property 'firstName' does not exist on type 'User'.",
127127
' 25 | const user: User = this.user;',
128128
' 26 | ',
@@ -133,7 +133,7 @@ describe('TypeScript Vue Extension', () => {
133133
' 30 | async logout() {',
134134
].join('\n'),
135135
[
136-
'ERROR in src/model/User.ts 11:16-25',
136+
'ERROR in src/model/User.ts:11:16',
137137
"TS2339: Property 'firstName' does not exist on type 'User'.",
138138
' 9 | ',
139139
' 10 | function getUserName(user: User): string {',

test/e2e/TypeScriptWatchApi.spec.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ describe('TypeScript Watch API', () => {
7373
errors = await driver.waitForErrors();
7474
expect(errors).toEqual([
7575
[
76-
'ERROR in src/index.ts 34:7-28',
76+
'ERROR in src/index.ts:34:7',
7777
`TS2367: This condition will always return 'false' since the types 'Role' and '"admin"' have no overlap.`,
7878
' 32 | const user = await login(email, password);',
7979
' 33 | ',
@@ -115,7 +115,7 @@ describe('TypeScript Watch API', () => {
115115
);
116116
expect(errors).toEqual([
117117
[
118-
'ERROR in src/model/User.ts 1:22-30',
118+
'ERROR in src/model/User.ts:1:22',
119119
"TS2307: Cannot find module './Role'.",
120120
" > 1 | import { Role } from './Role';",
121121
' | ^^^^^^^^',
@@ -135,7 +135,7 @@ describe('TypeScript Watch API', () => {
135135
errors = await driver.waitForErrors();
136136
expect(errors).toEqual([
137137
[
138-
'ERROR in src/index.ts 34:7-31',
138+
'ERROR in src/index.ts:34:7',
139139
"TS2367: This condition will always return 'false' since the types 'Role' and '\"provider\"' have no overlap.",
140140
' 32 | const user = await login(email, password);',
141141
' 33 | ',
@@ -194,7 +194,7 @@ describe('TypeScript Watch API', () => {
194194
errors = await driver.waitForErrors();
195195
expect(errors).toEqual([
196196
[
197-
'ERROR in src/index.ts 34:7-28',
197+
'ERROR in src/index.ts:34:7',
198198
`TS2367: This condition will always return 'false' since the types 'Role' and '"admin"' have no overlap.`,
199199
' 32 | const user = await login(email, password);',
200200
' 33 | ',
@@ -236,7 +236,7 @@ describe('TypeScript Watch API', () => {
236236
);
237237
expect(errors).toEqual([
238238
[
239-
'ERROR in src/model/User.ts 1:22-30',
239+
'ERROR in src/model/User.ts:1:22',
240240
"TS2307: Cannot find module './Role'.",
241241
" > 1 | import { Role } from './Role';",
242242
' | ^^^^^^^^',
@@ -256,7 +256,7 @@ describe('TypeScript Watch API', () => {
256256
errors = await driver.waitForErrors();
257257
expect(errors).toEqual([
258258
[
259-
'ERROR in src/index.ts 34:7-31',
259+
'ERROR in src/index.ts:34:7',
260260
"TS2367: This condition will always return 'false' since the types 'Role' and '\"provider\"' have no overlap.",
261261
' 32 | const user = await login(email, password);',
262262
' 33 | ',
@@ -308,7 +308,7 @@ describe('TypeScript Watch API', () => {
308308
errors = await driver.waitForErrors();
309309
expect(errors).toEqual([
310310
[
311-
'ERROR in src/model/User.ts 11:16-25',
311+
'ERROR in src/model/User.ts:11:16',
312312
"TS2339: Property 'firstName' does not exist on type 'User'.",
313313
' 9 | ',
314314
' 10 | function getUserName(user: User): string {',
@@ -319,7 +319,7 @@ describe('TypeScript Watch API', () => {
319319
' 14 | }',
320320
].join('\n'),
321321
[
322-
'ERROR in src/model/User.ts 11:32-40',
322+
'ERROR in src/model/User.ts:11:32',
323323
"TS2339: Property 'lastName' does not exist on type 'User'.",
324324
' 9 | ',
325325
' 10 | function getUserName(user: User): string {',
@@ -350,7 +350,7 @@ describe('TypeScript Watch API', () => {
350350
errors = await driver.waitForErrors();
351351
expect(errors).toEqual([
352352
[
353-
'ERROR in src/index.ts 1:23-39',
353+
'ERROR in src/index.ts:1:23',
354354
"TS2307: Cannot find module './authenticate'.",
355355
" > 1 | import { login } from './authenticate';",
356356
' | ^^^^^^^^^^^^^^^^',
@@ -394,7 +394,7 @@ describe('TypeScript Watch API', () => {
394394
errors = await driver.waitForErrors();
395395
expect(errors).toEqual([
396396
[
397-
'ERROR in src/index.ts 34:12-16',
397+
'ERROR in src/index.ts:34:12',
398398
"TS2339: Property 'role' does not exist on type 'void'.",
399399
' 32 | const user = await login(email, password);',
400400
' 33 | ',
@@ -405,7 +405,7 @@ describe('TypeScript Watch API', () => {
405405
' 37 | console.log(`Logged in as ${getUserName(user)}`);',
406406
].join('\n'),
407407
[
408-
'ERROR in src/index.ts 35:45-49',
408+
'ERROR in src/index.ts:35:45',
409409
"TS2345: Argument of type 'void' is not assignable to parameter of type 'User'.",
410410
' 33 | ',
411411
" 34 | if (user.role === 'admin') {",
@@ -416,7 +416,7 @@ describe('TypeScript Watch API', () => {
416416
' 38 | }',
417417
].join('\n'),
418418
[
419-
'ERROR in src/index.ts 37:45-49',
419+
'ERROR in src/index.ts:37:45',
420420
"TS2345: Argument of type 'void' is not assignable to parameter of type 'User'.",
421421
' 35 | console.log(`Logged in as ${getUserName(user)} [admin].`);',
422422
' 36 | } else {',

test/e2e/WebpackIssueScope.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ describe('Webpack Issue Scope', () => {
8181
const errors = await driver.waitForErrors();
8282
expect(errors).toEqual([
8383
[
84-
'ERROR in src/notUsedFile.ts 1:7-8',
84+
'ERROR in src/notUsedFile.ts:1:7',
8585
"TS2322: Type '\"1\"' is not assignable to type 'number'.",
8686
' > 1 | const x: number = "1";',
8787
' | ^',
@@ -96,7 +96,7 @@ describe('Webpack Issue Scope', () => {
9696
const errors = await driver.waitForErrors();
9797
expect(errors).toEqual([
9898
[
99-
'ERROR in src/notUsedFile.ts 1:7-8',
99+
'ERROR in src/notUsedFile.ts:1:7',
100100
"TS2322: Type '\"1\"' is not assignable to type 'number'.",
101101
' > 1 | const x: number = "1";',
102102
' | ^',

test/e2e/WebpackProductionBuild.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ describe('Webpack Production Build', () => {
120120
// first error is from the webpack module resolution
121121
expect.anything(),
122122
[
123-
'ERROR in src/authenticate.ts 1:22-36',
123+
'ERROR in src/authenticate.ts:1:22',
124124
"TS2307: Cannot find module './model/User'.",
125125
" > 1 | import { User } from './model/User';",
126126
' | ^^^^^^^^^^^^^^',
@@ -129,7 +129,7 @@ describe('Webpack Production Build', () => {
129129
' 4 | const response = await fetch(',
130130
].join('\n'),
131131
[
132-
'ERROR in src/index.ts 2:29-43',
132+
'ERROR in src/index.ts:2:29',
133133
"TS2307: Cannot find module './model/User'.",
134134
" 1 | import { login } from './authenticate';",
135135
" > 2 | import { getUserName } from './model/User';",

test/unit/formatter/WebpackFormatter.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,18 @@ describe('formatter/WebpackFormatter', () => {
4242
});
4343

4444
it('formats location', () => {
45-
expect(formatter(issue)).toContain('1:7-16');
45+
expect(formatter(issue)).toContain(':1:7');
4646
expect(
4747
formatter({
4848
...issue,
4949
location: { start: { line: 1, column: 7 }, end: { line: 10, column: 16 } },
5050
})
51-
).toContain('1:7-10:16');
51+
).toContain(':1:7');
5252
});
5353

5454
it('formats issue header like webpack', () => {
5555
expect(formatter(issue)).toEqual(
56-
[`ERROR in some/file.ts 1:7-16`, 'TS123: Some issue content', ''].join(os.EOL)
56+
[`ERROR in some/file.ts:1:7`, 'TS123: Some issue content', ''].join(os.EOL)
5757
);
5858
});
5959
});

0 commit comments

Comments
 (0)