Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ fileignoreconfig:
checksum: da69dab1717422e12f3b3865604667151d46c96bde5faba13ae862c41d856fba
- filename: tests/unit/generateTS/generateTS.test.ts
checksum: 10e5139168a951a488760626d8305f379db1a7e5df626feb63ef55409ab76a03
- filename: src/constants/messages.ts
checksum: d8e9492f9294725f54711be06cef880993ab91a4ece37cf361c34ac18fc18a7c
- filename: tests/integration/graphqlTS/graphqlTS.test.ts
checksum: b111cb55740d871a3031bc0214eb445239cd6f62ebbdd922eb34af47f0714a54
version: "1.0"
2 changes: 2 additions & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ export const REGIONS = {
GCP_EU: "GCP_EU",
CUSTOM: "CUSTOM",
};

export { ERROR_MESSAGES, INFO_MESSAGES, WARNING_MESSAGES } from "./messages";
63 changes: 63 additions & 0 deletions src/constants/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Centralized error and info messages for the types-generator
* This file contains all user-facing messages to ensure consistency and easier maintenance
*/

export const ERROR_MESSAGES = {
// Validation Errors
MISSING_REQUIRED_PARAMS: "Missing required parameters",
REQUIRED_PARAMS_LIST: "Required: token, apiKey, environment, region",
UNSUPPORTED_REGION: (region: string) => `Unsupported region: ${region}`,
SUPPORTED_REGIONS: "Supported regions: US, EU, AU, AZURE_NA, AZURE_EU, GCP_NA, GCP_EU",
CUSTOM_HOST_OPTION: "Or provide a custom host",

// Content Type Errors
NO_CONTENT_TYPES: "No Content Types found in the Stack",
CREATE_CONTENT_MODELS: "Please create Content Models to generate type definitions",
NO_CONTENT_TYPES_DETAILED: "There are no Content Types in the Stack, please create Content Models to generate type definitions",

// Authentication Errors
UNAUTHORIZED: "Unauthorized: The apiKey, token or region is not valid.",
INVALID_CREDENTIALS: "Invalid credentials. Please verify your apiKey, token, and region.",
INVALID_CREDENTIALS_GRAPHQL: "Unauthorized: The apiKey, token or environment is not valid.",

// API Errors
API_ERROR_DEFAULT: "Something went wrong",
API_ERROR_WITH_STATUS: (status: number, message?: string) =>
`API error occurred. Status: ${status}${message ? `. ${message}` : ""}`,
GRAPHQL_SCHEMA_ERROR: "An error occurred while processing GraphQL schema",

// Field/Block Skip Messages
SKIPPED_FIELD_UNKNOWN_TYPE: (uid: string, dataType: string, reason: string) =>
`Skipped field "${uid}" with unknown type "${dataType}": ${reason}`,
SKIPPED_GLOBAL_FIELD_REFERENCE: (uid: string, referenceTo: string, reason: string) =>
`Skipped global field reference "${uid}" to "${referenceTo}": ${reason}`,
SKIPPED_FIELD_AT_PATH: (uid: string, path: string, reason: string) =>
`Skipped field "${uid}" at path "${path}": ${reason}`,
SKIPPED_BLOCK_AT_PATH: (uid: string, path: string, reason: string) =>
`Skipped block "${uid}" at path "${path}": ${reason}`,
SKIPPED_GLOBAL_FIELD: (uid: string, reason: string) =>
`Skipped global field "${uid}": ${reason}`,
SKIPPED_GLOBAL_FIELD_NO_SCHEMA: (uid: string, reason: string) =>
`Skipped global field "${uid}": ${reason}. Did you forget to include it?`,
SKIPPED_REFERENCE: (reference: string, reason: string) =>
`Skipped reference to content type "${reference}": ${reason}`,

// Summary Messages
SUMMARY_HEADER: "Summary of Skipped Items:",
TOTAL_SKIPPED_ITEMS: (count: number) => `Total skipped items: ${count}`,
GENERATION_COMPLETED_PARTIAL: "Generation completed successfully with partial schema.",

// GraphQL Errors
GRAPHQL_API_UNAVAILABLE: (region: string) =>
`GraphQL content delivery api unavailable for '${region}' region and no custom host provided`,
} as const;

export const INFO_MESSAGES = {
// Informational messages can be added here
} as const;

export const WARNING_MESSAGES = {
// Warning-specific messages can be added here
} as const;

23 changes: 12 additions & 11 deletions src/generateTS/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
checkNumericIdentifierExclusion,
throwNumericIdentifierValidationError,
} from "./shared/utils";
import { ERROR_MESSAGES } from "../constants";

export type TSGenOptions = {
docgen: DocumentationGenerator;
Expand Down Expand Up @@ -276,7 +277,7 @@ export default function (userOptions: TSGenOptions) {
const reason = `Unknown field type: ${field.data_type}`;
skippedFields.push({ uid: field.uid, path: field.uid, reason });
logger?.warn(
`Skipped field "${field.uid}" with unknown type "${field.data_type}": ${reason}`
ERROR_MESSAGES.SKIPPED_FIELD_UNKNOWN_TYPE(field.uid, field.data_type, reason)
);
type = "Record<string, unknown>"; // Use Record<string, unknown> for balanced type safety
}
Expand All @@ -294,7 +295,7 @@ export default function (userOptions: TSGenOptions) {
if (exclusionCheck.shouldExclude) {
skippedFields.push(exclusionCheck.record!);
logger?.warn(
`Skipped global field reference "${field.uid}" to "${field.reference_to}": ${NUMERIC_IDENTIFIER_EXCLUSION_REASON}`
ERROR_MESSAGES.SKIPPED_GLOBAL_FIELD_REFERENCE(field.uid, field.reference_to, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
);
return "string"; // Use string as fallback for global field references
}
Expand Down Expand Up @@ -348,7 +349,7 @@ export default function (userOptions: TSGenOptions) {
if (exclusionCheck.shouldExclude) {
skippedFields.push(exclusionCheck.record!);
logger?.warn(
`Skipped field "${field.uid}" at path "${fieldPath}": ${NUMERIC_IDENTIFIER_EXCLUSION_REASON}`
ERROR_MESSAGES.SKIPPED_FIELD_AT_PATH(field.uid, fieldPath, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
);
continue;
}
Expand Down Expand Up @@ -411,7 +412,7 @@ export default function (userOptions: TSGenOptions) {
if (exclusionCheck.shouldExclude) {
skippedBlocks.push(exclusionCheck.record!);
logger?.warn(
`Skipped block "${block.uid}" at path "${blockPath}": ${NUMERIC_IDENTIFIER_EXCLUSION_REASON}`
ERROR_MESSAGES.SKIPPED_BLOCK_AT_PATH(block.uid, blockPath, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
);
return null; // Return null to filter out later
}
Expand Down Expand Up @@ -513,7 +514,7 @@ export default function (userOptions: TSGenOptions) {
if (exclusionCheck.shouldExclude) {
skippedFields.push(exclusionCheck.record!);
logger?.warn(
`Skipped global field "${field.uid}": ${NUMERIC_IDENTIFIER_EXCLUSION_REASON}`
ERROR_MESSAGES.SKIPPED_GLOBAL_FIELD(field.uid, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
);
return "string"; // Use string as fallback for global fields
}
Expand All @@ -522,7 +523,7 @@ export default function (userOptions: TSGenOptions) {
const reason = "Schema not found for global field";
skippedFields.push({ uid: field.uid, path: field.uid, reason });
logger?.warn(
`Skipped global field "${field.uid}": ${reason}. Did you forget to include it?`
ERROR_MESSAGES.SKIPPED_GLOBAL_FIELD_NO_SCHEMA(field.uid, reason)
);
return "string"; // Use string as fallback
}
Expand Down Expand Up @@ -559,7 +560,7 @@ export default function (userOptions: TSGenOptions) {
references.push(name_type(v));
} else {
logger?.warn(
`Skipped reference to content type "${v}": ${NUMERIC_IDENTIFIER_EXCLUSION_REASON}`
ERROR_MESSAGES.SKIPPED_REFERENCE(v, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
);
}
});
Expand All @@ -569,7 +570,7 @@ export default function (userOptions: TSGenOptions) {
references.push(name_type(field.reference_to));
} else {
logger?.warn(
`Skipped reference to content type "${field.reference_to}": ${NUMERIC_IDENTIFIER_EXCLUSION_REASON}`
ERROR_MESSAGES.SKIPPED_REFERENCE(field.reference_to, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
);
}
}
Expand Down Expand Up @@ -603,7 +604,7 @@ export default function (userOptions: TSGenOptions) {
// Log summary table of skipped fields and blocks
if (logger && (skippedFields.length > 0 || skippedBlocks.length > 0)) {
logger.info("");
logger.info("Summary of Skipped Items:");
logger.info(ERROR_MESSAGES.SUMMARY_HEADER);

// Create combined table data for all skipped items
const allSkippedItems = [
Expand Down Expand Up @@ -636,8 +637,8 @@ export default function (userOptions: TSGenOptions) {

const totalSkipped = skippedFields.length + skippedBlocks.length;
logger.info("");
logger.warn(`Total skipped items: ${totalSkipped}`);
logger.success(" Generation completed successfully with partial schema.");
logger.warn(ERROR_MESSAGES.TOTAL_SKIPPED_ITEMS(totalSkipped));
logger.success(ERROR_MESSAGES.GENERATION_COMPLETED_PARTIAL);
}

return {
Expand Down
22 changes: 8 additions & 14 deletions src/generateTS/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import async from "async";
import { flatMap, flatten } from "lodash";
import { TOKEN_TYPE } from "../constants";
import { TOKEN_TYPE, ERROR_MESSAGES } from "../constants";
import { initializeContentstackSdk } from "../sdk/utils";
import { GenerateTS, GenerateTSFromContentTypes } from "../types";
import { DocumentationGenerator } from "./docgen/doc";
Expand Down Expand Up @@ -55,13 +55,9 @@ export const generateTS = async ({
const { content_types }: any = contentTypes;

if (!content_types.length) {
logger.error("No Content Types found in the Stack");
logger.warn(
"Please create Content Models to generate type definitions"
);
throw createValidationError(
"There are no Content Types in the Stack, please create Content Models to generate type definitions"
);
logger.error(ERROR_MESSAGES.NO_CONTENT_TYPES);
logger.warn(ERROR_MESSAGES.CREATE_CONTENT_MODELS);
throw createValidationError(ERROR_MESSAGES.NO_CONTENT_TYPES_DETAILED);
}

let schemas: ContentType[] = [];
Expand Down Expand Up @@ -97,23 +93,21 @@ export const generateTS = async ({
};
} else {
const errorObj = JSON.parse(error?.message?.replace("Error: ", ""));
let errorMessage = "Something went wrong";
let errorMessage: string = ERROR_MESSAGES.API_ERROR_DEFAULT;
let errorCode = "API_ERROR";

if (errorObj.status) {
switch (errorObj.status) {
case 401:
errorMessage =
"Unauthorized: The apiKey, token or region is not valid.";
errorMessage = ERROR_MESSAGES.UNAUTHORIZED;
errorCode = "AUTHENTICATION_FAILED";
break;
case 412:
errorMessage =
"Invalid Credentials: Please check the provided apiKey, token and region.";
errorMessage = ERROR_MESSAGES.INVALID_CREDENTIALS;
errorCode = "INVALID_CREDENTIALS";
break;
default:
errorMessage = `${errorMessage}, ${errorObj.error_message}`;
errorMessage = ERROR_MESSAGES.API_ERROR_WITH_STATUS(errorObj.status, errorObj.error_message);
errorCode = `API_ERROR_${errorObj.status}`;
}
}
Expand Down
22 changes: 9 additions & 13 deletions src/graphqlTS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { GraphQLBase } from "../types";
import { introspectionQuery } from "./queries";
import axios from "axios";
import { createLogger } from "../logger";
import { ERROR_MESSAGES } from "../constants";

type RegionUrlMap = {
[prop: string]: string;
Expand Down Expand Up @@ -31,8 +32,8 @@ export async function graphqlTS({
const logger = createLogger(loggerInstance);
try {
if (!token || !apiKey || !environment || !region) {
logger.error("Missing required parameters");
logger.warn("Required: token, apiKey, environment, region");
logger.error(ERROR_MESSAGES.MISSING_REQUIRED_PARAMS);
logger.warn(ERROR_MESSAGES.REQUIRED_PARAMS_LIST);
throw {
type: "validation",
error_message:
Expand Down Expand Up @@ -61,14 +62,12 @@ export async function graphqlTS({
}

if (!GRAPHQL_REGION_URL_MAPPING[region] && !host) {
logger.error(`Unsupported region: ${region}`);
logger.warn(
"Supported regions: US, EU, AU, AZURE_NA, AZURE_EU, GCP_NA, GCP_EU"
);
logger.warn("Or provide a custom host");
logger.error(ERROR_MESSAGES.UNSUPPORTED_REGION(region));
logger.warn(ERROR_MESSAGES.SUPPORTED_REGIONS);
logger.warn(ERROR_MESSAGES.CUSTOM_HOST_OPTION);
throw {
type: "validation",
error_message: `GraphQL content delivery api unavailable for '${region}' region and no custom host provided`,
error_message: ERROR_MESSAGES.GRAPHQL_API_UNAVAILABLE(region),
};
}

Expand All @@ -92,8 +91,7 @@ export async function graphqlTS({

if (error.response?.status === 412) {
throw {
error_message:
"Unauthorized: The apiKey, token or environment is not valid.",
error_message: ERROR_MESSAGES.INVALID_CREDENTIALS_GRAPHQL,
};
} else {
let details = "";
Expand All @@ -120,9 +118,7 @@ export async function graphqlTS({

throw {
error_message:
details ||
errorMessage ||
"An error occurred while processing GraphQL schema",
details || errorMessage || ERROR_MESSAGES.GRAPHQL_SCHEMA_ERROR,
};
}
}
Expand Down
Loading