@@ -10,7 +10,19 @@ import _ from "lodash";
1010import * as path from "path" ;
1111import { getConfig } from "../utils/config" ;
1212import { getSettings } from "../utils/settings" ;
13- import { CLIError } from "../utils/errors" ;
13+ import {
14+ ConfigError ,
15+ AuthenticationError ,
16+ ValidationError ,
17+ LocalizationError ,
18+ BucketProcessingError ,
19+ getCLIErrorType ,
20+ isLocalizationError ,
21+ isBucketProcessingError ,
22+ ErrorDetail ,
23+ aggregateErrorAnalytics ,
24+ createPreviousErrorContext ,
25+ } from "../utils/errors" ;
1426import Ora from "ora" ;
1527import createBucketLoader from "../loaders" ;
1628import { createAuthenticator } from "../utils/auth" ;
@@ -79,7 +91,23 @@ export default new Command()
7991 updateGitignore ( ) ;
8092
8193 const ora = Ora ( ) ;
82- const flags = parseFlags ( options ) ;
94+ let flags : ReturnType < typeof parseFlags > ;
95+
96+ try {
97+ flags = parseFlags ( options ) ;
98+ } catch ( parseError : any ) {
99+ // Handle flag validation errors (like invalid locale codes)
100+ await trackEvent ( "unknown" , "cmd.i18n.error" , {
101+ errorType : "validation_error" ,
102+ errorName : parseError . name || "ValidationError" ,
103+ errorMessage : parseError . message || "Invalid command line options" ,
104+ errorStack : parseError . stack ,
105+ fatal : true ,
106+ errorCount : 1 ,
107+ stage : "flag_validation" ,
108+ } ) ;
109+ throw parseError ;
110+ }
83111
84112 if ( flags . debug ) {
85113 // wait for user input, use inquirer
@@ -94,6 +122,7 @@ export default new Command()
94122
95123 let hasErrors = false ;
96124 let authId : string | null = null ;
125+ const errorDetails : ErrorDetail [ ] = [ ] ;
97126 try {
98127 ora . start ( "Loading configuration..." ) ;
99128 const i18nConfig = getConfig ( ) ;
@@ -469,9 +498,23 @@ export default new Command()
469498 ) ;
470499 }
471500 } catch ( _error : any ) {
472- const error = new Error (
501+ const error = new LocalizationError (
473502 `[${ sourceLocale } -> ${ targetLocale } ] Localization failed: ${ _error . message } ` ,
503+ {
504+ bucket : bucket . type ,
505+ sourceLocale,
506+ targetLocale,
507+ pathPattern : bucketPath . pathPattern ,
508+ } ,
474509 ) ;
510+ errorDetails . push ( {
511+ type : "locale_error" ,
512+ bucket : bucket . type ,
513+ locale : `${ sourceLocale } -> ${ targetLocale } ` ,
514+ pathPattern : bucketPath . pathPattern ,
515+ message : _error . message ,
516+ stack : _error . stack ,
517+ } ) ;
475518 if ( flags . strict ) {
476519 throw error ;
477520 } else {
@@ -488,9 +531,16 @@ export default new Command()
488531 }
489532 }
490533 } catch ( _error : any ) {
491- const error = new Error (
534+ const error = new BucketProcessingError (
492535 `Failed to process bucket ${ bucket . type } : ${ _error . message } ` ,
536+ bucket . type ,
493537 ) ;
538+ errorDetails . push ( {
539+ type : "bucket_error" ,
540+ bucket : bucket . type ,
541+ message : _error . message ,
542+ stack : _error . stack ,
543+ } ) ;
494544 if ( flags . strict ) {
495545 throw error ;
496546 } else {
@@ -503,21 +553,59 @@ export default new Command()
503553 if ( ! hasErrors ) {
504554 ora . succeed ( "Localization completed." ) ;
505555 await trackEvent ( authId , "cmd.i18n.success" , {
506- i18nConfig,
556+ i18nConfig : {
557+ sourceLocale : i18nConfig ! . locale . source ,
558+ targetLocales : i18nConfig ! . locale . targets ,
559+ bucketTypes : Object . keys ( i18nConfig ! . buckets ) ,
560+ } ,
507561 flags,
562+ bucketCount : buckets . length ,
563+ localeCount : targetLocales . length ,
564+ processedSuccessfully : true ,
508565 } ) ;
509566 } else {
510567 ora . warn ( "Localization completed with errors." ) ;
511568 await trackEvent ( authId || "unknown" , "cmd.i18n.error" , {
512569 flags,
570+ ...aggregateErrorAnalytics (
571+ errorDetails ,
572+ buckets ,
573+ targetLocales ,
574+ i18nConfig ! ,
575+ ) ,
513576 } ) ;
514577 }
515578 } catch ( error : any ) {
516579 ora . fail ( error . message ) ;
517580
581+ // Use robust error type detection
582+ const errorType = getCLIErrorType ( error ) ;
583+
584+ // Extract additional context from typed errors
585+ let errorContext : any = { } ;
586+ if ( isLocalizationError ( error ) ) {
587+ errorContext = {
588+ bucket : error . bucket ,
589+ sourceLocale : error . sourceLocale ,
590+ targetLocale : error . targetLocale ,
591+ pathPattern : error . pathPattern ,
592+ } ;
593+ } else if ( isBucketProcessingError ( error ) ) {
594+ errorContext = {
595+ bucket : error . bucket ,
596+ } ;
597+ }
598+
518599 await trackEvent ( authId || "unknown" , "cmd.i18n.error" , {
519600 flags,
520- error,
601+ errorType,
602+ errorName : error . name || "Error" ,
603+ errorMessage : error . message ,
604+ errorStack : error . stack ,
605+ errorContext,
606+ fatal : true ,
607+ errorCount : errorDetails . length + 1 ,
608+ previousErrors : createPreviousErrorContext ( errorDetails ) ,
521609 } ) ;
522610 }
523611 } ) ;
@@ -541,7 +629,7 @@ function parseFlags(options: any) {
541629// Export validateAuth for use in other commands
542630export async function validateAuth ( settings : ReturnType < typeof getSettings > ) {
543631 if ( ! settings . auth . apiKey ) {
544- throw new CLIError ( {
632+ throw new AuthenticationError ( {
545633 message :
546634 "Not authenticated. Please run `lingo.dev login` to authenticate." ,
547635 docUrl : "authError" ,
@@ -554,7 +642,7 @@ export async function validateAuth(settings: ReturnType<typeof getSettings>) {
554642 } ) ;
555643 const user = await authenticator . whoami ( ) ;
556644 if ( ! user ) {
557- throw new CLIError ( {
645+ throw new AuthenticationError ( {
558646 message : "Invalid API key. Please run `lingo.dev login` to authenticate." ,
559647 docUrl : "authError" ,
560648 } ) ;
@@ -568,21 +656,21 @@ function validateParams(
568656 flags : ReturnType < typeof parseFlags > ,
569657) {
570658 if ( ! i18nConfig ) {
571- throw new CLIError ( {
659+ throw new ConfigError ( {
572660 message :
573661 "i18n.json not found. Please run `lingo.dev init` to initialize the project." ,
574662 docUrl : "i18nNotFound" ,
575663 } ) ;
576664 } else if ( ! i18nConfig . buckets || ! Object . keys ( i18nConfig . buckets ) . length ) {
577- throw new CLIError ( {
665+ throw new ConfigError ( {
578666 message :
579667 "No buckets found in i18n.json. Please add at least one bucket containing i18n content." ,
580668 docUrl : "bucketNotFound" ,
581669 } ) ;
582670 } else if (
583671 flags . locale ?. some ( ( locale ) => ! i18nConfig . locale . targets . includes ( locale ) )
584672 ) {
585- throw new CLIError ( {
673+ throw new ValidationError ( {
586674 message : `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.` ,
587675 docUrl : "localeTargetNotFound" ,
588676 } ) ;
@@ -592,7 +680,7 @@ function validateParams(
592680 ! i18nConfig . buckets [ bucket as keyof typeof i18nConfig . buckets ] ,
593681 )
594682 ) {
595- throw new CLIError ( {
683+ throw new ValidationError ( {
596684 message : `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.` ,
597685 docUrl : "bucketNotFound" ,
598686 } ) ;
0 commit comments