From e10b98a336f074ff4aef06501dd9f2818893ba11 Mon Sep 17 00:00:00 2001 From: naman-contentstack Date: Mon, 25 Aug 2025 11:24:32 +0530 Subject: [PATCH] restructured for better readability and optimization --- .talismanrc | 2 + src/generateTS/factory.ts | 49 +------------- src/generateTS/shared/utils.ts | 118 +++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 47 deletions(-) diff --git a/.talismanrc b/.talismanrc index fe7d1d2..153ecc3 100644 --- a/.talismanrc +++ b/.talismanrc @@ -18,4 +18,6 @@ fileignoreconfig: checksum: 7ffa82084fd0fc2f5ec9c8e8124cdf1bce08c7f75c5be2ede2eb5cd506812db1 - filename: tests/integration/generateTS/generateTS.test.ts checksum: 7c1bc7d659ee2f9f52bf644b9e512984f89e0ff6aa4288b6e30b2c899bf80123 + - filename: src/generateTS/shared/utils.ts + checksum: da69dab1717422e12f3b3865604667151d46c96bde5faba13ae862c41d856fba version: "1.0" diff --git a/src/generateTS/factory.ts b/src/generateTS/factory.ts index fb63fdb..327c1f9 100644 --- a/src/generateTS/factory.ts +++ b/src/generateTS/factory.ts @@ -8,7 +8,7 @@ import { isNumericIdentifier, NUMERIC_IDENTIFIER_EXCLUSION_REASON, checkNumericIdentifierExclusion, - throwUIDValidationError, + throwNumericIdentifierValidationError, } from "./shared/utils"; export type TSGenOptions = { @@ -613,52 +613,7 @@ export default function (userOptions: TSGenOptions) { // Check for numeric identifier errors and throw them immediately if (numericIdentifierErrors.length > 0) { - // Group errors by type for better organization - const contentTypeErrors = numericIdentifierErrors.filter( - (err) => err.type === "content_type" - ); - const globalFieldErrors = numericIdentifierErrors.filter( - (err) => err.type === "global_field" - ); - - // Build the detailed error message - let errorDetails = ""; - 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`; - - if (contentTypeErrors.length > 0) { - errorDetails += "Content Types and Global Fields with Numeric UIDs\n"; - errorDetails += - "Note: Global Fields are also Content Types. If their UID begins with a number, they are listed here.\n\n"; - - contentTypeErrors.forEach((error, index) => { - errorDetails += `${index + 1}. UID: "${error.uid}"\n`; - errorDetails += `TypeScript constraint: Object keys cannot start with a number.\n`; - 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`; - }); - } - - if (globalFieldErrors.length > 0) { - errorDetails += "Global Fields Referencing Invalid Content Types:\n\n"; - - globalFieldErrors.forEach((error, index) => { - errorDetails += `${index + 1}. Global Field: "${error.uid}"\n`; - errorDetails += ` References: "${error.referenceTo || "Unknown"}"\n`; - errorDetails += `TypeScript constraint: Object keys cannot start with a number.\n`; - 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`; - }); - } - - errorDetails += "To resolve these issues:\n"; - errorDetails += - "• Use the --prefix flag to add a valid prefix to all interface names.\n"; - errorDetails += '• Example: --prefix "ContentType"\n'; - - // Throw a comprehensive error with all the details - throw { - type: "validation", - error_code: "VALIDATION_ERROR", - error_message: errorDetails, - }; + throwNumericIdentifierValidationError(numericIdentifierErrors); } // Log summary table of skipped fields and blocks diff --git a/src/generateTS/shared/utils.ts b/src/generateTS/shared/utils.ts index 0b9b13e..cea5a78 100644 --- a/src/generateTS/shared/utils.ts +++ b/src/generateTS/shared/utils.ts @@ -144,3 +144,121 @@ export function createErrorDetails( }; } } + +/** + * Helper function to format error details consistently + * @param error - The error object containing uid and other details + * @param index - The index number for the error + * @param skipHeader - Whether to skip the header (for global fields) + * @returns Formatted error details string + */ +export function formatErrorDetails( + error: any, + index: number, + skipHeader: boolean = false +): string { + if (skipHeader) { + // For global fields, skip the header since it's already added above + return `TypeScript constraint: Object keys cannot start with a number.\nSuggestion: Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType").\n\n`; + } + + // For content types, include the full header + return `${index}. UID: "${error.uid}"\nTypeScript constraint: Object keys cannot start with a number.\nSuggestion: Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType").\n\n`; +} + +/** + * Build the main error header for numeric identifier errors + * @param totalErrors - Total number of errors found + * @returns Error header string + */ +export function buildErrorHeader(totalErrors: number): string { + return `Type generation failed: ${totalErrors} items use numeric identifiers, which result in invalid TypeScript interface names. Use the --prefix flag to resolve this issue.\n\n`; +} + +/** + * Build content type errors section + * @param contentTypeErrors - Array of content type errors + * @returns Formatted content type errors section string + */ +export function buildContentTypeErrorsSection( + contentTypeErrors: any[] +): string { + if (contentTypeErrors.length === 0) return ""; + + let section = "Content Types and Global Fields with Numeric UIDs\n"; + section += + "Note: Global Fields are also Content Types. If their UID begins with a number, they are listed here.\n\n"; + + contentTypeErrors.forEach((error, index) => { + section += formatErrorDetails(error, index + 1); + }); + + return section; +} + +/** + * Build global field errors section + * @param globalFieldErrors - Array of global field errors + * @returns Formatted global field errors section string + */ +export function buildGlobalFieldErrorsSection( + globalFieldErrors: any[] +): string { + if (globalFieldErrors.length === 0) return ""; + + let section = "Global Fields Referencing Invalid Content Types:\n\n"; + + globalFieldErrors.forEach((error, index) => { + section += `${index + 1}. Global Field: "${error.uid}"\n`; + section += ` References: "${error.referenceTo || "Unknown"}"\n`; + section += formatErrorDetails(error, index + 1, true); + }); + + return section; +} + +/** + * Build resolution instructions section + * @returns Resolution instructions string + */ +export function buildResolutionInstructionsSection(): string { + return ( + "To resolve these issues:\n" + + "• Use the --prefix flag to add a valid prefix to all interface names.\n" + + '• Example: --prefix "ContentType"\n' + ); +} + +/** + * Parent method that orchestrates the error building process + * @param errors - Array of numeric identifier errors + * @returns Complete error message string + */ +export function buildNumericIdentifierErrorDetails(errors: any[]): string { + // Group errors by type for better organization + const contentTypeErrors = errors.filter((err) => err.type === "content_type"); + const globalFieldErrors = errors.filter((err) => err.type === "global_field"); + + // Build the complete error message by calling each section builder + let errorDetails = buildErrorHeader(errors.length); + errorDetails += buildContentTypeErrorsSection(contentTypeErrors); + errorDetails += buildGlobalFieldErrorsSection(globalFieldErrors); + errorDetails += buildResolutionInstructionsSection(); + + return errorDetails; +} + +/** + * Create and throw validation error for numeric identifiers + * @param errors - Array of numeric identifier errors + * @throws A validation error object + */ +export function throwNumericIdentifierValidationError(errors: any[]): never { + const errorDetails = buildNumericIdentifierErrorDetails(errors); + + throw { + type: "validation", + error_code: "VALIDATION_ERROR", + error_message: errorDetails, + }; +}