@eang/core
Version:
eang - model driven enterprise event processing
204 lines • 7.72 kB
JavaScript
export function createEmptyDiagramDocument() {
return {
version: 1,
viewport: {
scale: 1,
translateX: 0,
translateY: 0
},
occurrences: {
objs: {},
cnxs: {}
}
};
}
export function isDiagramDocument(value) {
if (!isRecord(value) || value.version !== 1) {
return false;
}
const viewport = value.viewport;
const occurrences = value.occurrences;
return (isRecord(viewport) &&
typeof viewport.scale === 'number' &&
typeof viewport.translateX === 'number' &&
typeof viewport.translateY === 'number' &&
isRecord(occurrences) &&
isRecord(occurrences.objs) &&
isRecord(occurrences.cnxs) &&
(occurrences.texts === undefined || isRecord(occurrences.texts)) &&
(value.order === undefined ||
(Array.isArray(value.order) && value.order.every((item) => typeof item === 'string'))));
}
export function applyDiagramPatch(document, patch) {
const nextDocument = cloneDiagramDocument(document);
for (const operation of patch) {
mutateDiagramDocument(nextDocument, operation);
}
return nextDocument;
}
export function applyDiagramPatchOperation(document, operation) {
const nextDocument = cloneDiagramDocument(document);
mutateDiagramDocument(nextDocument, operation);
return nextDocument;
}
function cloneDiagramDocument(document) {
return {
version: document.version,
viewport: { ...document.viewport },
occurrences: {
objs: { ...document.occurrences.objs },
cnxs: { ...document.occurrences.cnxs },
...(document.occurrences.texts
? { texts: { ...document.occurrences.texts } }
: {})
},
...(document.order ? { order: [...document.order] } : {})
};
}
function mutateDiagramDocument(document, operation) {
switch (operation.op) {
case 'set_viewport': {
if (!isRecord(operation.value)) {
throw new Error('set_viewport requires a viewport object value');
}
document.viewport = mergeObjects(document.viewport, operation.value);
return;
}
case 'put_obj_occurrence': {
const occurrence = getOperationValue(operation);
const occurrenceId = resolveOccurrenceId(operation, occurrence);
document.occurrences.objs[occurrenceId] = {
...occurrence,
id: occurrenceId
};
ensureOccurrenceInOrder(document, occurrenceId);
return;
}
case 'patch_obj_occurrence': {
const occurrenceId = resolveOccurrenceId(operation);
const existing = document.occurrences.objs[occurrenceId];
if (!existing) {
throw new Error(`Cannot patch missing object occurrence '${occurrenceId}'`);
}
document.occurrences.objs[occurrenceId] = mergeObjects(existing, getOperationValue(operation));
return;
}
case 'delete_obj_occurrence': {
const occurrenceId = resolveOccurrenceId(operation);
delete document.occurrences.objs[occurrenceId];
removeOccurrenceFromOrder(document, occurrenceId);
return;
}
case 'put_cnx_occurrence': {
const occurrence = getOperationValue(operation);
const occurrenceId = resolveOccurrenceId(operation, occurrence);
document.occurrences.cnxs[occurrenceId] = {
...occurrence,
id: occurrenceId
};
ensureOccurrenceInOrder(document, occurrenceId);
return;
}
case 'patch_cnx_occurrence': {
const occurrenceId = resolveOccurrenceId(operation);
const existing = document.occurrences.cnxs[occurrenceId];
if (!existing) {
throw new Error(`Cannot patch missing connection occurrence '${occurrenceId}'`);
}
document.occurrences.cnxs[occurrenceId] = mergeObjects(existing, getOperationValue(operation));
return;
}
case 'delete_cnx_occurrence': {
const occurrenceId = resolveOccurrenceId(operation);
delete document.occurrences.cnxs[occurrenceId];
removeOccurrenceFromOrder(document, occurrenceId);
return;
}
case 'put_text_occurrence': {
const occurrence = getOperationValue(operation);
const occurrenceId = resolveOccurrenceId(operation, occurrence);
if (!document.occurrences.texts) {
document.occurrences.texts = {};
}
document.occurrences.texts[occurrenceId] = {
...occurrence,
id: occurrenceId
};
ensureOccurrenceInOrder(document, occurrenceId);
return;
}
case 'patch_text_occurrence': {
const occurrenceId = resolveOccurrenceId(operation);
const existing = document.occurrences.texts?.[occurrenceId];
if (!existing) {
throw new Error(`Cannot patch missing text occurrence '${occurrenceId}'`);
}
document.occurrences.texts = {
...(document.occurrences.texts || {}),
[occurrenceId]: mergeObjects(existing, getOperationValue(operation))
};
return;
}
case 'delete_text_occurrence': {
const occurrenceId = resolveOccurrenceId(operation);
if (document.occurrences.texts) {
delete document.occurrences.texts[occurrenceId];
if (Object.keys(document.occurrences.texts).length === 0) {
delete document.occurrences.texts;
}
}
removeOccurrenceFromOrder(document, occurrenceId);
return;
}
case 'reorder': {
if (!Array.isArray(operation.value) || !operation.value.every((id) => typeof id === 'string')) {
throw new Error('reorder requires a string[] value');
}
document.order = [...operation.value];
return;
}
}
}
function ensureOccurrenceInOrder(document, occurrenceId) {
if (!document.order || document.order.includes(occurrenceId)) {
return;
}
document.order = [...document.order, occurrenceId];
}
function removeOccurrenceFromOrder(document, occurrenceId) {
if (!document.order) {
return;
}
document.order = document.order.filter((id) => id !== occurrenceId);
}
function resolveOccurrenceId(operation, value) {
const occurrenceId = operation.occurrenceId || value?.id;
if (!occurrenceId) {
throw new Error(`Operation '${operation.op}' requires an occurrenceId`);
}
return occurrenceId;
}
function getOperationValue(operation) {
if (operation.value === undefined) {
throw new Error(`Operation '${operation.op}' requires a value`);
}
return operation.value;
}
function isRecord(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
function mergeObjects(current, patch) {
if (!isRecord(current) || !isRecord(patch)) {
return patch;
}
const merged = { ...current };
for (const [key, value] of Object.entries(patch)) {
const existingValue = merged[key];
merged[key] =
isRecord(existingValue) && isRecord(value)
? mergeObjects(existingValue, value)
: value;
}
return merged;
}
//# sourceMappingURL=diagram.js.map