react-obsidian 0.0.13 → 0.0.17

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 (124) hide show
  1. package/README.md +72 -9
  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/Singleton.d.ts +1 -1
  8. package/dist/src/decorators/Singleton.d.ts.map +1 -1
  9. package/dist/src/decorators/inject/Inject.d.ts +2 -0
  10. package/dist/src/decorators/inject/Inject.d.ts.map +1 -0
  11. package/dist/src/decorators/inject/Inject.js +21 -0
  12. package/dist/src/decorators/inject/Inject.js.map +1 -0
  13. package/dist/src/decorators/inject/Injectable.d.ts +4 -0
  14. package/dist/src/decorators/inject/Injectable.d.ts.map +1 -0
  15. package/dist/src/decorators/inject/Injectable.js +13 -0
  16. package/dist/src/decorators/inject/Injectable.js.map +1 -0
  17. package/dist/src/decorators/inject/LazyInject.d.ts +2 -0
  18. package/dist/src/decorators/inject/LazyInject.d.ts.map +1 -0
  19. package/dist/src/decorators/inject/LazyInject.js +15 -0
  20. package/dist/src/decorators/inject/LazyInject.js.map +1 -0
  21. package/dist/src/graph/ObjectGraph.d.ts +2 -0
  22. package/dist/src/graph/ObjectGraph.d.ts.map +1 -1
  23. package/dist/src/graph/ObjectGraph.js +6 -1
  24. package/dist/src/graph/ObjectGraph.js.map +1 -1
  25. package/dist/src/graph/ProviderBinder.d.ts.map +1 -1
  26. package/dist/src/graph/ProviderBinder.js +2 -3
  27. package/dist/src/graph/ProviderBinder.js.map +1 -1
  28. package/dist/src/graph/registry/GraphRegistry.d.ts +3 -0
  29. package/dist/src/graph/registry/GraphRegistry.d.ts.map +1 -1
  30. package/dist/src/graph/registry/GraphRegistry.js +11 -0
  31. package/dist/src/graph/registry/GraphRegistry.js.map +1 -1
  32. package/dist/src/index.d.ts +4 -2
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/index.js +9 -5
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/injectors/class/ClassInjector.d.ts +12 -0
  37. package/dist/src/injectors/class/ClassInjector.d.ts.map +1 -0
  38. package/dist/src/injectors/class/ClassInjector.js +60 -0
  39. package/dist/src/injectors/class/ClassInjector.js.map +1 -0
  40. package/dist/src/injectors/class/ConstructorArgs.d.ts +8 -0
  41. package/dist/src/injectors/class/ConstructorArgs.d.ts.map +1 -0
  42. package/dist/src/injectors/class/ConstructorArgs.js +25 -0
  43. package/dist/src/injectors/class/ConstructorArgs.js.map +1 -0
  44. package/dist/src/injectors/class/InjectionMetadata.d.ts +15 -0
  45. package/dist/src/injectors/class/InjectionMetadata.d.ts.map +1 -0
  46. package/dist/src/injectors/class/InjectionMetadata.js +41 -0
  47. package/dist/src/injectors/class/InjectionMetadata.js.map +1 -0
  48. package/dist/src/injectors/class/LazyInjector.d.ts +8 -0
  49. package/dist/src/injectors/class/LazyInjector.d.ts.map +1 -0
  50. package/dist/src/injectors/class/LazyInjector.js +28 -0
  51. package/dist/src/injectors/class/LazyInjector.js.map +1 -0
  52. package/dist/src/injectors/components/ComponentInjector.d.ts +0 -1
  53. package/dist/src/injectors/components/ComponentInjector.d.ts.map +1 -1
  54. package/dist/src/injectors/components/ComponentInjector.js +0 -1
  55. package/dist/src/injectors/components/ComponentInjector.js.map +1 -1
  56. package/dist/test/integration/fixtures/MainGraph.d.ts +1 -0
  57. package/dist/test/integration/fixtures/MainGraph.d.ts.map +1 -1
  58. package/dist/test/integration/fixtures/MainGraph.js +10 -0
  59. package/dist/test/integration/fixtures/MainGraph.js.map +1 -1
  60. package/dist/test/integration/fixtures/injectedValues.d.ts +1 -0
  61. package/dist/test/integration/fixtures/injectedValues.d.ts.map +1 -1
  62. package/dist/test/integration/fixtures/injectedValues.js +1 -0
  63. package/dist/test/integration/fixtures/injectedValues.js.map +1 -1
  64. package/dist/testkit/index.d.ts +6 -5
  65. package/dist/testkit/index.d.ts.map +1 -1
  66. package/dist/testkit/index.js +18 -11
  67. package/dist/testkit/index.js.map +1 -1
  68. package/dist/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/helpers/index.d.ts +4 -2
  69. package/dist/transformers/babel-plugin-obsidian/helpers/index.d.ts.map +1 -0
  70. package/dist/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/helpers/index.js +28 -4
  71. package/dist/transformers/babel-plugin-obsidian/helpers/index.js.map +1 -0
  72. package/dist/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/index.d.ts +0 -0
  73. package/dist/transformers/babel-plugin-obsidian/index.d.ts.map +1 -0
  74. package/dist/transformers/babel-plugin-obsidian/index.js +45 -0
  75. package/dist/transformers/babel-plugin-obsidian/index.js.map +1 -0
  76. package/dist/transformers/babel-plugin-obsidian/unmagler/index.d.ts +10 -0
  77. package/dist/transformers/babel-plugin-obsidian/unmagler/index.d.ts.map +1 -0
  78. package/dist/transformers/babel-plugin-obsidian/unmagler/index.js +14 -0
  79. package/dist/transformers/babel-plugin-obsidian/unmagler/index.js.map +1 -0
  80. package/dist/transformers/babel-plugin-obsidian/unmagler/method.d.ts +4 -0
  81. package/dist/transformers/babel-plugin-obsidian/unmagler/method.d.ts.map +1 -0
  82. package/dist/transformers/babel-plugin-obsidian/unmagler/method.js +26 -0
  83. package/dist/transformers/babel-plugin-obsidian/unmagler/method.js.map +1 -0
  84. package/dist/transformers/babel-plugin-obsidian/unmagler/property.d.ts +4 -0
  85. package/dist/transformers/babel-plugin-obsidian/unmagler/property.d.ts.map +1 -0
  86. package/dist/transformers/babel-plugin-obsidian/unmagler/property.js +14 -0
  87. package/dist/transformers/babel-plugin-obsidian/unmagler/property.js.map +1 -0
  88. package/example/babel.config.js +2 -2
  89. package/example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  90. package/jest.config.js +4 -0
  91. package/jest.setup-after-env.js +1 -0
  92. package/jest.setup.ts +1 -0
  93. package/package.json +14 -12
  94. package/src/Obsidian.ts +5 -0
  95. package/src/decorators/Singleton.ts +1 -1
  96. package/src/decorators/inject/Inject.ts +17 -0
  97. package/src/decorators/inject/Injectable.ts +8 -0
  98. package/src/decorators/inject/LazyInject.ts +8 -0
  99. package/src/graph/ObjectGraph.ts +7 -0
  100. package/src/graph/ProviderBinder.ts +2 -3
  101. package/src/graph/registry/GraphRegistry.ts +13 -0
  102. package/src/index.ts +5 -2
  103. package/src/injectors/class/ClassInjector.ts +49 -0
  104. package/src/injectors/class/ConstructorArgs.ts +20 -0
  105. package/src/injectors/class/InjectionMetadata.ts +57 -0
  106. package/src/injectors/class/LazyInjector.ts +22 -0
  107. package/src/injectors/components/ComponentInjector.tsx +0 -1
  108. package/testkit/index.ts +13 -14
  109. package/transformers/{babel-plugin-obsidian-provide → babel-plugin-obsidian}/helpers/index.ts +38 -2
  110. package/transformers/babel-plugin-obsidian/index.ts +46 -0
  111. package/transformers/babel-plugin-obsidian/unmagler/index.ts +9 -0
  112. package/transformers/babel-plugin-obsidian/unmagler/method.ts +31 -0
  113. package/transformers/babel-plugin-obsidian/unmagler/property.ts +21 -0
  114. package/dist/src/decorators/injectClass.d.ts +0 -7
  115. package/dist/src/decorators/injectClass.d.ts.map +0 -1
  116. package/dist/src/decorators/injectClass.js +0 -34
  117. package/dist/src/decorators/injectClass.js.map +0 -1
  118. package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.d.ts.map +0 -1
  119. package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.js.map +0 -1
  120. package/dist/transformers/babel-plugin-obsidian-provide/index.d.ts.map +0 -1
  121. package/dist/transformers/babel-plugin-obsidian-provide/index.js +0 -39
  122. package/dist/transformers/babel-plugin-obsidian-provide/index.js.map +0 -1
  123. package/src/decorators/injectClass.ts +0 -28
  124. package/transformers/babel-plugin-obsidian-provide/index.ts +0 -47
@@ -2,7 +2,7 @@ module.exports = {
2
2
  presets: ['module:metro-react-native-babel-preset'],
3
3
  plugins: [
4
4
  ['@babel/plugin-proposal-decorators', {legacy: true}],
5
- ['@babel/plugin-proposal-class-properties', {legacy: true}],
6
- [`${__dirname}/../dist/transformers/babel-plugin-obsidian-provide`],
5
+ ['@babel/plugin-proposal-class-properties', {loose: true}],
6
+ [`${__dirname}/../dist/transformers/babel-plugin-obsidian`],
7
7
  ],
8
8
  };
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>IDEDidComputeMac32BitWarning</key>
6
+ <true/>
7
+ </dict>
8
+ </plist>
package/jest.config.js CHANGED
@@ -7,6 +7,10 @@ const config = {
7
7
  'transformers',
8
8
  'test',
9
9
  ],
10
+ setupFilesAfterEnv: [
11
+ './jest.setup-after-env.js'
12
+ ],
13
+ testEnvironment: 'jsdom'
10
14
  };
11
15
 
12
16
  module.exports = config;
@@ -0,0 +1 @@
1
+ require('setimmediate');
package/jest.setup.ts ADDED
@@ -0,0 +1 @@
1
+ import 'reflect-metadata';
package/package.json CHANGED
@@ -1,7 +1,13 @@
1
1
  {
2
2
  "name": "react-obsidian",
3
- "version": "0.0.13",
3
+ "version": "0.0.17",
4
4
  "description": "Dependency injection framework for React and React Native applications",
5
+ "scripts": {
6
+ "prepack": "npm run lint && tsc --project tsconfig.prod.json",
7
+ "lint": "npx eslint src transformers test --ignore-pattern '*.d.ts' --ext .ts,.tsx,.js",
8
+ "pretest": "tsc",
9
+ "test": "npx jest"
10
+ },
5
11
  "main": "src/index.ts",
6
12
  "directories": {
7
13
  "test": "test"
@@ -11,17 +17,18 @@
11
17
  "reflect-metadata": "~0.1.13"
12
18
  },
13
19
  "peerDependencies": {
14
- "react": "*"
20
+ "react": "*",
21
+ "lodash": "*"
15
22
  },
16
23
  "devDependencies": {
17
24
  "@babel/core": "7.16.x",
18
- "@babel/generator": "7.16.x",
19
- "@babel/plugin-proposal-class-properties": "7.16.x",
20
25
  "@babel/plugin-proposal-decorators": "7.16.x",
21
26
  "@babel/preset-env": "7.16.x",
27
+ "babel-plugin-parameter-decorator": "1.x.x",
22
28
  "@babel/preset-react": "7.16.x",
23
29
  "@babel/preset-typescript": "7.16.x",
24
30
  "@babel/types": "7.16.x",
31
+ "@babel/traverse": "7.16.x",
25
32
  "@johanblumenberg/ts-mockito": "1.x.x",
26
33
  "@testing-library/react": "^12.1.2",
27
34
  "@testing-library/react-hooks": "^7.0.2",
@@ -40,17 +47,12 @@
40
47
  "eslint-plugin-jsx-a11y": "^6.4.1",
41
48
  "eslint-plugin-react": "^7.26.1",
42
49
  "eslint-plugin-react-hooks": "^4.2.0",
43
- "jest": "26.x.x",
50
+ "jest": "27.x.x",
44
51
  "lodash": "^4.17.21",
45
52
  "react": "17.0.2",
46
53
  "react-dom": "17.0.2",
47
- "typescript": "^4.4.4"
48
- },
49
- "scripts": {
50
- "prepack": "npm run lint && tsc --project tsconfig.prod.json",
51
- "lint": "npx eslint src transformers test --ignore-pattern '*.d.ts' --ext .ts,.tsx,.js",
52
- "pretest": "tsc",
53
- "test": "npx jest"
54
+ "typescript": "^4.5.4",
55
+ "setimmediate": "^1.0.5"
54
56
  },
55
57
  "repository": {
56
58
  "type": "git",
package/src/Obsidian.ts CHANGED
@@ -2,6 +2,7 @@ import graphRegistry from './graph/registry/GraphRegistry';
2
2
  import { ObjectGraph } from './graph/ObjectGraph';
3
3
  import { Constructable, GraphInternals, ServiceLocator } from './types';
4
4
  import { GraphMiddleware } from './graph/registry/GraphMiddleware';
5
+ import lazyInjector from './injectors/class/LazyInjector';
5
6
 
6
7
  export default class Obsidian {
7
8
  obtain<T extends ObjectGraph<P>, P = any>(
@@ -11,6 +12,10 @@ export default class Obsidian {
11
12
  return graphRegistry.resolve(Graph, props) as unknown as ServiceLocator<T>;
12
13
  }
13
14
 
15
+ inject<T extends object>(target: T) {
16
+ return lazyInjector.inject(target);
17
+ }
18
+
14
19
  addGraphMiddleware(middleware: GraphMiddleware) {
15
20
  graphRegistry.addGraphMiddleware(middleware);
16
21
  }
@@ -1,4 +1,4 @@
1
- import { Constructable } from 'src';
1
+ import { Constructable } from '../types';
2
2
  import { ObjectGraph } from '../graph/ObjectGraph';
3
3
 
4
4
  export function Singleton() {
@@ -0,0 +1,17 @@
1
+ import { isNumber } from 'lodash';
2
+ import InjectionMetadata from '../../injectors/class/InjectionMetadata';
3
+
4
+ export function Inject(name?: string) {
5
+ return (
6
+ target: Object | any,
7
+ _propertyKey?: string,
8
+ indexOrPropertyDescriptor?: number | PropertyDescriptor,
9
+ ) => {
10
+ const metadata = new InjectionMetadata();
11
+ if (isNumber(indexOrPropertyDescriptor)) {
12
+ metadata.saveConstructorParamMetadata(target, name!, indexOrPropertyDescriptor);
13
+ } else {
14
+ metadata.savePropertyMetadata(target.constructor, name!);
15
+ }
16
+ };
17
+ }
@@ -0,0 +1,8 @@
1
+ import { Constructable } from '../../types';
2
+ import { Graph } from '../../graph/Graph';
3
+ import graphRegistry from '../../graph/registry/GraphRegistry';
4
+ import ClassInjector from '../../injectors/class/ClassInjector';
5
+
6
+ export function Injectable(Graph: Constructable<Graph>): any {
7
+ return new ClassInjector(graphRegistry).inject(Graph);
8
+ }
@@ -0,0 +1,8 @@
1
+ import InjectionMetadata from '../../injectors/class/InjectionMetadata';
2
+
3
+ export function LazyInject(name?: string): any {
4
+ return (target: object) => {
5
+ const metadata = new InjectionMetadata();
6
+ metadata.saveLazyPropertyMetadata(target.constructor, name!);
7
+ };
8
+ }
@@ -3,6 +3,7 @@ import Memoize from '../decorators/Memoize';
3
3
  import { bindProviders } from './ProviderBinder';
4
4
  import { Graph } from './Graph';
5
5
  import PropertyRetriever from './PropertyRetriever';
6
+ import { Constructable } from '../types';
6
7
 
7
8
  export abstract class ObjectGraph<T = unknown> implements Graph {
8
9
  private propertyRetriever = new PropertyRetriever(this);
@@ -20,3 +21,9 @@ export abstract class ObjectGraph<T = unknown> implements Graph {
20
21
  return this.propertyRetriever.retrieve(property, receiver) as Dependency | undefined;
21
22
  }
22
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
  }
@@ -6,6 +6,7 @@ import GraphMiddlewareChain from './GraphMiddlewareChain';
6
6
  export class GraphRegistry {
7
7
  private readonly constructorToInstance = new Map<Constructable<Graph>, Set<Graph>>();
8
8
  private readonly instanceToConstructor = new Map<Graph, Constructable<Graph>>();
9
+ private readonly nameToInstance = new Map<string, Graph>();
9
10
  private readonly graphToSubgraphs = new Map<Constructable<Graph>, Set<Constructable<Graph>>>();
10
11
  private readonly graphMiddlewares = new GraphMiddlewareChain();
11
12
 
@@ -19,6 +20,10 @@ export class GraphRegistry {
19
20
  return Array.from(subgraphs).map((G) => this.resolve(G));
20
21
  }
21
22
 
23
+ getGraphInstance(name: string): Graph {
24
+ return this.nameToInstance.get(name)!;
25
+ }
26
+
22
27
  resolve<T extends Graph>(Graph: Constructable<T>, props?: any): T {
23
28
  if (this.isSingleton(Graph) && this.has(Graph)) {
24
29
  return this.getFirst(Graph);
@@ -41,6 +46,7 @@ export class GraphRegistry {
41
46
  graphs.add(graph);
42
47
  this.constructorToInstance.set(Graph, graphs);
43
48
  this.instanceToConstructor.set(graph, Graph);
49
+ this.nameToInstance.set(graph.name, graph);
44
50
  }
45
51
 
46
52
  private isSingleton(Graph: Constructable<Graph>): boolean {
@@ -51,6 +57,7 @@ export class GraphRegistry {
51
57
  const Graph = this.instanceToConstructor.get(graph)!;
52
58
  this.instanceToConstructor.delete(graph);
53
59
  this.constructorToInstance.get(Graph)!.delete(graph);
60
+ this.nameToInstance.delete(graph.name);
54
61
  }
55
62
 
56
63
  addGraphMiddleware(middleware: Middleware<Graph>) {
@@ -60,6 +67,12 @@ export class GraphRegistry {
60
67
  clearGraphMiddlewares() {
61
68
  this.graphMiddlewares.clear();
62
69
  }
70
+
71
+ reset() {
72
+ this.instanceToConstructor.clear();
73
+ this.constructorToInstance.clear();
74
+ this.nameToInstance.clear();
75
+ }
63
76
  }
64
77
 
65
78
  export default new GraphRegistry();
package/src/index.ts CHANGED
@@ -12,8 +12,9 @@ export { Singleton } from './decorators/Singleton';
12
12
  export { ObjectGraph } from './graph/ObjectGraph';
13
13
  export { Graph as IGraph } from './graph/Graph';
14
14
  export { Provides } from './decorators/provides/Provides';
15
- export { Injectable } from './decorators/injectClass';
16
- 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';
17
18
  export { GraphMiddleware } from './graph/registry/GraphMiddleware';
18
19
  export { GraphResolveChain as ResolveChain } from './graph/registry/GraphResolveChain';
19
20
  export const Obsidian = new _Obsidian();
@@ -29,3 +30,5 @@ export const injectHook = <Args, Result> (
29
30
  hook: (args: Args) => Result,
30
31
  Graph: Constructable<_ObjectGraph>,
31
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';
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,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"}