lakutata
Version:
An IoC-based universal application framework.
496 lines (434 loc) • 14.9 kB
JavaScript
"use strict";
const e = require("./Package.1.cjs");
const t = require("../src/lib/base/async-constructor/AsyncConstructor.cjs");
const s = require("../src/decorators/di/Lifetime.cjs");
const r = require("../src/exceptions/MethodNotFoundException.cjs");
const i = require("../src/lib/ioc/DependencyInjectionContainer.cjs");
const o = require("node:crypto");
const n = require("../src/lib/base/internal/ConfigurableRecordsInjection.cjs");
const a = require("../src/lib/base/internal/ObjectConfiguration.cjs");
const c = require("../src/lib/base/internal/ObjectInjection.cjs");
const l = require("../src/lib/base/internal/ObjectContainer.cjs");
const d = require("./Package.2.cjs");
const h = require("../src/lib/helpers/ObjectConstructor.cjs");
const u = require("../src/lib/helpers/As.cjs");
const p = require("../src/lib/helpers/DevNull.cjs");
const b = require("../src/lib/helpers/ObjectParentConstructors.cjs");
const y = require("../src/exceptions/di/DependencyInjectionException.cjs");
const O = require("../src/lib/base/internal/ConstructorSymbol.cjs");
const m = require("../src/decorators/dto/Expect.cjs");
const f = require("../src/decorators/dto/IndexSignature.cjs");
const j = require("../src/lib/ioc/Resolvers.cjs");
const g = require("../src/lib/base/internal/ObjectLifetime.cjs");
const w = require("../src/decorators/dto/Accept.cjs");
const C = require("../src/lib/ioc/ListModules.cjs");
const P = require("url");
const S = require("../src/lib/ioc/Utils.cjs");
const T = require("../src/lib/helpers/IsEmptyObject.cjs");
const R = require("../src/lib/base/internal/ObjectWeakRefs.cjs");
var x;
const I = Symbol("OBJECT_ID");
exports.LoadObjectOptions = class LoadObjectOptions extends d.DTO {
static {
x = I;
}
};
e.__decorate([ m.Expect(d.DTO.Alternatives(d.DTO.String(), d.DTO.Symbol()).optional()), e.__metadata("design:type", Object) ], exports.LoadObjectOptions.prototype, x, void 0);
e.__decorate([ m.Expect(d.DTO.Class((() => exports.BaseObject)).required()), e.__metadata("design:type", Object) ], exports.LoadObjectOptions.prototype, "class", void 0);
exports.LoadObjectOptions = e.__decorate([ f.IndexSignature(d.DTO.Any()) ], exports.LoadObjectOptions);
const A = Symbol("LAKUTATA.DI.CONTAINER.SYMBOL");
const N = Symbol("LAKUTATA.DI.OWNER.SYMBOL");
class Container {
#e;
#t;
#s;
constructor(e, t) {
this.#t = new Set;
this.#s = false;
this.injectionNames = new Set;
this.parent = e;
this.#e = e ? e.#e.createScope() : i.createContainer({
injectionMode: "PROXY",
strict: false
});
if (this.parent) this.parent.#t.add(this);
this.#e.register(A, j.asValue(this));
if (t) this.#e.register(N, j.asValue(new WeakRef(t)));
}
async disposer(e) {
try {
await e.getMethod(B, false)();
} catch (e) {
p.DevNull(e);
}
}
buildResolverOptions(e) {
const t = g.GetObjectLifetime(e);
return {
lifetime: t,
dispose: e => this.disposer(e)
};
}
async processResolved(e, t, s = {}) {
const r = n.GetConfigurableRecords(u.As(e.constructor), t);
const i = d.DTO.isValid(e.constructor, d.DTO.Class(exports.BaseObject));
if (i) {
n.SetIdToInstance(u.As(e), t);
n.SetConfigurableRecordsToInstance(u.As(e), {
...r,
...s
});
}
return Promise.resolve(e);
}
buildNameAndRegistrationPairFromOptions(e) {
const t = {};
const s = e[I] ? e[I] : O.ConstructorSymbol(e.class);
const r = {
...e,
class: void 0
};
delete r.id;
delete r.class;
n.SetConfigurableRecords(e.class, s, r);
t[s] = j.asClass(e.class, this.buildResolverOptions(e.class));
return t;
}
async buildNameAndRegistrationPairFromGlob(e) {
const t = [];
C.listModules(e).forEach((e => {
t.push(new Promise((t => {
import(P.pathToFileURL(e.path).toString()).then((e => {
Object.keys(e).forEach((s => {
const r = e[s];
if (S.isClass(r) && d.DTO.isValid(r, d.DTO.Class(exports.BaseObject))) {
const e = r;
const s = {};
s[O.ConstructorSymbol(e)] = j.asClass(e, this.buildResolverOptions(e));
return t(s);
} else {
return t({});
}
}));
})).catch((() => t({})));
})));
}));
const s = await Promise.all(t);
let r = {};
s.forEach((e => {
r = {
...r,
...e
};
}));
return r;
}
owner() {
const e = this.#e.resolve(N, {
allowUnregistered: true
});
return e ? e.deref() : undefined;
}
async load(e) {
let t = {};
const s = [];
e.forEach((e => {
if (typeof e === "string") {
s.push(new Promise(((t, s) => this.buildNameAndRegistrationPairFromGlob(e).then(t).catch(s))));
} else if (S.isClass(u.As(e))) {
const s = {
class: u.As(e)
};
t = {
...t,
...this.buildNameAndRegistrationPairFromOptions(s)
};
} else {
const s = u.As(e);
t = {
...t,
...this.buildNameAndRegistrationPairFromOptions(s)
};
}
}));
if (s.length) {
const e = await Promise.all(s);
e.forEach((e => {
t = {
...e,
...t
};
}));
}
if (!T.IsEmptyObject(t)) {
Object.getOwnPropertyNames(t).forEach((e => this.injectionNames.add(e)));
Object.getOwnPropertySymbols(t).forEach((e => this.injectionNames.add(e)));
this.#e.register(t);
}
}
async get(e, t = {}) {
const s = typeof e === "function" ? O.ConstructorSymbol(e) : e;
if (!this.#e.hasRegistration(s) && typeof e === "function" && c.GetObjectIsAutoload(u.As(e))) {
await this.load([ {
id: s,
class: u.As(e)
} ]);
}
return (this.#e.getRegistration(s)?.lifetime === "SINGLETON" || this.#e.getRegistration(s)?.lifetime === "MODULE_SINGLETON") && !this.injectionNames.has(s) && this.parent ? await this.parent.get(s, t) : await this.processResolved(this.#e.resolve(s), s, t);
}
has(e) {
if (typeof e === "function") return this.#e.hasRegistration(O.ConstructorSymbol(e));
return this.#e.hasRegistration(e);
}
async set(e, t = {}) {
await this.load([ {
...t,
class: e
} ]);
return await this.get(e);
}
async setNamed(e, t, s = {}) {
await this.load([ {
...s,
class: t,
[I]: e
} ]);
return await this.get(e);
}
async register(e, t = {}) {
await this.load([ {
...t,
class: e
} ]);
}
async registerNamed(e, t, s = {}) {
await this.load([ {
...s,
class: t,
[I]: e
} ]);
}
async build(e, t = {}) {
const s = await this.processResolved(this.#e.build(e, this.buildResolverOptions(e)), O.ConstructorSymbol(e), t);
R.AppendObjectWeakRefs(this.#e, s);
return s;
}
createScope() {
return new Container(this, this.owner());
}
registerContainerToItsParent() {
if (this.parent) this.parent.#t.add(this);
}
async clear() {
const e = [];
this.#t.forEach((t => e.push(new Promise(((e, s) => t.destroy().then(e).catch(s))))));
await Promise.all(e);
await this.#e.dispose();
const t = [];
R.GetObjectWeakRefs(this.#e).forEach((e => {
let s = e.deref();
if (!s) return;
if (s[B]) {
t.push(new Promise((e => s ? Promise.resolve(s[B]()).then((() => {
s = undefined;
return e();
})).catch(p.DevNull) : e())));
}
}));
await Promise.all(t);
R.ClearObjectWeakRefs(this.#e);
}
async destroy() {
if (this.#s) return;
this.#s = true;
if (this.parent) this.parent.#t.delete(this);
await this.clear();
}
}
e.__decorate([ w.Accept(d.DTO.Array(d.DTO.Alternatives(exports.LoadObjectOptions.Schema(), d.DTO.Class((() => exports.BaseObject)), d.DTO.Glob()))), e.__metadata("design:type", Function), e.__metadata("design:paramtypes", [ Array ]), e.__metadata("design:returntype", Promise) ], Container.prototype, "load", null);
const _ = Symbol("OBJECT.TYPE");
exports.ObjectType = void 0;
(function(e) {
e["Unknown"] = "Unknown";
e["Object"] = "Object";
e["Provider"] = "Provider";
e["Controller"] = "Controller";
e["Component"] = "Component";
e["Module"] = "Module";
})(exports.ObjectType || (exports.ObjectType = {}));
function D(e) {
return t => v(t, e);
}
function v(e, t) {
Reflect.defineMetadata(_, d.DTO.isValid(e, d.DTO.Class(exports.BaseObject)) ? t : exports.ObjectType.Unknown, e);
return e;
}
function E(e) {
if (Reflect.hasOwnMetadata(_, e)) return Reflect.getOwnMetadata(_, e);
let t = exports.ObjectType.Unknown;
for (const s of b.ObjectParentConstructors(e)) {
if (Reflect.hasOwnMetadata(_, s)) {
t = Reflect.getOwnMetadata(_, s);
break;
}
}
v(e, t);
return E(e);
}
var q;
var M;
const L = Symbol("__init");
const B = Symbol("__destroy");
const G = Symbol("anonymous");
const k = Symbol("OBJECT.SYMBOL.PROPERTY");
exports.BaseObject = M = class BaseObject extends t.AsyncConstructor {
#r;
#i;
#o=o.randomUUID();
#n=false;
async #a() {
const e = n.GetConfigurableRecordsFromInstance(this);
const t = [];
a.GetObjectConfigurableProperties(this).forEach(((s, r) => {
if (d.IsSymbol(r)) return;
t.push(new Promise(((t, i) => {
d.DTO.validateAsync(e[u.As(r)], s.schema, {
targetName: r
}).then((e => Promise.resolve(s.fn.bind(this)(e)).then((e => {
this[r] = e;
return t();
})).catch(i))).catch(i);
})));
}));
await Promise.all(t);
}
async #c() {
const e = c.GetObjectInjectItemsByPrototype(this);
const t = [];
e.forEach(((e, s) => {
const r = e.name;
t.push(new Promise(((t, i) => {
this.#r.get(r).then((r => {
Promise.resolve(e.transform(r)).then((e => {
Reflect.set(this, s, e);
return t();
})).catch(i);
})).catch((e => i(new y.DependencyInjectionException("Unable to inject value for property {0} of {1} because: {2}", [ s, this.className, e.message ]))));
})));
}));
await Promise.all(t);
}
#l() {
const e = n.GetIdFromInstance(this);
this.#i = e ? e : G;
}
constructor(e) {
super((async () => {
this.#l();
const e = Object.getOwnPropertyDescriptor(this, "then");
if (e) Object.defineProperty(this, "then", {
enumerable: false
});
await this[L]();
}));
this.#r = new Container(e[A], this);
l.SetObjectContainerGetter(this, this.#r);
}
static get className() {
return this.name;
}
get className() {
return h.ObjectConstructor(this).name;
}
async [L](...e) {
this.#r.registerContainerToItsParent();
if (!this.#n) {
await this.#c();
await this.#a();
this.#n = true;
}
for (const t of e) await t();
await this.init();
}
async [B](...e) {
await this.#r.destroy();
for (const t of e) await t();
await this.destroy();
}
async init() {}
async destroy() {}
async getObject(e, t = {}) {
return await this.#r.get(e, t);
}
async buildObject(e, t = {}) {
return this.#r.build(e, t);
}
getParent() {
return this.#r.parent?.owner();
}
getModule() {
let e = this.getParent();
while (e && E(u.As(h.ObjectConstructor(e))) !== exports.ObjectType.Module) {
e = this.getParent();
}
return u.As(e);
}
get $uuid() {
return this.#o;
}
get $id() {
return this.#i;
}
get $symbol() {
if (Reflect.hasOwnMetadata(k, this)) return Reflect.getOwnMetadata(k, this);
Reflect.defineMetadata(k, Symbol(this.$uuid), this);
return this.$symbol;
}
setProperty(e, t) {
this[e] = t;
}
getProperty(e, t) {
if (this.hasProperty(e)) return u.As(this[e]);
return u.As(t);
}
hasProperty(e) {
return typeof e === "string" ? this.propertyNames().includes(e) : this.propertySymbols().includes(e);
}
propertySymbols() {
return Object.getOwnPropertySymbols(this);
}
propertyNames() {
return Object.getOwnPropertyNames(this);
}
hasMethod(e) {
const t = this.hasProperty(e);
if (t) return false;
return typeof this[e] === "function";
}
getMethod(e, t = false) {
if (this.hasMethod(e)) {
return (...t) => this[e](...t);
} else if (t) {
throw new r.MethodNotFoundException('Method "{methodName}" not found in "{className}"', {
methodName: e,
className: this.constructor.name
});
} else {
return (...e) => p.DevNull(...e);
}
}
async dispose() {
await this.destroy();
}
};
exports.BaseObject = M = e.__decorate([ s.Transient(), D(exports.ObjectType.Object), e.__metadata("design:paramtypes", [ Object ]) ], exports.BaseObject);
exports.Container = Container;
exports.DefineObjectType = D;
exports.GetObjectType = E;
exports.OBJECT_ID = I;
exports.SetObjectType = v;
exports.__destroy = B;
exports.__init = L;
exports.anonymousId = G;
exports.containerSymbol = A;
exports.ownerSymbol = N;