88 isNumericIdentifier ,
99 NUMERIC_IDENTIFIER_EXCLUSION_REASON ,
1010 checkNumericIdentifierExclusion ,
11+ throwUIDValidationError ,
1112} from "./shared/utils" ;
1213
1314export type TSGenOptions = {
@@ -94,6 +95,13 @@ export default function (userOptions: TSGenOptions) {
9495 const skippedBlocks : Array < { uid : string ; path : string ; reason : string } > =
9596 [ ] ;
9697
98+ // Collect numeric identifier errors instead of throwing immediately
99+ const numericIdentifierErrors : Array < {
100+ uid : string ;
101+ referenceTo ?: string ;
102+ type : "content_type" | "global_field" ;
103+ } > = [ ] ;
104+
97105 const typeMap : TypeMap = {
98106 text : { func : type_text , track : true , flag : TypeFlags . BuiltinJS } ,
99107 number : { func : type_number , track : true , flag : TypeFlags . BuiltinJS } ,
@@ -152,6 +160,12 @@ export default function (userOptions: TSGenOptions) {
152160 }
153161
154162 function name_type ( uid : string ) {
163+ // Check if the UID starts with a number, which would create invalid TypeScript
164+ if ( isNumericIdentifier ( uid ) ) {
165+ // Return a fallback name to continue processing
166+ return `InvalidInterface_${ uid } ` ;
167+ }
168+
155169 return [ options ?. naming ?. prefix , _ . upperFirst ( _ . camelCase ( uid ) ) ]
156170 . filter ( ( v ) => v )
157171 . join ( "" ) ;
@@ -161,14 +175,41 @@ export default function (userOptions: TSGenOptions) {
161175 contentType : ContentstackTypes . ContentType | ContentstackTypes . GlobalField ,
162176 systemFields = false
163177 ) {
164- const interface_declaration = [
165- "export interface" ,
166- name_type (
167- contentType . data_type === "global_field"
168- ? ( contentType . reference_to as string )
169- : contentType . uid
170- ) ,
171- ] ;
178+ // Validate the interface name before creating it
179+ let interfaceName : string ;
180+
181+ const isGlobalField = contentType . data_type === "global_field" ;
182+
183+ // Check if the content type's own UID starts with a number
184+ if ( isNumericIdentifier ( contentType . uid ) ) {
185+ numericIdentifierErrors . push ( {
186+ uid : contentType . uid ,
187+ type : "content_type" ,
188+ } ) ;
189+ // Return a fallback interface declaration to continue processing
190+ interfaceName = `InvalidInterface_${ contentType . uid } ` ;
191+ } else if (
192+ isGlobalField &&
193+ contentType . reference_to &&
194+ isNumericIdentifier ( contentType . reference_to as string )
195+ ) {
196+ // For global fields, check if the referenced content type has a numeric identifier
197+ // This is a global field error because it references an invalid content type
198+ numericIdentifierErrors . push ( {
199+ uid : contentType . uid , // The global field's UID
200+ type : "global_field" ,
201+ referenceTo : contentType . reference_to as string , // The referenced content type's UID
202+ } ) ;
203+ // Return a fallback interface declaration to continue processing
204+ interfaceName = `InvalidInterface_${ contentType . reference_to } ` ;
205+ } else {
206+ // No numeric identifier issues, generate normal interface name
207+ interfaceName = name_type (
208+ isGlobalField ? ( contentType . reference_to as string ) : contentType . uid
209+ ) ;
210+ }
211+
212+ const interface_declaration = [ "export interface" , interfaceName ] ;
172213 if ( systemFields && contentType . schema_type !== "global_field" ) {
173214 interface_declaration . push ( "extends" , name_type ( "SystemFields" ) ) ;
174215 }
@@ -570,6 +611,56 @@ export default function (userOptions: TSGenOptions) {
570611
571612 const definition = visit_content_type ( contentType ) ;
572613
614+ // Check for numeric identifier errors and throw them immediately
615+ if ( numericIdentifierErrors . length > 0 ) {
616+ // Group errors by type for better organization
617+ const contentTypeErrors = numericIdentifierErrors . filter (
618+ ( err ) => err . type === "content_type"
619+ ) ;
620+ const globalFieldErrors = numericIdentifierErrors . filter (
621+ ( err ) => err . type === "global_field"
622+ ) ;
623+
624+ // Build the detailed error message
625+ let errorDetails = "" ;
626+ errorDetails += `Type generation failed: ${ numericIdentifierErrors . length } items use numeric identifiers, which result in invalid TypeScript interface names. Use the --prefix flag to resolve this issue.\n\n` ;
627+
628+ if ( contentTypeErrors . length > 0 ) {
629+ errorDetails += "Content Types and Global Fields with Numeric UIDs\n" ;
630+ errorDetails +=
631+ "Note: Global Fields are also Content Types. If their UID begins with a number, they are listed here.\n\n" ;
632+
633+ contentTypeErrors . forEach ( ( error , index ) => {
634+ errorDetails += `${ index + 1 } . UID: "${ error . uid } "\n` ;
635+ errorDetails += `TypeScript constraint: Object keys cannot start with a number.\n` ;
636+ errorDetails += `Suggestion: Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType").\n\n` ;
637+ } ) ;
638+ }
639+
640+ if ( globalFieldErrors . length > 0 ) {
641+ errorDetails += "Global Fields Referencing Invalid Content Types:\n\n" ;
642+
643+ globalFieldErrors . forEach ( ( error , index ) => {
644+ errorDetails += `${ index + 1 } . Global Field: "${ error . uid } "\n` ;
645+ errorDetails += ` References: "${ error . referenceTo || "Unknown" } "\n` ;
646+ errorDetails += `TypeScript constraint: Object keys cannot start with a number.\n` ;
647+ errorDetails += `Suggestion: Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType").\n\n` ;
648+ } ) ;
649+ }
650+
651+ errorDetails += "To resolve these issues:\n" ;
652+ errorDetails +=
653+ "• Use the --prefix flag to add a valid prefix to all interface names.\n" ;
654+ errorDetails += '• Example: --prefix "ContentType"\n' ;
655+
656+ // Throw a comprehensive error with all the details
657+ throw {
658+ type : "validation" ,
659+ error_code : "VALIDATION_ERROR" ,
660+ error_message : errorDetails ,
661+ } ;
662+ }
663+
573664 // Log summary table of skipped fields and blocks
574665 if ( skippedFields . length > 0 || skippedBlocks . length > 0 ) {
575666 cliux . print ( "" ) ;
0 commit comments