UNPKG

contentful-orm

Version:

A TypeScript-first ORM for Contentful CMS that enables a code-first approach to content modeling

119 lines (118 loc) 5.29 kB
import contentfulManagement from 'contentful-management'; import { ContentfulFieldType } from '../types/index.js'; import { getContentTypeMetadata, getFieldsMetadata } from '../decorators/index.js'; const CONTENTFUL_FIELD_TYPES = { [ContentfulFieldType.Text]: 'Symbol', [ContentfulFieldType.RichText]: 'RichText', [ContentfulFieldType.Number]: 'Number', [ContentfulFieldType.Date]: 'Date', [ContentfulFieldType.Location]: 'Location', [ContentfulFieldType.Media]: 'Link', [ContentfulFieldType.Boolean]: 'Boolean', [ContentfulFieldType.Reference]: 'Link', [ContentfulFieldType.Array]: 'Array' }; export class ContentfulSync { client; space; environment; spaceId; environmentId; constructor(accessToken, spaceId, environmentId = 'master') { this.client = contentfulManagement.createClient({ accessToken }); this.spaceId = spaceId; this.environmentId = environmentId; this.space = this.client.getSpace(spaceId); this.environment = this.space.then(space => space.getEnvironment(environmentId)); } transformValidation(validation) { if (validation.regexp) { const { pattern, flags } = validation.regexp; return { ...validation, regexp: { pattern, flags: flags ?? '' } }; } return validation; } transformFieldsToContentful(fieldsMap) { const fieldsMetadata = Object.fromEntries(fieldsMap); return Object.entries(fieldsMetadata).map(([id, options]) => { const field = { id, name: id, type: CONTENTFUL_FIELD_TYPES[options.type], required: options.required ?? false, localized: options.localized ?? false, validations: options.validations?.map((v) => this.transformValidation(v)) ?? [] }; if (options.type === ContentfulFieldType.Array && options.itemsType) { field.items = { type: CONTENTFUL_FIELD_TYPES[options.itemsType], validations: options.items?.validations?.map((v) => this.transformValidation(v)) ?? [] }; if (options.itemsLinkType) { field.items.linkType = options.itemsLinkType; } } if (options.type === ContentfulFieldType.Reference || options.type === ContentfulFieldType.Media) { field.linkType = options.itemsLinkType ?? 'Entry'; } return field; }); } async syncContentType(entity) { const contentTypeMetadata = getContentTypeMetadata(entity); if (!contentTypeMetadata) { throw new Error(`No content type metadata found for ${entity.name}`); } console.log(`Syncing content type: ${contentTypeMetadata.name}`); const fieldsMetadata = getFieldsMetadata(entity); const fields = this.transformFieldsToContentful(fieldsMetadata); console.log('Transformed fields:', JSON.stringify(fields, null, 2)); console.log(`Using space: ${this.spaceId}, environment: ${this.environmentId}`); const environment = await this.environment; try { console.log(`Checking if content type ${contentTypeMetadata.name} exists...`); const existingContentType = await environment.getContentType(contentTypeMetadata.name); console.log('Content type exists, updating...'); // Unpublish first if published if (existingContentType.sys.publishedVersion) { console.log('Unpublishing content type...'); await existingContentType.unpublish(); } // Get the latest version after unpublishing const latestVersion = await environment.getContentType(contentTypeMetadata.name); const updatedContentType = await latestVersion.update({ name: contentTypeMetadata.name, displayField: contentTypeMetadata.displayField, description: contentTypeMetadata.description, fields }); console.log('Content type updated, publishing...'); await updatedContentType.publish(); console.log('Content type published successfully'); } catch (error) { if (error instanceof Error && 'name' in error && error.name === 'NotFound') { console.log('Content type not found, creating new...'); const contentType = await environment.createContentTypeWithId(contentTypeMetadata.name, { name: contentTypeMetadata.name, displayField: contentTypeMetadata.displayField, description: contentTypeMetadata.description, fields }); console.log('Content type created, publishing...'); await contentType.publish(); console.log('Content type published successfully'); } else { console.error('Error:', error); throw error; } } } }