120 lines
3.1 KiB
TypeScript
120 lines
3.1 KiB
TypeScript
|
|
|
||
|
|
import Serializable from './Serializable.js';
|
||
|
|
import minify from './minify.js';
|
||
|
|
import debug from 'debug';
|
||
|
|
import _ from 'lodash';
|
||
|
|
const log = debug('vogue:instance');
|
||
|
|
import vm from 'vm';
|
||
|
|
import Module, { Link } from './Module.js';
|
||
|
|
import System from './System.js';
|
||
|
|
import { KV } from './KV.js';
|
||
|
|
/**
|
||
|
|
* @typedef {import('./System.js').default} System
|
||
|
|
* @typedef {import('./Module.js').default} Module
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
export default class Instance extends Serializable {
|
||
|
|
module: Module;
|
||
|
|
links = {}
|
||
|
|
system: System;
|
||
|
|
context: vm.Context;
|
||
|
|
locals = [];
|
||
|
|
internalFunctions = {};
|
||
|
|
_link: Instance;
|
||
|
|
location: string;
|
||
|
|
|
||
|
|
createContext(): vm.Context {
|
||
|
|
if(this.context) return this.context;
|
||
|
|
|
||
|
|
const initialContext: KV = {};
|
||
|
|
|
||
|
|
// system globals!
|
||
|
|
// TODO turn this into its own vogue module! system.create/instance.create
|
||
|
|
// TODO request context from system...
|
||
|
|
initialContext.create = this.system.createInstance.bind(this.system);
|
||
|
|
for(const name in this.system.staticInstances)
|
||
|
|
initialContext[name] = this.system.staticInstances[name];
|
||
|
|
|
||
|
|
// local links!
|
||
|
|
// optional arrays
|
||
|
|
// TODO maybe make these property accessors to allow for some automation
|
||
|
|
for(const link of this.module.links.filter((v: Link) => v.array && !v.required))
|
||
|
|
initialContext[link.name] = [];
|
||
|
|
for(const link of this.module.links.filter((v: Link) => !v.array && !v.required))
|
||
|
|
initialContext[link.name] = null;
|
||
|
|
|
||
|
|
const context = vm.createContext(initialContext);
|
||
|
|
|
||
|
|
for(const name in this.module.functions) {
|
||
|
|
const { code, parameters, async } = this.module.functions[name];
|
||
|
|
const injectedScript =
|
||
|
|
`
|
||
|
|
var ${name} = ${async ? 'async' : ''} function ${name}(${parameters.join(', ')}) ${code}
|
||
|
|
`;
|
||
|
|
vm.runInContext(injectedScript, context);
|
||
|
|
}
|
||
|
|
|
||
|
|
// local functions time!
|
||
|
|
// for(const name of this.module.functions)
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// let ctx = vm.createContext({
|
||
|
|
// create: this.system.newInstance.bind(this.system),
|
||
|
|
// ...this.system.staticInstances,
|
||
|
|
// ...this.internalFunctions
|
||
|
|
// });
|
||
|
|
|
||
|
|
|
||
|
|
// for(const name in this.module.imports) {
|
||
|
|
// ctx[name] = this.module.imports[name];
|
||
|
|
// this.locals.push(name);
|
||
|
|
// }
|
||
|
|
// ctx = {
|
||
|
|
// ...ctx,
|
||
|
|
|
||
|
|
// }
|
||
|
|
// for(const identifier in this.system.staticInstances) {
|
||
|
|
// this.locals.push(identifier);
|
||
|
|
// }
|
||
|
|
// // ctx.create =
|
||
|
|
// this.locals.push('create');
|
||
|
|
return context;
|
||
|
|
};
|
||
|
|
|
||
|
|
constructor(module: Module, location: string, parameters: {[name: string]: any}, system: System) {
|
||
|
|
super();
|
||
|
|
this.module = module;
|
||
|
|
this.location = location;
|
||
|
|
this.system = system;
|
||
|
|
this.context = this.createContext();
|
||
|
|
|
||
|
|
this._link = new Proxy(this, {
|
||
|
|
get(target: Instance, prop, receiver) {
|
||
|
|
if(prop === 'restore') return undefined;
|
||
|
|
if(prop in target.module.functions) {
|
||
|
|
// TODO return the fn
|
||
|
|
return
|
||
|
|
}
|
||
|
|
return undefined;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
hasPublicFunction(name: string) {
|
||
|
|
return (name in this.module.functions);
|
||
|
|
}
|
||
|
|
|
||
|
|
invokeInternal(name: string, ...args: any[]): any {
|
||
|
|
log('invoking', this.module.name.full + '.' + name, 'with args', args);
|
||
|
|
|
||
|
|
if(typeof this.context[name] === 'function') {
|
||
|
|
this.context[name](...args);
|
||
|
|
} else throw new Error(`${name} is not a function in ${this.module.name.full}`)
|
||
|
|
}
|
||
|
|
|
||
|
|
get link () {
|
||
|
|
return this._link;
|
||
|
|
}
|
||
|
|
}
|