@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
JavaScript
/// <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