alinea
Version:
Headless git-based CMS
142 lines (140 loc) • 4.2 kB
JavaScript
import {
YMap
} from "../../chunks/chunk-QUIANN6B.js";
import "../../chunks/chunk-AJJSW27C.js";
import "../../chunks/chunk-NZLE2WMY.js";
// src/core/shape/UnionShape.ts
import { createId } from "../Id.js";
import { entries, fromEntries } from "../util/Objects.js";
import { RecordShape } from "./RecordShape.js";
import { ScalarShape } from "./ScalarShape.js";
var UnionRow;
((UnionRow2) => {
UnionRow2.id = "_id";
UnionRow2.type = "_type";
})(UnionRow || (UnionRow = {}));
var UnionShape = class {
constructor(label, shapes, initialValue, postProcess) {
this.label = label;
this.initialValue = initialValue;
this.postProcess = postProcess;
this.shapes = fromEntries(
entries(shapes).map(([key, type]) => {
return [
key,
new RecordShape(label, {
[UnionRow.id]: new ScalarShape("Id"),
[UnionRow.type]: new ScalarShape("Type"),
...type.shapes
})
];
})
);
}
shapes;
create() {
return this.initialValue ?? {};
}
toY(value) {
if (Array.isArray(value)) value = value[0] ?? {};
else value = value ?? {};
const type = value[UnionRow.type];
const shape = this.shapes[type];
const self = value || {};
const map = new YMap();
map.set(UnionRow.type, type);
map.set(UnionRow.id, value[UnionRow.id] || createId());
if (!shape) return map;
for (const [key, field] of entries(shape.shapes)) {
map.set(key, field.toY(self[key]));
}
return map;
}
fromY(map) {
if (!map || typeof map.get !== "function") return {};
const type = map.get(UnionRow.type);
const recordType = this.shapes[type];
if (recordType) return recordType.fromY(map);
return {};
}
applyY(value, parent, key) {
const current = parent.get(key);
if (!current || !value) return void parent.set(key, this.toY(value));
const currentType = current.get(UnionRow.type);
if (currentType !== value[UnionRow.type])
return void parent.set(key, this.toY(value));
const shape = this.shapes[currentType];
if (!shape) return;
shape.applyY(value, parent, key);
}
init(parent, key) {
if (!parent.has(key)) parent.set(key, this.toY(this.create()));
}
watch(parent, key) {
return (fun) => {
const observe = (events, tx) => {
if (tx.origin === "self") return;
const self = parent.get(key);
for (const event of events) {
if (event.target === parent && event.keys.has(key)) return fun();
if (event.target === self) return fun();
}
};
parent.observeDeep(observe);
return () => parent.unobserveDeep(observe);
};
}
mutator(parent, key) {
return {
replace: (value) => {
if (!value) return parent.set(key, null);
const type = value[UnionRow.type];
const shape = this.shapes[type];
if (!shape) throw new Error(`Could not find type "${type}"`);
shape.applyY(value, parent, key);
}
};
}
async applyLinks(value, loader) {
if (!value) return;
const type = value[UnionRow.type];
if (!type) return;
const shape = this.shapes[type];
if (!shape) return;
const tasks = [];
if (shape) tasks.push(shape.applyLinks(value, loader));
await Promise.all(tasks);
if (this.postProcess) await this.postProcess(value, loader);
}
toV1(value) {
if (Array.isArray(value)) value = value[0] ?? {};
if (!value) return {};
if (UnionRow.type in value) return value;
const { id, type, ...data } = value;
if (!id || !type) return {};
const shape = this.shapes[type];
if (!shape) return {};
return {
[UnionRow.type]: type,
[UnionRow.id]: id,
...shape.toV1(data)
};
}
searchableText(value) {
let res = "";
if (Array.isArray(value)) value = value[0] ?? {};
else value = value ?? {};
const type = value[UnionRow.type];
const shape = this.shapes[type];
const self = value || {};
if (!shape) return "";
for (const [key, field] of entries(shape.shapes)) {
res += field.searchableText(self[key]);
}
return res;
}
};
export {
UnionRow,
UnionShape
};