UNPKG

@dossierhq/core

Version:

The core Dossier library used by clients and server alike, used to interact with schema and entities directly, as well as remotely through a client.

191 lines 6.61 kB
/// <reference types="./ContentTraverser.d.ts" /> import { isComponentItemField, isRichTextComponentNode, isRichTextElementNode, isRichTextItemField, } from './ContentTypeUtils.js'; import { checkFieldItemTraversable, checkFieldTraversable, checkRichTextNodeTraversable, } from './ContentUtils.js'; export const ContentTraverseNodeType = { component: 'component', entity: 'entity', error: 'error', field: 'field', fieldItem: 'fieldItem', richTextNode: 'richTextNode', }; export const ContentTraverseNodeErrorType = { generic: 'generic', missingTypeSpec: 'missingTypeSpec', }; export function* traverseEntity(schema, path, entity) { const entitySpec = schema.getEntityTypeSpecification(entity.info.type); if (!entitySpec) { const errorNode = { type: ContentTraverseNodeType.error, path, errorType: ContentTraverseNodeErrorType.missingTypeSpec, message: `Couldn’t find spec for entity type ${entity.info.type}`, typeName: entity.info.type, kind: 'entity', }; yield errorNode; return; } const entityNode = { type: ContentTraverseNodeType.entity, path, entitySpec, entity, }; yield entityNode; yield* traverseContentFields(schema, [...path, 'fields'], entitySpec, entity.fields); } export function* traverseComponent(schema, path, component) { if (!component.type) { const errorNode = { type: ContentTraverseNodeType.error, path: [...path, 'type'], errorType: ContentTraverseNodeErrorType.generic, message: 'Missing a Component type', }; yield errorNode; return; } const componentSpec = schema.getComponentTypeSpecification(component.type); if (!componentSpec) { const errorNode = { type: ContentTraverseNodeType.error, path, errorType: ContentTraverseNodeErrorType.missingTypeSpec, message: `Couldn’t find spec for component ${component.type}`, typeName: component.type, kind: 'component', }; yield errorNode; return; } const componentNode = { type: ContentTraverseNodeType.component, path, componentSpec, component, }; yield componentNode; yield* traverseContentFields(schema, path, componentSpec, component); } function* traverseContentFields(schema, path, typeSpec, fields) { for (const fieldSpec of typeSpec.fields) { const fieldPath = [...path, fieldSpec.name]; const fieldValue = fields?.[fieldSpec.name]; yield* traverseContentField(schema, fieldPath, fieldSpec, fieldValue); } } export function* traverseContentField(schema, path, fieldSpec, value) { const traversableError = checkFieldTraversable(fieldSpec, value); if (traversableError) { const errorNode = { type: ContentTraverseNodeType.error, path: [...path, ...traversableError.path], errorType: ContentTraverseNodeErrorType.generic, message: traversableError.message, }; yield errorNode; return; } const fieldNode = { type: ContentTraverseNodeType.field, path, fieldSpec, value, }; yield fieldNode; if (fieldSpec.list) { if (value === null || value === undefined) { return; } if (Array.isArray(value)) { for (let i = 0; i < value.length; i += 1) { const fieldItemPath = [...path, i]; const fieldItem = value[i]; yield* traverseContentFieldValue(schema, fieldItemPath, fieldSpec, fieldItem); } } } else { yield* traverseContentFieldValue(schema, path, fieldSpec, value); } } function* traverseContentFieldValue(schema, path, fieldSpec, itemValue) { const traversableError = checkFieldItemTraversable(fieldSpec, itemValue); if (traversableError) { const errorNode = { type: ContentTraverseNodeType.error, path: [...path, ...traversableError.path], errorType: ContentTraverseNodeErrorType.generic, message: traversableError.message, }; yield errorNode; return; } const fieldValueNode = { type: ContentTraverseNodeType.fieldItem, path, fieldSpec, value: itemValue, }; yield fieldValueNode; if (isComponentItemField(fieldSpec, itemValue) && itemValue) { yield* traverseComponent(schema, path, itemValue); } else if (isRichTextItemField(fieldSpec, itemValue) && itemValue) { if (typeof itemValue !== 'object') { const errorNode = { type: ContentTraverseNodeType.error, path, errorType: ContentTraverseNodeErrorType.generic, message: `Expected object got ${typeof itemValue}`, }; yield errorNode; return; } const root = itemValue.root; if (root === undefined) { const errorNode = { type: ContentTraverseNodeType.error, path, errorType: ContentTraverseNodeErrorType.generic, message: 'Missing root', }; yield errorNode; return; } yield* traverseRichTextNode(schema, path, fieldSpec, root); } } function* traverseRichTextNode(schema, path, fieldSpec, node) { const traversableError = checkRichTextNodeTraversable(node); if (traversableError) { const errorNode = { type: ContentTraverseNodeType.error, path: [...path, ...traversableError.path], errorType: ContentTraverseNodeErrorType.generic, message: traversableError.message, }; yield errorNode; return; } const traverseNode = { type: ContentTraverseNodeType.richTextNode, path, fieldSpec, node, }; yield traverseNode; if (isRichTextComponentNode(node) && node.data) { yield* traverseComponent(schema, [...path, 'data'], node.data); } if (isRichTextElementNode(node)) { for (let i = 0; i < node.children.length; i += 1) { const childPath = [...path, i]; const child = node.children[i]; yield* traverseRichTextNode(schema, childPath, fieldSpec, child); } } } //# sourceMappingURL=ContentTraverser.js.map