react-obsidian 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.buildkite/pipeline.yml +0 -0
- package/.eslintignore +1 -0
- package/.eslintrc.json +93 -0
- package/.nvmrc +1 -0
- package/LICENSE +7 -0
- package/README.md +160 -0
- package/babel.config.js +12 -0
- package/dist/src/GraphProperties.d.ts +6 -0
- package/dist/src/GraphProperties.d.ts.map +1 -0
- package/dist/src/GraphProperties.js +16 -0
- package/dist/src/GraphProperties.js.map +1 -0
- package/dist/src/Obsidian.d.ts +9 -0
- package/dist/src/Obsidian.d.ts.map +1 -0
- package/dist/src/Obsidian.js +22 -0
- package/dist/src/Obsidian.js.map +1 -0
- package/dist/src/ProvidedPropertiesStore.d.ts +10 -0
- package/dist/src/ProvidedPropertiesStore.d.ts.map +1 -0
- package/dist/src/ProvidedPropertiesStore.js +27 -0
- package/dist/src/ProvidedPropertiesStore.js.map +1 -0
- package/dist/src/Provides.d.ts +9 -0
- package/dist/src/Provides.d.ts.map +1 -0
- package/dist/src/Provides.js +15 -0
- package/dist/src/Provides.js.map +1 -0
- package/dist/src/ReferenceCounter.d.ts +8 -0
- package/dist/src/ReferenceCounter.d.ts.map +1 -0
- package/dist/src/ReferenceCounter.js +25 -0
- package/dist/src/ReferenceCounter.js.map +1 -0
- package/dist/src/ScopedValuesRegistry.d.ts +11 -0
- package/dist/src/ScopedValuesRegistry.d.ts.map +1 -0
- package/dist/src/ScopedValuesRegistry.js +25 -0
- package/dist/src/ScopedValuesRegistry.js.map +1 -0
- package/dist/src/decorators/Graph.d.ts +10 -0
- package/dist/src/decorators/Graph.d.ts.map +1 -0
- package/dist/src/decorators/Graph.js +17 -0
- package/dist/src/decorators/Graph.js.map +1 -0
- package/dist/src/decorators/injectClass.d.ts +7 -0
- package/dist/src/decorators/injectClass.d.ts.map +1 -0
- package/dist/src/decorators/injectClass.js +34 -0
- package/dist/src/decorators/injectClass.js.map +1 -0
- package/dist/src/graph/Graph.d.ts +6 -0
- package/dist/src/graph/Graph.d.ts.map +1 -0
- package/dist/src/graph/Graph.js +3 -0
- package/dist/src/graph/Graph.js.map +1 -0
- package/dist/src/graph/ObjectGraph.d.ts +11 -0
- package/dist/src/graph/ObjectGraph.d.ts.map +1 -0
- package/dist/src/graph/ObjectGraph.js +26 -0
- package/dist/src/graph/ObjectGraph.js.map +1 -0
- package/dist/src/graph/PropertyRetriever.d.ts +8 -0
- package/dist/src/graph/PropertyRetriever.d.ts.map +1 -0
- package/dist/src/graph/PropertyRetriever.js +40 -0
- package/dist/src/graph/PropertyRetriever.js.map +1 -0
- package/dist/src/graph/PropertyRetrieverDelegate.d.ts +5 -0
- package/dist/src/graph/PropertyRetrieverDelegate.d.ts.map +1 -0
- package/dist/src/graph/PropertyRetrieverDelegate.js +3 -0
- package/dist/src/graph/PropertyRetrieverDelegate.js.map +1 -0
- package/dist/src/graph/registry/DefaultGraphResolver.d.ts +7 -0
- package/dist/src/graph/registry/DefaultGraphResolver.d.ts.map +1 -0
- package/dist/src/graph/registry/DefaultGraphResolver.js +30 -0
- package/dist/src/graph/registry/DefaultGraphResolver.js.map +1 -0
- package/dist/src/graph/registry/GraphMiddleware.d.ts +12 -0
- package/dist/src/graph/registry/GraphMiddleware.d.ts.map +1 -0
- package/dist/src/graph/registry/GraphMiddleware.js +25 -0
- package/dist/src/graph/registry/GraphMiddleware.js.map +1 -0
- package/dist/src/graph/registry/GraphMiddlewareChain.d.ts +12 -0
- package/dist/src/graph/registry/GraphMiddlewareChain.d.ts.map +1 -0
- package/dist/src/graph/registry/GraphMiddlewareChain.js +30 -0
- package/dist/src/graph/registry/GraphMiddlewareChain.js.map +1 -0
- package/dist/src/graph/registry/GraphRegistry.d.ts +22 -0
- package/dist/src/graph/registry/GraphRegistry.d.ts.map +1 -0
- package/dist/src/graph/registry/GraphRegistry.js +65 -0
- package/dist/src/graph/registry/GraphRegistry.js.map +1 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +24 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/injectHook.d.ts +5 -0
- package/dist/src/injectHook.d.ts.map +1 -0
- package/dist/src/injectHook.js +30 -0
- package/dist/src/injectHook.js.map +1 -0
- package/dist/src/injectors/components/ComponentInjector.d.ts +9 -0
- package/dist/src/injectors/components/ComponentInjector.d.ts.map +1 -0
- package/dist/src/injectors/components/ComponentInjector.js +48 -0
- package/dist/src/injectors/components/ComponentInjector.js.map +1 -0
- package/dist/src/injectors/components/PropsInjector.d.ts +7 -0
- package/dist/src/injectors/components/PropsInjector.d.ts.map +1 -0
- package/dist/src/injectors/components/PropsInjector.js +19 -0
- package/dist/src/injectors/components/PropsInjector.js.map +1 -0
- package/dist/src/injectors/components/useGraph.d.ts +5 -0
- package/dist/src/injectors/components/useGraph.d.ts.map +1 -0
- package/dist/src/injectors/components/useGraph.js +17 -0
- package/dist/src/injectors/components/useGraph.js.map +1 -0
- package/dist/test/integration/fixtures/InjectedComponent.d.ts +8 -0
- package/dist/test/integration/fixtures/InjectedComponent.d.ts.map +1 -0
- package/dist/test/integration/fixtures/InjectedComponent.js +14 -0
- package/dist/test/integration/fixtures/InjectedComponent.js.map +1 -0
- package/dist/test/integration/fixtures/MainGraph.d.ts +6 -0
- package/dist/test/integration/fixtures/MainGraph.d.ts.map +1 -0
- package/dist/test/integration/fixtures/MainGraph.js +53 -0
- package/dist/test/integration/fixtures/MainGraph.js.map +1 -0
- package/dist/test/integration/fixtures/StringProvider.d.ts +5 -0
- package/dist/test/integration/fixtures/StringProvider.d.ts.map +1 -0
- package/dist/test/integration/fixtures/StringProvider.js +15 -0
- package/dist/test/integration/fixtures/StringProvider.js.map +1 -0
- package/dist/test/integration/fixtures/Subgraph.d.ts +8 -0
- package/dist/test/integration/fixtures/Subgraph.d.ts.map +1 -0
- package/dist/test/integration/fixtures/Subgraph.js +71 -0
- package/dist/test/integration/fixtures/Subgraph.js.map +1 -0
- package/dist/test/integration/fixtures/ThrowingMainGraph.d.ts +5 -0
- package/dist/test/integration/fixtures/ThrowingMainGraph.d.ts.map +1 -0
- package/dist/test/integration/fixtures/ThrowingMainGraph.js +52 -0
- package/dist/test/integration/fixtures/ThrowingMainGraph.js.map +1 -0
- package/dist/test/integration/fixtures/injectedValues.d.ts +6 -0
- package/dist/test/integration/fixtures/injectedValues.d.ts.map +1 -0
- package/dist/test/integration/fixtures/injectedValues.js +7 -0
- package/dist/test/integration/fixtures/injectedValues.js.map +1 -0
- package/dist/testkit/index.d.ts +8 -0
- package/dist/testkit/index.d.ts.map +1 -0
- package/dist/testkit/index.js +46 -0
- package/dist/testkit/index.js.map +1 -0
- package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.d.ts +9 -0
- package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.d.ts.map +1 -0
- package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.js +54 -0
- package/dist/transformers/babel-plugin-obsidian-provide/helpers/index.js.map +1 -0
- package/dist/transformers/babel-plugin-obsidian-provide/index.d.ts +3 -0
- package/dist/transformers/babel-plugin-obsidian-provide/index.d.ts.map +1 -0
- package/dist/transformers/babel-plugin-obsidian-provide/index.js +35 -0
- package/dist/transformers/babel-plugin-obsidian-provide/index.js.map +1 -0
- package/example/.buckconfig +6 -0
- package/example/.editorconfig +3 -0
- package/example/.eslintrc.js +4 -0
- package/example/.flowconfig +65 -0
- package/example/.gitattributes +3 -0
- package/example/.prettierrc.js +7 -0
- package/example/.watchmanconfig +1 -0
- package/example/App.tsx +31 -0
- package/example/MyInjectedComponent.tsx +28 -0
- package/example/__tests__/App-test.js +14 -0
- package/example/android/app/BUCK +55 -0
- package/example/android/app/build.gradle +227 -0
- package/example/android/app/build_defs.bzl +19 -0
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +10 -0
- package/example/android/app/src/debug/AndroidManifest.xml +13 -0
- package/example/android/app/src/debug/java/com/example/ReactNativeFlipper.java +72 -0
- package/example/android/app/src/main/AndroidManifest.xml +25 -0
- package/example/android/app/src/main/java/com/example/MainActivity.java +15 -0
- package/example/android/app/src/main/java/com/example/MainApplication.java +80 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +3 -0
- package/example/android/app/src/main/res/values/styles.xml +8 -0
- package/example/android/build.gradle +38 -0
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/example/android/gradle.properties +28 -0
- package/example/android/gradlew +185 -0
- package/example/android/gradlew.bat +89 -0
- package/example/android/settings.gradle +3 -0
- package/example/app.json +4 -0
- package/example/babel.config.js +8 -0
- package/example/index.js +9 -0
- package/example/ios/Podfile +30 -0
- package/example/ios/Podfile.lock +526 -0
- package/example/ios/example/AppDelegate.h +8 -0
- package/example/ios/example/AppDelegate.m +62 -0
- package/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json +38 -0
- package/example/ios/example/Images.xcassets/Contents.json +6 -0
- package/example/ios/example/Info.plist +55 -0
- package/example/ios/example/LaunchScreen.storyboard +47 -0
- package/example/ios/example/main.m +9 -0
- package/example/ios/example.xcodeproj/project.pbxproj +689 -0
- package/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme +88 -0
- package/example/ios/example.xcworkspace/contents.xcworkspacedata +10 -0
- package/example/ios/exampleTests/Info.plist +24 -0
- package/example/ios/exampleTests/exampleTests.m +65 -0
- package/example/metro.config.js +44 -0
- package/example/package.json +35 -0
- package/example/tsconfig.json +45 -0
- package/jest.config.js +12 -0
- package/package.json +79 -0
- package/src/@types/obsidian.d.ts +19 -0
- package/src/GraphProperties.ts +11 -0
- package/src/Obsidian.ts +18 -0
- package/src/ProvidedPropertiesStore.ts +22 -0
- package/src/Provides.ts +16 -0
- package/src/ReferenceCounter.ts +20 -0
- package/src/ScopedValuesRegistry.ts +26 -0
- package/src/decorators/Graph.ts +20 -0
- package/src/decorators/injectClass.ts +28 -0
- package/src/graph/Graph.ts +7 -0
- package/src/graph/ObjectGraph.ts +19 -0
- package/src/graph/PropertyRetriever.ts +36 -0
- package/src/graph/PropertyRetrieverDelegate.ts +5 -0
- package/src/graph/registry/DefaultGraphResolver.ts +9 -0
- package/src/graph/registry/GraphMiddleware.ts +24 -0
- package/src/graph/registry/GraphMiddlewareChain.ts +31 -0
- package/src/graph/registry/GraphRegistry.ts +70 -0
- package/src/index.ts +23 -0
- package/src/injectHook.ts +26 -0
- package/src/injectors/components/ComponentInjector.tsx +29 -0
- package/src/injectors/components/PropsInjector.ts +14 -0
- package/src/injectors/components/useGraph.ts +14 -0
- package/testkit/index.ts +25 -0
- package/transformers/babel-plugin-obsidian-provide/helpers/index.ts +59 -0
- package/transformers/babel-plugin-obsidian-provide/index.ts +44 -0
- package/tsconfig.base.json +43 -0
- package/tsconfig.json +3 -0
- package/tsconfig.prod.json +7 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Constructable } from '@Obsidian';
|
|
2
|
+
import Graph from '../Graph';
|
|
3
|
+
import { GraphMiddleware, ResolveChain } from './GraphMiddleware';
|
|
4
|
+
|
|
5
|
+
export default class DefaultGraphMiddleware extends GraphMiddleware {
|
|
6
|
+
resolve<T extends Graph, Props>(_resolveChain: ResolveChain, Graph: Constructable<T>, props?: Props): T {
|
|
7
|
+
return new Graph(props);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Constructable } from '@Obsidian';
|
|
2
|
+
import Graph from '../Graph';
|
|
3
|
+
|
|
4
|
+
export abstract class GraphMiddleware {
|
|
5
|
+
private next!: GraphMiddleware;
|
|
6
|
+
|
|
7
|
+
public setNext(next: GraphMiddleware) {
|
|
8
|
+
this.next = next;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public get resolveChain(): ResolveChain {
|
|
12
|
+
return {
|
|
13
|
+
proceed: <T extends Graph, Props>(Graph: Constructable<T>, props?: Props): T => {
|
|
14
|
+
return this.next.resolve(this.next.resolveChain, Graph, props);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
abstract resolve<T extends Graph, Props>(resolveChain: ResolveChain, Graph: Constructable<T>, props?: Props): T;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ResolveChain {
|
|
23
|
+
proceed<T extends Graph, Props>(Graph: Constructable<T>, props?: Props): T;
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Constructable } from '@Obsidian';
|
|
2
|
+
import Graph from '../Graph';
|
|
3
|
+
import DefaultGraphMiddleware from './DefaultGraphResolver';
|
|
4
|
+
import { GraphMiddleware } from './GraphMiddleware';
|
|
5
|
+
|
|
6
|
+
export default class GraphMiddlewareChain {
|
|
7
|
+
private middlewares: GraphMiddleware[];
|
|
8
|
+
|
|
9
|
+
constructor(defaultMiddleware: GraphMiddleware = new DefaultGraphMiddleware()) {
|
|
10
|
+
this.middlewares = [defaultMiddleware];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
resolve<T extends Graph>(Graph: Constructable<T>, props?: any): T {
|
|
14
|
+
return this.middlewares[0].resolve(this.middlewares[0].resolveChain, Graph, props);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
add(middleware: GraphMiddleware) {
|
|
18
|
+
this.middlewares.unshift(middleware);
|
|
19
|
+
this.updateResolveChain();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private updateResolveChain() {
|
|
23
|
+
if (this.middlewares.length > 1) {
|
|
24
|
+
this.middlewares[0].setNext(this.middlewares[1]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
clear() {
|
|
29
|
+
this.middlewares = [new DefaultGraphMiddleware()];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Constructable, Scope } from '@Obsidian';
|
|
2
|
+
import Graph from '../Graph';
|
|
3
|
+
import { GraphMiddleware } from './GraphMiddleware';
|
|
4
|
+
import GraphMiddlewareChain from './GraphMiddlewareChain';
|
|
5
|
+
|
|
6
|
+
class GraphRegistry {
|
|
7
|
+
private readonly scopedGraphs: Record<Scope, Constructable<Graph>> = {};
|
|
8
|
+
private readonly constructorToInstance = new Map<Constructable<Graph>, Graph>();
|
|
9
|
+
private readonly instanceToConstructor = new Map<Graph, Constructable<Graph>>();
|
|
10
|
+
private readonly graphToSubgraphs = new Map<Constructable<Graph>, Set<Constructable<Graph>>>();
|
|
11
|
+
private graphMiddlewares = new GraphMiddlewareChain();
|
|
12
|
+
|
|
13
|
+
register(
|
|
14
|
+
constructor: Constructable<Graph>,
|
|
15
|
+
scope: Scope | undefined = undefined,
|
|
16
|
+
subgraphs: Constructable<Graph>[] = [],
|
|
17
|
+
) {
|
|
18
|
+
if (scope) this.scopedGraphs[scope] = constructor;
|
|
19
|
+
this.graphToSubgraphs.set(constructor, new Set(subgraphs));
|
|
20
|
+
}
|
|
21
|
+
|
|
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
|
+
getSubgraphs(graph: Graph): Graph[] {
|
|
36
|
+
const Graph = this.instanceToConstructor.get(graph)!;
|
|
37
|
+
const subgraphs = this.graphToSubgraphs.get(Graph) ?? new Set();
|
|
38
|
+
return Array.from(subgraphs).map((G) => this.resolve(G));
|
|
39
|
+
}
|
|
40
|
+
|
|
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;
|
|
47
|
+
|
|
48
|
+
// this.set(Graph, new Graph(props));
|
|
49
|
+
}
|
|
50
|
+
const graph = this.graphMiddlewares.resolve(Graph, props);
|
|
51
|
+
this.set(Graph, graph);
|
|
52
|
+
return graph;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
clear(graph: Graph) {
|
|
56
|
+
const Graph = this.instanceToConstructor.get(graph)!;
|
|
57
|
+
this.instanceToConstructor.delete(graph);
|
|
58
|
+
this.constructorToInstance.delete(Graph);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
addGraphMiddleware(middleware: GraphMiddleware) {
|
|
62
|
+
this.graphMiddlewares.add(middleware);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
clearGraphMiddlewares() {
|
|
66
|
+
this.graphMiddlewares.clear();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default new GraphRegistry();
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Constructable } from '@Obsidian';
|
|
3
|
+
import _Graph from './decorators/Graph';
|
|
4
|
+
import _ObjectGraph from './graph/ObjectGraph';
|
|
5
|
+
import _injectHook from './injectHook';
|
|
6
|
+
import ComponentInjector from './injectors/components/ComponentInjector';
|
|
7
|
+
import _Provides from './Provides';
|
|
8
|
+
import { Inject as _Inject, Injectable as _Injectable } from './decorators/injectClass';
|
|
9
|
+
import _obsidian from './Obsidian';
|
|
10
|
+
|
|
11
|
+
export const Graph = _Graph;
|
|
12
|
+
export const ObjectGraph = _ObjectGraph;
|
|
13
|
+
export const injectHook = _injectHook;
|
|
14
|
+
export const Provides = _Provides;
|
|
15
|
+
export const Injectable = _Injectable;
|
|
16
|
+
export const Inject = _Inject;
|
|
17
|
+
export const Obsidian = new _obsidian();
|
|
18
|
+
|
|
19
|
+
const componentInjector = new ComponentInjector();
|
|
20
|
+
export const injectComponent = <P> (
|
|
21
|
+
__Target: React.FunctionComponent<P>,
|
|
22
|
+
__Graph: Constructable<_ObjectGraph>,
|
|
23
|
+
) => componentInjector.inject(__Target, __Graph);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Constructable } from '@Obsidian';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import 'reflect-metadata';
|
|
4
|
+
import graphRegistry from './graph/registry/GraphRegistry';
|
|
5
|
+
import ObjectGraph from './graph/ObjectGraph';
|
|
6
|
+
import referenceCounter from './ReferenceCounter';
|
|
7
|
+
|
|
8
|
+
export default function injectHook<S, T>(target: (args: S) => T, Graph: Constructable<ObjectGraph>) {
|
|
9
|
+
return (args?: Partial<S>): T => {
|
|
10
|
+
const [graph] = useState(graphRegistry.resolve(Graph, args));
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
referenceCounter.retain(graph);
|
|
13
|
+
return () => referenceCounter.release(graph, (g) => graphRegistry.clear(g));
|
|
14
|
+
}, [graph]);
|
|
15
|
+
|
|
16
|
+
return target(new Proxy(args ?? {}, new Injector(graph)));
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class Injector implements ProxyHandler<any> {
|
|
21
|
+
constructor(private graph: ObjectGraph) {}
|
|
22
|
+
|
|
23
|
+
get(obj: any, property: string, receiver: any): any {
|
|
24
|
+
return property in obj ? obj[property] : this.graph.retrieve(property, receiver);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Constructable } from '@Obsidian';
|
|
3
|
+
import hoistNonReactStatics from 'hoist-non-react-statics';
|
|
4
|
+
import 'reflect-metadata';
|
|
5
|
+
import ObjectGraph from '../../graph/ObjectGraph';
|
|
6
|
+
import PropsInjector from './PropsInjector';
|
|
7
|
+
import useGraph from './useGraph';
|
|
8
|
+
|
|
9
|
+
export default class ComponentInjector {
|
|
10
|
+
inject<P>(
|
|
11
|
+
Target: React.FunctionComponent<P>,
|
|
12
|
+
Graph: Constructable<ObjectGraph>,
|
|
13
|
+
): React.FunctionComponent<Partial<P>> {
|
|
14
|
+
const Wrapped = this.wrapComponent(Target, Graph);
|
|
15
|
+
hoistNonReactStatics(Wrapped, Target);
|
|
16
|
+
return Wrapped;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private wrapComponent<P>(
|
|
20
|
+
Target: React.FunctionComponent<P>,
|
|
21
|
+
Graph: Constructable<ObjectGraph>,
|
|
22
|
+
): React.FunctionComponent<Partial<P>> {
|
|
23
|
+
return (passedProps: Partial<P>) => {
|
|
24
|
+
const graph = useGraph(Graph, passedProps);
|
|
25
|
+
const [proxiedProps] = useState(new PropsInjector(graph).inject(passedProps));
|
|
26
|
+
return <>{Target(proxiedProps as unknown as P)}</>;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import ObjectGraph from 'src/graph/ObjectGraph';
|
|
2
|
+
|
|
3
|
+
export default class PropsInjector<Props> {
|
|
4
|
+
constructor(private graph: ObjectGraph) {}
|
|
5
|
+
|
|
6
|
+
inject(passedProps: Props): Partial<Props> {
|
|
7
|
+
// eslint-disable-next-line prefer-object-spread
|
|
8
|
+
return new Proxy(Object.assign({}, passedProps), {
|
|
9
|
+
get: (target: object, p: string, receiver: any): any => {
|
|
10
|
+
return p in target ? Reflect.get(target, p, receiver) : this.graph.retrieve(p, receiver);
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Constructable } from '@Obsidian';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import ObjectGraph from 'src/graph/ObjectGraph';
|
|
4
|
+
import graphRegistry from '../../graph/registry/GraphRegistry';
|
|
5
|
+
import referenceCounter from '../../ReferenceCounter';
|
|
6
|
+
|
|
7
|
+
export default <P>(Graph: Constructable<ObjectGraph>, props: Partial<P>) => {
|
|
8
|
+
const [graph] = useState(graphRegistry.resolve(Graph, props));
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
referenceCounter.retain(graph);
|
|
11
|
+
return () => referenceCounter.release(graph, (g) => graphRegistry.clear(g));
|
|
12
|
+
}, [graph]);
|
|
13
|
+
return graph;
|
|
14
|
+
};
|
package/testkit/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { GraphMiddleware, ResolveChain } from '../src/graph/registry/GraphMiddleware';
|
|
2
|
+
import ObjectGraph from '../src/graph/Graph';
|
|
3
|
+
import { Constructable } from '../src/@types/obsidian';
|
|
4
|
+
import { Obsidian } from '../src';
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
Obsidian.clearGraphMiddlewares();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
class Index {
|
|
11
|
+
mockGraphs(graphNameToGraph: Record<string, Constructable<ObjectGraph>>) {
|
|
12
|
+
const graphMiddleware = new class extends GraphMiddleware {
|
|
13
|
+
resolve<T extends ObjectGraph, Props>(resolveChain: ResolveChain, Graph: Constructable<T>, props?: Props) {
|
|
14
|
+
if (graphNameToGraph[Graph.name]) {
|
|
15
|
+
const TheGraph = graphNameToGraph[Graph.name];
|
|
16
|
+
return new TheGraph(props) as unknown as T;
|
|
17
|
+
}
|
|
18
|
+
return resolveChain.proceed(Graph, props);
|
|
19
|
+
}
|
|
20
|
+
}();
|
|
21
|
+
Obsidian.addGraphMiddleware(graphMiddleware);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default new Index();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
import { types as t } from '@babel/core';
|
|
3
|
+
import {
|
|
4
|
+
CallExpression,
|
|
5
|
+
ClassMethod,
|
|
6
|
+
Decorator,
|
|
7
|
+
Identifier,
|
|
8
|
+
ObjectExpression,
|
|
9
|
+
ObjectPattern,
|
|
10
|
+
} from '@babel/types';
|
|
11
|
+
import { get } from 'lodash';
|
|
12
|
+
|
|
13
|
+
export function providerIsNotNamed(decorator: Decorator): boolean {
|
|
14
|
+
const argument = getDecoratorArgument(decorator);
|
|
15
|
+
if (t.isObjectExpression(argument)) {
|
|
16
|
+
return argument.properties.find((p) => {
|
|
17
|
+
if (t.isObjectProperty(p)) {
|
|
18
|
+
return t.isIdentifier(p.key) && p.key.name === 'name';
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}) === undefined;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function addNameToProviderArguments(node: ClassMethod, decorator: Decorator) {
|
|
27
|
+
const argument = getDecoratorArgument(decorator) ?? t.objectExpression([]);
|
|
28
|
+
argument.properties.push(t.objectProperty(
|
|
29
|
+
t.identifier('name'),
|
|
30
|
+
t.stringLiteral(getMethodName(node)),
|
|
31
|
+
));
|
|
32
|
+
(decorator.expression as CallExpression).arguments = [argument];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getDecoratorArgument(decorator: Decorator): ObjectExpression | undefined {
|
|
36
|
+
if (t.isCallExpression(decorator.expression)) {
|
|
37
|
+
return decorator.expression.arguments.find((a) => t.isObjectExpression(a)) as ObjectExpression;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getMethodName(node: ClassMethod): string {
|
|
43
|
+
if (t.isIdentifier(node.key)) return node.key.name;
|
|
44
|
+
throw new Error(`Tried to get class name but encountered unexpected key of type: ${node.key.type}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getProviderDecorator(decorators: Array<Decorator> | undefined | null): Decorator | undefined {
|
|
48
|
+
return decorators?.find((decorator) => get(decorator, 'expression.callee.name') === 'Provides');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getDecoratorName(decorator?: Decorator): string | undefined {
|
|
52
|
+
return get(decorator, 'expression.callee.name');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function paramsToDestructuringAssignment(params: (Identifier | any)[]): ObjectPattern {
|
|
56
|
+
return t.objectPattern(params
|
|
57
|
+
.filter((p) => t.isIdentifier(p))
|
|
58
|
+
.map((p) => t.objectProperty(t.identifier(p.name), t.identifier(p.name))));
|
|
59
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
import { ClassMethod, Decorator, Program } from '@babel/types';
|
|
3
|
+
import { NodePath, PluginObj } from '@babel/core';
|
|
4
|
+
import {
|
|
5
|
+
addNameToProviderArguments,
|
|
6
|
+
getDecoratorName,
|
|
7
|
+
getProviderDecorator,
|
|
8
|
+
paramsToDestructuringAssignment,
|
|
9
|
+
providerIsNotNamed,
|
|
10
|
+
} from './helpers';
|
|
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
|
+
const decorator = getProviderDecorator(node.decorators);
|
|
24
|
+
if (getDecoratorName(decorator) === 'Provides') {
|
|
25
|
+
convertProviderParamsToDestructuringAssignment(node);
|
|
26
|
+
saveUnmangledMethodNameInProviderArguments(node, decorator!);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function convertProviderParamsToDestructuringAssignment(node: ClassMethod) {
|
|
33
|
+
node.params.fill(paramsToDestructuringAssignment(node.params));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function saveUnmangledMethodNameInProviderArguments(node: ClassMethod, decorator: Decorator) {
|
|
37
|
+
if (providerIsNotNamed(decorator)) {
|
|
38
|
+
addNameToProviderArguments(node, decorator);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default function plugin() {
|
|
43
|
+
return providerArgumentsTransformer;
|
|
44
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": [
|
|
3
|
+
"src/**/*",
|
|
4
|
+
"transformers/**/*",
|
|
5
|
+
"test/**/*"
|
|
6
|
+
],
|
|
7
|
+
"exclude": [
|
|
8
|
+
"node_modules",
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"compilerOptions": {
|
|
12
|
+
"target": "es5",
|
|
13
|
+
"module": "commonjs",
|
|
14
|
+
"lib": [
|
|
15
|
+
"ES6",
|
|
16
|
+
"DOM",
|
|
17
|
+
"esnext"
|
|
18
|
+
],
|
|
19
|
+
"moduleResolution": "node",
|
|
20
|
+
"outDir": "./dist",
|
|
21
|
+
"declaration": true,
|
|
22
|
+
"declarationMap": true,
|
|
23
|
+
"sourceMap": true,
|
|
24
|
+
"strict": true,
|
|
25
|
+
"noImplicitReturns": true,
|
|
26
|
+
"noFallthroughCasesInSwitch": true,
|
|
27
|
+
"noUnusedLocals": true,
|
|
28
|
+
"noUnusedParameters": true,
|
|
29
|
+
"noImplicitOverride": true,
|
|
30
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
31
|
+
"forceConsistentCasingInFileNames": true,
|
|
32
|
+
"jsx": "react",
|
|
33
|
+
"esModuleInterop": true,
|
|
34
|
+
"resolveJsonModule": true,
|
|
35
|
+
"experimentalDecorators": true,
|
|
36
|
+
"emitDecoratorMetadata": true,
|
|
37
|
+
"types": ["reflect-metadata", "jest"],
|
|
38
|
+
"baseUrl": "./",
|
|
39
|
+
"paths": {
|
|
40
|
+
"@Obsidian": ["./src/@types/obsidian.d.ts"]
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
}
|
package/tsconfig.json
ADDED