@microphi/json-db 2.2.0

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.
Files changed (62) hide show
  1. package/README.md +12 -0
  2. package/lib/index.d.ts +2 -0
  3. package/lib/index.d.ts.map +1 -0
  4. package/lib/index.js +2 -0
  5. package/lib/index.js.map +1 -0
  6. package/lib/lib/aspects/after.decorator.d.ts +35 -0
  7. package/lib/lib/aspects/after.decorator.d.ts.map +1 -0
  8. package/lib/lib/aspects/after.decorator.js +45 -0
  9. package/lib/lib/aspects/after.decorator.js.map +1 -0
  10. package/lib/lib/aspects/before.decorator.d.ts +28 -0
  11. package/lib/lib/aspects/before.decorator.d.ts.map +1 -0
  12. package/lib/lib/aspects/before.decorator.js +46 -0
  13. package/lib/lib/aspects/before.decorator.js.map +1 -0
  14. package/lib/lib/container/bootstrap.d.ts +3 -0
  15. package/lib/lib/container/bootstrap.d.ts.map +1 -0
  16. package/lib/lib/container/bootstrap.js +15 -0
  17. package/lib/lib/container/bootstrap.js.map +1 -0
  18. package/lib/lib/container/di.decorator.d.ts +10 -0
  19. package/lib/lib/container/di.decorator.d.ts.map +1 -0
  20. package/lib/lib/container/di.decorator.js +15 -0
  21. package/lib/lib/container/di.decorator.js.map +1 -0
  22. package/lib/lib/container/graph.d.ts +171 -0
  23. package/lib/lib/container/graph.d.ts.map +1 -0
  24. package/lib/lib/container/graph.js +429 -0
  25. package/lib/lib/container/graph.js.map +1 -0
  26. package/lib/lib/injctable/inject.decorator.d.ts +7 -0
  27. package/lib/lib/injctable/inject.decorator.d.ts.map +1 -0
  28. package/lib/lib/injctable/inject.decorator.js +31 -0
  29. package/lib/lib/injctable/inject.decorator.js.map +1 -0
  30. package/lib/lib/injctable/injectable.decorator.d.ts +16 -0
  31. package/lib/lib/injctable/injectable.decorator.d.ts.map +1 -0
  32. package/lib/lib/injctable/injectable.decorator.js +52 -0
  33. package/lib/lib/injctable/injectable.decorator.js.map +1 -0
  34. package/lib/lib/injctable/injector.d.ts +4 -0
  35. package/lib/lib/injctable/injector.d.ts.map +1 -0
  36. package/lib/lib/injctable/injector.js +25 -0
  37. package/lib/lib/injctable/injector.js.map +1 -0
  38. package/lib/lib/list/list.d.ts +28 -0
  39. package/lib/lib/list/list.d.ts.map +1 -0
  40. package/lib/lib/list/list.js +94 -0
  41. package/lib/lib/list/list.js.map +1 -0
  42. package/lib/lib/provider/providers.d.ts +15 -0
  43. package/lib/lib/provider/providers.d.ts.map +1 -0
  44. package/lib/lib/provider/providers.js +80 -0
  45. package/lib/lib/provider/providers.js.map +1 -0
  46. package/lib/lib/scan.d.ts +3 -0
  47. package/lib/lib/scan.d.ts.map +1 -0
  48. package/lib/lib/scan.js +19 -0
  49. package/lib/lib/scan.js.map +1 -0
  50. package/lib/lib/testing/mocked.d.ts +9 -0
  51. package/lib/lib/testing/mocked.d.ts.map +1 -0
  52. package/lib/lib/testing/mocked.js +58 -0
  53. package/lib/lib/testing/mocked.js.map +1 -0
  54. package/lib/lib/testing/test-bed.d.ts +7 -0
  55. package/lib/lib/testing/test-bed.d.ts.map +1 -0
  56. package/lib/lib/testing/test-bed.js +20 -0
  57. package/lib/lib/testing/test-bed.js.map +1 -0
  58. package/lib/lib/types.d.ts +10 -0
  59. package/lib/lib/types.d.ts.map +1 -0
  60. package/lib/lib/types.js +4 -0
  61. package/lib/lib/types.js.map +1 -0
  62. package/package.json +37 -0
@@ -0,0 +1,429 @@
1
+ export class CycleError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ Object.setPrototypeOf(this, CycleError.prototype);
5
+ }
6
+ }
7
+ /**
8
+ * A graph data structure with depth-first search and topological sort.
9
+ */
10
+ export class Graph {
11
+ constructor(serialized) {
12
+ /**
13
+ * The adjacency list of the graph.
14
+ * Keys are node ids.
15
+ * Values are adjacent node id arrays.
16
+ */
17
+ this.edges = {};
18
+ /**
19
+ * The weights of edges.
20
+ * Keys are string encodings of edges.
21
+ * Values are weights (numbers).
22
+ */
23
+ this.edgeWeights = {};
24
+ if (serialized) {
25
+ this.deserialize(serialized);
26
+ }
27
+ }
28
+ /**
29
+ * Deserializes the given serialized graph.
30
+ * @param serialized
31
+ */
32
+ deserialize(serialized) {
33
+ serialized.nodes.forEach((node) => {
34
+ this.addNode(node.id);
35
+ });
36
+ serialized.links.forEach((link) => {
37
+ this.addEdge(link.source, link.target, link.weight);
38
+ });
39
+ return this;
40
+ }
41
+ /**
42
+ * Gets the adjacent node list for the given node.
43
+ * Returns an empty array for unknown nodes.
44
+ * @param node
45
+ */
46
+ adjacent(node) {
47
+ return this.edges[node] || [];
48
+ }
49
+ /**
50
+ * Adds a node to the graph.
51
+ * If node was already added, this function does nothing.
52
+ * If node was not already added, this function sets up an empty adjacency list.
53
+ * @param node
54
+ */
55
+ addNode(node) {
56
+ this.edges[node] = this.adjacent(node);
57
+ return this;
58
+ }
59
+ /**
60
+ * Adds an edge from node u to node v.
61
+ * Implicitly adds the nodes if they were not already added.
62
+ * @param u
63
+ * @param v
64
+ * @param weight
65
+ */
66
+ addEdge(u, v, weight) {
67
+ this.addNode(u);
68
+ this.addNode(v);
69
+ this.adjacent(u).push(v);
70
+ if (weight !== undefined) {
71
+ this.setEdgeWeight(u, v, weight);
72
+ }
73
+ return this;
74
+ }
75
+ /**
76
+ * Sets the weight of the given edge.
77
+ * @param u
78
+ * @param v
79
+ * @param weight
80
+ */
81
+ setEdgeWeight(u, v, weight) {
82
+ this.edgeWeights[this.encodeEdge(u, v)] = weight;
83
+ return this;
84
+ }
85
+ /**
86
+ * Computes a string encoding of an edge,
87
+ * for use as a key in an object.
88
+ * @param u
89
+ * @param v
90
+ */
91
+ encodeEdge(u, v) {
92
+ return u + '|' + v;
93
+ }
94
+ /**
95
+ * Removes a node from the graph.
96
+ * Also removes incoming and outgoing edges.
97
+ * @param node
98
+ */
99
+ removeNode(node) {
100
+ // Remove incoming edges.
101
+ Object.keys(this.edges).forEach((u) => {
102
+ this.edges[u].forEach((v) => {
103
+ if (v === node) {
104
+ this.removeEdge(u, v);
105
+ }
106
+ });
107
+ });
108
+ // Remove outgoing edges (and signal that the node no longer exists).
109
+ delete this.edges[node];
110
+ return this;
111
+ }
112
+ /**
113
+ * Gets the list of nodes that have been added to the graph.
114
+ */
115
+ nodes() {
116
+ // TODO: Better implementation with set data structure
117
+ const nodeSet = {};
118
+ Object.keys(this.edges).forEach((u) => {
119
+ nodeSet[u] = true;
120
+ this.edges[u].forEach((v) => {
121
+ nodeSet[v] = true;
122
+ });
123
+ });
124
+ return Object.keys(nodeSet);
125
+ }
126
+ /**
127
+ * Gets the weight of the given edge.
128
+ * Returns 1 if no weight was previously set.
129
+ * @param u
130
+ * @param v
131
+ */
132
+ getEdgeWeight(u, v) {
133
+ const weight = this.edgeWeights[this.encodeEdge(u, v)];
134
+ return weight ?? 1;
135
+ }
136
+ /**
137
+ * Removes the edge from node u to node v.
138
+ * Does not remove the nodes.
139
+ * Does nothing if the edge does not exist.
140
+ * @param u
141
+ * @param v
142
+ */
143
+ removeEdge(u, v) {
144
+ if (this.edges[u]) {
145
+ this.edges[u] = this.adjacent(u).filter((_v) => {
146
+ return _v !== v;
147
+ });
148
+ }
149
+ return this;
150
+ }
151
+ /**
152
+ * Returns true if there is an edge from node u to node v.
153
+ * @param u
154
+ * @param v
155
+ */
156
+ hasEdge(u, v) {
157
+ return this.adjacent(u).includes(v);
158
+ }
159
+ /**
160
+ * Computes the indegree for the given node.
161
+ * Not very efficient, costs O(E) where E = number of edges.
162
+ *
163
+ * @param node
164
+ */
165
+ inDegree(node) {
166
+ let degree = 0;
167
+ function check(v) {
168
+ if (v === node) {
169
+ degree++;
170
+ }
171
+ }
172
+ Object.keys(this.edges).forEach((u) => {
173
+ this.edges[u].forEach(check);
174
+ });
175
+ return degree;
176
+ }
177
+ /**
178
+ * Computes the outdegree for the given node.
179
+ *
180
+ * @param node
181
+ */
182
+ outDegree(node) {
183
+ return node in this.edges ? this.edges[node].length : 0;
184
+ }
185
+ /**
186
+ * Depth First Search algorithm, inspired by
187
+ * Cormen et al. 'Introduction to Algorithms' 3rd Ed. p. 604
188
+ * The additional option `includeSourceNodes` specifies whether to
189
+ * include or exclude the source nodes from the result (true by default).
190
+ * If `sourceNodes` is not specified, all nodes in the graph
191
+ * are used as source nodes.
192
+ *
193
+ * @param sourceNodes
194
+ * @param includeSourceNodes
195
+ * @param errorOnCycle
196
+ */
197
+ depthFirstSearch(sourceNodes, includeSourceNodes = true, errorOnCycle = false) {
198
+ if (!sourceNodes) {
199
+ sourceNodes = this.nodes();
200
+ }
201
+ if (typeof includeSourceNodes !== 'boolean') {
202
+ includeSourceNodes = true;
203
+ }
204
+ const visited = {};
205
+ const visiting = {};
206
+ const nodeList = [];
207
+ const DFSVisit = (node) => {
208
+ if (visiting[node] && errorOnCycle) {
209
+ throw new CycleError('Cycle found');
210
+ }
211
+ if (!visited[node]) {
212
+ visited[node] = true;
213
+ visiting[node] = true; // temporary flag while visiting
214
+ this.adjacent(node).forEach(DFSVisit);
215
+ visiting[node] = false;
216
+ nodeList.push(node);
217
+ }
218
+ };
219
+ if (includeSourceNodes) {
220
+ sourceNodes.forEach(DFSVisit);
221
+ }
222
+ else {
223
+ sourceNodes.forEach((node) => {
224
+ visited[node] = true;
225
+ });
226
+ sourceNodes.forEach((node) => {
227
+ this.adjacent(node).forEach(DFSVisit);
228
+ });
229
+ }
230
+ return nodeList;
231
+ }
232
+ /**
233
+ * Returns true if the graph has one or more cycles and false otherwise
234
+ */
235
+ hasCycle() {
236
+ try {
237
+ this.depthFirstSearch(undefined, true, true);
238
+ // No error thrown -> no cycles
239
+ return false;
240
+ }
241
+ catch (error) {
242
+ if (error instanceof CycleError) {
243
+ return true;
244
+ }
245
+ else {
246
+ throw error;
247
+ }
248
+ }
249
+ }
250
+ /**
251
+ * Least Common Ancestors
252
+ * Inspired by https://github.com/relaxedws/lca/blob/master/src/LowestCommonAncestor.php code
253
+ * but uses depth search instead of breadth. Also uses some optimizations
254
+ *
255
+ * @param node1
256
+ * @param node2
257
+ */
258
+ lowestCommonAncestors(node1, node2) {
259
+ const node1Ancestors = [];
260
+ const lcas = [];
261
+ const CA1Visit = (visited, node) => {
262
+ if (!visited[node]) {
263
+ visited[node] = true;
264
+ node1Ancestors.push(node);
265
+ if (node == node2) {
266
+ lcas.push(node);
267
+ return false; // found - shortcut
268
+ }
269
+ return this.adjacent(node).every(node => {
270
+ return CA1Visit(visited, node);
271
+ });
272
+ }
273
+ else {
274
+ return true;
275
+ }
276
+ };
277
+ const CA2Visit = (visited, node) => {
278
+ if (!visited[node]) {
279
+ visited[node] = true;
280
+ if (node1Ancestors.indexOf(node) >= 0) {
281
+ lcas.push(node);
282
+ }
283
+ else if (lcas.length == 0) {
284
+ this.adjacent(node).forEach(node => {
285
+ CA2Visit(visited, node);
286
+ });
287
+ }
288
+ }
289
+ };
290
+ if (CA1Visit({}, node1)) {
291
+ // No shortcut worked
292
+ CA2Visit({}, node2);
293
+ }
294
+ return lcas;
295
+ }
296
+ /**
297
+ * The topological sort algorithm yields a list of visited nodes
298
+ * such that for each visited edge (u, v), u comes before v in the list.
299
+ * Amazingly, this comes from just reversing the result from depth first search.
300
+ * Cormen et al. 'Introduction to Algorithms' 3rd Ed. p. 613
301
+ *
302
+ * @param sourceNodes
303
+ * @param includeSourceNodes
304
+ */
305
+ topologicalSort(sourceNodes, includeSourceNodes = true) {
306
+ return this.depthFirstSearch(sourceNodes, includeSourceNodes, true).reverse();
307
+ }
308
+ /**
309
+ * Dijkstra's Shortest Path Algorithm.
310
+ * Cormen et al. 'Introduction to Algorithms' 3rd Ed. p. 658
311
+ * Variable and function names correspond to names in the book.
312
+ *
313
+ * @param source
314
+ * @param destination
315
+ */
316
+ shortestPath(source, destination) {
317
+ // Upper bounds for shortest path weights from source.
318
+ const d = {};
319
+ // Predecessors.
320
+ const p = {};
321
+ // Poor man's priority queue, keyed on d.
322
+ let q = {};
323
+ const initializeSingleSource = () => {
324
+ this.nodes().forEach((node) => {
325
+ d[node] = Infinity;
326
+ });
327
+ if (d[source] !== Infinity) {
328
+ throw new Error('Source node is not in the graph');
329
+ }
330
+ if (d[destination] !== Infinity) {
331
+ throw new Error('Destination node is not in the graph');
332
+ }
333
+ d[source] = 0;
334
+ };
335
+ // Adds entries in q for all nodes.
336
+ const initializePriorityQueue = () => {
337
+ this.nodes().forEach((node) => {
338
+ q[node] = true;
339
+ });
340
+ };
341
+ // Returns true if q is empty.
342
+ const priorityQueueEmpty = () => {
343
+ return Object.keys(q).length === 0;
344
+ };
345
+ // Linear search to extract (find and remove) min from q.
346
+ const extractMin = () => {
347
+ let min = Infinity;
348
+ let minNode;
349
+ Object.keys(q).forEach((node) => {
350
+ if (d[node] < min) {
351
+ min = d[node];
352
+ minNode = node;
353
+ }
354
+ });
355
+ if (minNode === undefined) {
356
+ // If we reach here, there's a disconnected subgraph, and we're done.
357
+ q = {};
358
+ return null;
359
+ }
360
+ delete q[minNode];
361
+ return minNode;
362
+ };
363
+ const relax = (u, v) => {
364
+ const w = this.getEdgeWeight(u, v);
365
+ if (d[v] > d[u] + w) {
366
+ d[v] = d[u] + w;
367
+ p[v] = u;
368
+ }
369
+ };
370
+ const dijkstra = () => {
371
+ initializeSingleSource();
372
+ initializePriorityQueue();
373
+ while (!priorityQueueEmpty()) {
374
+ const u = extractMin();
375
+ if (u === null)
376
+ return;
377
+ this.adjacent(u).forEach((v) => {
378
+ relax(u, v);
379
+ });
380
+ }
381
+ };
382
+ // Assembles the shortest path by traversing the
383
+ // predecessor subgraph from destination to source.
384
+ const path = () => {
385
+ const nodeList = {
386
+ path: [],
387
+ weight: 0,
388
+ };
389
+ let node = destination;
390
+ while (p[node]) {
391
+ nodeList.path.push(node);
392
+ nodeList.weight += this.getEdgeWeight(p[node], node);
393
+ node = p[node];
394
+ }
395
+ if (node !== source) {
396
+ throw new Error('No path found');
397
+ }
398
+ nodeList.path.push(node);
399
+ nodeList.path.reverse();
400
+ // nodeList.weight = 0;
401
+ return nodeList;
402
+ };
403
+ dijkstra();
404
+ return path();
405
+ }
406
+ /**
407
+ * Serializes the graph.
408
+ */
409
+ serialize() {
410
+ const serialized = {
411
+ nodes: this.nodes().map((id) => {
412
+ return { id: id };
413
+ }),
414
+ links: []
415
+ };
416
+ serialized.nodes.forEach((node) => {
417
+ const source = node.id;
418
+ this.adjacent(source).forEach((target) => {
419
+ serialized.links.push({
420
+ source: source,
421
+ target: target,
422
+ weight: this.getEdgeWeight(source, target)
423
+ });
424
+ });
425
+ });
426
+ return serialized;
427
+ }
428
+ }
429
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/lib/container/graph.ts"],"names":[],"mappings":"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","sourcesContent":["export type NodeId = string;\nexport type EdgeWeight = number;\nexport type EncodedEdge = string;\n\nexport interface Serialized {\n nodes: { id: NodeId }[];\n links: { source: NodeId; target: NodeId; weight: EdgeWeight }[];\n}\n\nexport class CycleError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, CycleError.prototype);\n }\n}\n\n/**\n * A graph data structure with depth-first search and topological sort.\n */\nexport class Graph {\n /**\n * The adjacency list of the graph.\n * Keys are node ids.\n * Values are adjacent node id arrays.\n */\n edges: Record<NodeId, NodeId[]> = {};\n\n /**\n * The weights of edges.\n * Keys are string encodings of edges.\n * Values are weights (numbers).\n */\n edgeWeights: Record<EncodedEdge, EdgeWeight> = {};\n\n constructor(serialized?: Serialized) {\n if (serialized) {\n this.deserialize(serialized);\n }\n }\n\n /**\n * Deserializes the given serialized graph.\n * @param serialized\n */\n deserialize(serialized: Serialized) {\n serialized.nodes.forEach((node) => {\n this.addNode(node.id);\n });\n serialized.links.forEach((link) => {\n this.addEdge(link.source, link.target, link.weight);\n });\n return this;\n }\n\n /**\n * Gets the adjacent node list for the given node.\n * Returns an empty array for unknown nodes.\n * @param node\n */\n adjacent(node: NodeId): NodeId[] {\n return this.edges[node] || [];\n }\n\n /**\n * Adds a node to the graph.\n * If node was already added, this function does nothing.\n * If node was not already added, this function sets up an empty adjacency list.\n * @param node\n */\n addNode(node: NodeId) {\n this.edges[node] = this.adjacent(node);\n return this;\n }\n\n /**\n * Adds an edge from node u to node v.\n * Implicitly adds the nodes if they were not already added.\n * @param u\n * @param v\n * @param weight\n */\n addEdge(u: NodeId, v: NodeId, weight?: EdgeWeight) {\n this.addNode(u);\n this.addNode(v);\n this.adjacent(u).push(v);\n\n if (weight !== undefined) {\n this.setEdgeWeight(u, v, weight);\n }\n\n return this;\n }\n\n /**\n * Sets the weight of the given edge.\n * @param u\n * @param v\n * @param weight\n */\n setEdgeWeight(u: NodeId, v: NodeId, weight: EdgeWeight) {\n this.edgeWeights[this.encodeEdge(u, v)] = weight;\n return this;\n }\n\n /**\n * Computes a string encoding of an edge,\n * for use as a key in an object.\n * @param u\n * @param v\n */\n encodeEdge(u: NodeId, v: NodeId): EncodedEdge {\n return u + '|' + v;\n }\n\n /**\n * Removes a node from the graph.\n * Also removes incoming and outgoing edges.\n * @param node\n */\n removeNode(node: NodeId) {\n // Remove incoming edges.\n Object.keys(this.edges).forEach((u) => {\n this.edges[u].forEach((v) => {\n if (v === node) {\n this.removeEdge(u, v);\n }\n });\n });\n\n // Remove outgoing edges (and signal that the node no longer exists).\n delete this.edges[node];\n\n return this;\n }\n\n /**\n * Gets the list of nodes that have been added to the graph.\n */\n nodes(): NodeId[] {\n // TODO: Better implementation with set data structure\n const nodeSet: Record<NodeId, boolean> = {};\n\n Object.keys(this.edges).forEach((u) => {\n nodeSet[u] = true;\n this.edges[u].forEach((v) => {\n nodeSet[v] = true;\n });\n });\n return Object.keys(nodeSet);\n }\n\n /**\n * Gets the weight of the given edge.\n * Returns 1 if no weight was previously set.\n * @param u\n * @param v\n */\n getEdgeWeight(u: NodeId, v: NodeId): EdgeWeight {\n const weight = this.edgeWeights[this.encodeEdge(u, v)];\n return weight ?? 1;\n }\n\n /**\n * Removes the edge from node u to node v.\n * Does not remove the nodes.\n * Does nothing if the edge does not exist.\n * @param u\n * @param v\n */\n removeEdge(u: NodeId, v: NodeId) {\n if (this.edges[u]) {\n this.edges[u] = this.adjacent(u).filter((_v) => {\n return _v !== v;\n });\n }\n return this;\n }\n\n /**\n * Returns true if there is an edge from node u to node v.\n * @param u\n * @param v\n */\n hasEdge(u: NodeId, v: NodeId) {\n return this.adjacent(u).includes(v);\n }\n\n /**\n * Computes the indegree for the given node.\n * Not very efficient, costs O(E) where E = number of edges.\n *\n * @param node\n */\n inDegree(node: NodeId) {\n let degree = 0;\n function check(v: NodeId) {\n if (v === node) {\n degree++;\n }\n }\n Object.keys(this.edges).forEach((u) => {\n this.edges[u].forEach(check);\n });\n return degree;\n }\n\n /**\n * Computes the outdegree for the given node.\n *\n * @param node\n */\n outDegree(node: NodeId) {\n return node in this.edges ? this.edges[node].length : 0;\n }\n\n\n /**\n * Depth First Search algorithm, inspired by\n * Cormen et al. 'Introduction to Algorithms' 3rd Ed. p. 604\n * The additional option `includeSourceNodes` specifies whether to\n * include or exclude the source nodes from the result (true by default).\n * If `sourceNodes` is not specified, all nodes in the graph\n * are used as source nodes.\n *\n * @param sourceNodes\n * @param includeSourceNodes\n * @param errorOnCycle\n */\n depthFirstSearch(\n sourceNodes: NodeId[]|undefined,\n includeSourceNodes: boolean = true,\n errorOnCycle: boolean = false,\n ) {\n if (!sourceNodes) {\n sourceNodes = this.nodes();\n }\n\n if (typeof includeSourceNodes !== 'boolean') {\n includeSourceNodes = true;\n }\n\n const visited: Record<NodeId, boolean> = {};\n const visiting: Record<NodeId, boolean> = {};\n const nodeList: NodeId[] = [];\n\n const DFSVisit = (node: NodeId) => {\n if (visiting[node] && errorOnCycle) {\n throw new CycleError('Cycle found');\n }\n if (!visited[node]) {\n visited[node] = true;\n visiting[node] = true; // temporary flag while visiting\n this.adjacent(node).forEach(DFSVisit);\n visiting[node] = false;\n nodeList.push(node);\n }\n };\n\n if (includeSourceNodes) {\n sourceNodes.forEach(DFSVisit);\n } else {\n sourceNodes.forEach((node) => {\n visited[node] = true;\n });\n sourceNodes.forEach((node) => {\n this.adjacent(node).forEach(DFSVisit);\n });\n }\n\n return nodeList;\n }\n\n\n /**\n * Returns true if the graph has one or more cycles and false otherwise\n */\n hasCycle(): boolean {\n try {\n this.depthFirstSearch(undefined, true, true);\n // No error thrown -> no cycles\n return false;\n }\n catch (error) {\n if (error instanceof CycleError) {\n return true;\n }\n else {\n throw error;\n }\n }\n }\n\n /**\n * Least Common Ancestors\n * Inspired by https://github.com/relaxedws/lca/blob/master/src/LowestCommonAncestor.php code\n * but uses depth search instead of breadth. Also uses some optimizations\n *\n * @param node1\n * @param node2\n */\n lowestCommonAncestors(node1: NodeId, node2: NodeId) {\n const node1Ancestors: NodeId[] = [];\n const lcas: NodeId[] = [];\n\n const CA1Visit = (\n visited: Record<NodeId, boolean>,\n node: NodeId\n ): boolean => {\n if (!visited[node]) {\n visited[node] = true;\n node1Ancestors.push(node);\n if (node == node2) {\n lcas.push(node);\n return false; // found - shortcut\n }\n return this.adjacent(node).every(node => {\n return CA1Visit(visited, node);\n });\n } else {\n return true;\n }\n };\n\n const CA2Visit = (visited: Record<NodeId, boolean>, node: NodeId) => {\n if (!visited[node]) {\n visited[node] = true;\n if (node1Ancestors.indexOf(node) >= 0) {\n lcas.push(node);\n } else if (lcas.length == 0) {\n this.adjacent(node).forEach(node => {\n CA2Visit(visited, node);\n });\n }\n }\n };\n\n if (CA1Visit({}, node1)) {\n // No shortcut worked\n CA2Visit({}, node2);\n }\n\n return lcas;\n }\n\n /**\n * The topological sort algorithm yields a list of visited nodes\n * such that for each visited edge (u, v), u comes before v in the list.\n * Amazingly, this comes from just reversing the result from depth first search.\n * Cormen et al. 'Introduction to Algorithms' 3rd Ed. p. 613\n *\n * @param sourceNodes\n * @param includeSourceNodes\n */\n topologicalSort(\n sourceNodes?: NodeId[],\n includeSourceNodes: boolean = true\n ) {\n return this.depthFirstSearch(sourceNodes, includeSourceNodes, true).reverse();\n }\n\n /**\n * Dijkstra's Shortest Path Algorithm.\n * Cormen et al. 'Introduction to Algorithms' 3rd Ed. p. 658\n * Variable and function names correspond to names in the book.\n *\n * @param source\n * @param destination\n */\n shortestPath(source: NodeId, destination: NodeId) {\n // Upper bounds for shortest path weights from source.\n const d: Record<NodeId, EdgeWeight> = {};\n\n // Predecessors.\n const p: Record<NodeId, NodeId> = {};\n\n // Poor man's priority queue, keyed on d.\n let q: Record<NodeId, boolean> = {};\n\n const initializeSingleSource = () => {\n this.nodes().forEach((node) => {\n d[node] = Infinity;\n });\n if (d[source] !== Infinity) {\n throw new Error('Source node is not in the graph');\n }\n if (d[destination] !== Infinity) {\n throw new Error('Destination node is not in the graph');\n }\n d[source] = 0;\n };\n\n // Adds entries in q for all nodes.\n const initializePriorityQueue = () => {\n this.nodes().forEach((node) => {\n q[node] = true;\n });\n };\n\n // Returns true if q is empty.\n const priorityQueueEmpty = () => {\n return Object.keys(q).length === 0;\n };\n\n // Linear search to extract (find and remove) min from q.\n const extractMin = (): NodeId | null => {\n let min = Infinity;\n let minNode;\n Object.keys(q).forEach((node) => {\n if (d[node] < min) {\n min = d[node];\n minNode = node;\n }\n });\n if (minNode === undefined) {\n // If we reach here, there's a disconnected subgraph, and we're done.\n q = {};\n return null;\n }\n delete q[minNode];\n return minNode;\n };\n\n const relax = (u: NodeId, v: NodeId) => {\n const w = this.getEdgeWeight(u, v);\n if (d[v] > d[u] + w) {\n d[v] = d[u] + w;\n p[v] = u;\n }\n };\n\n const dijkstra = () => {\n initializeSingleSource();\n initializePriorityQueue();\n while (!priorityQueueEmpty()) {\n const u = extractMin();\n if (u === null) return;\n this.adjacent(u).forEach((v) => {\n relax(u as string, v);\n });\n }\n };\n\n // Assembles the shortest path by traversing the\n // predecessor subgraph from destination to source.\n const path = () => {\n const nodeList: { path: NodeId[], weight: EdgeWeight } = {\n path: [],\n weight: 0,\n };\n let node = destination;\n while (p[node]) {\n nodeList.path.push(node);\n nodeList.weight += this.getEdgeWeight(p[node], node);\n node = p[node];\n }\n if (node !== source) {\n throw new Error('No path found');\n }\n nodeList.path.push(node);\n nodeList.path.reverse();\n // nodeList.weight = 0;\n return nodeList;\n };\n\n dijkstra();\n\n return path();\n }\n\n /**\n * Serializes the graph.\n */\n serialize() {\n const serialized: Serialized = {\n nodes: this.nodes().map((id) => {\n return { id: id };\n }),\n links: []\n };\n\n serialized.nodes.forEach((node) => {\n const source = node.id;\n this.adjacent(source).forEach((target) => {\n serialized.links.push({\n source: source,\n target: target,\n weight: this.getEdgeWeight(source, target)\n });\n });\n });\n\n return serialized;\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { Class } from 'utility-types';
2
+ export declare function Inject<K extends Class<unknown>>(klass: K): ParameterDecorator;
3
+ export declare function getInjectMetadata(target: any): {
4
+ parameterIndex: number;
5
+ klass: Class<unknown>;
6
+ }[];
7
+ //# sourceMappingURL=inject.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/injctable/inject.decorator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAUtC,wBAAgB,MAAM,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,kBAAkB,CA+B7E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,GAAG,GAAG;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;CAAC,EAAE,CAEhG"}
@@ -0,0 +1,31 @@
1
+ import { Graph } from '../container/graph';
2
+ import { getDebugger } from '@microphi/debug';
3
+ import { ClassNameSymbol } from './injectable.decorator';
4
+ const d = getDebugger('microphi:di:inject.decorator');
5
+ const dependencies = new Graph();
6
+ const InjectSymbol = Symbol.for('@Inject');
7
+ export function Inject(klass) {
8
+ return (target, propertyKey, parameterIndex) => {
9
+ const targetClassName = target['name'];
10
+ d('class', targetClassName, 'depends on', klass[ClassNameSymbol]);
11
+ const originalClassName = klass[ClassNameSymbol];
12
+ dependencies.addEdge(originalClassName, targetClassName);
13
+ d('are there cycles?', dependencies.hasCycle());
14
+ if (dependencies.hasCycle()) {
15
+ console.error(dependencies.serialize());
16
+ throw new Error(`Cycle dependency found ${originalClassName}`);
17
+ }
18
+ d('dependencies', dependencies.serialize());
19
+ const deps = getInjectMetadata(target);
20
+ deps.push({
21
+ parameterIndex,
22
+ klass
23
+ });
24
+ d('defined deps', deps);
25
+ return Reflect.metadata(InjectSymbol, deps)(target);
26
+ };
27
+ }
28
+ export function getInjectMetadata(target) {
29
+ return Reflect.getMetadata(InjectSymbol, target) || [];
30
+ }
31
+ //# sourceMappingURL=inject.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.decorator.js","sourceRoot":"","sources":["../../../src/lib/injctable/inject.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,CAAC,GAAG,WAAW,CAAC,8BAA8B,CAAC,CAAC;AAEtD,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE,CAAC;AAEjC,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAE3C,MAAM,UAAU,MAAM,CAA2B,KAAQ;IAEvD,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE;QAE7C,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAEvC,CAAC,CAAC,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;QAElE,MAAM,iBAAiB,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAEjD,YAAY,CAAC,OAAO,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC;QAGzD,CAAC,CAAC,mBAAmB,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEhD,IAAI,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,0BAA0B,iBAAiB,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,CAAC,CAAC,cAAc,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;QAE5C,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC;YACR,cAAc;YACd,KAAK;SACN,CAAC,CAAC;QACH,CAAC,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QAExB,OAAO,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,MAAa,CAAC,CAAC;IAC7D,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAW;IAC3C,OAAO,OAAO,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;AACzD,CAAC","sourcesContent":["import { Graph } from '../container/graph';\nimport { Class } from 'utility-types';\nimport { getDebugger } from '@microphi/debug';\nimport { ClassNameSymbol } from './injectable.decorator';\n\nconst d = getDebugger('microphi:di:inject.decorator');\n\nconst dependencies = new Graph();\n\nconst InjectSymbol = Symbol.for('@Inject');\n\nexport function Inject<K extends Class<unknown>>(klass: K): ParameterDecorator {\n\n return (target, propertyKey, parameterIndex) => {\n\n const targetClassName = target['name'];\n\n d('class', targetClassName, 'depends on', klass[ClassNameSymbol]);\n\n const originalClassName = klass[ClassNameSymbol];\n\n dependencies.addEdge(originalClassName, targetClassName);\n\n\n d('are there cycles?', dependencies.hasCycle());\n\n if (dependencies.hasCycle()) {\n console.error(dependencies.serialize());\n throw new Error(`Cycle dependency found ${originalClassName}`);\n }\n\n d('dependencies', dependencies.serialize());\n\n const deps = getInjectMetadata(target);\n deps.push({\n parameterIndex,\n klass\n });\n d('defined deps', deps);\n\n return Reflect.metadata(InjectSymbol, deps)(target as any);\n };\n}\n\nexport function getInjectMetadata(target: any): {parameterIndex: number, klass: Class<unknown>}[] {\n return Reflect.getMetadata(InjectSymbol, target) || [];\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import 'reflect-metadata';
2
+ import { Klass } from '../types';
3
+ export declare const ClassNameSymbol: unique symbol;
4
+ /**
5
+ * Annotate a Class to be part of the DI system
6
+ * @constructor
7
+ */
8
+ export declare function Injectable(): (target: any) => any;
9
+ export declare function InjectableDecorator<T extends {
10
+ new (...args: any[]): {};
11
+ }>(klass: T): {
12
+ new (...args: any[]): {};
13
+ [ClassNameSymbol]: string;
14
+ } & T;
15
+ export declare function getInjectableMetadata(klass: Klass): string;
16
+ //# sourceMappingURL=injectable.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injectable.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/injctable/injectable.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAI1B,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAKjC,eAAO,MAAM,eAAe,eAAsB,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,UAAU,yBAKzB;AAGD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAC,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;CAAC,EAAE,KAAK,EAAE,CAAC;kBAkBxD,GAAG,EAAE;;MAiB7B;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAE1D"}
@@ -0,0 +1,52 @@
1
+ import 'reflect-metadata';
2
+ import { getDebugger } from '@microphi/debug';
3
+ import { injector } from './injector';
4
+ import { getInjectMetadata } from './inject.decorator';
5
+ const d = getDebugger('microphi:di:injectable.decorator');
6
+ export const ClassNameSymbol = Symbol('ClassName');
7
+ /**
8
+ * Annotate a Class to be part of the DI system
9
+ * @constructor
10
+ */
11
+ export function Injectable() {
12
+ return target => {
13
+ d('annotating', target.name);
14
+ return InjectableDecorator(target);
15
+ };
16
+ }
17
+ // eslint-disable-next-line @typescript-eslint/ban-types
18
+ export function InjectableDecorator(klass) {
19
+ var _a, _b;
20
+ // this is needed because minified code can have different classes with the same name
21
+ // leading to a dependency cycle error which is not really there
22
+ // appending a random number will fix this problem
23
+ // TODO ideally this should be collision free hashing
24
+ const suffix = (Math.random() * 10000).toFixed(0).toString();
25
+ Reflect.metadata(ClassNameSymbol, klass)(klass);
26
+ const injectMetadata = getInjectMetadata(klass);
27
+ return _b = class extends klass {
28
+ constructor(...args) {
29
+ d(args);
30
+ d({ injectMetadata });
31
+ for (const { parameterIndex, klass } of injectMetadata) {
32
+ // TODO implement a factory
33
+ // factory should be configurable from the @DI container so that
34
+ // dependencies can be passed
35
+ args[parameterIndex] = injector(klass);
36
+ }
37
+ super(...args);
38
+ // d('class name', this[ClassNameSymbol]);
39
+ }
40
+ },
41
+ _a = ClassNameSymbol,
42
+ _b[_a] = `${klass.name}_${suffix}`,
43
+ (() => {
44
+ d('this is the static portion of', klass.name + suffix);
45
+ d('here symbol has been set');
46
+ })(),
47
+ _b;
48
+ }
49
+ export function getInjectableMetadata(klass) {
50
+ return Reflect.getMetadata(ClassNameSymbol, klass);
51
+ }
52
+ //# sourceMappingURL=injectable.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injectable.decorator.js","sourceRoot":"","sources":["../../../src/lib/injctable/injectable.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAGvD,MAAM,CAAC,GAAG,WAAW,CAAC,kCAAkC,CAAC,CAAC;AAG1D,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;AAEnD;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,MAAM,CAAC,EAAE;QACd,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,mBAAmB,CAAsC,KAAQ;;IAC/E,qFAAqF;IACrF,gEAAgE;IAChE,kDAAkD;IAClD,qDAAqD;IACrD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAE9D,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAEhD,YAAO,KAAM,SAAQ,KAAK;YAQxB,YAAY,GAAG,IAAW;gBACxB,CAAC,CAAC,IAAI,CAAC,CAAC;gBACR,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC;gBAEtB,KAAK,MAAM,EAAC,cAAc,EAAE,KAAK,EAAC,IAAI,cAAc,EAAE,CAAC;oBACrD,2BAA2B;oBAC3B,gEAAgE;oBAChE,6BAA6B;oBAC7B,IAAI,CAAC,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACzC,CAAC;gBAED,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;gBAEf,0CAA0C;YAE5C,CAAC;SACF;aAvBS,eAAe;QAAhB,MAAiB,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,MAAM,EAAG;QAErD;YACE,CAAC,CAAC,+BAA+B,EAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;YACxD,CAAC,CAAC,0BAA0B,CAAC,CAAC;QAChC,CAAC,GAAA;WAkBD;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAY;IAChD,OAAO,OAAO,CAAC,WAAW,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import 'reflect-metadata';\nimport { getDebugger } from '@microphi/debug';\nimport { injector } from './injector';\nimport { getInjectMetadata } from './inject.decorator';\nimport { Klass } from '../types';\n\nconst d = getDebugger('microphi:di:injectable.decorator');\n\n\nexport const ClassNameSymbol = Symbol('ClassName');\n\n/**\n * Annotate a Class to be part of the DI system\n * @constructor\n */\nexport function Injectable() {\n return target => {\n d('annotating', target.name);\n return InjectableDecorator(target);\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function InjectableDecorator<T extends {new(...args: any[]): {}}>(klass: T) {\n // this is needed because minified code can have different classes with the same name\n // leading to a dependency cycle error which is not really there\n // appending a random number will fix this problem\n // TODO ideally this should be collision free hashing\n const suffix = (Math.random() * 10_000).toFixed(0).toString();\n\n Reflect.metadata(ClassNameSymbol, klass)(klass);\n const injectMetadata = getInjectMetadata(klass);\n\n return class extends klass {\n static [ClassNameSymbol] = `${klass.name}_${suffix}`;\n\n static {\n d('this is the static portion of', klass.name + suffix);\n d('here symbol has been set');\n }\n\n constructor(...args: any[]) {\n d(args);\n d({ injectMetadata });\n\n for (const {parameterIndex, klass} of injectMetadata) {\n // TODO implement a factory\n // factory should be configurable from the @DI container so that\n // dependencies can be passed\n args[parameterIndex] = injector(klass);\n }\n\n super(...args);\n\n // d('class name', this[ClassNameSymbol]);\n\n }\n };\n}\n\nexport function getInjectableMetadata(klass: Klass): string {\n return Reflect.getMetadata(ClassNameSymbol, klass);\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { Class } from 'utility-types';
2
+ import 'reflect-metadata';
3
+ export declare function injector<K extends Class<any>>(klass: K): InstanceType<K>;
4
+ //# sourceMappingURL=injector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injector.d.ts","sourceRoot":"","sources":["../../../src/lib/injctable/injector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAItC,OAAO,kBAAkB,CAAC;AAI1B,wBAAgB,QAAQ,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAoBxE"}
@@ -0,0 +1,25 @@
1
+ import { getDebugger } from '@microphi/debug';
2
+ import { ClassNameSymbol } from './injectable.decorator';
3
+ import { providers } from '../container/di.decorator';
4
+ import 'reflect-metadata';
5
+ const d = getDebugger('microphi:di:injector');
6
+ export function injector(klass) {
7
+ d('searching singleton for', klass);
8
+ // here class is the @Injectable() version so we need to get original class name
9
+ if (providers.hasInjectable(klass)) {
10
+ return providers.getInstance(klass);
11
+ }
12
+ else {
13
+ // what happens here is that `klass` may not be available for injection for
14
+ // two reasons:
15
+ // 1 - is annotated with `@Injectable` but is not "provided" in the DI container
16
+ // 2 - it is not annotated
17
+ if (ClassNameSymbol in klass) {
18
+ throw Error(`Did you forgot to add ${klass[ClassNameSymbol]} to the list of providers`);
19
+ }
20
+ else {
21
+ throw Error(`Is ${klass.name} annotated with @Injectable()`);
22
+ }
23
+ }
24
+ }
25
+ //# sourceMappingURL=injector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injector.js","sourceRoot":"","sources":["../../../src/lib/injctable/injector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,kBAAkB,CAAC;AAE1B,MAAM,CAAC,GAAG,WAAW,CAAC,sBAAsB,CAAC,CAAC;AAE9C,MAAM,UAAU,QAAQ,CAAuB,KAAQ;IACrD,CAAC,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IACpC,gFAAgF;IAGhF,IAAI,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QAEN,2EAA2E;QAC3E,eAAe;QACf,gFAAgF;QAChF,0BAA0B;QAC1B,IAAI,eAAe,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,KAAK,CAAC,yBAAyB,KAAK,CAAC,eAAe,CAAC,2BAA2B,CAAC,CAAC;QAC1F,CAAC;aAAM,CAAC;YAEN,MAAM,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,+BAA+B,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import { Class } from 'utility-types';\nimport { getDebugger } from '@microphi/debug';\nimport { ClassNameSymbol } from './injectable.decorator';\nimport { providers } from '../container/di.decorator';\nimport 'reflect-metadata';\n\nconst d = getDebugger('microphi:di:injector');\n\nexport function injector<K extends Class<any>>(klass: K): InstanceType<K> {\n d('searching singleton for', klass);\n // here class is the @Injectable() version so we need to get original class name\n\n\n if (providers.hasInjectable(klass)) {\n return providers.getInstance(klass);\n } else {\n\n // what happens here is that `klass` may not be available for injection for\n // two reasons:\n // 1 - is annotated with `@Injectable` but is not \"provided\" in the DI container\n // 2 - it is not annotated\n if (ClassNameSymbol in klass) {\n throw Error(`Did you forgot to add ${klass[ClassNameSymbol]} to the list of providers`);\n } else {\n\n throw Error(`Is ${klass.name} annotated with @Injectable()`);\n }\n }\n}\n"]}