This repository has been archived on 2023-11-14. You can view files and clone it, but cannot push or open issues/pull-requests.
vogue/src/Instance.ts

96 lines
2.7 KiB
TypeScript
Raw Normal View History

2021-05-20 00:19:25 -04:00
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';
2021-05-20 20:34:50 -04:00
import Module, { Link } from './Module.js';
import System from './System.js';
import { KV } from './KV.js';
2021-05-20 00:19:25 -04:00
/**
* @typedef {import('./System.js').default} System
* @typedef {import('./Module.js').default} Module
*/
export default class Instance extends Serializable {
2021-05-20 20:34:50 -04:00
module: Module;
2021-05-20 00:19:25 -04:00
links = {}
2021-05-20 20:34:50 -04:00
system: System;
context: vm.Context;
2021-05-20 00:19:25 -04:00
locals = [];
internalFunctions = {};
2021-05-20 20:34:50 -04:00
_link: Instance;
location: string;
2021-05-20 00:19:25 -04:00
2021-05-20 20:34:50 -04:00
createContext(): vm.Context {
if(this.context) return this.context;
const initialContext: KV = {};
2021-05-20 00:19:25 -04:00
// system globals!
// TODO turn this into its own vogue module! system.create/instance.create
// TODO request context from system...
initialContext.create = this.system.newInstance.bind(this.system);
initialContext.process = process;
2021-05-20 20:34:50 -04:00
for(const name in this.system.staticInstances)
2021-05-20 00:19:25 -04:00
initialContext[name] = this.system.staticInstances[name];
// local links!
// optional arrays
// TODO maybe make these property accessors to allow for some automation
2021-05-20 20:34:50 -04:00
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;
for(const variable of this.module.variables)
initialContext[variable.name] = null;
for(const name in this.module.imports)
initialContext[name] = this.module.imports[name];
2021-05-20 20:34:50 -04:00
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, {
});
2021-05-20 20:34:50 -04:00
}
2021-05-20 00:19:25 -04:00
2021-05-20 20:34:50 -04:00
return context;
2021-05-20 00:19:25 -04:00
};
2021-05-20 20:34:50 -04:00
constructor(module: Module, location: string, parameters: {[name: string]: any}, system: System) {
2021-05-20 00:19:25 -04:00
super();
this.module = module;
this.location = location;
this.system = system;
2021-05-20 20:34:50 -04:00
this.context = this.createContext();
2021-05-20 00:19:25 -04:00
this._link = new Proxy(this, {
get(target: Instance, prop: string, receiver) {
log(`getting ${target.module.name.full}.${prop}: (${target.module.identifiers[prop]}|${typeof target.context[prop]})`);
const DNEText = `${target.module.name.full}.${prop.toString()} either does not exist, or is not accessible`;
if(prop === 'restore') throw new Error(DNEText);
2021-05-20 00:19:25 -04:00
if(prop in target.module.functions) {
return target.context[prop];
2021-05-20 00:19:25 -04:00
}
throw new Error(DNEText);
2021-05-20 00:19:25 -04:00
}
});
}
restore() {
return this.context.restore?.();
2021-05-20 00:19:25 -04:00
}
get link () {
return this._link;
}
}