diff --git a/lib/config.ts b/lib/config.ts index b1092cc..cd2e984 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -46,6 +46,7 @@ export const deliveryConfig = { contentTypesFolderName: `content-types`, contentTypeSnippetsFolderName: `content-type-snippets`, taxonomiesFolderName: `taxonomies`, + typeGuardsFileName: 'delivery.type-guards', systemTypesFolderName: 'system', coreCodenamesFilename: 'delivery.codenames', coreTypeFilename: 'core.type', diff --git a/lib/core/resolvers.ts b/lib/core/resolvers.ts index 467af59..16691c8 100644 --- a/lib/core/resolvers.ts +++ b/lib/core/resolvers.ts @@ -33,13 +33,22 @@ export function mapFilename(resolver: FilenameReso }; } -export function mapName(resolver: NameResolver, defaultCase: CaseType): MapObjectToName { +export function mapName( + resolver: NameResolver, + defaultCase: CaseType, + options?: { + prefix?: string; + } +): MapObjectToName { return (item) => { - return match(resolver) - .returnType() - .with(P.instanceOf(Function), (resolver) => resolver(item)) - .with(undefined, () => resolveCase(item.name, defaultCase)) - .otherwise((resolverType) => resolveCase(item.name, resolverType)); + return ( + `${options?.prefix ? options.prefix : ''}` + + match(resolver) + .returnType() + .with(P.instanceOf(Function), (resolver) => resolver(item)) + .with(undefined, () => resolveCase(item.name, defaultCase)) + .otherwise((resolverType) => resolveCase(item.name, resolverType)) + ); }; } diff --git a/lib/generators/delivery/delivery-content-type.generator.ts b/lib/generators/delivery/delivery-content-type.generator.ts index 758d224..b014306 100644 --- a/lib/generators/delivery/delivery-content-type.generator.ts +++ b/lib/generators/delivery/delivery-content-type.generator.ts @@ -32,6 +32,7 @@ import { getWorkflowCodenamesType, getWorkflowStepCodenamesType } from '../shared/type-codename.generator.js'; +import { deliveryTypeGuardGenerator } from './delivery-type-guard.generator.js'; interface ExtractImportsResult { readonly typeName: string; @@ -268,11 +269,6 @@ ${importer.importType({ })} ${importsResult.imports.join('\n')} -${wrapComment(` -* Type representing all available element codenames for ${snippet.name} -`)} -${getContentTypeElementCodenamesType(nameOfTypeRepresentingAllElementCodenames, flattenedElements)} - ${wrapComment(` * ${snippet.name} * @@ -281,6 +277,11 @@ ${wrapComment(` `)} export type ${importsResult.typeName} = ${deliveryConfig.sdkTypes.snippet}<${nameOfTypeRepresentingAllElementCodenames}, ${getElementsCode(flattenedElements)}>; + +${wrapComment(` +* Type representing all available element codenames for ${snippet.name} +`)} +${getContentTypeElementCodenamesType(nameOfTypeRepresentingAllElementCodenames, flattenedElements)} `; }; @@ -306,11 +307,6 @@ ${importer.importType({ })} ${importsResult.imports.join('\n')} -${wrapComment(` -* Type representing all available element codenames for ${contentType.name} -`)} -${getContentTypeElementCodenamesType(nameOfTypeRepresentingAllElementCodenames, flattenedElements)} - ${wrapComment(` * ${contentType.name} * @@ -319,7 +315,17 @@ ${wrapComment(` `)} export type ${importsResult.typeName} = ${deliveryConfig.coreContentTypeName}< ${getElementsCode(flattenedElements)}${importsResult.contentTypeExtends ? ` ${importsResult.contentTypeExtends}` : ''}, -'${contentType.codename}'>; +'${contentType.codename}'> + +${wrapComment(` +* Type representing all available element codenames for ${contentType.name} +`)} +${getContentTypeElementCodenamesType(nameOfTypeRepresentingAllElementCodenames, flattenedElements)}; + +${wrapComment(` +* Type guard for ${contentType.name} +`)} +${deliveryTypeGuardGenerator(config).getTypeGuardFunction(contentType)}; `; }; diff --git a/lib/generators/delivery/delivery-type-guard.generator.ts b/lib/generators/delivery/delivery-type-guard.generator.ts new file mode 100644 index 0000000..e88f4c5 --- /dev/null +++ b/lib/generators/delivery/delivery-type-guard.generator.ts @@ -0,0 +1,28 @@ +import { ContentTypeModels } from '@kontent-ai/management-sdk'; +import { deliveryConfig } from '../../config.js'; +import { ContentTypeNameResolver, mapName } from '../../core/resolvers.js'; + +export interface DeliveryTypeGuardGeneratorConfig { + readonly nameResolvers?: { + readonly contentType?: ContentTypeNameResolver; + }; +} + +export function deliveryTypeGuardGenerator(config: DeliveryTypeGuardGeneratorConfig) { + const nameResolvers = { + typeGuardFunctionName: mapName(config.nameResolvers?.contentType, 'pascalCase', { + prefix: 'is' + }), + typeName: mapName(config.nameResolvers?.contentType, 'pascalCase') + }; + + const getTypeGuardFunction = (contentType: Readonly): string => { + return `export function ${nameResolvers.typeGuardFunctionName(contentType)}(item: ${deliveryConfig.coreContentTypeName}): item is ${nameResolvers.typeName(contentType)} { + return item.system.type === '${contentType.codename}'; + }`; + }; + + return { + getTypeGuardFunction + }; +} diff --git a/sample/delivery/content-types/actor.ts b/sample/delivery/content-types/actor.ts index ef6042d..aeef488 100644 --- a/sample/delivery/content-types/actor.ts +++ b/sample/delivery/content-types/actor.ts @@ -16,11 +16,6 @@ import type { Elements } from '@kontent-ai/delivery-sdk'; import type { CoreContentType } from '../system/index.js'; -/** - * Type representing all available element codenames for Actor - */ -export type ActorElementCodenames = 'url' | 'first_name' | 'last_name' | 'photo'; - /** * Actor * @@ -69,3 +64,15 @@ export type Actor = CoreContentType< }, 'actor' >; + +/** + * Type representing all available element codenames for Actor + */ +export type ActorElementCodenames = 'url' | 'first_name' | 'last_name' | 'photo'; + +/** + * Type guard for Actor + */ +export function isActor(item: CoreContentType): item is Actor { + return item.system.type === 'actor'; +} diff --git a/sample/delivery/content-types/movie.ts b/sample/delivery/content-types/movie.ts index 657b442..c0058dd 100644 --- a/sample/delivery/content-types/movie.ts +++ b/sample/delivery/content-types/movie.ts @@ -18,20 +18,6 @@ import type { Actor } from './index.js'; import type { CoreContentType } from '../system/index.js'; import type { Releasecategory } from '../taxonomies/index.js'; -/** - * Type representing all available element codenames for Movie - */ -export type MovieElementCodenames = - | 'title' - | 'plot' - | 'released' - | 'length' - | 'poster' - | 'category' - | 'stars' - | 'seoname' - | 'releasecategory'; - /** * Movie * @@ -126,3 +112,24 @@ export type Movie = CoreContentType< }, 'movie' >; + +/** + * Type representing all available element codenames for Movie + */ +export type MovieElementCodenames = + | 'title' + | 'plot' + | 'released' + | 'length' + | 'poster' + | 'category' + | 'stars' + | 'seoname' + | 'releasecategory'; + +/** + * Type guard for Movie + */ +export function isMovie(item: CoreContentType): item is Movie { + return item.system.type === 'movie'; +} diff --git a/sample/delivery/index.ts b/sample/delivery/index.ts index b223413..a93bf4e 100644 --- a/sample/delivery/index.ts +++ b/sample/delivery/index.ts @@ -1,16 +1,17 @@ -/** - * This file has been auto-generated by '@kontent-ai/model-generator@8.0.0-5'. - * - * (c) Kontent.ai - * - * ------------------------------------------------------------------------------- - * - * Project: Movie Database - * Environment: Production - * Id: da5abe9f-fdad-4168-97cd-b3464be2ccb9 - * - * ------------------------------------------------------------------------------- - **/ + +/** +* This file has been auto-generated by '@kontent-ai/model-generator@8.0.0-5'. +* +* (c) Kontent.ai +* +* ------------------------------------------------------------------------------- +* +* Project: Movie Database +* Environment: Production +* Id: da5abe9f-fdad-4168-97cd-b3464be2ccb9 +* +* ------------------------------------------------------------------------------- +**/ export * from './content-type-snippets/index.js'; export * from './content-types/index.js';