@tpluscode/rdfine
Version:
RDF/JS idiomatic, native, effective
83 lines (82 loc) • 3.13 kB
JavaScript
import { createProxy } from './proxy.js';
export default class {
constructor(__env) {
this.__env = __env;
this.__mixins = new Set();
this.__alwaysMixins = new Set();
this.__typeMixins = new Map();
this.__typeCache = new Map();
this.BaseClass = __env.rdfine.Resource;
}
addMixin(...mixins) {
this.__typeCache.clear();
mixins.forEach(mixin => {
if ('appliesTo' in mixin) {
const current = this.__typeMixins.get(mixin.appliesTo.value) || [];
this.__typeMixins.set(mixin.appliesTo.value, [...current, mixin]);
}
else {
if (mixin.shouldApply === true) {
this.__alwaysMixins.add(mixin);
}
this.__mixins.add(mixin);
}
});
}
createEntity(pointer, typeAndMixins = [], options = {}) {
let BaseClass = this.BaseClass;
let explicitMixins = typeAndMixins;
if (typeAndMixins.length > 0) {
const [BaseClassOrMixin, ...rest] = typeAndMixins;
if (this.__isConstructor(BaseClassOrMixin)) {
BaseClass = BaseClassOrMixin;
explicitMixins = rest;
}
}
const types = pointer.out(this.__env.ns.rdf.type).values;
for (const type of options.initializer?.types || []) {
if ('termType' in type) {
types.push(type.value);
}
else {
types.push(type.id.value);
}
}
BaseClass = this.__getBaseClass(BaseClass, types);
const entity = new BaseClass(pointer, this.__env);
const mixins = [...this.__mixins].reduce((selected, next) => {
if (next.shouldApply === true || (typeof next.shouldApply === 'function' && next.shouldApply(entity))) {
selected.add(next);
}
return selected;
}, new Set(explicitMixins));
const Type = this.__extend(BaseClass, [...mixins]);
return createProxy(new Type(pointer, options.parent || this.__env, options.initializer));
}
__getBaseClass(baseClass, types) {
const cacheKey = [baseClass.name, ...types].toString();
const cached = this.__typeCache.get(cacheKey);
if (cached) {
return cached;
}
const rdfTypeMixins = types.reduce((mixins, type) => {
const typeMixins = this.__typeMixins.get(type);
if (typeMixins) {
typeMixins.forEach(m => mixins.add(m));
}
return mixins;
}, new Set());
const type = this.__extend(baseClass, [...this.__alwaysMixins, ...rdfTypeMixins]);
this.__typeCache.set(cacheKey, type);
return type;
}
__extend(baseClass, mixins) {
const type = mixins.reduce((Mixed, Next) => Next(Mixed), baseClass);
const baseMixins = baseClass.__mixins || [];
type.__mixins = [...baseMixins, ...mixins];
return type;
}
__isConstructor(value) {
return '__mixins' in value;
}
}