Skip to content

Commit d04b861

Browse files
authored
Print diagnostics when a protoplugin fails to emit files (#1003)
1 parent 31ece2d commit d04b861

2 files changed

Lines changed: 89 additions & 1 deletion

File tree

packages/protoplugin-test/src/transpile.test.ts.ts renamed to packages/protoplugin-test/src/transpile.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,66 @@ describe("built-in transpile", () => {
9797
]);
9898
});
9999
});
100+
101+
describe("failing to emit", () => {
102+
test("raises error with helpful message", async () => {
103+
await expect(async () =>
104+
testTranspileToDts([
105+
`export interface Foo {`,
106+
` p: {`,
107+
` [K in keyof P]: string;`,
108+
` },`,
109+
`}`,
110+
]),
111+
).rejects.toThrow(
112+
/^A problem occurred during transpilation and files were not generated\. {2}Contact the plugin author for support\.\n/,
113+
);
114+
});
115+
test("raises error with diagnostics", async () => {
116+
await expect(async () =>
117+
testTranspileToDts([
118+
`export interface Foo {`,
119+
` p: {`,
120+
` [K in keyof P]: string;`,
121+
` },`,
122+
`}`,
123+
]),
124+
).rejects.toThrow(
125+
/test\.ts\(3,17\): error TS4033: Property 'p' of exported interface has or is using private name 'P'\.$/,
126+
);
127+
});
128+
test("raises error with 3 diagnostics, and elides the rest", async () => {
129+
await expect(async () =>
130+
testTranspileToDts([
131+
`export interface Foo1 {`,
132+
` p: {`,
133+
` [K in keyof P]: string;`,
134+
` },`,
135+
`}`,
136+
`export interface Foo2 {`,
137+
` p: {`,
138+
` [K in keyof P]: string;`,
139+
` },`,
140+
`}`,
141+
`export interface Foo3 {`,
142+
` p: {`,
143+
` [K in keyof P]: string;`,
144+
` },`,
145+
`}`,
146+
`export interface Foo4 {`,
147+
` p: {`,
148+
` [K in keyof P]: string;`,
149+
` },`,
150+
`}`,
151+
`export interface Foo5 {`,
152+
` p: {`,
153+
` [K in keyof P]: string;`,
154+
` },`,
155+
`}`,
156+
]),
157+
).rejects.toThrow(
158+
/(?:test\.ts\(\d+,\d+\): .+\n){3}2 more diagnostics elided/,
159+
);
160+
});
161+
});
100162
});

packages/protoplugin/src/transpile.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,35 @@ export function transpile(
158158
throw err;
159159
}
160160
if (result.emitSkipped) {
161+
// When compilation fails, this error message is printed to stderr.
162+
const diagnostics = formatDiagnostics(result.diagnostics);
161163
throw Error(
162-
"A problem occurred during transpilation and files were not generated. Contact the plugin author for support.",
164+
`A problem occurred during transpilation and files were not generated. Contact the plugin author for support.\n\n${diagnostics}`,
163165
);
164166
}
165167
return results;
166168
}
169+
170+
function formatDiagnostics(diagnostics: readonly ts.Diagnostic[]): string {
171+
const sorted = ts.sortAndDeduplicateDiagnostics(diagnostics);
172+
if (sorted.length == 0) {
173+
return "";
174+
}
175+
const first = sorted.slice(0, 3);
176+
const formatHost: ts.FormatDiagnosticsHost = {
177+
getCanonicalFileName(fileName: string): string {
178+
return fileName;
179+
},
180+
getCurrentDirectory(): string {
181+
return ".";
182+
},
183+
getNewLine(): string {
184+
return "\n";
185+
},
186+
};
187+
let out = ts.formatDiagnostics(first, formatHost).trim();
188+
if (first.length < sorted.length) {
189+
out += `\n${sorted.length - first.length} more diagnostics elided`;
190+
}
191+
return out;
192+
}

0 commit comments

Comments
 (0)