UNPKG

@strapi/utils

Version:

Shared utilities for the Strapi packages

187 lines (184 loc) • 6.89 kB
import { curry, isObject, isNil, clone, isArray } from 'lodash/fp'; import { isRelationalAttribute, isMediaAttribute } from './content-types.mjs'; const traverseEntity = async (visitor, options, entity)=>{ const { path = { raw: null, attribute: null, rawWithIndices: null }, schema, getModel } = options; let parent = options.parent; const traverseMorphRelationTarget = async (visitor, path, entry)=>{ const targetSchema = getModel(entry.__type); const traverseOptions = { schema: targetSchema, path, getModel, parent }; return traverseEntity(visitor, traverseOptions, entry); }; const traverseRelationTarget = (schema)=>async (visitor, path, entry)=>{ const traverseOptions = { schema, path, getModel, parent }; return traverseEntity(visitor, traverseOptions, entry); }; const traverseMediaTarget = async (visitor, path, entry)=>{ const targetSchemaUID = 'plugin::upload.file'; const targetSchema = getModel(targetSchemaUID); const traverseOptions = { schema: targetSchema, path, getModel, parent }; return traverseEntity(visitor, traverseOptions, entry); }; const traverseComponent = async (visitor, path, schema, entry)=>{ const traverseOptions = { schema, path, getModel, parent }; return traverseEntity(visitor, traverseOptions, entry); }; const visitDynamicZoneEntry = async (visitor, path, entry)=>{ const targetSchema = getModel(entry.__component); const traverseOptions = { schema: targetSchema, path, getModel, parent }; return traverseEntity(visitor, traverseOptions, entry); }; // End recursion if (!isObject(entity) || isNil(schema)) { return entity; } // Don't mutate the original entity object // only clone at 1st level as the next level will get clone when traversed const copy = clone(entity); const visitorUtils = createVisitorUtils({ data: copy }); const keys = Object.keys(copy); for(let i = 0; i < keys.length; i += 1){ const key = keys[i]; // Retrieve the attribute definition associated to the key from the schema const attribute = schema.attributes[key]; const newPath = { ...path }; newPath.raw = isNil(path.raw) ? key : `${path.raw}.${key}`; newPath.rawWithIndices = isNil(path.rawWithIndices) ? key : `${path.rawWithIndices}.${key}`; if (!isNil(attribute)) { newPath.attribute = isNil(path.attribute) ? key : `${path.attribute}.${key}`; } // Visit the current attribute const visitorOptions = { data: copy, schema, key, value: copy[key], attribute, path: newPath, getModel, parent }; await visitor(visitorOptions, visitorUtils); // Extract the value for the current key (after calling the visitor) const value = copy[key]; // Ignore Nil values or attributes if (isNil(value) || isNil(attribute)) { continue; } // The current attribute becomes the parent once visited parent = { schema, key, attribute, path: newPath }; if (isRelationalAttribute(attribute)) { const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph'); const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target)); if (isArray(value)) { const res = new Array(value.length); for(let i = 0; i < value.length; i += 1){ const arrayPath = { ...newPath, rawWithIndices: isNil(newPath.rawWithIndices) ? `${i}` : `${newPath.rawWithIndices}.${i}` }; res[i] = await method(visitor, arrayPath, value[i]); } copy[key] = res; } else { copy[key] = await method(visitor, newPath, value); } continue; } if (isMediaAttribute(attribute)) { // need to update copy if (isArray(value)) { const res = new Array(value.length); for(let i = 0; i < value.length; i += 1){ const arrayPath = { ...newPath, rawWithIndices: isNil(newPath.rawWithIndices) ? `${i}` : `${newPath.rawWithIndices}.${i}` }; res[i] = await traverseMediaTarget(visitor, arrayPath, value[i]); } copy[key] = res; } else { copy[key] = await traverseMediaTarget(visitor, newPath, value); } continue; } if (attribute.type === 'component') { const targetSchema = getModel(attribute.component); if (isArray(value)) { const res = new Array(value.length); for(let i = 0; i < value.length; i += 1){ const arrayPath = { ...newPath, rawWithIndices: isNil(newPath.rawWithIndices) ? `${i}` : `${newPath.rawWithIndices}.${i}` }; res[i] = await traverseComponent(visitor, arrayPath, targetSchema, value[i]); } copy[key] = res; } else { copy[key] = await traverseComponent(visitor, newPath, targetSchema, value); } continue; } if (attribute.type === 'dynamiczone' && isArray(value)) { const res = new Array(value.length); for(let i = 0; i < value.length; i += 1){ const arrayPath = { ...newPath, rawWithIndices: isNil(newPath.rawWithIndices) ? `${i}` : `${newPath.rawWithIndices}.${i}` }; res[i] = await visitDynamicZoneEntry(visitor, arrayPath, value[i]); } copy[key] = res; continue; } } return copy; }; const createVisitorUtils = ({ data })=>({ remove (key) { delete data[key]; }, set (key, value) { data[key] = value; } }); var traverseEntity$1 = curry(traverseEntity); export { traverseEntity$1 as default }; //# sourceMappingURL=traverse-entity.mjs.map