react-obsidian 0.0.32 → 0.0.33
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/.eslintrc.json +3 -0
- package/README.md +21 -326
- package/dist/src/graph/registry/GraphResolveChain.d.ts +1 -1
- package/dist/src/graph/registry/GraphResolveChain.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/injectors/hooks/HookInjector.js +1 -1
- package/dist/src/injectors/hooks/HookInjector.js.map +1 -1
- package/dist/src/observable/Observable.d.ts +12 -0
- package/dist/src/observable/Observable.d.ts.map +1 -0
- package/dist/src/observable/Observable.js +31 -0
- package/dist/src/observable/Observable.js.map +1 -0
- package/dist/src/observable/useObserver.d.ts +3 -0
- package/dist/src/observable/useObserver.d.ts.map +1 -0
- package/dist/src/observable/useObserver.js +18 -0
- package/dist/src/observable/useObserver.js.map +1 -0
- package/dist/src/types/index.d.ts +8 -8
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/React.d.ts +1 -1
- package/dist/src/utils/React.d.ts.map +1 -1
- package/dist/test/fixtures/LifecycleBoundGraph.d.ts +7 -2
- package/dist/test/fixtures/LifecycleBoundGraph.d.ts.map +1 -1
- package/dist/test/fixtures/LifecycleBoundGraph.js +15 -3
- package/dist/test/fixtures/LifecycleBoundGraph.js.map +1 -1
- package/dist/test/fixtures/MainGraph.d.ts +1 -1
- package/dist/test/fixtures/MainGraph.d.ts.map +1 -1
- package/dist/transformers/babel-plugin-obsidian/helpers/index.d.ts +1 -1
- package/dist/transformers/babel-plugin-obsidian/helpers/index.d.ts.map +1 -1
- package/documentation/README.md +41 -0
- package/documentation/babel.config.js +3 -0
- package/documentation/blog/2019-05-28-first-blog-post.md +12 -0
- package/documentation/blog/2019-05-29-long-blog-post.md +44 -0
- package/documentation/blog/2021-08-01-mdx-blog-post.mdx +20 -0
- package/documentation/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- package/documentation/blog/2021-08-26-welcome/index.md +25 -0
- package/documentation/blog/authors.yml +17 -0
- package/documentation/docs/documentation/documentation.mdx +191 -0
- package/documentation/docs/documentation/installation.mdx +65 -0
- package/documentation/docs/documentation/meta/clearingGraphs.mdx +13 -0
- package/documentation/docs/documentation/meta/middlewares.mdx +27 -0
- package/documentation/docs/documentation/usage/ClassComponents.mdx +18 -0
- package/documentation/docs/documentation/usage/Classes.mdx +41 -0
- package/documentation/docs/documentation/usage/FunctionalComponents.mdx +57 -0
- package/documentation/docs/documentation/usage/Graphs.mdx +146 -0
- package/documentation/docs/documentation/usage/Hooks.mdx +85 -0
- package/documentation/docs/documentation/usage/ServiceLocator.mdx +38 -0
- package/documentation/docs/documentation/usage/_category_.json +9 -0
- package/documentation/docs/guides/configurableApplications.mdx +205 -0
- package/documentation/docs/guides/mockDependencies.mdx +141 -0
- package/documentation/docusaurus.config.js +146 -0
- package/documentation/package-lock.json +21290 -0
- package/documentation/package.json +46 -0
- package/documentation/sidebars.js +34 -0
- package/documentation/src/components/HomepageFeatures/index.tsx +71 -0
- package/documentation/src/components/HomepageFeatures/styles.module.css +11 -0
- package/documentation/src/css/custom.css +30 -0
- package/documentation/src/pages/index.module.css +23 -0
- package/documentation/src/pages/index.tsx +41 -0
- package/documentation/static/.nojekyll +0 -0
- package/documentation/static/img/api.svg +101 -0
- package/documentation/static/img/favicon.ico +0 -0
- package/documentation/static/img/logo.svg +265 -0
- package/documentation/static/img/obsidian.png +0 -0
- package/documentation/static/img/prototype.svg +1 -0
- package/documentation/static/img/stethoscope.svg +37 -0
- package/documentation/tsconfig.json +7 -0
- package/package.json +4 -4
- package/src/index.ts +3 -0
- package/src/injectors/hooks/HookInjector.ts +1 -1
- package/src/observable/Observable.ts +26 -0
- package/src/observable/useObserver.ts +17 -0
|
@@ -29,18 +29,30 @@ var src_1 = require("../../src");
|
|
|
29
29
|
var LifecycleBound_1 = require("../../src/decorators/LifecycleBound");
|
|
30
30
|
var LifecycleBoundGraph = /** @class */ (function (_super) {
|
|
31
31
|
__extends(LifecycleBoundGraph, _super);
|
|
32
|
-
function LifecycleBoundGraph() {
|
|
33
|
-
var _this = _super.call(this) || this;
|
|
32
|
+
function LifecycleBoundGraph(props) {
|
|
33
|
+
var _this = _super.call(this, props) || this;
|
|
34
|
+
_this.props = props;
|
|
34
35
|
LifecycleBoundGraph_1.timesCreated++;
|
|
35
36
|
return _this;
|
|
36
37
|
}
|
|
37
38
|
LifecycleBoundGraph_1 = LifecycleBoundGraph;
|
|
39
|
+
LifecycleBoundGraph.prototype.computedFromProps = function () {
|
|
40
|
+
return this.props.stringFromProps
|
|
41
|
+
? "A string passed via props: ".concat(this.props.stringFromProps)
|
|
42
|
+
: 'stringFromProps does not exist';
|
|
43
|
+
};
|
|
38
44
|
var LifecycleBoundGraph_1;
|
|
39
45
|
LifecycleBoundGraph.timesCreated = 0;
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, src_1.Provides)(),
|
|
48
|
+
__metadata("design:type", Function),
|
|
49
|
+
__metadata("design:paramtypes", []),
|
|
50
|
+
__metadata("design:returntype", String)
|
|
51
|
+
], LifecycleBoundGraph.prototype, "computedFromProps", null);
|
|
40
52
|
LifecycleBoundGraph = LifecycleBoundGraph_1 = __decorate([
|
|
41
53
|
(0, LifecycleBound_1.LifecycleBound)(),
|
|
42
54
|
(0, src_1.Graph)(),
|
|
43
|
-
__metadata("design:paramtypes", [])
|
|
55
|
+
__metadata("design:paramtypes", [Object])
|
|
44
56
|
], LifecycleBoundGraph);
|
|
45
57
|
return LifecycleBoundGraph;
|
|
46
58
|
}(src_1.ObjectGraph));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LifecycleBoundGraph.js","sourceRoot":"","sources":["../../../test/fixtures/LifecycleBoundGraph.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"LifecycleBoundGraph.js","sourceRoot":"","sources":["../../../test/fixtures/LifecycleBoundGraph.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAyD;AACzD,sEAAqE;AAKrE;IAAiD,uCAAsB;IAIrE,6BAAY,KAAgB;QAA5B,YACE,kBAAM,KAAK,CAAC,SAGb;QAFC,KAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,qBAAmB,CAAC,YAAY,EAAE,CAAC;;IACrC,CAAC;4BARU,mBAAmB;IAW9B,+CAAiB,GADjB;QAEE,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe;YAC/B,CAAC,CAAC,qCAA8B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAE;YAC5D,CAAC,CAAC,gCAAgC,CAAC;IACvC,CAAC;;IAdM,gCAAY,GAAG,CAAC,CAAC;IASxB;QAAC,IAAA,cAAQ,GAAE;;;;gEAKV;IAfU,mBAAmB;QAD/B,IAAA,+BAAc,GAAE;QAAE,IAAA,WAAK,GAAE;;OACb,mBAAmB,CAgB/B;IAAD,0BAAC;CAAA,AAjBD,CACiD,iBAAW,GAgB3D;AAhBY,kDAAmB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ObjectGraph, DependenciesOf } from '../../src';
|
|
2
2
|
import StringProvider from './StringProvider';
|
|
3
3
|
import Subgraph from './Subgraph';
|
|
4
|
-
export
|
|
4
|
+
export type Dependencies = DependenciesOf<[MainGraph, Subgraph]>;
|
|
5
5
|
export default class MainGraph extends ObjectGraph {
|
|
6
6
|
someString(stringProvider: StringProvider): string;
|
|
7
7
|
anotherString(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MainGraph.d.ts","sourceRoot":"","sources":["../../../test/fixtures/MainGraph.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EAEX,cAAc,EACf,MAAM,WAAW,CAAC;AAEnB,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,
|
|
1
|
+
{"version":3,"file":"MainGraph.d.ts","sourceRoot":"","sources":["../../../test/fixtures/MainGraph.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EAEX,cAAc,EACf,MAAM,WAAW,CAAC;AAEnB,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGjE,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,WAAW;IAEhD,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,MAAM;IAKlD,aAAa,IAAI,MAAM;CAGxB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClassMethod, ClassProperty, Decorator, Identifier, ObjectExpression, ObjectPattern, TSParameterProperty } from '@babel/types';
|
|
2
|
-
export
|
|
2
|
+
export type AcceptedNodeType = Identifier | TSParameterProperty | ClassProperty;
|
|
3
3
|
export declare function providerIsNotNamed(decorator: Decorator): boolean;
|
|
4
4
|
export declare function addNameToProviderArguments(node: ClassMethod, decorator: Decorator): void;
|
|
5
5
|
export declare function getDecoratorArgument(decorator: Decorator): ObjectExpression | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../transformers/babel-plugin-obsidian/helpers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,WAAW,EACX,aAAa,EACb,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAKtB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../transformers/babel-plugin-obsidian/helpers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,WAAW,EACX,aAAa,EACb,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAKtB,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,mBAAmB,GAAG,aAAa,CAAC;AAEhF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAWhE;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,QAOjF;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,GAAG,gBAAgB,GAAG,SAAS,CAKvF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAGvD;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,IAAI,EAC/C,aAAa,EAAE,MAAM,GACpB,SAAS,GAAG,SAAS,CAEvB;AAED,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,CAAC,UAAU,GAAG,GAAG,CAAC,EAAE,GAAG,aAAa,CAI3F;AAED,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,SAAS,QAOrB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Website
|
|
2
|
+
|
|
3
|
+
This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
|
|
4
|
+
|
|
5
|
+
### Installation
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
$ yarn
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Local Development
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
$ yarn start
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
|
18
|
+
|
|
19
|
+
### Build
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
$ yarn build
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
|
26
|
+
|
|
27
|
+
### Deployment
|
|
28
|
+
|
|
29
|
+
Using SSH:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
$ USE_SSH=true yarn deploy
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Not using SSH:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
$ GIT_USER=<Your GitHub username> yarn deploy
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
slug: first-blog-post
|
|
3
|
+
title: First Blog Post
|
|
4
|
+
authors:
|
|
5
|
+
name: Gao Wei
|
|
6
|
+
title: Docusaurus Core Team
|
|
7
|
+
url: https://github.com/wgao19
|
|
8
|
+
image_url: https://github.com/wgao19.png
|
|
9
|
+
tags: [hola, docusaurus]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
slug: long-blog-post
|
|
3
|
+
title: Long Blog Post
|
|
4
|
+
authors: endi
|
|
5
|
+
tags: [hello, docusaurus]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This is the summary of a very long blog post,
|
|
9
|
+
|
|
10
|
+
Use a `<!--` `truncate` `-->` comment to limit blog post size in the list view.
|
|
11
|
+
|
|
12
|
+
<!--truncate-->
|
|
13
|
+
|
|
14
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
15
|
+
|
|
16
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
17
|
+
|
|
18
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
19
|
+
|
|
20
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
21
|
+
|
|
22
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
23
|
+
|
|
24
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
25
|
+
|
|
26
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
27
|
+
|
|
28
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
29
|
+
|
|
30
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
31
|
+
|
|
32
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
33
|
+
|
|
34
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
35
|
+
|
|
36
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
37
|
+
|
|
38
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
39
|
+
|
|
40
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
41
|
+
|
|
42
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
43
|
+
|
|
44
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
slug: mdx-blog-post
|
|
3
|
+
title: MDX Blog Post
|
|
4
|
+
authors: [slorber]
|
|
5
|
+
tags: [docusaurus]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/).
|
|
9
|
+
|
|
10
|
+
:::tip
|
|
11
|
+
|
|
12
|
+
Use the power of React to create interactive blog posts.
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
<button onClick={() => alert('button clicked!')}>Click me!</button>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
<button onClick={() => alert('button clicked!')}>Click me!</button>
|
|
19
|
+
|
|
20
|
+
:::
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
slug: welcome
|
|
3
|
+
title: Welcome
|
|
4
|
+
authors: [slorber, yangshun]
|
|
5
|
+
tags: [facebook, hello, docusaurus]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).
|
|
9
|
+
|
|
10
|
+
Simply add Markdown files (or folders) to the `blog` directory.
|
|
11
|
+
|
|
12
|
+
Regular blog authors can be added to `authors.yml`.
|
|
13
|
+
|
|
14
|
+
The blog post date can be extracted from filenames, such as:
|
|
15
|
+
|
|
16
|
+
- `2019-05-30-welcome.md`
|
|
17
|
+
- `2019-05-30-welcome/index.md`
|
|
18
|
+
|
|
19
|
+
A blog post folder can be convenient to co-locate blog post images:
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
The blog supports tags as well!
|
|
24
|
+
|
|
25
|
+
**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
endi:
|
|
2
|
+
name: Endilie Yacop Sucipto
|
|
3
|
+
title: Maintainer of Docusaurus
|
|
4
|
+
url: https://github.com/endiliey
|
|
5
|
+
image_url: https://github.com/endiliey.png
|
|
6
|
+
|
|
7
|
+
yangshun:
|
|
8
|
+
name: Yangshun Tay
|
|
9
|
+
title: Front End Engineer @ Facebook
|
|
10
|
+
url: https://github.com/yangshun
|
|
11
|
+
image_url: https://github.com/yangshun.png
|
|
12
|
+
|
|
13
|
+
slorber:
|
|
14
|
+
name: Sébastien Lorber
|
|
15
|
+
title: Docusaurus maintainer
|
|
16
|
+
url: https://sebastienlorber.com
|
|
17
|
+
image_url: https://github.com/slorber.png
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 1
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
import Tabs from '@theme/Tabs';
|
|
6
|
+
import TabItem from '@theme/TabItem';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Introduction
|
|
10
|
+
|
|
11
|
+
Obsidian is a dependency injection container with first-class support for React and React Native applications.
|
|
12
|
+
|
|
13
|
+
Get started by **following the installation guide** bellow.
|
|
14
|
+
<!-- Or **try Obsidian immediately** in the **[Online Playground](https://docusaurus.new)**. -->
|
|
15
|
+
|
|
16
|
+
## The 2 steps tutorial for injecting dependencies with Obsidian
|
|
17
|
+
|
|
18
|
+
### Step 1: Declare how dependencies should be created
|
|
19
|
+
|
|
20
|
+
Define a singleton graph that is instantiated once and is retained throughout the lifespan of the application. All dependencies it provides are also singletons. The graph bellow provides two dependencies that can be injected: `fooService` and `barManager`.
|
|
21
|
+
```ts title="A singleton graph that provides two dependencies"
|
|
22
|
+
import {Singleton, Graph, ObjectGraph, Provides} from 'react-obsidian';
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@Singleton() @Graph()
|
|
26
|
+
export class ApplicationGraph extends ObjectGraph {
|
|
27
|
+
|
|
28
|
+
// fooService requires a barManager so it receives one as a parameter.
|
|
29
|
+
@Provides()
|
|
30
|
+
fooService(barManager: BarManager): FooService {
|
|
31
|
+
return new FooService(barManager);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@Provides()
|
|
36
|
+
barManager(): BarManager {
|
|
37
|
+
return new BarManager();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 2: Inject the dependencies
|
|
43
|
+
Obsidian can inject dependencies into components, hooks, and classes.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
<Tabs>
|
|
48
|
+
<TabItem value="functionalComponent" label="Functional component injection" default>
|
|
49
|
+
|
|
50
|
+
Injecting React functional components essentially revolves around two things: declaring the required dependencies in the hook's prototype and exporting an injected hook using the `injectComponent` function.
|
|
51
|
+
|
|
52
|
+
```ts title="MyComponent.tsx"
|
|
53
|
+
import {DependenciesOf, injectComponent} from 'react-obsidian';
|
|
54
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
55
|
+
|
|
56
|
+
// 1. Declare which dependencies should be injected.
|
|
57
|
+
type Props = DependenciesOf<ApplicationGraph, 'fooService'>; // {fooService: FooService}
|
|
58
|
+
|
|
59
|
+
// 2. Implement the component.
|
|
60
|
+
const myComponent = ({fooService}: Props) => {
|
|
61
|
+
// Do something useful with fooService
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 3. Export the injected component.
|
|
65
|
+
export default injectComponent(myComponent, ApplicationGraph);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Now we can use the injected component without providing its dependencies manually:
|
|
69
|
+
```tsx title="SomeComponent.tsx"
|
|
70
|
+
import MyComponent from './MyComponent';
|
|
71
|
+
|
|
72
|
+
const SomeComponent = () => {
|
|
73
|
+
// 4. Render the component - its dependencies are resolved automatically by Obsidian.
|
|
74
|
+
return <MyComponent />;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
</TabItem>
|
|
78
|
+
<TabItem value="hook" label="Hook injection">
|
|
79
|
+
|
|
80
|
+
Hooks are injected in a similar way to functional components. The only difference is that the `injectHook` function is used instead of `injectComponent`.
|
|
81
|
+
|
|
82
|
+
```ts title="MyHook.ts"
|
|
83
|
+
import {DependenciesOf, injectHook} from 'react-obsidian';
|
|
84
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
85
|
+
|
|
86
|
+
// 1. Declare which dependencies should be injected.
|
|
87
|
+
type Props = DependenciesOf<ApplicationGraph, 'fooService'>; // {fooService: FooService}
|
|
88
|
+
|
|
89
|
+
// 2. Implement the hook.
|
|
90
|
+
const myHook = ({fooService}: Props) => {
|
|
91
|
+
// Do something useful with fooService
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 3. Export the injected hook.
|
|
95
|
+
export default injectHook(myHook, ApplicationGraph);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The injected hook can be used without providing its dependencies manually:
|
|
99
|
+
```tsx title="SomeComponent.tsx"
|
|
100
|
+
import myHook from './MyHook';
|
|
101
|
+
|
|
102
|
+
const SomeComponent = () => {
|
|
103
|
+
// 4. Use the hook without providing any dependencies manually - they are injected automatically.
|
|
104
|
+
myHook();
|
|
105
|
+
|
|
106
|
+
return <>Obsidian is awesome!</>;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
</TabItem>
|
|
110
|
+
<TabItem value="classComponent" label="Class component injection">
|
|
111
|
+
|
|
112
|
+
To inject a class, annotate it with the `@Injectable` decorator. The `@Injectable` decorator takes a single parameter - the graph that should be used to resolve the dependencies. Declare the dependencies as class members and annotate them with the `@Inject` decorator.
|
|
113
|
+
|
|
114
|
+
```ts title="MyComponent.tsx"
|
|
115
|
+
import {Injectable, Inject} from 'react-obsidian';
|
|
116
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
117
|
+
|
|
118
|
+
@Injectable(ApplicationGraph)
|
|
119
|
+
export MyClassComponent extends React.Component {
|
|
120
|
+
@Inject() private fooService!: FooService;
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Render the injected component. Obsidian resolves the required dependencies automatically.
|
|
126
|
+
```tsx title="SomeComponent.tsx"
|
|
127
|
+
import MyComponent from './MyComponent';
|
|
128
|
+
|
|
129
|
+
const SomeComponent = () => {
|
|
130
|
+
// 4. Render the component - its dependencies are resolved automatically by Obsidian.
|
|
131
|
+
return <MyComponent />;
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
</TabItem>
|
|
136
|
+
<TabItem value="class" label="Class constructor injection">
|
|
137
|
+
|
|
138
|
+
To inject a class, annotate it with the `@Injectable` decorator. The `@Injectable` decorator takes a single parameter - the graph that should be used to resolve the dependencies.
|
|
139
|
+
Declare the dependencies as constructor parameters and annotate them with the `@Inject` decorator.
|
|
140
|
+
|
|
141
|
+
```ts title="MyClass.tsx"
|
|
142
|
+
import {Injectable, Inject} from 'react-obsidian';
|
|
143
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
144
|
+
|
|
145
|
+
@Injectable(ApplicationGraph)
|
|
146
|
+
export MyClass {
|
|
147
|
+
constructor (fooService?: FooService);
|
|
148
|
+
constructor(@Inject() private fooService: FooService) { }
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Now we can use the injected class without providing its dependencies manually:
|
|
153
|
+
```ts
|
|
154
|
+
const myClass = new MyClass();
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Of course, passing dependencies explicitly is still possible:
|
|
158
|
+
```ts
|
|
159
|
+
const myClass = new MyClass(new FooService());
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
</TabItem>
|
|
163
|
+
</Tabs>
|
|
164
|
+
|
|
165
|
+
___
|
|
166
|
+
|
|
167
|
+
## Features
|
|
168
|
+
|
|
169
|
+
* ⚛️ Inject all React constructs
|
|
170
|
+
* Functional components
|
|
171
|
+
* Hooks
|
|
172
|
+
* Class components
|
|
173
|
+
* 🛠 Improve code structure
|
|
174
|
+
* Easily write object-oriented code with Single Responsibility in mind
|
|
175
|
+
* Eliminate circular dependencies
|
|
176
|
+
* Avoid implicit dependencies to make your code easier to reason about
|
|
177
|
+
* ❤️ Developer experience
|
|
178
|
+
* Seamlessly integrates into existing projects
|
|
179
|
+
* Easy to adopt gradually
|
|
180
|
+
* Scales well
|
|
181
|
+
* Idiomatic API that's easy to understand
|
|
182
|
+
|
|
183
|
+
## Design principles
|
|
184
|
+
|
|
185
|
+
React Obsidian is guided by the principles of the Dependency Injection pattern, but does not strictly follow them. We allowed ourselves a degree of freedom when designing the library in order to reduce boilerplate code and library footprint.
|
|
186
|
+
|
|
187
|
+
* **Easy to start** - Obsidian requires very little code to get you started. Once you declare a graph, using it to inject dependencies requires as little as two lines of code.
|
|
188
|
+
* **Intuitive API** - The API should be verbose and understandable even to new users without prior experience with Dependency Injection.
|
|
189
|
+
* **Minimal boilerplate** - Require the bare minimum in order to construct dependencies and resolve them.
|
|
190
|
+
|
|
191
|
+
<!-- ## Comparison with other libraries -->
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 2
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Installation
|
|
6
|
+
|
|
7
|
+
Like most Dependency Injection frameworks, Obsidian uses automatic code generation to create the bindings necessary for resolving dependencies. This approach helps reduce the amount of boilerplate code required by developers. Obsidian relies on Babel for code generation, so you'll need to have Babel configured in your project.
|
|
8
|
+
|
|
9
|
+
## 1. Install Obsidian
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install react-obsidian
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 2. Install Reflect-metadata
|
|
16
|
+
First, install and enable the reflect-metadata polyfill.
|
|
17
|
+
```bash
|
|
18
|
+
npm install reflect-metadata
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then, add the following line to the top of your application's entry point (usually index.js or index.ts):
|
|
22
|
+
```js
|
|
23
|
+
import 'reflect-metadata';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 3. Enable experimental decorators
|
|
27
|
+
Obsidian uses the Decorators feature whose proposal is at stage 3.
|
|
28
|
+
|
|
29
|
+
Add the following options to your tsconfig.json file.
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
{
|
|
33
|
+
"compilerOptions": {
|
|
34
|
+
"experimentalDecorators": true,
|
|
35
|
+
"emitDecoratorMetadata": true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 4. Add the required Babel plugins
|
|
41
|
+
Add the transformer to the list of plugins in your `.babel` file.
|
|
42
|
+
|
|
43
|
+
```diff
|
|
44
|
+
module.exports = {
|
|
45
|
+
presets: [
|
|
46
|
+
'module:metro-react-native-babel-preset',
|
|
47
|
+
+ ['@babel/preset-typescript', {'onlyRemoveTypeImports': true}]
|
|
48
|
+
],
|
|
49
|
+
plugins: [
|
|
50
|
+
+ react-obsidian/dist/transformers/babel-plugin-obsidian,
|
|
51
|
+
+ ['@babel/plugin-proposal-decorators', {legacy: true}],
|
|
52
|
+
+ ['@babel/plugin-proposal-class-properties', { legacy: true }],
|
|
53
|
+
+ 'babel-plugin-parameter-decorator'
|
|
54
|
+
]
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 5. Jest
|
|
59
|
+
If you're using Jest, you'll need to add react-obsidian to [transformIgnorePatterns](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring) so it's transpiled before tests are executed.
|
|
60
|
+
|
|
61
|
+
## 6. Peer Dependencies
|
|
62
|
+
Obsidian has a peer dependency on `lodash`.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 2
|
|
3
|
+
title: "Clearing graphs"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Graphs can be cleared by invoking the `Obsidian.clearGraphs()` function. This is useful in tests or when you need to reset the system to it's original state, for example after a user logs out.
|
|
7
|
+
|
|
8
|
+
#### Clearing graphs automatically during execution of Jest tests
|
|
9
|
+
Create a `jest.setup.js` file and add it to [setupFilesAfterEnv](https://jestjs.io/docs/configuration#setupfilesafterenv-array). Then, import the following file when ensures graphs are cleared before each test.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import 'react-obsidian/clearGraphs';
|
|
13
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 1
|
|
3
|
+
title: "Graph middlewares"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Graph middlewares let you plug into the graph creation process and modify the graph in any way you want. This is useful when working on large scale applications where "observability" is a key concern. For example, you can use a middleware to swizzle providers, add logging, or even add a new provider to the graph.
|
|
7
|
+
|
|
8
|
+
Middleware follow the Chain of Responsibility pattern and therefore must always return a graph, either by creating one explicitly or by returning the instance created by another member in the resolve chain.
|
|
9
|
+
|
|
10
|
+
## Example: adding a logging middleware
|
|
11
|
+
The following example demonstrates how to add a middleware that's used for logging purposes.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { GraphMiddleware } from 'react-obsidian';
|
|
15
|
+
|
|
16
|
+
const loggingMiddleware = new class extends GraphMiddleware {
|
|
17
|
+
resolve<Props>(resolveChain: GraphResolveChain, Graph: Constructable<T>, props?: Props) {
|
|
18
|
+
const t1 = Date.now();
|
|
19
|
+
const graph = resolveChain.proceed(Graph, props);
|
|
20
|
+
const t2 = Date.now();
|
|
21
|
+
console.log(`Graph created in ${t2 - t1} milliseconds`);
|
|
22
|
+
return graph;
|
|
23
|
+
}
|
|
24
|
+
}();
|
|
25
|
+
|
|
26
|
+
Obsidian.addGraphMiddleware(loggingMiddleware);
|
|
27
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 4
|
|
3
|
+
title: "Class components"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Injecting class components
|
|
7
|
+
Injecting class components is a two step process. First, annotate the class with the `@Injectable` annotation and pass the graph from which dependencies should be resolve. Then, declare the dependencies as class members and annotate them with the `@Inject` annotation.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {Injectable, Inject} from 'react-obsidian';
|
|
11
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
12
|
+
|
|
13
|
+
@Injectable(ApplicationGraph)
|
|
14
|
+
export class ClassComponent extends React.Component {
|
|
15
|
+
@Inject() private httpClient!: HttpClient;
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 5
|
|
3
|
+
title: "Classes"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Injecting classes
|
|
7
|
+
Injecting classes is a two step process. First, annotate the class with the `@Injectable` annotation and pass the graph from which dependencies should be resolve. Then, declare the dependencies as class members and annotate them with the `@Inject` annotation.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {Injectable, Inject} from 'react-obsidian';
|
|
11
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
12
|
+
|
|
13
|
+
@Injectable(ApplicationGraph)
|
|
14
|
+
export class MyClass {
|
|
15
|
+
@Inject() private httpClient!: HttpClient;
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
:::important Always prefer constructor injection over field injection
|
|
21
|
+
Constructor injection is the preferred way to inject dependencies. It is more explicit and easier to test. **Field injection should only be used when a class is not instantiated by a graph.**
|
|
22
|
+
:::
|
|
23
|
+
|
|
24
|
+
## Lazy injection
|
|
25
|
+
Dependencies annotated with the `@Inject` annotation are resolved immediately **after** the constructor is called. If you want to inject a class at a later point in time, you can use the `@LazyInject` annotation instead, and inject the dependencies by manually with the `Obsidian.inject()` function.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import {Injectable, LazyInject} from 'react-obsidian';
|
|
29
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
30
|
+
|
|
31
|
+
@Injectable(ApplicationGraph)
|
|
32
|
+
export class MyClass {
|
|
33
|
+
@LazyInject() private httpClient!: HttpClient;
|
|
34
|
+
|
|
35
|
+
public init() {
|
|
36
|
+
console.log(this.httpClient === undefined); // true
|
|
37
|
+
Obsidian.inject(this);
|
|
38
|
+
console.log(this.httpClient === undefined); // false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 3
|
|
3
|
+
title: "Functional components"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Injecting functional components
|
|
7
|
+
Component injection is identical in principle to how hooks are injected. The only difference is that instead of using the `injectHook` function, you use the `injectComponent` function. The `injectComponent` function takes the same arguments as the `injectHook` function, except that it takes a component as the second argument instead of a hook.
|
|
8
|
+
|
|
9
|
+
```tsx title="Injecting a functional component"
|
|
10
|
+
import { injectComponent, DependenciesOf } from 'react-obsidian';
|
|
11
|
+
import { ApplicationGraph } from './ApplicationGraph';
|
|
12
|
+
|
|
13
|
+
const MyComponent = ({httpService}: DependenciesOf<ApplicationGraph, 'httpClient'>) => {
|
|
14
|
+
return <div>My component</div>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default injectComponent(MyComponent, ApplicationGraph);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
:::tip Prefer injecting hooks over components
|
|
21
|
+
Every entity (class, functional component etc.) in your application should have a single responsibility, and as such, there should be only one reason to change it. Components are responsible for rendering the UI, and therefor should change only when UI requirements change.
|
|
22
|
+
|
|
23
|
+
Prefer injecting hooks that will bridge between components and application logic. This allows components to emphasize "what" they need instead of "how", thus, preventing implementation details from leaking into them.
|
|
24
|
+
:::
|
|
25
|
+
|
|
26
|
+
## Strongly typed components
|
|
27
|
+
The `injectComponent` function leverages *generics* to correctly type injected components.
|
|
28
|
+
|
|
29
|
+
### Typing components that require props and injected dependencies
|
|
30
|
+
In cases where a component requires both props and injected dependencies, we recommend typing them separately and declaring the component's props as the intersection of the two types. This way the component returned by the `injectComponent` function will require its `Own` props while all `Injected` dependencies will be marked as optional. `Injected` dependencies are marked as optional because they can either be injected manually or automatically by Obsidian.
|
|
31
|
+
|
|
32
|
+
```tsx title="Separate declaration for passed (own) props and injected dependencies"
|
|
33
|
+
import { injectComponent, DependenciesOf } from 'react-obsidian';
|
|
34
|
+
import {ApplicationGraph} from './ApplicationGraph';
|
|
35
|
+
|
|
36
|
+
type Injected = DependenciesOf<ApplicationGraph, 'httpClient'>;
|
|
37
|
+
type Own = {name: string};
|
|
38
|
+
|
|
39
|
+
const MyComponent = ({name, httpService}: Own & Injected) => {
|
|
40
|
+
return <div>Hey, my name is: {name} 👋</div>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// The result type is React.FunctionComponent<{name: string , httpClient?: HttpClient}>
|
|
44
|
+
export default injectComponent<Own, Injected>(MyComponent, ApplicationGraph);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Typing components that don't require Props
|
|
48
|
+
If a component doesn't require any props from its parent component, simply use the `DependenciesOf` utility type provided by Obsidian to type the component's props. There's no need to use generics in this case as all props will are marked as optional.
|
|
49
|
+
|
|
50
|
+
```tsx title="Typing components that don't require props"
|
|
51
|
+
const MyComponent = ({httpService}: DependenciesOf<ApplicationGraph, 'httpClient'>) => {
|
|
52
|
+
return <div>Hello world 👋</div>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The result type is React.FunctionComponent<{httpClient?: HttpClient}>
|
|
56
|
+
export default injectComponent(MyComponent, ApplicationGraph);
|
|
57
|
+
```
|