import * as os from "os"; import * as path from "path"; import startsWith = require("lodash/startsWith"); import { ThenableAsyncGenerator, ThenableGenerator } from 'thenable-generator'; import * as util from "check-iterable"; const WinPipe = "\\\\?\\pipe\\"; export const local = Symbol("local"); export const remotized = Symbol("remotized"); export const noLocal = Symbol("noLocal"); export function absPath(filename: string, withPipe?: boolean): string { // resolve path to be absolute if (!path.isAbsolute(filename)) { filename = path.resolve(process.cwd(), filename); } if (withPipe && os.platform() == "win32" && !startsWith(filename, WinPipe)) { filename = WinPipe + filename; } return filename; } export function set(target: any, prop: any, value: any, writable = false) { Object.defineProperty(target, prop, { configurable: true, enumerable: false, writable, value }); } export function getInstance(mod: ModuleProxy, instantiate = true): T { let ins: T; let { ctor } = mod; if (ctor) { if (instantiate) { if (typeof ctor.getInstance === "function") { ins = ctor.getInstance(); } else { ins = mod.create(); } } else { // Create instance without instantiating, used for remote instance. ins = Object.create(ctor.prototype); } } else { ins = mod.proto; } return ins; } export function mergeFnProperties(fn: Function, origin: Function) { set(fn, "proxified", true); set(fn, "name", origin.name); set(fn, "length", origin.length); set(fn, "toString", function toString() { return Function.prototype.toString.call(origin); }, true); return fn; } export function createRemoteInstance( mod: ModuleProxy, fnCreator: (prop: string) => Function ) { // Generate a proxified singleton instance to the module, so that it can // be used for remote requests. the remote instance should only return // methods. return new Proxy(getInstance(mod, false), { get: (ins, prop: string) => { let type = typeof ins[prop]; let isFn = type === "function"; if (isFn && !ins[prop].proxified && !(ins).hasOwnProperty(prop) ) { set(ins, prop, mergeFnProperties(fnCreator(prop), ins[prop])); } return isFn ? ins[prop] : (type === "undefined" ? undefined : null); }, has: (ins, prop: string) => { return typeof ins[prop] === "function"; } }); } export function createLocalInstance(mod: ModuleProxy) { return new Proxy(getInstance(mod), { get: (ins, prop: string) => { if (typeof ins[prop] === "function" && !ins[prop].proxified && !(ins).hasOwnProperty(prop) ) { let origin: Function = ins[prop]; set(ins, prop, mergeFnProperties(generable(origin), origin), true); } return ins[prop]; } }); } function generable(origin: Function) { return function (this: any, ...args: any[]) { try { let res = origin.apply(this, args); if (res && util.isAsyncGenerator(res)) { return new ThenableAsyncGenerator(res); } else if (res && util.isGenerator(res)) { return new ThenableGenerator(res); } else { return res; } } catch (err) { throw err; } }; }