@@ -5,296 +5,101 @@ _A semantic dependency injection framework_
5
5
[ ![ Build Status] ( https://travis-ci.org/LinkedSoftwareDependencies/Components.js.svg?branch=master )] ( https://travis-ci.org/LinkedSoftwareDependencies/Components.js )
6
6
[ ![ npm version] ( https://badge.fury.io/js/lsd-components.svg )] ( https://www.npmjs.com/package/lsd-components )
7
7
8
- ## Installation
8
+ This repository contains the source code of Components.js.
9
+ Full documentation on its usage can be found at http://componentsjs.readthedocs.io/ .
9
10
10
- ``` bash
11
- $ [sudo] npm install lsd-components
12
- ```
13
-
14
- ## Terminology
15
- A ** module** is equivalent to a ** Node module** and can contain several ** components** .
16
-
17
- A ** component** is either a ** class** or an ** instance** that can be respectively instantiated or retrieved.
18
- A ** class** can be instantiated by creating a new ** instance** of that type with zero or more ** parameter** values.
19
- ** Parameters** are defined by the class and its superclasses.
11
+ ## Introduction
20
12
21
- A ** component configuration** is a declarative instantiation of
22
- ** components** into ** instances** based on ** parameters** .
13
+ Components.js is a [ dependency injection] framework for JavaScript applications.
23
14
24
- ## Workflow
15
+ Instead of hard-wiring software components together, Components.js allows these components to be _ instantiated_ and _ wired together_ declaratively using _ semantic configuration files_ .
16
+ The advantage of these semantic configuration files is that software components can be uniquely and globally identified using [ URIs] .
25
17
26
- This framework provides the following workflow for injecting components .
18
+ Configurations can be written in any [ RDF ] serialization, such as [ JSON-LD ] .
27
19
28
- - Defining a Module
29
- - Defining a Component
30
- - Configuring a Component
31
- - Invoking a Component configuration
32
-
33
- This injection framework is based on RDF config files.
34
- The RDF serializations that are currently supported are JSON-LD, Turtle, TriG, N-Triples and N-Quads.
35
-
36
- ## Prefixes
37
-
38
- We use the following prefixes in the following examples:
39
- ```
40
- @prefix oo: <https://linkedsoftwaredependencies.org/vocabularies/object-oriented#>.
41
- @prefix om: <https://linkedsoftwaredependencies.org/vocabularies/object-mapping#>.
42
- @prefix doap: <http://usefulinc.com/ns/doap#>.
43
- ```
20
+ This software is aimed for developers who want to build _ modular_ and _ easily configurable_ and _ rewireable_ JavaScript applications.
44
21
45
- For the JSON-LD format, we provide a context for simplified config files:
46
- [ https://linkedsoftwaredependencies.org/contexts/components.jsonld ] ( https://linkedsoftwaredependencies.org/contexts/components.jsonld )
22
+ ## Quick Start
47
23
48
- ## Defining a Module
49
-
50
- Example:
51
- ```
52
- :SomeModule a oo:Module;
53
- doap:name "helloworld";
54
- oo:component :SomeModule#Component1.
24
+ Components.js can be installed using npm:
25
+ ``` bash
26
+ $ [sudo] npm install lsd-components
55
27
```
56
28
57
- ## Defining a Component
58
-
59
- A component is either a ** class** or an ** instance** .
60
- A ** class** can be instantiated into an ** instance** based on a set of parameters.
61
- An ** instance** can be used directly without instantiation.
62
-
63
- ### Defining a Component: Unmapped
64
-
65
- Parameter values will directly be sent to the constructor.
66
-
67
- Example:
68
- ```
69
- :SomeModule#Component1 a oo:Class;
70
- oo:componentPath "Hello";
71
- oo:parameter hello:say;
72
- oo:parameter hello:world.
73
- ```
29
+ #### 1. Define your module and its components
74
30
75
- In this case the ` Hello ` component will always receive a single object as argument like :
76
- ```
31
+ ` my-module.jsonld ` :
32
+ ``` json
77
33
{
78
- 'http://example.org/hello/say': 'Hello',
79
- 'http://example.org/hello/world': 'World'
34
+ "@context" : [
35
+ " https://linkedsoftwaredependencies.org/contexts/components.jsonld" ,
36
+ { "ex" : " http://example.org/" }
37
+ ],
38
+ "@id" : " ex:MyModule" ,
39
+ "@type" : " Module" ,
40
+ "requireName" : " my-module" ,
41
+ "components" : [
42
+ {
43
+ "@id" : " ex:MyModule/MyComponent" ,
44
+ "@type" : " Class" ,
45
+ "requireElement" : " MyComponent" ,
46
+ "parameters" : [
47
+ { "@id" : " ex:MyModule/MyComponent#name" , "unique" : true }
48
+ ],
49
+ "constructorArguments" : [
50
+ { "@id" : " ex:MyModule/MyComponent#name" }
51
+ ]
52
+ }
53
+ ]
80
54
}
81
55
```
82
56
83
- ### Defining a Component: Mapped
57
+ The npm module ` my-module ` exports a component with the name ` MyComponent ` .
84
58
85
- Parameter values will first be mapped to a configured parameter structure before being sent to the constructor .
59
+ The constructor of ` MyComponent ` takes a single ` name ` argument .
86
60
87
- Example:
88
- ```
89
- :SomeModule#Component1 a oo:Class;
90
- oo:componentPath "Hello";
91
- oo:parameter hello:say;
92
- oo:parameter hello:world;
93
- oo:constructorArguments (
94
- [
95
- rdf:value hello:say.
96
- ],
97
- [
98
- rdf:value hello:world.
99
- ]
100
- ).
101
- ```
102
- In this case the ` Hello ` component will receive two objects as arguments like:
103
- ```
104
- [
105
- 'Hello',
106
- 'World'
107
- ]
108
- ```
61
+ #### 2. Create a configuration file containing a component instantiation
109
62
110
- Each argument can be an ` om:ObjectMapping ` as follows:
111
- ```
112
- :SomeModule#Component1 a oo:Class;
113
- oo:componentPath "Hello";
114
- oo:parameter hello:say;
115
- oo:parameter hello:world;
116
- oo:constructorArguments (
117
- [
118
- om:field [
119
- om:fieldName "say",
120
- om:fieldValue hello:say.
121
- ];
122
- om:field [
123
- om:fieldName "world",
124
- om:fieldValue hello:world.
125
- ];
126
- ],
127
- [
128
- om:fieldValue hello:world.
129
- ]
130
- ).
131
- ```
132
- In this case the ` Hello ` component will receive two object as arguments like:
133
- ```
134
- [
63
+ ` config-my-component.jsonld ` :
64
+ ``` json
65
+ {
66
+ "@context" : [
67
+ " https://linkedsoftwaredependencies.org/contexts/components.jsonld" ,
135
68
{
136
- 'say': 'Hello',
137
- 'world': 'World'
138
- },
139
- 'World'
140
- ]
141
- ```
142
-
143
- ## Configuring a Component
144
-
145
- If a component definition exists (the component is _ named_ ), parameter predicates are defined and can be used.
146
- If no such definition exists (the component is _ unnamed_ ), the constructor arguments must be provided in the configuration.
147
-
148
- ### Configuring a Component: Named
149
-
150
- When a component definition exists, parameter predicates can be used to fill in the parameters.
151
-
152
- Example:
153
- ```
154
- :myComponent a :SomeModule#Component1;
155
- hello:say "Hello";
156
- hello:world "World".
157
- ```
158
-
159
- ### Configuring a Component: Unnamed
160
-
161
- When a component definition does not exists, constructor arguments can be filled in manually using the ` oo:arguments ` predicate.
162
- The NPM module name and the component element path must be provided as well.
163
-
164
- Example:
165
- ```
166
- :myComponent a :SomeModule#Component1;
167
- doap:name "helloworld",
168
- oo:componentPath "Hello",
169
- oo:arguments (
170
- [
171
- om:fieldValue "SAY".
172
- ],
173
- [
174
- om:fieldValue "WORLD".
175
- ]
176
- ).
177
- ```
178
-
179
- Each argument can be an ` om:ObjectMapping ` as follows:
180
- ```
181
- :myComponent a :SomeModule#Component1;
182
- doap:name "helloworld",
183
- oo:componentPath "Hello",
184
- oo:arguments (
185
- [
186
- om:field [
187
- om:fieldName "say",
188
- om:fieldValue "SAY".
189
- ];
190
- om:field [
191
- om:fieldName "world",
192
- om:fieldValue "WORLD".
193
- ];
194
- ],
195
- [
196
- om:fieldValue "WORLD".
197
- ]
198
- ).
199
- ```
200
-
201
- ## Invoking a Component configuration
202
-
203
- Components can be constructed in code based on an RDF document, triple stream or by manually passing parameters.
204
-
205
- First, a stream containing modules and components must be registered to the Loader.
206
- After that, either a component config URI with a config stream must be passed,
207
- or a component URI with a set of manual parameters.
208
-
209
- ### from an RDF document
210
- ``` javascript
211
- const Loader = require (' lsd-components' ).Loader ;
212
-
213
- let loader = new Loader ();
214
- loader .registerModuleResourcesUrl (' module-hello-world.jsonld' )
215
- .then (() => loader .instantiateFromUrl (' http://example.org/myHelloWorld' , ' config-hello-world.jsonld' ))
216
- .then ((helloWorld ) => helloWorld .run ());
217
- ```
218
-
219
- ### from a triple stream
220
- ``` javascript
221
- const Loader = require (' lsd-components' ).Loader ;
222
- const JsonLdStreamParser = require (' lsd-components' ).JsonLdStreamParser ;
223
-
224
- let loader = new Loader ();
225
- let moduleStream = fs .createReadStream (' module-hello-world.jsonld' ).pipe (new JsonLdStreamParser ());
226
- let configStream = fs .createReadStream (' config-hello-world.jsonld' ).pipe (new JsonLdStreamParser ());
227
- loader .registerModuleResourcesUrl (' module-hello-world.jsonld' )
228
- .then (() => loader .runConfigStream (' http://example.org/myHelloWorld' , configStream))
229
- .then ((helloWorld ) => helloWorld .run ());
69
+ "ex" : " http://example.org/" ,
70
+ "name" : " ex:MyModule/MyComponent#name"
71
+ }
72
+ ],
73
+ "@id" : " http://example.org/myInstance" ,
74
+ "@type" : " ex:MyModule/MyComponent" ,
75
+ "name" : " John"
76
+ }
230
77
```
231
78
232
- ### manually
233
- ``` javascript
234
- const Loader = require (' lsd-components' ).Loader ;
235
- const JsonLdStreamParser = require (' lsd-components' ).JsonLdStreamParser ;
236
-
237
- let loader = new Loader ();
238
- let moduleStream = fs .createReadStream (' module-hello-world.jsonld' ).pipe (new JsonLdStreamParser ());
239
- let params = {};
240
- params[' http://example.org/hello/hello' ] = ' WORLD' ;
241
- params[' http://example.org/hello/say' ] = ' BONJOUR' ;
242
- params[' http://example.org/hello/bla' ] = ' BLA' ;
243
- loader .registerModuleResourcesStream (moduleStream)
244
- .then (() => loader .runManually (' http://example.org/HelloWorldModule#SayHelloComponent' , params))
245
- .then ((helloWorld ) => helloWorld .run ());
246
- ```
79
+ This configuration is a semantic representation of the instantiation of ` MyComponent ` with ` name ` set to ` "John" ` .
247
80
248
- ### Module scanning
249
- Instead of loading module resources manually,
250
- the current node module and its dependencies can be scanned automatically for modules.
81
+ #### 3. Instantiate your component programmatically
251
82
252
83
``` javascript
84
+ ...
253
85
const Loader = require (' lsd-components' ).Loader ;
254
86
255
- let loader = new Loader ();
256
- loader .registerAvailableModuleResources ()
257
- .then (() => loader .instantiateFromUrl (' http://example.org/myHelloWorld' , ' config-hello-world.jsonld' ))
258
- .then ((helloWorld ) => helloWorld .run ());
87
+ const loader = new Loader ();
88
+ await loader .registerModuleResourcesUrl (' path/or/url/to/my-module.jsonld' );
89
+ const myComponent = await loader .instantiateFromUrl (
90
+ ' http://example.org/myInstance' , ' path/or/url/to/config-my-component.jsonld' );
91
+ ...
259
92
```
260
93
261
- If global modules should also be scanned, the ` scanGlobal ` flag
262
- in the ` Loader ` constructor can be set to ` true ` , as follows: ` new Loader({ scanGlobal: true }) `
263
-
264
- ## Exposing Modules and Components
265
-
266
- Once a module and its components have been defined,
267
- they can be exposed through Node's package.json.
268
- The ` lsd:module ` entry is used to refer to the module URI.
269
- The ` lsd:components ` entry is used to refer to the components file path relative to the module root.
94
+ ` myComponent ` is an instance of type ` MyComponent ` , as defined in the config file.
270
95
271
- An example package.json could look as follows:
272
- ``` json
273
- {
274
- "name" : " my-module" ,
275
- "description" : " My Module" ,
276
- "version" : " 1.0.0" ,
277
- "lsd:module" : " https://linkedsoftwaredependencies.org/bundles/npm/my-module" ,
278
- "lsd:components" : " components/my-components.jsonld"
279
- }
280
- ```
281
-
282
- Additionally, JSON-LD context files can be defined in the package.json.
283
- When this is done, users that refer to JSON-LD contexts,
284
- will use the predefined contexts instead of fetching them over HTTP.
285
- For example:
286
- ``` json
287
- {
288
- "name" : " my-module" ,
289
- "description" : " My Module" ,
290
- "version" : " 1.0.0" ,
291
- "lsd:module" : " https://linkedsoftwaredependencies.org/bundles/npm/my-module" ,
292
- "lsd:components" : " components/my-components.jsonld" ,
293
- "lsd:contexts" : {
294
- "https://example.org/context.jsonld" : " contexts/my-context.jsonld"
295
- }
296
- }
297
- ```
96
+ [ Components.js ] : https://github.com/LinkedSoftwareDependencies/Components.js
97
+ [ GitHub ] : https://github.com/LinkedSoftwareDependencies/Documentation-Components.js
98
+ [ dependency injection ] : https://martinfowler.com/articles/injection.html
99
+ [ Node.js ] : https://nodejs.org/en/
100
+ [ URIs ] : https://www.w3.org/wiki/URI
101
+ [ RDF ] : https://www.w3.org/RDF/
102
+ [ JSON-LD ] : https://json-ld.org/
298
103
299
104
## License
300
105
Components.js is written by [ Ruben Taelman] ( http://www.rubensworks.net/ ) .
0 commit comments