UNPKG

@tpluscode/rdfine

Version:
83 lines (82 loc) 3.13 kB
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; } }