react-obsidian 0.0.12 → 0.0.16

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 (155) hide show
  1. package/README.md +105 -10
  2. package/babel.config.js +5 -4
  3. package/dist/src/Obsidian.d.ts +1 -0
  4. package/dist/src/Obsidian.d.ts.map +1 -1
  5. package/dist/src/Obsidian.js +4 -0
  6. package/dist/src/Obsidian.js.map +1 -1
  7. package/dist/src/decorators/Graph.d.ts +2 -3
  8. package/dist/src/decorators/Graph.d.ts.map +1 -1
  9. package/dist/src/decorators/Graph.js +2 -3
  10. package/dist/src/decorators/Graph.js.map +1 -1
  11. package/dist/src/decorators/Singleton.d.ts +4 -0
  12. package/dist/src/decorators/Singleton.d.ts.map +1 -0
  13. package/dist/src/decorators/Singleton.js +12 -0
  14. package/dist/src/decorators/Singleton.js.map +1 -0
  15. package/dist/src/decorators/inject/Inject.d.ts +2 -0
  16. package/dist/src/decorators/inject/Inject.d.ts.map +1 -0
  17. package/dist/src/decorators/inject/Inject.js +21 -0
  18. package/dist/src/decorators/inject/Inject.js.map +1 -0
  19. package/dist/src/decorators/inject/Injectable.d.ts +4 -0
  20. package/dist/src/decorators/inject/Injectable.d.ts.map +1 -0
  21. package/dist/src/decorators/inject/Injectable.js +13 -0
  22. package/dist/src/decorators/inject/Injectable.js.map +1 -0
  23. package/dist/src/decorators/inject/LazyInject.d.ts +2 -0
  24. package/dist/src/decorators/inject/LazyInject.d.ts.map +1 -0
  25. package/dist/src/decorators/inject/LazyInject.js +15 -0
  26. package/dist/src/decorators/inject/LazyInject.js.map +1 -0
  27. package/dist/src/decorators/provides/MemoizeDescriptor.d.ts.map +1 -1
  28. package/dist/src/decorators/provides/MemoizeDescriptor.js +4 -4
  29. package/dist/src/decorators/provides/MemoizeDescriptor.js.map +1 -1
  30. package/dist/src/decorators/provides/Provides.d.ts +0 -2
  31. package/dist/src/decorators/provides/Provides.d.ts.map +1 -1
  32. package/dist/src/decorators/provides/Provides.js.map +1 -1
  33. package/dist/src/graph/ObjectGraph.d.ts +2 -2
  34. package/dist/src/graph/ObjectGraph.d.ts.map +1 -1
  35. package/dist/src/graph/ObjectGraph.js +6 -1
  36. package/dist/src/graph/ObjectGraph.js.map +1 -1
  37. package/dist/src/graph/ProviderBinder.d.ts.map +1 -1
  38. package/dist/src/graph/ProviderBinder.js +2 -3
  39. package/dist/src/graph/ProviderBinder.js.map +1 -1
  40. package/dist/src/graph/registry/GraphRegistry.d.ts +11 -8
  41. package/dist/src/graph/registry/GraphRegistry.d.ts.map +1 -1
  42. package/dist/src/graph/registry/GraphRegistry.js +34 -22
  43. package/dist/src/graph/registry/GraphRegistry.js.map +1 -1
  44. package/dist/src/index.d.ts +5 -2
  45. package/dist/src/index.d.ts.map +1 -1
  46. package/dist/src/index.js +11 -5
  47. package/dist/src/index.js.map +1 -1
  48. package/dist/src/injectors/class/ClassInjector.d.ts +12 -0
  49. package/dist/src/injectors/class/ClassInjector.d.ts.map +1 -0
  50. package/dist/src/injectors/class/ClassInjector.js +60 -0
  51. package/dist/src/injectors/class/ClassInjector.js.map +1 -0
  52. package/dist/src/injectors/class/ConstructorArgs.d.ts +8 -0
  53. package/dist/src/injectors/class/ConstructorArgs.d.ts.map +1 -0
  54. package/dist/src/injectors/class/ConstructorArgs.js +25 -0
  55. package/dist/src/injectors/class/ConstructorArgs.js.map +1 -0
  56. package/dist/src/injectors/class/InjectionMetadata.d.ts +15 -0
  57. package/dist/src/injectors/class/InjectionMetadata.d.ts.map +1 -0
  58. package/dist/src/injectors/class/InjectionMetadata.js +41 -0
  59. package/dist/src/injectors/class/InjectionMetadata.js.map +1 -0
  60. package/dist/src/injectors/class/LazyInjector.d.ts +8 -0
  61. package/dist/src/injectors/class/LazyInjector.d.ts.map +1 -0
  62. package/dist/src/injectors/class/LazyInjector.js +28 -0
  63. package/dist/src/injectors/class/LazyInjector.js.map +1 -0
  64. package/dist/src/injectors/components/ComponentInjector.d.ts +0 -1
  65. package/dist/src/injectors/components/ComponentInjector.d.ts.map +1 -1
  66. package/dist/src/injectors/components/ComponentInjector.js +0 -1
  67. package/dist/src/injectors/components/ComponentInjector.js.map +1 -1
  68. package/dist/src/types/index.d.ts +0 -1
  69. package/dist/src/types/index.d.ts.map +1 -1
  70. package/dist/test/integration/fixtures/MainGraph.d.ts +1 -0
  71. package/dist/test/integration/fixtures/MainGraph.d.ts.map +1 -1
  72. package/dist/test/integration/fixtures/MainGraph.js +10 -0
  73. package/dist/test/integration/fixtures/MainGraph.js.map +1 -1
  74. package/dist/test/integration/fixtures/SingletonGraph.d.ts +6 -0
  75. package/dist/test/integration/fixtures/SingletonGraph.d.ts.map +1 -0
  76. package/dist/test/integration/fixtures/SingletonGraph.js +53 -0
  77. package/dist/test/integration/fixtures/SingletonGraph.js.map +1 -0
  78. package/dist/test/integration/fixtures/UniqueNumberGraph.d.ts +8 -0
  79. package/dist/test/integration/fixtures/UniqueNumberGraph.d.ts.map +1 -0
  80. package/dist/test/integration/fixtures/UniqueNumberGraph.js +62 -0
  81. package/dist/test/integration/fixtures/UniqueNumberGraph.js.map +1 -0
  82. package/dist/test/integration/fixtures/injectedValues.d.ts +1 -0
  83. package/dist/test/integration/fixtures/injectedValues.d.ts.map +1 -1
  84. package/dist/test/integration/fixtures/injectedValues.js +1 -0
  85. package/dist/test/integration/fixtures/injectedValues.js.map +1 -1
  86. package/dist/testkit/index.d.ts +6 -5
  87. package/dist/testkit/index.d.ts.map +1 -1
  88. package/dist/testkit/index.js +18 -11
  89. package/dist/testkit/index.js.map +1 -1
  90. package/dist/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/helpers/index.d.ts +4 -2
  91. package/dist/transformers/babel-plugin-obsidian/helpers/index.d.ts.map +1 -0
  92. package/dist/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/helpers/index.js +28 -4
  93. package/dist/transformers/babel-plugin-obsidian/helpers/index.js.map +1 -0
  94. package/dist/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/index.d.ts +0 -0
  95. package/dist/transformers/babel-plugin-obsidian/index.d.ts.map +1 -0
  96. package/dist/transformers/babel-plugin-obsidian/index.js +45 -0
  97. package/dist/transformers/babel-plugin-obsidian/index.js.map +1 -0
  98. package/dist/transformers/babel-plugin-obsidian/unmagler/index.d.ts +10 -0
  99. package/dist/transformers/babel-plugin-obsidian/unmagler/index.d.ts.map +1 -0
  100. package/dist/transformers/babel-plugin-obsidian/unmagler/index.js +14 -0
  101. package/dist/transformers/babel-plugin-obsidian/unmagler/index.js.map +1 -0
  102. package/dist/transformers/babel-plugin-obsidian/unmagler/method.d.ts +4 -0
  103. package/dist/transformers/babel-plugin-obsidian/unmagler/method.d.ts.map +1 -0
  104. package/dist/transformers/babel-plugin-obsidian/unmagler/method.js +26 -0
  105. package/dist/transformers/babel-plugin-obsidian/unmagler/method.js.map +1 -0
  106. package/dist/transformers/babel-plugin-obsidian/unmagler/property.d.ts +4 -0
  107. package/dist/transformers/babel-plugin-obsidian/unmagler/property.d.ts.map +1 -0
  108. package/dist/transformers/babel-plugin-obsidian/unmagler/property.js +14 -0
  109. package/dist/transformers/babel-plugin-obsidian/unmagler/property.js.map +1 -0
  110. package/example/babel.config.js +2 -2
  111. package/example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  112. package/jest.config.js +4 -0
  113. package/jest.setup-after-env.js +1 -0
  114. package/jest.setup.ts +1 -0
  115. package/package.json +13 -12
  116. package/src/Obsidian.ts +5 -0
  117. package/src/decorators/Graph.ts +2 -5
  118. package/src/decorators/Singleton.ts +14 -0
  119. package/src/decorators/inject/Inject.ts +17 -0
  120. package/src/decorators/inject/Injectable.ts +8 -0
  121. package/src/decorators/inject/LazyInject.ts +8 -0
  122. package/src/decorators/provides/MemoizeDescriptor.ts +3 -4
  123. package/src/decorators/provides/Provides.ts +0 -2
  124. package/src/graph/ObjectGraph.ts +7 -3
  125. package/src/graph/ProviderBinder.ts +2 -3
  126. package/src/graph/registry/GraphRegistry.ts +40 -32
  127. package/src/index.ts +6 -2
  128. package/src/injectors/class/ClassInjector.ts +49 -0
  129. package/src/injectors/class/ConstructorArgs.ts +20 -0
  130. package/src/injectors/class/InjectionMetadata.ts +57 -0
  131. package/src/injectors/class/LazyInjector.ts +22 -0
  132. package/src/injectors/components/ComponentInjector.tsx +0 -1
  133. package/src/types/index.ts +0 -2
  134. package/testkit/index.ts +13 -14
  135. package/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/helpers/index.ts +38 -2
  136. package/transformers/babel-plugin-obsidian/index.ts +46 -0
  137. package/transformers/babel-plugin-obsidian/unmagler/index.ts +9 -0
  138. package/transformers/babel-plugin-obsidian/unmagler/method.ts +31 -0
  139. package/transformers/babel-plugin-obsidian/unmagler/property.ts +21 -0
  140. package/dist/src/ScopedValuesRegistry.d.ts +0 -11
  141. package/dist/src/ScopedValuesRegistry.d.ts.map +0 -1
  142. package/dist/src/ScopedValuesRegistry.js +0 -25
  143. package/dist/src/ScopedValuesRegistry.js.map +0 -1
  144. package/dist/src/decorators/injectClass.d.ts +0 -7
  145. package/dist/src/decorators/injectClass.d.ts.map +0 -1
  146. package/dist/src/decorators/injectClass.js +0 -34
  147. package/dist/src/decorators/injectClass.js.map +0 -1
  148. package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.d.ts.map +0 -1
  149. package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.js.map +0 -1
  150. package/dist/transformers/babel-plugin-obsidian-provide/index.d.ts.map +0 -1
  151. package/dist/transformers/babel-plugin-obsidian-provide/index.js +0 -39
  152. package/dist/transformers/babel-plugin-obsidian-provide/index.js.map +0 -1
  153. package/src/ScopedValuesRegistry.ts +0 -26
  154. package/src/decorators/injectClass.ts +0 -28
  155. package/transformers/babel-plugin-obsidian-provide/index.ts +0 -47
@@ -2,12 +2,11 @@
2
2
  export function memoizeDescriptor(propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
3
3
  const originalValue = descriptor.value;
4
4
  descriptor.value = function value(...args: any[]) {
5
+ const memoizationTarget = Reflect.getMetadata('isSingleton', descriptor) ? descriptor : this;
5
6
  const key = `memoized${propertyKey}`;
6
- if (Reflect.hasMetadata(key, this)) {
7
- return Reflect.getMetadata(key, this);
8
- }
7
+ if (Reflect.hasMetadata(key, memoizationTarget)) return Reflect.getMetadata(key, memoizationTarget);
9
8
  const result = originalValue.apply(this, args);
10
- Reflect.defineMetadata(key, result, this);
9
+ Reflect.defineMetadata(key, result, memoizationTarget);
11
10
  return result;
12
11
  };
13
12
  return descriptor;
@@ -1,10 +1,8 @@
1
- import { Scope } from '../../types';
2
1
  import { Graph } from '../../graph/Graph';
3
2
  import providedPropertiesStore from '../../ProvidedPropertiesStore';
4
3
  import { memoizeDescriptor } from './MemoizeDescriptor';
5
4
 
6
5
  interface ProvidesParams {
7
- scope?: Scope;
8
6
  name: string;
9
7
  }
10
8
 
@@ -1,13 +1,11 @@
1
1
  import { uniqueId } from 'lodash';
2
2
  import Memoize from '../decorators/Memoize';
3
- import { Scope } from '../types';
4
3
  import { bindProviders } from './ProviderBinder';
5
4
  import { Graph } from './Graph';
6
5
  import PropertyRetriever from './PropertyRetriever';
6
+ import { Constructable } from '../types';
7
7
 
8
8
  export abstract class ObjectGraph<T = unknown> implements Graph {
9
- // TODO? rename scope to singleInstance
10
- public scope!: Scope;
11
9
  private propertyRetriever = new PropertyRetriever(this);
12
10
 
13
11
  @Memoize()
@@ -23,3 +21,9 @@ export abstract class ObjectGraph<T = unknown> implements Graph {
23
21
  return this.propertyRetriever.retrieve(property, receiver) as Dependency | undefined;
24
22
  }
25
23
  }
24
+
25
+ Reflect.set(ObjectGraph, 'typeDiscriminator', 'ObjectGraph');
26
+
27
+ export function isGraph(object: Constructable<ObjectGraph> | any): object is Constructable<ObjectGraph> {
28
+ return Reflect.get(object, 'typeDiscriminator') === 'ObjectGraph';
29
+ }
@@ -4,9 +4,8 @@ import { Graph } from './Graph';
4
4
 
5
5
  export function bindProviders(graph: Graph & Record<string, any>) {
6
6
  providedPropertiesStore.getMangledProperties(graph)
7
+ .filter((method) => graph[method])
7
8
  .forEach((method) => {
8
- if (graph[method] !== undefined) {
9
- graph[method] = graph[method].bind(graph);
10
- }
9
+ graph[method] = graph[method].bind(graph);
11
10
  });
12
11
  }
@@ -1,61 +1,63 @@
1
- import { Constructable, Scope } from '../../types';
1
+ import { Constructable } from '../../types';
2
2
  import { Graph } from '../Graph';
3
3
  import { Middleware } from './Middleware';
4
4
  import GraphMiddlewareChain from './GraphMiddlewareChain';
5
5
 
6
- class GraphRegistry {
7
- private readonly scopedGraphs: Record<Scope, Constructable<Graph>> = {};
8
- private readonly constructorToInstance = new Map<Constructable<Graph>, Graph>();
6
+ export class GraphRegistry {
7
+ private readonly constructorToInstance = new Map<Constructable<Graph>, Set<Graph>>();
9
8
  private readonly instanceToConstructor = new Map<Graph, Constructable<Graph>>();
9
+ private readonly nameToInstance = new Map<string, Graph>();
10
10
  private readonly graphToSubgraphs = new Map<Constructable<Graph>, Set<Constructable<Graph>>>();
11
- private graphMiddlewares = new GraphMiddlewareChain();
11
+ private readonly graphMiddlewares = new GraphMiddlewareChain();
12
12
 
13
- register(
14
- constructor: Constructable<Graph>,
15
- scope: Scope | undefined = undefined,
16
- subgraphs: Constructable<Graph>[] = [],
17
- ) {
18
- if (scope) this.scopedGraphs[scope] = constructor;
13
+ register(constructor: Constructable<Graph>, subgraphs: Constructable<Graph>[] = []) {
19
14
  this.graphToSubgraphs.set(constructor, new Set(subgraphs));
20
15
  }
21
16
 
22
- has(Graph: Constructable<Graph>) {
23
- return this.constructorToInstance.has(Graph);
24
- }
25
-
26
- get<T extends Graph>(Graph: Constructable<T>): T {
27
- return this.constructorToInstance.get(Graph)! as unknown as T;
28
- }
29
-
30
- set(Graph: Constructable<Graph>, graph: Graph) {
31
- this.constructorToInstance.set(Graph, graph);
32
- this.instanceToConstructor.set(graph, Graph);
33
- }
34
-
35
17
  getSubgraphs(graph: Graph): Graph[] {
36
18
  const Graph = this.instanceToConstructor.get(graph)!;
37
19
  const subgraphs = this.graphToSubgraphs.get(Graph) ?? new Set();
38
20
  return Array.from(subgraphs).map((G) => this.resolve(G));
39
21
  }
40
22
 
41
- resolve<T extends Graph>(Graph: Constructable<T>, props?: any): T {
42
- if (this.has(Graph)) {
43
- return this.get(Graph);
44
- // const graph: T = this.get(Graph);
45
- // const scope = Reflect.getMetadata('scope', Graph);
46
- // if (scope) return graph;
23
+ getGraphInstance(name: string): Graph {
24
+ return this.nameToInstance.get(name)!;
25
+ }
47
26
 
48
- // this.set(Graph, new Graph(props));
27
+ resolve<T extends Graph>(Graph: Constructable<T>, props?: any): T {
28
+ if (this.isSingleton(Graph) && this.has(Graph)) {
29
+ return this.getFirst(Graph);
49
30
  }
50
31
  const graph = this.graphMiddlewares.resolve(Graph, props);
51
32
  this.set(Graph, graph);
52
33
  return graph as T;
53
34
  }
54
35
 
36
+ private has(Graph: Constructable<Graph>) {
37
+ return this.constructorToInstance.has(Graph);
38
+ }
39
+
40
+ private getFirst<T extends Graph>(Graph: Constructable<T>): T {
41
+ return this.constructorToInstance.get(Graph)!.values().next().value;
42
+ }
43
+
44
+ private set(Graph: Constructable<Graph>, graph: Graph) {
45
+ const graphs = this.constructorToInstance.get(Graph) ?? new Set();
46
+ graphs.add(graph);
47
+ this.constructorToInstance.set(Graph, graphs);
48
+ this.instanceToConstructor.set(graph, Graph);
49
+ this.nameToInstance.set(graph.name, graph);
50
+ }
51
+
52
+ private isSingleton(Graph: Constructable<Graph>): boolean {
53
+ return Reflect.getMetadata('isSingleton', Graph) ?? false;
54
+ }
55
+
55
56
  clear(graph: Graph) {
56
57
  const Graph = this.instanceToConstructor.get(graph)!;
57
58
  this.instanceToConstructor.delete(graph);
58
- this.constructorToInstance.delete(Graph);
59
+ this.constructorToInstance.get(Graph)!.delete(graph);
60
+ this.nameToInstance.delete(graph.name);
59
61
  }
60
62
 
61
63
  addGraphMiddleware(middleware: Middleware<Graph>) {
@@ -65,6 +67,12 @@ class GraphRegistry {
65
67
  clearGraphMiddlewares() {
66
68
  this.graphMiddlewares.clear();
67
69
  }
70
+
71
+ reset() {
72
+ this.instanceToConstructor.clear();
73
+ this.constructorToInstance.clear();
74
+ this.nameToInstance.clear();
75
+ }
68
76
  }
69
77
 
70
78
  export default new GraphRegistry();
package/src/index.ts CHANGED
@@ -8,11 +8,13 @@ import { Constructable } from './types';
8
8
  export * from './types';
9
9
 
10
10
  export { Graph } from './decorators/Graph';
11
+ export { Singleton } from './decorators/Singleton';
11
12
  export { ObjectGraph } from './graph/ObjectGraph';
12
13
  export { Graph as IGraph } from './graph/Graph';
13
14
  export { Provides } from './decorators/provides/Provides';
14
- export { Injectable } from './decorators/injectClass';
15
- export { Inject } from './decorators/injectClass';
15
+ export { Injectable } from './decorators/inject/Injectable';
16
+ export { Inject } from './decorators/inject/Inject';
17
+ export { LazyInject } from './decorators/inject/LazyInject';
16
18
  export { GraphMiddleware } from './graph/registry/GraphMiddleware';
17
19
  export { GraphResolveChain as ResolveChain } from './graph/registry/GraphResolveChain';
18
20
  export const Obsidian = new _Obsidian();
@@ -28,3 +30,5 @@ export const injectHook = <Args, Result> (
28
30
  hook: (args: Args) => Result,
29
31
  Graph: Constructable<_ObjectGraph>,
30
32
  ) => hookInjector.inject(hook, Graph);
33
+
34
+ export { testKit } from '../testkit';
@@ -0,0 +1,49 @@
1
+ import { Constructable } from '../../types';
2
+ import { GraphRegistry } from '../../graph/registry/GraphRegistry';
3
+ import { Graph } from '../../graph/Graph';
4
+ import InjectionMetadata from './InjectionMetadata';
5
+ import { GRAPH_INSTANCE_NAME_KEY } from './LazyInjector';
6
+
7
+ export default class ClassInjector {
8
+ constructor(
9
+ private graphRegistry: GraphRegistry,
10
+ private injectionMetadata: InjectionMetadata = new InjectionMetadata(),
11
+ ) {}
12
+
13
+ inject(Graph: Constructable<Graph>) {
14
+ return (Target: Constructable<any>) => {
15
+ return new Proxy(Target, this.createProxyHandler(Graph, this.graphRegistry, this.injectionMetadata));
16
+ };
17
+ }
18
+
19
+ private createProxyHandler(
20
+ Graph: Constructable<Graph>,
21
+ graphRegistry: GraphRegistry,
22
+ injectionMetadata: InjectionMetadata,
23
+ ): ProxyHandler<any> {
24
+ return new class Handler implements ProxyHandler<any> {
25
+ construct(target: any, args: any[], newTarget: Function): any {
26
+ const graph = graphRegistry.resolve(Graph);
27
+ Reflect.defineMetadata(GRAPH_INSTANCE_NAME_KEY, graph.name, target);
28
+ const argsToInject = this.injectConstructorArgs(args, graph, target);
29
+ const createdObject = Reflect.construct(target, argsToInject, newTarget);
30
+ this.injectProperties(target, createdObject, graph);
31
+ return createdObject;
32
+ }
33
+
34
+ private injectConstructorArgs(args: any[], graph: Graph, target: any): any[] {
35
+ const argsToInject = injectionMetadata.getConstructorArgsToInject(target);
36
+ if (!argsToInject.hasArgs()) return args;
37
+ return [...args, ...new Array(Math.abs(args.length - argsToInject.size()))].map((value, idx): any => {
38
+ return value ?? graph.retrieve(argsToInject.getProperty(idx));
39
+ });
40
+ }
41
+
42
+ private injectProperties(target: any, createdObject: any, graph: Graph) {
43
+ injectionMetadata.getPropertiesToInject(target).forEach((key) => {
44
+ Reflect.set(createdObject, key, graph.retrieve(key));
45
+ });
46
+ }
47
+ }();
48
+ }
49
+ }
@@ -0,0 +1,20 @@
1
+ export class ConstructorArgs {
2
+ private readonly args = new Array<[string, number]>();
3
+
4
+ hasArgs(): boolean {
5
+ return this.args.length > 0;
6
+ }
7
+
8
+ size(): number {
9
+ return this.args.length;
10
+ }
11
+
12
+ add(paramName: string, index: number) {
13
+ this.args.push([paramName, index]);
14
+ }
15
+
16
+ getProperty(index: number): any {
17
+ if (this.args.length <= index) throw new Error('IOOB while trying to get constructor args to inject');
18
+ return this.args[index][0];
19
+ }
20
+ }
@@ -0,0 +1,57 @@
1
+ import { ConstructorArgs } from './ConstructorArgs';
2
+
3
+ export default class InjectionMetadata {
4
+ private readonly injectionMetadataKey = 'injectionMetadata';
5
+ private readonly injectedConstructorArgsKey = 'injectedConstructorArgsKey';
6
+ private readonly lazyInjectionMetadataKey = 'lazyInjectionMetadataKey';
7
+
8
+ getConstructorArgsToInject(target: any): ConstructorArgs {
9
+ return Reflect.getMetadata(this.injectedConstructorArgsKey, target) ?? new ConstructorArgs();
10
+ }
11
+
12
+ getPropertiesToInject(target: any): Set<string> {
13
+ return this.getProperties(this.injectionMetadataKey, target);
14
+ }
15
+
16
+ getLazyPropertiesToInject(target: any): Set<string> {
17
+ return this.getProperties(this.lazyInjectionMetadataKey, target);
18
+ }
19
+
20
+ saveConstructorParamMetadata(target: any, paramName: string, index: number) {
21
+ const argsToInject = this.getConstructorArgsToInject(target);
22
+ argsToInject.add(paramName, index);
23
+ Reflect.defineMetadata(
24
+ this.injectedConstructorArgsKey,
25
+ argsToInject,
26
+ target,
27
+ );
28
+ }
29
+
30
+ savePropertyMetadata(target: any, property: string) {
31
+ this.saveProperties(
32
+ this.injectionMetadataKey,
33
+ this.getPropertiesToInject(target).add(property),
34
+ target,
35
+ );
36
+ }
37
+
38
+ saveLazyPropertyMetadata(target: any, property: string) {
39
+ this.saveProperties(
40
+ this.lazyInjectionMetadataKey,
41
+ this.getLazyPropertiesToInject(target).add(property),
42
+ target,
43
+ );
44
+ }
45
+
46
+ private saveProperties(key: string, properties: Set<string>, target: any) {
47
+ Reflect.defineMetadata(
48
+ key,
49
+ properties,
50
+ target,
51
+ );
52
+ }
53
+
54
+ private getProperties(key: string, target: any): Set<string> {
55
+ return Reflect.getMetadata(key, target) ?? new Set();
56
+ }
57
+ }
@@ -0,0 +1,22 @@
1
+ import graphRegistry from '../../graph/registry/GraphRegistry';
2
+ import InjectionMetadata from './InjectionMetadata';
3
+
4
+ export const GRAPH_INSTANCE_NAME_KEY = 'GRAPH_INSTANCE_NAME';
5
+
6
+ class LazyInjector<T extends object> {
7
+ inject(target: T): T {
8
+ const injectionMetadata = new InjectionMetadata();
9
+ const graph = this.getGraphInstance(target);
10
+ injectionMetadata.getLazyPropertiesToInject(target.constructor).forEach((key) => {
11
+ Reflect.set(target, key, graph.retrieve(key));
12
+ });
13
+ return target;
14
+ }
15
+
16
+ private getGraphInstance(target: T) {
17
+ const graphInstanceName = Reflect.getMetadata(GRAPH_INSTANCE_NAME_KEY, target.constructor);
18
+ return graphRegistry.getGraphInstance(graphInstanceName);
19
+ }
20
+ }
21
+
22
+ export default new LazyInjector();
@@ -1,6 +1,5 @@
1
1
  import React, { useState } from 'react';
2
2
  import hoistNonReactStatics from 'hoist-non-react-statics';
3
- import 'reflect-metadata';
4
3
  import { ObjectGraph } from '../../graph/ObjectGraph';
5
4
  import PropsInjector from './PropsInjector';
6
5
  import useGraph from './useGraph';
@@ -2,8 +2,6 @@ export type Constructable<T> = {
2
2
  new(...args: any): T;
3
3
  };
4
4
 
5
- export type Scope = string | number | symbol;
6
-
7
5
  export type Constructor = { new(...args: any[]): any };
8
6
 
9
7
  export type ServiceLocator<Clazz> = {
package/testkit/index.ts CHANGED
@@ -1,28 +1,27 @@
1
- import { GraphResolveChain } from 'src/graph/registry/GraphResolveChain';
2
- import {
3
- ObjectGraph,
4
- Constructable,
5
- GraphMiddleware,
6
- Obsidian,
7
- } from '../src';
1
+ import { GraphResolveChain } from '../src/graph/registry/GraphResolveChain';
2
+ import { isGraph, ObjectGraph } from '../src/graph/ObjectGraph';
3
+ import { GraphMiddleware } from '../src/graph/registry/GraphMiddleware';
4
+ import { Constructable } from '../src/types';
5
+ import graphRegistry from '../src/graph/registry/GraphRegistry';
8
6
 
9
7
  beforeEach(() => {
10
- Obsidian.clearGraphMiddlewares();
8
+ graphRegistry.clearGraphMiddlewares();
9
+ graphRegistry.reset();
11
10
  });
12
11
 
13
- class Index {
14
- mockGraphs(graphNameToGraph: Record<string, Constructable<ObjectGraph>>) {
12
+ class TestKit {
13
+ public mockGraphs(graphNameToGraph: Record<string, Constructable<ObjectGraph> | ((props: any) => ObjectGraph)>) {
15
14
  const graphMiddleware = new class extends GraphMiddleware {
16
15
  resolve<Props>(resolveChain: GraphResolveChain, Graph: Constructable<ObjectGraph>, props?: Props) {
17
16
  if (graphNameToGraph[Graph.name]) {
18
- const TheGraph = graphNameToGraph[Graph.name];
19
- return new TheGraph(props);
17
+ const GraphOrGenerator = graphNameToGraph[Graph.name];
18
+ return isGraph(GraphOrGenerator) ? new GraphOrGenerator(props) : GraphOrGenerator(props);
20
19
  }
21
20
  return resolveChain.proceed(Graph, props);
22
21
  }
23
22
  }();
24
- Obsidian.addGraphMiddleware(graphMiddleware);
23
+ graphRegistry.addGraphMiddleware(graphMiddleware);
25
24
  }
26
25
  }
27
26
 
28
- export default new Index();
27
+ export const testKit = new TestKit();
@@ -3,13 +3,19 @@ import { types as t } from '@babel/core';
3
3
  import {
4
4
  CallExpression,
5
5
  ClassMethod,
6
+ ClassProperty,
6
7
  Decorator,
7
8
  Identifier,
8
9
  ObjectExpression,
9
10
  ObjectPattern,
11
+ TSParameterProperty,
10
12
  } from '@babel/types';
11
13
  import { get } from 'lodash';
12
14
 
15
+ const never = '';
16
+
17
+ export type AcceptedNodeType = Identifier | TSParameterProperty | ClassProperty;
18
+
13
19
  export function providerIsNotNamed(decorator: Decorator): boolean {
14
20
  const argument = getDecoratorArgument(decorator);
15
21
  if (t.isObjectExpression(argument)) {
@@ -44,8 +50,11 @@ export function getMethodName(node: ClassMethod): string {
44
50
  throw new Error(`Tried to get class name but encountered unexpected key of type: ${node.key.type}`);
45
51
  }
46
52
 
47
- export function getProviderDecorator(decorators: Array<Decorator> | undefined | null): Decorator | undefined {
48
- return decorators?.find((decorator) => get(decorator, 'expression.callee.name') === 'Provides');
53
+ export function getDecoratorByName(
54
+ decorators: Array<Decorator> | undefined | null,
55
+ decoratorName: string,
56
+ ): Decorator | undefined {
57
+ return decorators?.find((decorator) => get(decorator, 'expression.callee.name') === decoratorName);
49
58
  }
50
59
 
51
60
  export function getDecoratorName(decorator?: Decorator): string | undefined {
@@ -57,3 +66,30 @@ export function paramsToDestructuringAssignment(params: (Identifier | any)[]): O
57
66
  .filter((p) => t.isIdentifier(p))
58
67
  .map((p) => t.objectProperty(t.identifier(p.name), t.identifier(p.name))));
59
68
  }
69
+
70
+ export function passParamNameAsInjectArgument(
71
+ node: AcceptedNodeType,
72
+ decorator: Decorator,
73
+ ) {
74
+ if (t.isCallExpression(decorator.expression)) {
75
+ decorator.expression.arguments = [
76
+ t.stringLiteral(getNodeName(node)),
77
+ ];
78
+ }
79
+ }
80
+
81
+ function getNodeName(node: AcceptedNodeType): string {
82
+ if (t.isTSParameterProperty(node)) {
83
+ if (t.isIdentifier(node.parameter)) {
84
+ return node.parameter.name;
85
+ }
86
+ return never;
87
+ }
88
+ if (t.isClassProperty(node)) {
89
+ if (t.isIdentifier(node.key)) {
90
+ return node.key.name;
91
+ }
92
+ return never;
93
+ }
94
+ return node.name;
95
+ }
@@ -0,0 +1,46 @@
1
+ /* eslint-disable no-param-reassign */
2
+ import {
3
+ ClassMethod,
4
+ ClassProperty,
5
+ Identifier,
6
+ Program,
7
+ TSParameterProperty,
8
+ } from '@babel/types';
9
+ import { NodePath, PluginObj } from '@babel/core';
10
+ import unmagler from './unmagler';
11
+
12
+ const providerArgumentsTransformer: PluginObj = {
13
+ visitor: {
14
+ Program(path: NodePath<Program>) {
15
+ path.traverse(internalVisitor);
16
+ },
17
+ },
18
+ };
19
+
20
+ const internalVisitor = {
21
+ ClassMethod: {
22
+ enter({ node }: NodePath<ClassMethod>) {
23
+ unmagler.saveClassMethod('Provides', node);
24
+ },
25
+ },
26
+ ClassProperty: {
27
+ enter({ node }: NodePath<ClassProperty>) {
28
+ unmagler.saveClassProperty('Inject', node);
29
+ unmagler.saveClassProperty('LazyInject', node);
30
+ },
31
+ },
32
+ Identifier: {
33
+ enter({ node }: NodePath<Identifier>) {
34
+ unmagler.saveIdentifier('Inject', node);
35
+ },
36
+ },
37
+ TSParameterProperty: {
38
+ enter({ node }: NodePath<TSParameterProperty>) {
39
+ unmagler.saveTSParameterProperty('Inject', node);
40
+ },
41
+ },
42
+ };
43
+
44
+ export default function plugin() {
45
+ return providerArgumentsTransformer;
46
+ }
@@ -0,0 +1,9 @@
1
+ import saveMethod from './method';
2
+ import saveProperty from './property';
3
+
4
+ export default {
5
+ saveClassMethod: saveMethod,
6
+ saveClassProperty: saveProperty,
7
+ saveIdentifier: saveProperty,
8
+ saveTSParameterProperty: saveProperty,
9
+ };
@@ -0,0 +1,31 @@
1
+ import { ClassMethod, Decorator } from '@babel/types';
2
+ import {
3
+ addNameToProviderArguments,
4
+ getDecoratorName,
5
+ getDecoratorByName,
6
+ paramsToDestructuringAssignment,
7
+ providerIsNotNamed,
8
+ } from '../helpers';
9
+
10
+ function saveMethod(name: string, node: ClassMethod) {
11
+ const decorator = getDecoratorByName(node.decorators, name);
12
+ if (getDecoratorName(decorator) === name) {
13
+ convertProviderParamsToDestructuringAssignment(node);
14
+ saveUnmangledMethodNameInProviderArguments(node, decorator!);
15
+ }
16
+ }
17
+
18
+ function convertProviderParamsToDestructuringAssignment(node: ClassMethod) {
19
+ if (node.params.length === 0) { return; }
20
+ const destructuredParams = paramsToDestructuringAssignment(node.params);
21
+ // eslint-disable-next-line no-param-reassign
22
+ node.params.length = 0;
23
+ node.params.push(destructuredParams);
24
+ }
25
+
26
+ function saveUnmangledMethodNameInProviderArguments(node: ClassMethod, decorator: Decorator) {
27
+ if (providerIsNotNamed(decorator)) {
28
+ addNameToProviderArguments(node, decorator);
29
+ }
30
+ }
31
+ export default saveMethod;
@@ -0,0 +1,21 @@
1
+ import { Decorator } from '@babel/types';
2
+ import {
3
+ getDecoratorName,
4
+ getDecoratorByName,
5
+ passParamNameAsInjectArgument,
6
+ getDecoratorArgument,
7
+ AcceptedNodeType,
8
+ } from '../helpers';
9
+
10
+ function savePropertyName(name: string, node: AcceptedNodeType) {
11
+ const decorator = getDecoratorByName(node.decorators, name);
12
+ if (getDecoratorName(decorator) === name && injectIsNotNamed(decorator!)) {
13
+ passParamNameAsInjectArgument(node, decorator!);
14
+ }
15
+ }
16
+
17
+ function injectIsNotNamed(decorator: Decorator): boolean {
18
+ return getDecoratorArgument(decorator) === undefined;
19
+ }
20
+
21
+ export default savePropertyName;
@@ -1,11 +0,0 @@
1
- import { Scope } from './types';
2
- declare class ScopedValuesRegistry {
3
- private readonly values;
4
- has(scope: Scope, property: string): boolean;
5
- get(scope: Scope, property: string): any;
6
- set(scope: Scope, property: string, value: any): void;
7
- clear(scope: Scope, property: string): void;
8
- }
9
- declare const _default: ScopedValuesRegistry;
10
- export default _default;
11
- //# sourceMappingURL=ScopedValuesRegistry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ScopedValuesRegistry.d.ts","sourceRoot":"","sources":["../../src/ScopedValuesRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,cAAM,oBAAoB;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IAEtD,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI5C,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG;IAOxC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG;IAI9C,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM;CAGrC;;AAED,wBAA0C"}
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- var ScopedValuesRegistry = /** @class */ (function () {
4
- function ScopedValuesRegistry() {
5
- this.values = new Map();
6
- }
7
- ScopedValuesRegistry.prototype.has = function (scope, property) {
8
- return this.values.has(scope.toString() + property);
9
- };
10
- ScopedValuesRegistry.prototype.get = function (scope, property) {
11
- if (this.values.has(scope.toString() + property)) {
12
- return this.values.get(scope.toString() + property);
13
- }
14
- throw new Error("Property ".concat(property, " does not exist"));
15
- };
16
- ScopedValuesRegistry.prototype.set = function (scope, property, value) {
17
- this.values.set(scope.toString() + property, value);
18
- };
19
- ScopedValuesRegistry.prototype.clear = function (scope, property) {
20
- this.values.delete(scope.toString() + property);
21
- };
22
- return ScopedValuesRegistry;
23
- }());
24
- exports.default = new ScopedValuesRegistry();
25
- //# sourceMappingURL=ScopedValuesRegistry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ScopedValuesRegistry.js","sourceRoot":"","sources":["../../src/ScopedValuesRegistry.ts"],"names":[],"mappings":";;AAEA;IAAA;QACmB,WAAM,GAAqB,IAAI,GAAG,EAAE,CAAC;IAoBxD,CAAC;IAlBC,kCAAG,GAAH,UAAI,KAAY,EAAE,QAAgB;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,kCAAG,GAAH,UAAI,KAAY,EAAE,QAAgB;QAChC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,EAAE;YAChD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,CAAC;SACrD;QACD,MAAM,IAAI,KAAK,CAAC,mBAAY,QAAQ,oBAAiB,CAAC,CAAC;IACzD,CAAC;IAED,kCAAG,GAAH,UAAI,KAAY,EAAE,QAAgB,EAAE,KAAU;QAC5C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,oCAAK,GAAL,UAAM,KAAY,EAAE,QAAgB;QAClC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,CAAC;IAClD,CAAC;IACH,2BAAC;AAAD,CAAC,AArBD,IAqBC;AAED,kBAAe,IAAI,oBAAoB,EAAE,CAAC"}
@@ -1,7 +0,0 @@
1
- import { Constructable } from '../types';
2
- import { ObjectGraph } from '../graph/ObjectGraph';
3
- export declare function Injectable<T extends {
4
- new (...args: any[]): any;
5
- }>(Graph: Constructable<ObjectGraph>): any;
6
- export declare function Inject(target: Object, propertyKey: string): void;
7
- //# sourceMappingURL=injectClass.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"injectClass.d.ts","sourceRoot":"","sources":["../../../src/decorators/injectClass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAInD,wBAAgB,UAAU,CAAC,CAAC,SAAS;IAAE,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAAA;CAAE,EAAE,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,GAAG,CAgBzG;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAGzD"}