UNPKG

kitsu-core

Version:

Simple, lightweight & framework agnostic JSON:API (de)serialsation components

103 lines (100 loc) 3.75 kB
import { error } from './error.mjs'; function isValid(isArray, type, payload, method) { const requireID = new Error(`${method} requires an ID for the ${type} type`); if (type === undefined) { throw new Error(`${method} requires a resource type`); } if (isArray) { if (method !== 'POST' && payload.length > 0) { for (const resource of payload) { if (!resource.id) throw requireID; } } } else { if (typeof payload !== 'object' || method !== 'POST' && Object.keys(payload).length === 0) { throw new Error(`${method} requires an object or array body`); } if (method !== 'POST' && !payload.id) { throw requireID; } } } function serialiseRelationOne(node, nodeType) { if (node === null) return node; let relation = {}; for (const prop of Object.keys(node)) { if (['id', 'type'].includes(prop)) relation[prop] = node[prop];else relation = serialiseAttr(node[prop], prop, relation); } if (!relation.type) relation.type = nodeType; return relation; } function serialiseRelationMany(node, nodeType) { const relation = []; for (const prop of node) { relation.push(serialiseRelationOne(prop, nodeType)); } return relation; } function serialiseRelation(node, nodeType, key, data) { if (!data.relationships) data.relationships = {}; data.relationships[key] = { data: Array.isArray(node.data) ? serialiseRelationMany(node.data, nodeType) : serialiseRelationOne(node.data, nodeType) }; if (node?.links?.self || node?.links?.related) data.relationships[key].links = node.links; if (node?.meta) data.relationships[key].meta = node.meta; return data; } function serialiseAttr(node, key, data) { if (!data.attributes) data.attributes = {}; if (key === 'links' && (typeof node.self === 'string' || typeof node.related === 'string')) data.links = node;else if (key === 'meta' && typeof node === 'object' && !Array.isArray(node) && node !== null) data.meta = node;else data.attributes[key] = node; return data; } function hasID(node) { if (node?.data === null || Array.isArray(node?.data) && node?.data?.length === 0) return true; if (!node.data) return false; const nodeData = Array.isArray(node.data) ? node.data[0] : node.data; return Object.prototype.hasOwnProperty.call(nodeData, 'id'); } function serialiseRootArray(type, payload, method, options) { isValid(true, type, payload, method); const data = []; for (const resource of payload) { data.push(serialiseRootObject(type, resource, method, options).data); } return { data }; } function serialiseRootObject(type, payload, method, options) { isValid(false, type, payload, method); type = options.pluralTypes(options.camelCaseTypes(type)); let data = { type }; if (payload?.id) data.id = String(payload.id); for (const key in payload) { const node = payload[key]; const nodeType = options.pluralTypes(options.camelCaseTypes(key)); if (typeof node === 'object' && !Array.isArray(node) && node !== null && hasID(node)) { data = serialiseRelation(node, nodeType, key, data); } else if (key !== 'id' && key !== 'type') { data = serialiseAttr(node, key, data); } } return { data }; } function serialise(type, data = {}, method = 'POST', options = {}) { try { if (!options.camelCaseTypes) options.camelCaseTypes = s => s; if (!options.pluralTypes) options.pluralTypes = s => s; if (data === null || Array.isArray(data) && data.length === 0) return { data }; if (Array.isArray(data) && data?.length > 0) return serialiseRootArray(type, data, method, options);else return serialiseRootObject(type, data, method, options); } catch (E) { throw error(E); } } export { serialise };