contentful-orm
Version:
A TypeScript-first ORM for Contentful CMS that enables a code-first approach to content modeling
123 lines • 5.13 kB
JavaScript
import contentfulManagement from 'contentful-management';
import { ContentfulFieldType } from '../types/index.js';
import { getContentTypeMetadata, getFieldsMetadata } from '../decorators/index.js';
const CONTENTFUL_FIELD_TYPES = {
[ContentfulFieldType.Symbol]: 'Symbol',
[ContentfulFieldType.Text]: 'Text',
[ContentfulFieldType.RichText]: 'RichText',
[ContentfulFieldType.Number]: 'Number',
[ContentfulFieldType.Integer]: 'Integer',
[ContentfulFieldType.Date]: 'Date',
[ContentfulFieldType.Location]: 'Location',
[ContentfulFieldType.Media]: 'Link',
[ContentfulFieldType.Boolean]: 'Boolean',
[ContentfulFieldType.Reference]: 'Link',
[ContentfulFieldType.Array]: 'Array',
[ContentfulFieldType.Object]: 'Object'
};
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) {
return Array.from(fieldsMap.entries()).map(([fieldName, options]) => {
const field = {
id: fieldName,
name: fieldName,
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) {
field.items = {
type: CONTENTFUL_FIELD_TYPES[options.itemsType ?? ContentfulFieldType.Text],
validations: options.itemsValidations?.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.type === ContentfulFieldType.Media ? 'Asset' : (options.linkType ?? 'Entry');
}
return field;
});
}
async unpublishContentType(contentType) {
try {
if (contentType.isPublished()) {
await contentType.unpublish();
}
}
catch (error) {
console.log('Content type was not published, continuing...');
}
}
async syncContentType(target) {
const metadata = getContentTypeMetadata(target);
if (!metadata) {
throw new Error(`No content type metadata found for ${target.name}`);
}
const fields = this.transformFieldsToContentful(getFieldsMetadata(target));
const contentType = {
name: metadata.name,
displayField: metadata.displayField,
description: metadata.description,
fields
};
const environment = await this.environment;
try {
// Get the latest version of the content type
const existingContentType = await environment.getContentType(metadata.name);
console.log(`Updating content type: ${metadata.name}`);
// Unpublish first if published
if (existingContentType.isPublished()) {
console.log('Unpublishing content type...');
await existingContentType.unpublish();
}
// Get the latest version after unpublishing
const latestVersion = await environment.getContentType(metadata.name);
console.log('Updating content type with latest version...');
const updatedContentType = await latestVersion.update(contentType);
// Publish the changes
console.log('Publishing content type...');
await updatedContentType.publish();
console.log(`Successfully updated content type: ${metadata.name}`);
}
catch (error) {
if (error.name === 'NotFound') {
console.log(`Creating content type: ${metadata.name}`);
const newContentType = await environment.createContentTypeWithId(metadata.name, contentType);
await newContentType.publish();
console.log(`Successfully created content type: ${metadata.name}`);
}
else {
throw error;
}
}
}
}
//# sourceMappingURL=index.js.map