Skip to content

Commit edc644d

Browse files
author
naman-contentstack
committed
added common functions for error handling
1 parent 9a2d2fc commit edc644d

4 files changed

Lines changed: 140 additions & 84 deletions

File tree

src/generateTS/factory.ts

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
isNumericIdentifier,
99
NUMERIC_IDENTIFIER_EXCLUSION_REASON,
1010
checkNumericIdentifierExclusion,
11+
throwUIDValidationError,
1112
} from "./shared/utils";
1213

1314
export type TSGenOptions = {
@@ -152,19 +153,13 @@ export default function (userOptions: TSGenOptions) {
152153
function name_type(uid: string) {
153154
// Check if the UID starts with a number, which would create invalid TypeScript
154155
if (isNumericIdentifier(uid)) {
155-
const error = {
156-
type: "validation",
157-
error_code: "INVALID_INTERFACE_NAME",
158-
error_message: `Content type UID "${uid}" starts with a number, which creates invalid TypeScript interface names. TypeScript interface names cannot start with numbers.`,
159-
details: {
160-
uid,
161-
reason: NUMERIC_IDENTIFIER_EXCLUSION_REASON,
162-
suggestion: `Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType")`,
163-
},
156+
throwUIDValidationError({
157+
uid,
158+
errorCode: "INVALID_INTERFACE_NAME",
159+
reason: NUMERIC_IDENTIFIER_EXCLUSION_REASON,
160+
suggestion: `Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType")`,
164161
context: "generateTSFromContentTypes",
165-
timestamp: new Date().toISOString(),
166-
};
167-
throw error;
162+
});
168163
}
169164

170165
return [options?.naming?.prefix, _.upperFirst(_.camelCase(uid))]
@@ -182,37 +177,25 @@ export default function (userOptions: TSGenOptions) {
182177
if (contentType.data_type === "global_field") {
183178
const referenceTo = contentType.reference_to as string;
184179
if (isNumericIdentifier(referenceTo)) {
185-
const error = {
186-
type: "validation",
187-
error_code: "INVALID_GLOBAL_FIELD_REFERENCE",
188-
error_message: `Global field "${contentType.uid}" references content type "${referenceTo}" which starts with a number, creating invalid TypeScript interface names.`,
189-
details: {
190-
uid: contentType.uid,
191-
reference_to: referenceTo,
192-
reason: NUMERIC_IDENTIFIER_EXCLUSION_REASON,
193-
suggestion: `Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType")`,
194-
},
180+
throwUIDValidationError({
181+
uid: contentType.uid,
182+
errorCode: "INVALID_GLOBAL_FIELD_REFERENCE",
183+
reason: NUMERIC_IDENTIFIER_EXCLUSION_REASON,
184+
suggestion: `Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType")`,
195185
context: "generateTSFromContentTypes",
196-
timestamp: new Date().toISOString(),
197-
};
198-
throw error;
186+
referenceTo,
187+
});
199188
}
200189
interfaceName = name_type(referenceTo);
201190
} else {
202191
if (isNumericIdentifier(contentType.uid)) {
203-
const error = {
204-
type: "validation",
205-
error_code: "INVALID_CONTENT_TYPE_UID",
206-
error_message: `Content type UID "${contentType.uid}" starts with a number, which creates invalid TypeScript interface names.`,
207-
details: {
208-
uid: contentType.uid,
209-
reason: NUMERIC_IDENTIFIER_EXCLUSION_REASON,
210-
suggestion: `Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType")`,
211-
},
192+
throwUIDValidationError({
193+
uid: contentType.uid,
194+
errorCode: "INVALID_CONTENT_TYPE_UID",
195+
reason: NUMERIC_IDENTIFIER_EXCLUSION_REASON,
196+
suggestion: `Since UIDs cannot be changed, use the --prefix flag to add a valid prefix to all interface names (e.g., --prefix "ContentType")`,
212197
context: "generateTSFromContentTypes",
213-
timestamp: new Date().toISOString(),
214-
};
215-
throw error;
198+
});
216199
}
217200
interfaceName = name_type(contentType.uid);
218201
}

src/generateTS/index.ts

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { defaultInterfaces } from "./stack/builtins";
1111
import { format } from "../format/index";
1212
import { ContentType } from "../types/schema";
1313
import { cliux } from "@contentstack/cli-utilities";
14+
import { createErrorDetails } from "./shared/utils";
1415

1516
export const generateTS = async ({
1617
token,
@@ -27,11 +28,14 @@ export const generateTS = async ({
2728
}: GenerateTS) => {
2829
try {
2930
if (!token || !tokenType || !apiKey || !environment || !region) {
30-
throw {
31-
type: "validation",
32-
error_message:
33-
"Please provide all the required params (token, tokenType, apiKey, environment, region)",
34-
};
31+
throw createErrorDetails(
32+
{
33+
type: "validation",
34+
error_message:
35+
"Please provide all the required params (token, tokenType, apiKey, environment, region)",
36+
},
37+
"generateTS"
38+
);
3539
}
3640

3741
if (tokenType === TOKEN_TYPE.DELIVERY) {
@@ -61,11 +65,14 @@ export const generateTS = async ({
6165
"Please create Content Models to generate type definitions",
6266
{ color: "yellow" }
6367
);
64-
throw {
65-
type: "validation",
66-
error_message:
67-
"There are no Content Types in the Stack, please create Content Models to generate type definitions",
68-
};
68+
throw createErrorDetails(
69+
{
70+
type: "validation",
71+
error_message:
72+
"There are no Content Types in the Stack, please create Content Models to generate type definitions",
73+
},
74+
"generateTS"
75+
);
6976
}
7077

7178
let schemas: ContentType[] = [];
@@ -94,9 +101,10 @@ export const generateTS = async ({
94101
} catch (error: any) {
95102
if (error.type === "validation") {
96103
// Handle validation errors with proper error codes
104+
const errorDetails = createErrorDetails(error, "generateTS");
97105
throw {
98-
error_message: error.error_message,
99-
error_code: error.error_code || "VALIDATION_ERROR",
106+
error_message: errorDetails.error_message,
107+
error_code: errorDetails.error_code,
100108
};
101109
} else {
102110
const errorObj = JSON.parse(error.message.replace("Error: ", ""));
@@ -185,31 +193,8 @@ export const generateTSFromContentTypes = async ({
185193

186194
return output;
187195
} catch (err: any) {
188-
// Enhanced error logging with more context
189-
let errorDetails;
190-
191-
if (err.type === "validation") {
192-
// Handle validation errors with proper error codes
193-
errorDetails = {
194-
error_message: err.error_message || "Validation error occurred", // Keep for backwards compatibility
195-
error_code: err.error_code || "VALIDATION_ERROR", // New property
196-
context: "generateTSFromContentTypes",
197-
timestamp: new Date().toISOString(),
198-
error_type: "ValidationError",
199-
details: err.details || {},
200-
};
201-
} else {
202-
// Handle other types of errors
203-
const errorMessage = err.message || "Unknown error occurred";
204-
errorDetails = {
205-
error_message: `Type generation failed: ${errorMessage}`, // Keep for backwards compatibility
206-
error_code: "TYPE_GENERATION_FAILED", // New property
207-
context: "generateTSFromContentTypes",
208-
timestamp: new Date().toISOString(),
209-
error_type: err.constructor.name,
210-
details: {},
211-
};
212-
}
196+
// Use common error details creation function
197+
const errorDetails = createErrorDetails(err, "generateTSFromContentTypes");
213198

214199
// Don't log the error here - let the CLI handle the display
215200
throw errorDetails;

src/generateTS/shared/utils.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,83 @@ export function checkNumericIdentifierExclusion(
5757
}
5858
return { shouldExclude: false };
5959
}
60+
61+
/**
62+
* Throws a UID validation error with standardized structure
63+
* @param params - Object containing error parameters
64+
* @param params.uid - The UID that caused the validation error
65+
* @param params.errorCode - The error code for the validation error
66+
* @param params.reason - The reason for the validation error
67+
* @param params.suggestion - The suggestion to resolve the issue
68+
* @param params.context - The context where the error occurred
69+
* @param params.referenceTo - Optional reference UID for global field errors
70+
* @throws A validation error object
71+
*/
72+
export function throwUIDValidationError({
73+
uid,
74+
errorCode,
75+
reason,
76+
suggestion,
77+
context,
78+
referenceTo,
79+
}: {
80+
uid: string;
81+
errorCode: string;
82+
reason: string;
83+
suggestion: string;
84+
context: string;
85+
referenceTo?: string;
86+
}): never {
87+
const errorMessage =
88+
errorCode === "INVALID_GLOBAL_FIELD_REFERENCE"
89+
? `Global field "${uid}" references content type "${referenceTo}" which starts with a number, creating invalid TypeScript interface names.`
90+
: `Content type UID "${uid}" starts with a number, which creates invalid TypeScript interface names.`;
91+
92+
throw {
93+
type: "validation",
94+
error_code: errorCode,
95+
error_message: errorMessage,
96+
details: {
97+
uid,
98+
...(referenceTo ? { reference_to: referenceTo } : {}),
99+
reason,
100+
suggestion,
101+
},
102+
context,
103+
timestamp: new Date().toISOString(),
104+
};
105+
}
106+
107+
/**
108+
* Creates standardized error details for different types of errors
109+
* @param err - The error object to process
110+
* @param context - The context where the error occurred
111+
* @returns Standardized error details object
112+
*/
113+
export function createErrorDetails(
114+
err: any,
115+
context: string = "generateTSFromContentTypes"
116+
) {
117+
if (err.type === "validation") {
118+
// Handle validation errors with proper error codes
119+
return {
120+
error_message: err.error_message || "Validation error occurred", // Keep for backwards compatibility
121+
error_code: err.error_code || "VALIDATION_ERROR", // New property
122+
context,
123+
timestamp: new Date().toISOString(),
124+
error_type: "ValidationError",
125+
details: err.details || {},
126+
};
127+
} else {
128+
// Handle other types of errors
129+
const errorMessage = err.message || "Unknown error occurred";
130+
return {
131+
error_message: `Type generation failed: ${errorMessage}`, // Keep for backwards compatibility
132+
error_code: "TYPE_GENERATION_FAILED", // New property
133+
context,
134+
timestamp: new Date().toISOString(),
135+
error_type: err.constructor.name,
136+
details: {},
137+
};
138+
}
139+
}

src/graphqlTS/index.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { GraphQLBase } from "../types";
33
import { introspectionQuery } from "./queries";
44
import axios from "axios";
55
import { cliux } from "@contentstack/cli-utilities";
6+
import { createErrorDetails } from "../generateTS/shared/utils";
67

78
type RegionUrlMap = {
89
[prop: string]: string;
@@ -36,11 +37,14 @@ export async function graphqlTS({
3637
cliux.print("Required: token, apiKey, environment, region", {
3738
color: "yellow",
3839
});
39-
throw {
40-
type: "validation",
41-
error_message:
42-
"Please provide all the required params (token, apiKey, environment, region)",
43-
};
40+
throw createErrorDetails(
41+
{
42+
type: "validation",
43+
error_message:
44+
"Please provide all the required params (token, apiKey, environment, region)",
45+
},
46+
"graphqlTS"
47+
);
4448
}
4549
let config = {
4650
method: "post",
@@ -73,10 +77,13 @@ export async function graphqlTS({
7377
{ color: "yellow" }
7478
);
7579
cliux.print("Or provide a custom host", { color: "yellow" });
76-
throw {
77-
type: "validation",
78-
error_message: `GraphQL content delivery api unavailable for '${region}' region and no custom host provided`,
79-
};
80+
throw createErrorDetails(
81+
{
82+
type: "validation",
83+
error_message: `GraphQL content delivery api unavailable for '${region}' region and no custom host provided`,
84+
},
85+
"graphqlTS"
86+
);
8087
}
8188

8289
const result = await axios.request(config);
@@ -90,7 +97,8 @@ export async function graphqlTS({
9097
return schema;
9198
} catch (error: any) {
9299
if (error.type === "validation") {
93-
throw { error_message: error.error_message };
100+
const errorDetails = createErrorDetails(error, "graphqlTS");
101+
throw { error_message: errorDetails.error_message };
94102
}
95103

96104
if (error.message && !error.response) {

0 commit comments

Comments
 (0)