UNPKG

@progress/sitefinity-nextjs-sdk

Version:

Provides OOB widgets developed using the Next.js framework, which includes an abstraction layer for Sitefinity communication. Additionally, it offers an expanded API, typings, and tools for further development and integration.

421 lines (420 loc) 17.9 kB
import { RestSdkTypes, RestClient } from './rest-client'; import { RootUrlService } from './root-url.service'; /** * ServiceMetadata is a static class that caches the service metadata definition and provides methods to access it. * It is used to fetch and store the metadata for the current Sitefinity CMS instance, including entity definitions and their properties. */ export class ServiceMetadata { static serviceMetadataCache; static serviceMetadataHash; static taxonomies; /** * Requests the content type metadata and initializes the service. * @returns {ServiceMetadataDefinition} The full types metadata definition. */ static async fetch(metadataHash, traceContext) { if (!ServiceMetadata.serviceMetadataCache || metadataHash !== ServiceMetadata.serviceMetadataHash) { const serviceUrl = RootUrlService.getServerCmsServiceUrl(); const metadataUrl = `${serviceUrl}/sfmeta`; const metadata = await RestClient.sendRequest({ url: metadataUrl, traceContext }); ServiceMetadata.serviceMetadataCache = metadata; const taxonomies = await RestClient.getItems({ type: RestSdkTypes.Taxonomies, traceContext }); ServiceMetadata.taxonomies = taxonomies.Items; ServiceMetadata.serviceMetadataHash = metadataHash; } return ServiceMetadata.serviceMetadataCache; } /** * Gets the default field name for a given item type. * @param typeFullName The full type name of the item type. * @returns The default field name for the specified type. */ static getDefaultFieldName(typeFullName) { const entitySet = this.getSetNameFromType(typeFullName); if (entitySet) { const entityTypeDef = this.getEntityDefinition(entitySet); const defaultFieldPropName = 'Telerik.Sitefinity.V1.DefaultField'; const propertiesPropName = 'properties'; if (entityTypeDef.hasOwnProperty(defaultFieldPropName)) { return entityTypeDef[defaultFieldPropName]; } else if (entityTypeDef.hasOwnProperty(propertiesPropName)) { const defaultFieldName = entityTypeDef[propertiesPropName][defaultFieldPropName]; if (defaultFieldName) { return defaultFieldName; } } } return 'Title'; } /** * Gets the full type name for a given set name. * e.g. newsitems -> Telerik.Sitefinity.News.Model.NewsItem * @param itemType The full type name of the item type. * @returns The full type name for the specified set. */ getTypeNameFromSetName(itemType) { const entitySet = ServiceMetadata.serviceMetadataCache.entityContainer.entitySets[itemType]; if (entitySet != null) { const entityTypeRef = entitySet.entityType['$ref']; return entityTypeRef.replace('#/definitions/', ''); } return itemType; } /** * Gets the set name for a given item full type name. * e.g. Telerik.Sitefinity.News.Model.NewsItem -> newsitems * @param itemType The full type name of the item type. * @returns The set name for the specified type if such is matched. */ static getSetNameFromType(itemType) { const definition = ServiceMetadata.serviceMetadataCache.definitions[itemType]; if (definition != null) { const sets = ServiceMetadata.serviceMetadataCache.entityContainer.entitySets; const setName = Object.keys(sets).find((x) => { return sets[x]['entityType']['$ref'].endsWith(itemType); }); return setName; } return itemType; } /** * Gets the display name of a given item type by its full type name. * @param itemType The full type name of the item type. * @returns The display name of the item type if such is found. */ static getModuleDisplayName(itemType) { const definition = ServiceMetadata.serviceMetadataCache.definitions[itemType]; if (definition) { const displayName = definition['properties']['Telerik.Sitefinity.V1.DisplayName']; return displayName; } return ''; } /** * Gets the current item's parent full type name. * @param itemType The child full type name. * @returns The parent item full type name. */ static getParentType(itemType) { const definition = ServiceMetadata.serviceMetadataCache.definitions[itemType]; if (definition != null) { const parent = definition['properties']['Parent']; if (parent != null) { const anyOfProperty = parent['anyOf']; if (anyOfProperty != null && anyOfProperty.length > 0) { let refProperty = anyOfProperty.find(x => x.$ref != null); if (refProperty != null) { return refProperty.$ref.replace('#/definitions/', ''); } } } } return null; } static getChildTypes(itemType) { const result = []; const definition = ServiceMetadata.serviceMetadataCache.definitions[itemType]; if (definition != null) { const childTypes = definition['properties']['Telerik.Sitefinity.V1.ChildTypes']; if (childTypes != null) { result.push(childTypes); childTypes.forEach(childType => { let grandChildTypes = this.getChildTypes(childType); for (let i = 0; i < grandChildTypes.length; i++) { let currentInheritanceLevel = result.at(i + 1); if (currentInheritanceLevel != null) { currentInheritanceLevel.push(...grandChildTypes[i]); } else { result.push(grandChildTypes[i]); } } }); } } return result; } static isPropertyACollection(type, propName) { let entityTypeDef = ServiceMetadata.serviceMetadataCache.definitions[type]; let propMeta = entityTypeDef['properties'][propName]; let propType = propMeta['type']; if (!propType) { return false; } if (Array.isArray(propType) || propType === 'array') { return true; } return false; } /** * Gets a type's related data field's item type name. * @param type The full content type name. * @param relationName The related data field name. * @returns The related data type. */ static getRelatedType(type, relationName) { const typeDefinition = ServiceMetadata.serviceMetadataCache.definitions[type]; let properties = typeDefinition['properties']; let property = properties[relationName]; if (typeof property !== 'object') { return null; } let relatedReferenceType = property['$ref']; if (relatedReferenceType == null) { let itemsProperty = property['items']; if (itemsProperty != null) { relatedReferenceType = itemsProperty['$ref']; } } if (relatedReferenceType == null) { let anyOfProperty = property['anyOf']; if (anyOfProperty && anyOfProperty.length > 0) { let relatedItemProperty = anyOfProperty.find(x => x['$ref'] != null); if (relatedItemProperty != null) { relatedReferenceType = relatedItemProperty['$ref']; } } } if (relatedReferenceType == null) { return null; } const foundEntity = Object.values(this.serviceMetadataCache.entityContainer.entitySets).some(x => x['entityType']['$ref'] === relatedReferenceType); if (foundEntity) { return relatedReferenceType.replace('#/definitions/', ''); } return null; } static serializeFilterValue(type, propName, value) { const definition = ServiceMetadata.serviceMetadataCache.definitions[type]; if (this.isPrimitiveProperty(type, propName)) { const propMeta = definition['properties'][propName]; const propType = propMeta['type']; const propFormat = propMeta['format']; let propFormatToString = null; if (propFormat != null) { propFormatToString = propFormat.toString(); } if (propType === null || propType === undefined) { return null; } const propTypeArray = propType; const propTypeString = propType.toString(); if (value === null) { if (propTypeArray != null && propTypeArray.some(x => x === 'null')) { return 'null'; } return null; } if (propTypeString === 'array') { if (propMeta.items && propMeta.items.format) { switch (propMeta.items.format) { case 'string': return `'${value}'`; default: return value.toString(); } } return null; } else if (propFormatToString === 'uuid') { return value.toString(); } else if (propFormatToString === 'date-time') { if (value instanceof Date) { return value.toISOString(); } else if (Date.parse(value)) { return new Date(Date.parse(value)).toISOString(); } return null; } else if (propTypeString === 'boolean' && value instanceof Boolean) { return value.toString(); } else if (propTypeArray != null && propType.length > 0) { if (propTypeArray.some(x => x.toString() === 'number') || propTypeArray.some(x => x.toString() === 'boolean')) { return value.ToString(); } else if (propTypeArray.some(x => x.toString() === 'string')) { return `'${value}'`; } } else if (value != null) { return value.ToString(); } } return null; } /** * Gets the names of the properties of a given type that are not related types. * @param type The full type name of the item type. * @returns A collection of the names of the properties of the given type that are not related types. */ static getSimpleFields(type) { let definition = ServiceMetadata.serviceMetadataCache.definitions[type]; let propertiesObject = definition['properties']; return Object.keys(propertiesObject).map((key) => { if (this.isPrimitiveProperty(type, key)) { return key; } return null; }).filter(x => !!x); } /** * Gets the names of the properties of a given type that are related types. * @param type The full type name of the item type. * @returns A collection of the names of the properties of the given type that are related types. */ static getRelationFields(type) { let definition = ServiceMetadata.serviceMetadataCache.definitions[type]; let propertiesObject = definition['properties']; return Object.keys(propertiesObject).map((key) => { if (this.isRelatedProperty(type, key)) { return key; } return null; }).filter(x => !!x); } /** * Gets the name of the taxonomy field for a given type by taxonomy name if such field exists on the type. * @param type The full type name of the item type. * @param taxonomyName The taxonomy name. * @returns The field name of the taxonomy field for the given type and taxonomy name if such field exists. */ static getTaxonomyFieldName(type, taxonomyName) { let definition = ServiceMetadata.serviceMetadataCache.definitions[type]; let propertiesObject = definition['properties']; return Object.keys(propertiesObject).find((key) => { const fieldMeta = propertiesObject[key]; return fieldMeta['Telerik.Sitefinity.V1.Taxonomy'] === taxonomyName; }); } /** * Gets the field type of a given property of a given type. * @param type The full type name of the item type. * @param propName The property name. * @returns {FieldType} The field type of the property. */ static getFieldType(type, propName) { const definition = ServiceMetadata.serviceMetadataCache.definitions[type]; const propMeta = definition['properties'][propName]; const fieldType = propMeta['Telerik.Sitefinity.V1.FieldType']?.toString(); if (fieldType === 'ShortText' || fieldType === 'LongText') { return FieldType.TextField; } else if (fieldType === 'Choices' || fieldType === 'MultipleChoice') { return FieldType.ChoiceField; } else if (fieldType === 'Number') { return FieldType.NumberField; } const propFormat = propMeta['format']?.toString(); if (propFormat === 'date-time') { return FieldType.DatetimeField; } const propType = propMeta['type']; if (propType) { const propTypeNumberArray = Array.isArray(propType); if (propTypeNumberArray) { const propAsArray = propType; if (propAsArray.includes('number')) { return FieldType.NumberField; } else if (propAsArray.includes('boolean')) { return FieldType.BooleanField; } else if (propAsArray.includes('string')) { return FieldType.TextField; } } else { if (propType === 'integer') { return FieldType.NumberField; } else if (propType === 'boolean') { return FieldType.BooleanField; } else if (propType === 'string') { return FieldType.TextField; } } } let taxonomy = propMeta['Telerik.Sitefinity.V1.Taxonomy']; if (taxonomy && ServiceMetadata.taxonomies.find(x => x.Name === taxonomy)) { return FieldType.ClassificationField; } return FieldType.TextField; } /** * Checks if a module is enabled in the service metadata. * @param moduleName The name of the module to check. * @returns True if the module is enabled, false otherwise. */ static isModuleEnabled(moduleName) { const modules = ServiceMetadata.serviceMetadataCache?.modules; if (modules != null) { const moduleState = modules[moduleName]; if (moduleState != null && typeof moduleState === 'boolean') { return moduleState; } } return false; } static getEntityDefinition(itemType) { const mainEntitySet = ServiceMetadata.serviceMetadataCache.entityContainer.entitySets[itemType]; if (!mainEntitySet) { throw new Error(`Could not find metadata for type ${itemType}`); } const entityTypeRef = mainEntitySet.entityType['$ref']; const entityTypeName = entityTypeRef.replace('#/definitions/', ''); const entityTypeDef = ServiceMetadata.serviceMetadataCache.definitions[entityTypeName]; return entityTypeDef; } static isRelatedProperty(type, propName) { return !!this.getRelatedType(type, propName); } static isPrimitiveProperty(type, propName) { const definition = ServiceMetadata.serviceMetadataCache.definitions[type]; let properties = definition['properties']; let property = properties[propName]; if (property == null) { throw new Error(`The field - ${propName} is not recognized as a property of the current type - ${type}`); } return (typeof property === 'object') && !this.isRelatedProperty(type, propName); } } /** * FieldType is an enumeration that defines the different types of fields that can be found in the Sitefinity CMS. * It is used to identify the type of field for a given property in the content type metadata. */ export var FieldType; (function (FieldType) { /** * Represents a text field, which can be either short or long text. */ FieldType[FieldType["TextField"] = 0] = "TextField"; /** * Represents a choice field, which can be either a single choice or multiple choices. */ FieldType[FieldType["ChoiceField"] = 1] = "ChoiceField"; /** * Represents a number field, which can be used for numeric values. */ FieldType[FieldType["NumberField"] = 2] = "NumberField"; /** * Represents a classification field, which is used for taxonomy fields. */ FieldType[FieldType["ClassificationField"] = 3] = "ClassificationField"; /** * Represents a date-time field, which is used for date and time values. */ FieldType[FieldType["DatetimeField"] = 4] = "DatetimeField"; /** * Represents a boolean field, which can be either true or false. */ FieldType[FieldType["BooleanField"] = 5] = "BooleanField"; })(FieldType || (FieldType = {}));