UNPKG

phecda-server

Version:

server framework that provide IOC/type-reuse/http&rpc-adaptor

312 lines (288 loc) 12.2 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _chunk4LLLQOMFjs = require('./chunk-4LLLQOMF.js'); // src/meta.ts var Meta = class { static { _chunk4LLLQOMFjs.__name.call(void 0, this, "Meta"); } constructor(data, paramsType, module, model) { this.data = data; this.paramsType = paramsType; this.module = module; this.model = model; } }; // src/core.ts var _events = require('events'); var _events2 = _interopRequireDefault(_events); var _phecdacore = require('phecda-core'); var _debug = require('debug'); var _debug2 = _interopRequireDefault(_debug); var debug = _debug2.default.call(void 0, "phecda-server(Factory)"); var emitter = new (0, _events2.default)(); function defaultServerInject() { if (!_phecdacore.getInject.call(void 0, "watcher")) { _phecdacore.setInject.call(void 0, "watcher", ({ eventName, instance, property, options }) => { const fn = typeof instance[property] === "function" ? instance[property].bind(instance) : (v) => instance[property] = v; if (_optionalChain([options, 'optionalAccess', _ => _.once])) emitter.once(eventName, fn); else emitter.on(eventName, fn); return () => { emitter.off(eventName, fn); }; }); } } _chunk4LLLQOMFjs.__name.call(void 0, defaultServerInject, "defaultServerInject"); var phecdaNamespace = /* @__PURE__ */ new Map(); var ServerPhecda = (_class = class { static { _chunk4LLLQOMFjs.__name.call(void 0, this, "ServerPhecda"); } __init() {this.moduleMap = /* @__PURE__ */ new Map()} __init2() {this.meta = []} __init3() {this.modelMap = /* @__PURE__ */ new WeakMap()} __init4() {this.modelSet = /* @__PURE__ */ new WeakSet()} __init5() {this.dependenceGraph = /* @__PURE__ */ new Map()} constructor(options) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this); defaultServerInject(); const { namespace = "default", parseModule = /* @__PURE__ */ _chunk4LLLQOMFjs.__name.call(void 0, (module) => module, "parseModule"), parseMeta = /* @__PURE__ */ _chunk4LLLQOMFjs.__name.call(void 0, (meta) => meta, "parseMeta"), generators = [] } = options; phecdaNamespace.set(namespace, this); this.parseMeta = parseMeta; this.parseModule = parseModule; this.generators = generators; } async start(models) { for (const model of models) await this.buildDepModule(model); this.hmr(); this.generateCode().then(() => { if (_chunk4LLLQOMFjs.IS_ONLY_GENERATE) { _chunk4LLLQOMFjs.log.call(void 0, "Only generate code"); process.exit(_chunk4LLLQOMFjs.PS_EXIT_CODE.EXIT); } }); } __init6() {this.generateCode = /* @__PURE__ */ _chunk4LLLQOMFjs.__name.call(void 0, async () => { return Promise.all(this.generators.map((generator) => { debug(`generate "${generator.name}" code to ${generator.path}`); return generator.output(this.meta); })); }, "generateCode")} hmr() { _chunk4LLLQOMFjs.HMR.call(void 0, async (oldModels, newModels) => { debug("reload models "); await this.replace(oldModels, newModels); this.generateCode(); }); } async destroy() { debug("destroy all"); this.replace(Object.values(this.modelMap), []); } createProxyModule(tag) { const that = this; return new Proxy({}, { get(_target, prop) { const module = that.moduleMap.get(tag); return Reflect.get(module, prop, module); }, set(_target, prop, newValue) { const module = that.moduleMap.get(tag); return Reflect.set(module, prop, newValue, module); }, has(_target, prop) { return Reflect.has(that.moduleMap.get(tag), prop); }, ownKeys() { return Reflect.ownKeys(that.moduleMap.get(tag)); }, getPrototypeOf() { return Reflect.getPrototypeOf(that.moduleMap.get(tag)); }, getOwnPropertyDescriptor(_target, prop) { return Reflect.getOwnPropertyDescriptor(that.moduleMap.get(tag), prop); } }); } async buildDepModule(Model) { const paramtypes = getParamTypes(Model); let module; const tag = _phecdacore.getTag.call(void 0, Model); if (this.moduleMap.has(tag)) { module = this.moduleMap.get(tag); if (!module) { _chunk4LLLQOMFjs.log.call(void 0, `Exist Circular-Dependency or Multiple modules with the same tag [${String(tag)}]`, "warn"); return { module: this.createProxyModule(tag), tag }; } if (this.modelMap.get(module) !== Model && !this.modelSet.has(Model)) { this.modelSet.add(Model); if (module instanceof Model) _chunk4LLLQOMFjs.log.call(void 0, `Module taged ${String(tag)} has been overridden`); else _chunk4LLLQOMFjs.log.call(void 0, `Synonym module: Module taged "${String(tag)}" has been loaded before, so phecda-server won't load Module "${Model.name}"`, "warn"); } return { module, tag }; } this.moduleMap.set(tag, void 0); debug(`instantiate module "${String(tag)}"`); if (paramtypes) { const paramtypesInstances = []; for (const i in paramtypes) { const { module: sub, tag: subTag } = await this.buildDepModule(paramtypes[i]); paramtypesInstances[i] = sub; if (!this.dependenceGraph.has(subTag)) this.dependenceGraph.set(subTag, /* @__PURE__ */ new Set()); this.dependenceGraph.get(subTag).add(tag); } module = this.parseModule(new Model(...paramtypesInstances)); } else { module = this.parseModule(new Model()); } this.meta.push(...getMetaFromInstance(module, tag, Model).map(this.parseMeta).filter((item) => !!item)); debug(`init module "${String(tag)}"`); if (!_chunk4LLLQOMFjs.IS_ONLY_GENERATE) await _phecdacore.invokeInit.call(void 0, module); debug(`add module "${String(tag)}"`); this.moduleMap.set(tag, module); this.modelMap.set(module, Model); return { module, tag }; } async replace(oldModels, newModels) { const oldModules = (await Promise.all(oldModels.map(async (model) => { const tag = _phecdacore.getTag.call(void 0, model); if (!this.has(tag)) return; const module = this.moduleMap.get(tag); debug(`unmount module "${String(tag)}"`); await _phecdacore.invokeUnmount.call(void 0, module); debug(`del module "${String(tag)}"`); this.moduleMap.delete(tag); this.modelMap.delete(module); for (let i = this.meta.length - 1; i >= 0; i--) { if (this.meta[i].data.tag === tag) this.meta.splice(i, 1); } return module; }))).filter((item) => item); for (const model of newModels) { debug(`mount module: ${model.name}`); await this.buildDepModule(model); } debug("replace old modules"); for (const module of oldModules) { const tag = _phecdacore.getTag.call(void 0, module); if (this.dependenceGraph.has(tag)) { [ ...this.dependenceGraph.get(tag) ].forEach((depTag) => { const depModule = this.moduleMap.get(depTag); if (depModule) { for (const key in depModule) { if (depModule[key] === module) depModule[key] = this.moduleMap.get(tag); } } }); } } } has(modelOrTag) { return this.moduleMap.has(typeof modelOrTag === "function" ? _phecdacore.getTag.call(void 0, modelOrTag) : modelOrTag); } get(modelOrTag) { const tag = typeof modelOrTag === "function" ? _phecdacore.getTag.call(void 0, modelOrTag) : modelOrTag; if (!this.has(tag)) throw new Error(`module "${tag.toString()}" doesn't exist`); return this.moduleMap.get(tag); } getModel(tag) { return this.modelMap.get(this.get(tag)); } }, _class); async function Factory(models, opts = {}) { const phecda = new ServerPhecda(opts); await phecda.start(models); return phecda; } _chunk4LLLQOMFjs.__name.call(void 0, Factory, "Factory"); function useS(nsOrModel, namespace) { if (!nsOrModel) { namespace = "default"; } else { if (typeof nsOrModel === "string") namespace = nsOrModel; else if (!namespace) namespace = "default"; } if (!phecdaNamespace.has(namespace)) throw new Error(`namespace "${namespace}" doesn't exist`); const serverPhecda = phecdaNamespace.get(namespace); if (nsOrModel && typeof nsOrModel !== "string") return serverPhecda.get(nsOrModel); else return serverPhecda; } _chunk4LLLQOMFjs.__name.call(void 0, useS, "useS"); function getMetaFromInstance(instance, tag, model) { const name = model.name; const propertyKeys = _phecdacore.getMetaKey.call(void 0, instance).filter((item) => typeof item === "string"); const baseMeta = _phecdacore.getMergedMeta.call(void 0, instance, void 0); const ctxs = baseMeta.ctxs; return propertyKeys.filter((i) => typeof instance[i] === "function").map((i) => { const meta = _phecdacore.getMergedMeta.call(void 0, instance, i); const metaData = { ...meta, name, tag, method: i }; if (baseMeta.controller) { if (typeof tag !== "string") _chunk4LLLQOMFjs.log.call(void 0, `can't use Tag with ${typeof tag} on controller "${instance.constructor.name}",instead with "${tag = String(tag)}"`, "error"); metaData.controller = baseMeta.controller; metaData[baseMeta.controller] = { ...baseMeta[baseMeta.controller], ...meta[baseMeta.controller] }; const params = _phecdacore.getMetaParams.call(void 0, instance, i).map((item) => _phecdacore.getMergedMeta.call(void 0, instance, i, item)); metaData.meta = meta; metaData.ctxs = ctxs; metaData.params = params.map((item, index) => { return { ...item, pipe: item.pipe || meta.pipe || baseMeta.pipe, define: item.define || {}, index, meta: item }; }); metaData.filter = meta.filter || baseMeta.filter; metaData.define = { ...baseMeta.define, ...meta.define }; for (const item of [ "addons", "guards" ]) { const set = new Set(baseMeta[item]); if (meta[item]) { meta[item].forEach((part) => { set.delete(part); set.add(part); }); } metaData[item] = [ ...set ]; } } return new Meta(deepFreeze(metaData), getParamTypes(instance, i) || [], instance, model); }); } _chunk4LLLQOMFjs.__name.call(void 0, getMetaFromInstance, "getMetaFromInstance"); function deepFreeze(object) { Object.freeze(object); Object.getOwnPropertyNames(object).forEach((prop) => { if (object[prop] !== null && (typeof object[prop] === "object" || typeof object[prop] === "function") && !Object.isFrozen(object[prop])) deepFreeze(object[prop]); }); return object; } _chunk4LLLQOMFjs.__name.call(void 0, deepFreeze, "deepFreeze"); function getParamTypes(Model, key) { return Reflect.getMetadata("design:paramtypes", Model, key); } _chunk4LLLQOMFjs.__name.call(void 0, getParamTypes, "getParamTypes"); exports.Meta = Meta; exports.emitter = emitter; exports.defaultServerInject = defaultServerInject; exports.phecdaNamespace = phecdaNamespace; exports.ServerPhecda = ServerPhecda; exports.Factory = Factory; exports.useS = useS;