Skip to content

Commit 900475a

Browse files
Merge pull request #122 from contentstack/enhancement/DX-3404
restructured for better readability and optimization
2 parents f5a8a58 + e10b98a commit 900475a

3 files changed

Lines changed: 122 additions & 47 deletions

File tree

.talismanrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ fileignoreconfig:
1818
checksum: 7ffa82084fd0fc2f5ec9c8e8124cdf1bce08c7f75c5be2ede2eb5cd506812db1
1919
- filename: tests/integration/generateTS/generateTS.test.ts
2020
checksum: 7c1bc7d659ee2f9f52bf644b9e512984f89e0ff6aa4288b6e30b2c899bf80123
21+
- filename: src/generateTS/shared/utils.ts
22+
checksum: da69dab1717422e12f3b3865604667151d46c96bde5faba13ae862c41d856fba
2123
version: "1.0"

src/generateTS/factory.ts

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
isNumericIdentifier,
99
NUMERIC_IDENTIFIER_EXCLUSION_REASON,
1010
checkNumericIdentifierExclusion,
11-
throwUIDValidationError,
11+
throwNumericIdentifierValidationError,
1212
} from "./shared/utils";
1313

1414
export type TSGenOptions = {
@@ -613,52 +613,7 @@ export default function (userOptions: TSGenOptions) {
613613

614614
// Check for numeric identifier errors and throw them immediately
615615
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-
};
616+
throwNumericIdentifierValidationError(numericIdentifierErrors);
662617
}
663618

664619
// Log summary table of skipped fields and blocks

src/generateTS/shared/utils.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,121 @@ export function createErrorDetails(
144144
};
145145
}
146146
}
147+
148+
/**
149+
* Helper function to format error details consistently
150+
* @param error - The error object containing uid and other details
151+
* @param index - The index number for the error
152+
* @param skipHeader - Whether to skip the header (for global fields)
153+
* @returns Formatted error details string
154+
*/
155+
export function formatErrorDetails(
156+
error: any,
157+
index: number,
158+
skipHeader: boolean = false
159+
): string {
160+
if (skipHeader) {
161+
// For global fields, skip the header since it's already added above
162+
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`;
163+
}
164+
165+
// For content types, include the full header
166+
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`;
167+
}
168+
169+
/**
170+
* Build the main error header for numeric identifier errors
171+
* @param totalErrors - Total number of errors found
172+
* @returns Error header string
173+
*/
174+
export function buildErrorHeader(totalErrors: number): string {
175+
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`;
176+
}
177+
178+
/**
179+
* Build content type errors section
180+
* @param contentTypeErrors - Array of content type errors
181+
* @returns Formatted content type errors section string
182+
*/
183+
export function buildContentTypeErrorsSection(
184+
contentTypeErrors: any[]
185+
): string {
186+
if (contentTypeErrors.length === 0) return "";
187+
188+
let section = "Content Types and Global Fields with Numeric UIDs\n";
189+
section +=
190+
"Note: Global Fields are also Content Types. If their UID begins with a number, they are listed here.\n\n";
191+
192+
contentTypeErrors.forEach((error, index) => {
193+
section += formatErrorDetails(error, index + 1);
194+
});
195+
196+
return section;
197+
}
198+
199+
/**
200+
* Build global field errors section
201+
* @param globalFieldErrors - Array of global field errors
202+
* @returns Formatted global field errors section string
203+
*/
204+
export function buildGlobalFieldErrorsSection(
205+
globalFieldErrors: any[]
206+
): string {
207+
if (globalFieldErrors.length === 0) return "";
208+
209+
let section = "Global Fields Referencing Invalid Content Types:\n\n";
210+
211+
globalFieldErrors.forEach((error, index) => {
212+
section += `${index + 1}. Global Field: "${error.uid}"\n`;
213+
section += ` References: "${error.referenceTo || "Unknown"}"\n`;
214+
section += formatErrorDetails(error, index + 1, true);
215+
});
216+
217+
return section;
218+
}
219+
220+
/**
221+
* Build resolution instructions section
222+
* @returns Resolution instructions string
223+
*/
224+
export function buildResolutionInstructionsSection(): string {
225+
return (
226+
"To resolve these issues:\n" +
227+
"• Use the --prefix flag to add a valid prefix to all interface names.\n" +
228+
'• Example: --prefix "ContentType"\n'
229+
);
230+
}
231+
232+
/**
233+
* Parent method that orchestrates the error building process
234+
* @param errors - Array of numeric identifier errors
235+
* @returns Complete error message string
236+
*/
237+
export function buildNumericIdentifierErrorDetails(errors: any[]): string {
238+
// Group errors by type for better organization
239+
const contentTypeErrors = errors.filter((err) => err.type === "content_type");
240+
const globalFieldErrors = errors.filter((err) => err.type === "global_field");
241+
242+
// Build the complete error message by calling each section builder
243+
let errorDetails = buildErrorHeader(errors.length);
244+
errorDetails += buildContentTypeErrorsSection(contentTypeErrors);
245+
errorDetails += buildGlobalFieldErrorsSection(globalFieldErrors);
246+
errorDetails += buildResolutionInstructionsSection();
247+
248+
return errorDetails;
249+
}
250+
251+
/**
252+
* Create and throw validation error for numeric identifiers
253+
* @param errors - Array of numeric identifier errors
254+
* @throws A validation error object
255+
*/
256+
export function throwNumericIdentifierValidationError(errors: any[]): never {
257+
const errorDetails = buildNumericIdentifierErrorDetails(errors);
258+
259+
throw {
260+
type: "validation",
261+
error_code: "VALIDATION_ERROR",
262+
error_message: errorDetails,
263+
};
264+
}

0 commit comments

Comments
 (0)