@resolid/di 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -130
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,130 +1 @@
|
|
|
1
|
-
|
|
2
|
-
const isDisposable = (obj) => !!obj && typeof obj.dispose === "function";
|
|
3
|
-
const formatChain = (chain, current) => {
|
|
4
|
-
return (current ? [...chain, current] : chain).map(String).join(" -> ");
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
//#endregion
|
|
8
|
-
//#region src/container/index.ts
|
|
9
|
-
const createContainer = () => {
|
|
10
|
-
const result = _createContainer();
|
|
11
|
-
return {
|
|
12
|
-
bind: result.bind,
|
|
13
|
-
resolve: result.resolve,
|
|
14
|
-
lazyResolve: result.lazyResolve,
|
|
15
|
-
dispose: result.dispose
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
const _createContainer = (parent, item, constructing) => {
|
|
19
|
-
const bindings = parent?.bindings ?? /* @__PURE__ */ new Map();
|
|
20
|
-
const singletons = parent?.singletons ?? /* @__PURE__ */ new Map();
|
|
21
|
-
const currentConstructing = item ? [...constructing ?? parent?.constructing ?? [], item] : [];
|
|
22
|
-
const lazyResolveQueue = [];
|
|
23
|
-
const container = {};
|
|
24
|
-
const enqueueLazyResolve = (name) => {
|
|
25
|
-
return new Promise((resolve$1) => {
|
|
26
|
-
const lazy = (value) => {
|
|
27
|
-
resolve$1(value);
|
|
28
|
-
};
|
|
29
|
-
lazyResolveQueue.push({
|
|
30
|
-
name,
|
|
31
|
-
resolve: lazy
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
const dequeueLazyResolves = async () => {
|
|
36
|
-
for (const lazyResolve$1 of lazyResolveQueue) try {
|
|
37
|
-
lazyResolve$1.resolve(await resolveBinding(lazyResolve$1.name, []));
|
|
38
|
-
} catch (e) {
|
|
39
|
-
throw new Error(`Failed to resolve lazy resolver for name ${lazyResolve$1.name.toString()}: ${e instanceof Error ? e.message : String(e)}`);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
const bind = (name) => {
|
|
43
|
-
const toValue = (value) => {
|
|
44
|
-
bindings.set(name, {
|
|
45
|
-
factory: () => value,
|
|
46
|
-
scope: "singleton"
|
|
47
|
-
});
|
|
48
|
-
};
|
|
49
|
-
const toFunction = (fn) => {
|
|
50
|
-
bindings.set(name, {
|
|
51
|
-
factory: () => fn,
|
|
52
|
-
scope: "singleton"
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
const toFactory = (fn, options) => {
|
|
56
|
-
bindings.set(name, {
|
|
57
|
-
factory: (resolve$1, lazyResolve$1) => {
|
|
58
|
-
return fn({
|
|
59
|
-
resolver: {
|
|
60
|
-
resolve: resolve$1,
|
|
61
|
-
lazyResolve: lazyResolve$1
|
|
62
|
-
},
|
|
63
|
-
config: options?.config
|
|
64
|
-
});
|
|
65
|
-
},
|
|
66
|
-
scope: options?.scope ?? "singleton",
|
|
67
|
-
config: options?.config
|
|
68
|
-
});
|
|
69
|
-
};
|
|
70
|
-
return {
|
|
71
|
-
toValue,
|
|
72
|
-
toFunction,
|
|
73
|
-
toFactory
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
const resolveBinding = async (name, constructing$1) => {
|
|
77
|
-
const binding = bindings.get(name);
|
|
78
|
-
if (!binding) throw new Error(`No binding found for name: ${name.toString()}`);
|
|
79
|
-
const isSingleton = binding.scope === "singleton";
|
|
80
|
-
if (isSingleton && singletons.has(name)) return singletons.get(name);
|
|
81
|
-
const child = _createContainer(container, name, constructing$1);
|
|
82
|
-
const result = await binding.factory(child.resolve, child.lazyResolve);
|
|
83
|
-
if (isSingleton) singletons.set(name, result);
|
|
84
|
-
await child.dequeueLazyResolves();
|
|
85
|
-
return result;
|
|
86
|
-
};
|
|
87
|
-
const resolve = async (name) => {
|
|
88
|
-
if (currentConstructing.includes(name)) throw new Error(`Circular dependency detected: ${formatChain(currentConstructing, name)}`);
|
|
89
|
-
return resolveBinding(name);
|
|
90
|
-
};
|
|
91
|
-
const lazyResolve = (name) => {
|
|
92
|
-
let value;
|
|
93
|
-
enqueueLazyResolve(name).then((resolved) => {
|
|
94
|
-
value = resolved;
|
|
95
|
-
});
|
|
96
|
-
return { get value() {
|
|
97
|
-
if (!value) throw new Error("Lazy binding is not yet resolved. Do not use lazy-resolved bindings before the binding construction ends.");
|
|
98
|
-
return value;
|
|
99
|
-
} };
|
|
100
|
-
};
|
|
101
|
-
const dispose = async () => {
|
|
102
|
-
const disposeErrors = [];
|
|
103
|
-
for (const [name, instance] of singletons) if (isDisposable(instance)) try {
|
|
104
|
-
await instance.dispose();
|
|
105
|
-
} catch (error) {
|
|
106
|
-
disposeErrors.push({
|
|
107
|
-
name,
|
|
108
|
-
error
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
if (disposeErrors.length > 0) {
|
|
112
|
-
const errorMessages = disposeErrors.map(({ name, error }) => `${name.toString()}: ${error instanceof Error ? error.message : String(error)}`).join("; ");
|
|
113
|
-
throw new Error(`Failed to dispose ${disposeErrors.length} binding(s): ${errorMessages}`);
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
Object.assign(container, {
|
|
117
|
-
bindings,
|
|
118
|
-
singletons,
|
|
119
|
-
constructing: currentConstructing,
|
|
120
|
-
dequeueLazyResolves,
|
|
121
|
-
bind,
|
|
122
|
-
resolve,
|
|
123
|
-
lazyResolve,
|
|
124
|
-
dispose
|
|
125
|
-
});
|
|
126
|
-
return container;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
//#endregion
|
|
130
|
-
export { createContainer };
|
|
1
|
+
const e=e=>!!e&&typeof e.dispose==`function`,t=(e,t)=>(t?[...e,t]:e).map(String).join(` -> `),n=()=>{let e=r();return{bind:e.bind,resolve:e.resolve,lazyResolve:e.lazyResolve,dispose:e.dispose}},r=(n,i,a)=>{let o=n?.bindings??new Map,s=n?.singletons??new Map,c=i?[...a??n?.constructing??[],i]:[],l=[],u={},d=e=>new Promise(t=>{l.push({name:e,resolve:e=>{t(e)}})}),f=async()=>{for(let e of l)try{e.resolve(await m(e.name,[]))}catch(t){throw Error(`Failed to resolve lazy resolver for name ${e.name.toString()}: ${t instanceof Error?t.message:String(t)}`)}},p=e=>({toValue:t=>{o.set(e,{factory:()=>t,scope:`singleton`})},toFunction:t=>{o.set(e,{factory:()=>t,scope:`singleton`})},toFactory:(t,n)=>{o.set(e,{factory:(e,r)=>t({resolver:{resolve:e,lazyResolve:r},config:n?.config}),scope:n?.scope??`singleton`,config:n?.config})}}),m=async(e,t)=>{let n=o.get(e);if(!n)throw Error(`No binding found for name: ${e.toString()}`);let i=n.scope===`singleton`;if(i&&s.has(e))return s.get(e);let a=r(u,e,t),c=await n.factory(a.resolve,a.lazyResolve);return i&&s.set(e,c),await a.dequeueLazyResolves(),c};return Object.assign(u,{bindings:o,singletons:s,constructing:c,dequeueLazyResolves:f,bind:p,resolve:async e=>{if(c.includes(e))throw Error(`Circular dependency detected: ${t(c,e)}`);return m(e)},lazyResolve:e=>{let t;return d(e).then(e=>{t=e}),{get value(){if(!t)throw Error(`Lazy binding is not yet resolved. Do not use lazy-resolved bindings before the binding construction ends.`);return t}}},dispose:async()=>{let t=[];for(let[n,r]of s)if(e(r))try{await r.dispose()}catch(e){t.push({name:n,error:e})}if(t.length>0){let e=t.map(({name:e,error:t})=>`${e.toString()}: ${t instanceof Error?t.message:String(t)}`).join(`; `);throw Error(`Failed to dispose ${t.length} binding(s): ${e}`)}}}),u};export{n as createContainer};
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
7
|
-
"version": "0.1.
|
|
7
|
+
"version": "0.1.1",
|
|
8
8
|
"description": "The Resolid DI Container package.",
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"typescript": "^5.9.3"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
|
-
"node": "^22.13.0 || >=24"
|
|
28
|
+
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
29
29
|
},
|
|
30
30
|
"homepage": "https://www.resolid.tech",
|
|
31
31
|
"repository": {
|