Skip to content

Commit 44a928b

Browse files
feat: remove process.exit(1) (#1231)
1 parent ec1179e commit 44a928b

File tree

5 files changed

+57
-81
lines changed

5 files changed

+57
-81
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@lingo.dev/_compiler": patch
3+
---
4+
5+
Compiler now throws errors instead of abruptly exiting the process, allowing parent applications to handle errors gracefully

packages/compiler/src/index.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ const unplugin = createUnplugin<Partial<typeof defaultParams> | undefined>(
7979
params.targetLocales,
8080
);
8181
if (invalidLocales.length > 0) {
82-
console.log(dedent`
83-
\n
82+
throw new Error(dedent`
8483
⚠️ Lingo.dev Localization Compiler requires LLM model setup for the following locales: ${invalidLocales.join(
8584
", ",
8685
)}.
@@ -89,10 +88,7 @@ const unplugin = createUnplugin<Partial<typeof defaultParams> | undefined>(
8988
1. Refer to documentation for help: https://lingo.dev/compiler
9089
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
9190
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
92-
93-
9491
`);
95-
process.exit(1);
9692
}
9793
}
9894
}
@@ -429,16 +425,15 @@ function validateLLMKeyDetails(configuredProviders: string[]): void {
429425
`);
430426
}
431427

432-
console.log(dedent`
428+
const errorMessage = dedent`
433429
\n
434430
⭐️ Also:
435431
1. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://lingo.dev/compiler
436432
2. If the model/provider you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
437433
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
438-
439-
440-
`);
441-
process.exit(1);
434+
`;
435+
console.log(errorMessage);
436+
throw new Error("Missing required LLM API keys. See details above.");
442437
} else if (foundProviders.length > 0) {
443438
console.log(dedent`
444439
\n

packages/compiler/src/lib/lcp/api/index.ts

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -397,38 +397,33 @@ export class LCPAPI {
397397
* The message explains why this situation is unusual and how to fix it.
398398
* @param providerId The ID of the LLM provider whose key is missing.
399399
*/
400-
private static _failMissingLLMKeyCi(providerId: string): void {
400+
private static _failMissingLLMKeyCi(providerId: string): never {
401401
let details = providerDetails[providerId];
402402
if (!details) {
403403
// Fallback for unsupported provider in failure message logic
404-
console.error(
404+
throw new Error(
405405
`Internal Error: Missing details for provider "${providerId}" when reporting missing key in CI/CD. You might be using an unsupported provider.`,
406406
);
407-
process.exit(1);
408407
}
409408

410-
console.log(
411-
dedent`
412-
\n
413-
💡 You're using Lingo.dev Localization Compiler, and it detected unlocalized components in your app.
414-
415-
The compiler needs a ${details.name} API key to translate missing strings, but ${details.apiKeyEnvVar} is not set in the environment.
409+
const errorMessage = dedent`
410+
💡 You're using Lingo.dev Localization Compiler, and it detected unlocalized components in your app.
416411
417-
This is unexpected: typically you run a full build locally, commit the generated translation files, and push them to CI/CD.
412+
The compiler needs a ${details.name} API key to translate missing strings, but ${details.apiKeyEnvVar} is not set in the environment.
418413
419-
However, If you want CI/CD to translate the new strings, provide the key with:
420-
• Session-wide: export ${details.apiKeyEnvVar}=<your-api-key>
421-
• Project-wide / CI: add ${details.apiKeyEnvVar}=<your-api-key> to your pipeline environment variables
414+
This is unexpected: typically you run a full build locally, commit the generated translation files, and push them to CI/CD.
422415
423-
⭐️ Also:
424-
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
425-
2. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://lingo.dev/compiler
426-
3. If the model you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
416+
However, If you want CI/CD to translate the new strings, provide the key with:
417+
• Session-wide: export ${details.apiKeyEnvVar}=<your-api-key>
418+
• Project-wide / CI: add ${details.apiKeyEnvVar}=<your-api-key> to your pipeline environment variables
427419
428-
429-
`,
430-
);
431-
process.exit(1);
420+
⭐️ Also:
421+
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
422+
2. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://lingo.dev/compiler
423+
3. If the model you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
424+
`;
425+
console.log(errorMessage);
426+
throw new Error(`Missing ${details.name} API key in CI/CD environment.`);
432427
}
433428

434429
/**
@@ -442,44 +437,39 @@ export class LCPAPI {
442437
providerId: string,
443438
targetLocale: string,
444439
errorMessage: string,
445-
): void {
440+
): never {
446441
const details = providerDetails[providerId];
447442
if (!details) {
448443
// Fallback
449-
console.error(
450-
`Internal Error: Missing details for provider "${providerId}" when reporting local failure.`,
444+
throw new Error(
445+
`Internal Error: Missing details for provider "${providerId}" when reporting local failure. Original Error: ${errorMessage}`,
451446
);
452-
console.error(`Original Error: ${errorMessage}`);
453-
process.exit(1);
454447
}
455448

456449
const isInvalidApiKey = errorMessage.match("Invalid API Key"); // TODO: This may change per-provider, so might update this later
457450

458451
if (isInvalidApiKey) {
459-
console.log(dedent`
460-
\n
461-
⚠️ Lingo.dev Compiler requires a valid ${details.name} API key to translate your application.
462-
463-
It looks like you set ${details.name} API key but it is not valid. Please check your API key and try again.
452+
const message = dedent`
453+
⚠️ Lingo.dev Compiler requires a valid ${details.name} API key to translate your application.
464454
465-
Error details from ${details.name} API: ${errorMessage}
455+
It looks like you set ${details.name} API key but it is not valid. Please check your API key and try again.
466456
467-
👉 You can set the API key in one of the following ways:
468-
1. User-wide: Run npx lingo.dev@latest config set ${details.apiKeyConfigKey} <your-api-key>
469-
2. Project-wide: Add ${details.apiKeyEnvVar}=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
470-
3 Session-wide: Run export ${details.apiKeyEnvVar}=<your-api-key> in your terminal before running the compiler to set the API key for the current session
457+
Error details from ${details.name} API: ${errorMessage}
471458
472-
⭐️ Also:
473-
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
474-
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
475-
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
459+
👉 You can set the API key in one of the following ways:
460+
1. User-wide: Run npx lingo.dev@latest config set ${details.apiKeyConfigKey} <your-api-key>
461+
2. Project-wide: Add ${details.apiKeyEnvVar}=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
462+
3 Session-wide: Run export ${details.apiKeyEnvVar}=<your-api-key> in your terminal before running the compiler to set the API key for the current session
476463
477-
478-
`);
464+
⭐️ Also:
465+
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
466+
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
467+
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
468+
`;
469+
console.log(message);
470+
throw new Error(`Invalid ${details.name} API key.`);
479471
} else {
480-
console.log(
481-
dedent`
482-
\n
472+
const message = dedent`
483473
⚠️ Lingo.dev Compiler tried to translate your application to "${targetLocale}" locale via ${
484474
details.name
485475
} but it failed.
@@ -502,11 +492,11 @@ export class LCPAPI {
502492
}?
503493
2. Did you reach any limits of your ${details.name} account?
504494
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
505-
506-
507-
`,
495+
`;
496+
console.log(message);
497+
throw new Error(
498+
`Translation failed for locale "${targetLocale}" using ${details.name}: ${errorMessage}`,
508499
);
509500
}
510-
process.exit(1);
511501
}
512502
}

packages/compiler/src/lib/lcp/index.spec.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,32 +34,20 @@ describe("LCP", () => {
3434
});
3535

3636
describe("ensureFile", () => {
37-
let originalExit: any;
38-
beforeEach(() => {
39-
// stub exit to avoid existing the actual test process
40-
originalExit = process.exit;
41-
// @ts-expect-error override for test
42-
process.exit = vi.fn();
43-
});
44-
afterEach(() => {
45-
// restore mocked exit behavior
46-
(process.exit as any) = originalExit;
47-
});
48-
49-
it("creates meta.json and exists the process", () => {
37+
it("creates meta.json and throws an error", () => {
5038
(fs.existsSync as any).mockReturnValueOnce(false);
51-
LCP.ensureFile({ sourceRoot: "src", lingoDir: "lingo" });
39+
expect(() => {
40+
LCP.ensureFile({ sourceRoot: "src", lingoDir: "lingo" });
41+
}).toThrow(/Lingo.dev Compiler detected missing meta.json file/);
5242
expect(fs.mkdirSync).toHaveBeenCalled();
5343
expect(fs.writeFileSync).toHaveBeenCalled();
54-
expect(process.exit).toHaveBeenCalledWith(1);
5544
});
5645

5746
it("does not create meta.json if it already exists", () => {
5847
(fs.existsSync as any).mockReturnValue(true);
5948
LCP.ensureFile({ sourceRoot: "src", lingoDir: "lingo" });
6049
expect(fs.mkdirSync).not.toHaveBeenCalled();
6150
expect(fs.writeFileSync).not.toHaveBeenCalled();
62-
expect(process.exit).not.toHaveBeenCalled();
6351
});
6452
});
6553

packages/compiler/src/lib/lcp/index.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,17 @@ export class LCP {
2929
}
3030
fs.writeFileSync(filePath, "{}");
3131

32-
console.log(dedent`
33-
\n
34-
⚠️ Lingo.dev Compiler detected missing meta.json file in lingo directory.
35-
Please restart the build / watch command to regenerate all Lingo.dev Compiler files.
36-
`);
3732
try {
3833
fs.rmdirSync(path.resolve(process.cwd(), ".next"), {
3934
recursive: true,
4035
});
4136
} catch (error) {
4237
// Ignore errors if directory doesn't exist
4338
}
44-
process.exit(1);
39+
throw new Error(dedent`
40+
⚠️ Lingo.dev Compiler detected missing meta.json file in lingo directory.
41+
Please restart the build / watch command to regenerate all Lingo.dev Compiler files.
42+
`);
4543
}
4644
}
4745

0 commit comments

Comments
 (0)