phecda-server
Version:
server framework that provide IOC/type-reuse/http&rpc-adaptor
312 lines (288 loc) • 12.2 kB
JavaScript
;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;