@platform/cell.typesystem
Version:
The 'strongly typed sheets' system of the CellOS.
80 lines (79 loc) • 2.81 kB
JavaScript
import { value, Uri } from '../common';
import { TypeBuilderNs } from './TypeBuilderNs';
import { TypeValue } from '../TypeSystem.core';
export class TypeBuilder {
constructor() {
this.builders = [];
}
toObject() {
return this.builders.reduce((acc, builder) => {
const ns = builder.uri.toString();
acc[ns] = this.toDef(builder);
return acc;
}, {});
}
ns(uri) {
uri = Uri.ns(uri);
const exists = this.builders.some(ns => ns.uri.toString() === uri.toString());
if (exists) {
const err = `The namespace '${uri.toString()}' already exists`;
throw new Error(err);
}
const ns = TypeBuilderNs.create({ uri });
this.builders.push(ns);
return ns;
}
type(typename, options) {
const ns = Uri.create.ns(Uri.cuid());
return this.ns(ns).type(typename, options);
}
formatType(value) {
value = (value || '').trim();
if (value.startsWith('/')) {
const typename = value.replace(/^\/*/, '');
const singular = TypeValue.trimArray(typename);
const match = this.builders.find(ns => ns.types.find(type => type.typename === singular));
if (!match) {
const err = `Failed to prefix type '${value}' with namespace. The typename '${typename}' was not found in any of the available namespaces.`;
throw new Error(err);
}
value = `${match.uri.toString()}/${typename}`;
}
return value;
}
toDef(ns) {
const columns = {};
const getOrCreateObject = (target, key) => {
return target[key] ? target[key] : (target[key] = {});
};
const attachDef = (def, column) => {
const props = getOrCreateObject(column, 'props');
if (!props.def) {
props.def = def;
}
else {
if (!Array.isArray(props.def)) {
props.def = [props.def];
}
props.def.push(def);
}
};
ns.types.forEach(type => {
const typename = type.typename;
type.props
.map(prop => prop.toObject())
.forEach(prop => {
const def = value.deleteUndefined({
prop: `${typename}.${prop.name}`,
type: this.formatType(prop.type),
target: prop.target,
default: prop.default,
});
const column = getOrCreateObject(columns, prop.column);
attachDef(def, column);
});
});
return { columns };
}
}
TypeBuilder.create = () => new TypeBuilder();