@superhero/core 1.8.5 → 4.0.0-beta.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/README.md +108 -739
- package/index.js +654 -54
- package/index.test.js +94 -0
- package/package.json +17 -31
- package/worker.js +12 -0
- package/LICENCE +0 -20
- package/bootstrap/config.js +0 -7
- package/bootstrap/index.js +0 -19
- package/bootstrap/locator.js +0 -16
- package/cli/config.js +0 -7
- package/cli/index.js +0 -49
- package/cli/locator.js +0 -17
- package/composer/bootstrap/error/schema-not-resolvable.js +0 -10
- package/composer/bootstrap/index.js +0 -62
- package/composer/bootstrap/locator.js +0 -20
- package/composer/config.js +0 -49
- package/composer/error/filter-is-not-honering-contract.js +0 -13
- package/composer/error/invalid-attribute.js +0 -13
- package/composer/error/invalid-collection.js +0 -13
- package/composer/error/invalid-schema.js +0 -13
- package/composer/error/schema-not-found.js +0 -13
- package/composer/error/validator-is-not-honering-contract.js +0 -13
- package/composer/error/validator-not-found.js +0 -13
- package/composer/filter/boolean/index.js +0 -44
- package/composer/filter/boolean/locator.js +0 -11
- package/composer/filter/decimal/index.js +0 -38
- package/composer/filter/decimal/locator.js +0 -11
- package/composer/filter/index.js +0 -10
- package/composer/filter/integer/index.js +0 -38
- package/composer/filter/integer/locator.js +0 -11
- package/composer/filter/json/index.js +0 -23
- package/composer/filter/json/locator.js +0 -11
- package/composer/filter/schema/error/missing-schema-definition.js +0 -13
- package/composer/filter/schema/index.js +0 -49
- package/composer/filter/schema/locator.js +0 -17
- package/composer/filter/string/index.js +0 -50
- package/composer/filter/string/locator.js +0 -11
- package/composer/filter/timestamp/index.js +0 -45
- package/composer/filter/timestamp/locator.js +0 -11
- package/composer/index.js +0 -180
- package/composer/locator.js +0 -17
- package/composer/validator/boolean/error/invalid.js +0 -13
- package/composer/validator/boolean/index.js +0 -17
- package/composer/validator/boolean/locator.js +0 -11
- package/composer/validator/decimal/error/invalid.js +0 -13
- package/composer/validator/decimal/index.js +0 -59
- package/composer/validator/decimal/locator.js +0 -11
- package/composer/validator/index.js +0 -10
- package/composer/validator/integer/error/invalid.js +0 -13
- package/composer/validator/integer/index.js +0 -65
- package/composer/validator/integer/locator.js +0 -11
- package/composer/validator/json/error/invalid.js +0 -13
- package/composer/validator/json/index.js +0 -23
- package/composer/validator/json/locator.js +0 -11
- package/composer/validator/schema/error/invalid.js +0 -13
- package/composer/validator/schema/index.js +0 -13
- package/composer/validator/schema/locator.js +0 -11
- package/composer/validator/string/error/invalid.js +0 -13
- package/composer/validator/string/index.js +0 -59
- package/composer/validator/string/locator.js +0 -11
- package/composer/validator/timestamp/error/invalid.js +0 -13
- package/composer/validator/timestamp/index.js +0 -54
- package/composer/validator/timestamp/locator.js +0 -11
- package/configuration/config.js +0 -7
- package/configuration/index.js +0 -23
- package/configuration/locator.js +0 -22
- package/console/config.js +0 -15
- package/console/index.js +0 -23
- package/console/locator.js +0 -21
- package/console/observer/error/config.js +0 -7
- package/console/observer/error/index.js +0 -14
- package/console/observer/error/locator.js +0 -17
- package/console/observer/info/config.js +0 -7
- package/console/observer/info/index.js +0 -14
- package/console/observer/info/locator.js +0 -17
- package/console/observer/warning/config.js +0 -7
- package/console/observer/warning/index.js +0 -14
- package/console/observer/warning/locator.js +0 -17
- package/core/config.js +0 -21
- package/core/error.js +0 -10
- package/deepcopy/config.js +0 -7
- package/deepcopy/error/failed-to-fast-copy.js +0 -10
- package/deepcopy/index.js +0 -18
- package/deepcopy/locator.js +0 -11
- package/deepfind/config.js +0 -7
- package/deepfind/index.js +0 -11
- package/deepfind/locator.js +0 -11
- package/deepfreeze/config.js +0 -7
- package/deepfreeze/index.js +0 -20
- package/deepfreeze/locator.js +0 -11
- package/deepmerge/config.js +0 -7
- package/deepmerge/index.js +0 -42
- package/deepmerge/locator.js +0 -11
- package/eventbus/bootstrap/error/observer-contract-not-honered.js +0 -10
- package/eventbus/bootstrap/index.js +0 -33
- package/eventbus/bootstrap/locator.js +0 -20
- package/eventbus/config.js +0 -17
- package/eventbus/index.js +0 -21
- package/eventbus/locator.js +0 -25
- package/eventbus/observer.js +0 -9
- package/factory.js +0 -55
- package/http/request/config.js +0 -7
- package/http/request/locator.js +0 -21
- package/http/server/config.js +0 -23
- package/http/server/dispatcher/chain/error/dispatcher-chain-ended.js +0 -10
- package/http/server/dispatcher/chain/index.js +0 -41
- package/http/server/dispatcher/chain/locator.js +0 -20
- package/http/server/dispatcher/collection/builder/error/dispatcher-can-not-be-resolved.js +0 -10
- package/http/server/dispatcher/collection/builder/error/not-honering-dispatcher-contract.js +0 -10
- package/http/server/dispatcher/collection/builder/index.js +0 -56
- package/http/server/dispatcher/collection/builder/locator.js +0 -20
- package/http/server/dispatcher/error/bad-gateway.js +0 -12
- package/http/server/dispatcher/error/bad-request.js +0 -12
- package/http/server/dispatcher/error/conflict.js +0 -12
- package/http/server/dispatcher/error/forbidden.js +0 -12
- package/http/server/dispatcher/error/gateway-timeout.js +0 -12
- package/http/server/dispatcher/error/index.js +0 -10
- package/http/server/dispatcher/error/method-not-allowed.js +0 -12
- package/http/server/dispatcher/error/not-implemented.js +0 -12
- package/http/server/dispatcher/error/page-not-found.js +0 -12
- package/http/server/dispatcher/error/request-timeout.js +0 -12
- package/http/server/dispatcher/error/server-error.js +0 -12
- package/http/server/dispatcher/error/service-unavailable.js +0 -12
- package/http/server/dispatcher/error/unauthorized.js +0 -12
- package/http/server/dispatcher/index.js +0 -26
- package/http/server/dispatcher/rest.js +0 -75
- package/http/server/error/no-endpoint-defined-in-route.js +0 -10
- package/http/server/error/view-contract-not-honered.js +0 -10
- package/http/server/index.js +0 -195
- package/http/server/locator.js +0 -34
- package/http/server/request/builder/index.js +0 -53
- package/http/server/request/builder/locator.js +0 -20
- package/http/server/route/builder/error/dto-invalid-reference.js +0 -10
- package/http/server/route/builder/error/routes-invalid-type.js +0 -10
- package/http/server/route/builder/index.js +0 -88
- package/http/server/route/builder/locator.js +0 -20
- package/http/server/session/builder/index.js +0 -34
- package/http/server/session/builder/locator.js +0 -11
- package/http/server/view/index.js +0 -12
- package/http/server/view/json/index.js +0 -17
- package/http/server/view/json/locator.js +0 -11
- package/http/server/view/locator.js +0 -11
- package/http/server/view/stream/index.js +0 -10
- package/http/server/view/stream/locator.js +0 -11
- package/http/server/view/text/index.js +0 -15
- package/http/server/view/text/locator.js +0 -11
- package/locator/constituent.js +0 -26
- package/locator/error/locator-not-implemented.js +0 -10
- package/locator/error/service-undefined.js +0 -10
- package/locator/index.js +0 -29
- package/path/config.js +0 -7
- package/path/index.js +0 -63
- package/path/locator.js +0 -11
- package/process/bootstrap/index.js +0 -31
- package/process/bootstrap/locator.js +0 -17
- package/process/config.js +0 -12
- package/process/index.js +0 -9
- package/process/locator.js +0 -11
- package/test/api/config.js +0 -43
- package/test/api/endpoint/append-calculation.js +0 -41
- package/test/api/endpoint/create-calculation.js +0 -18
- package/test/api/middleware/authentication.js +0 -27
- package/test/calculator/calculation.js +0 -29
- package/test/calculator/config.js +0 -14
- package/test/calculator/error/calculation-could-not-be-found.js +0 -13
- package/test/calculator/error/invalid-calculation-type.js +0 -13
- package/test/calculator/index.js +0 -67
- package/test/calculator/locator.js +0 -20
- package/test/init.js +0 -2
- package/test/logger/config.js +0 -15
- package/test/logger/index.js +0 -17
- package/test/logger/locator.js +0 -20
- package/test/mocha.opts +0 -4
- package/test/test.calculation.js +0 -58
- package/test/test.logger.js +0 -35
package/README.md
CHANGED
|
@@ -1,813 +1,182 @@
|
|
|
1
|
-
# Core
|
|
2
|
-
|
|
3
|
-
Licence: [MIT](https://opensource.org/licenses/MIT)
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
[](https://badge.fury.io/js/%40superhero%2Fcore)
|
|
8
|
-
|
|
9
|
-
- A core framework I use when developing in [nodejs](https://nodejs.org/en/docs/).
|
|
10
|
-
- I built the framework to help me build applications after a reactive [domain driven design (DDD)](https://en.wikipedia.org/wiki/Domain-driven_design) approch.
|
|
11
|
-
- The framework is designed to have little to no production dependencies.
|
|
12
|
-
- The framework offers solutions for different topics, not necessarily an http server.
|
|
13
|
-
- The vision of the framework is to offer a code structure to the developer that will help segregate responsibilities in projects through a [SOLID](https://en.wikipedia.org/wiki/SOLID) [OOP](https://en.wikipedia.org/wiki/Object-oriented_programming) approach.
|
|
14
|
-
|
|
15
|
-
## Addons
|
|
16
|
-
|
|
17
|
-
Consider extending the framework with one or multiple plugins where the extra functionality is required:
|
|
18
|
-
*Please note; you should use matching versions for core and the plugins by major and future releases*
|
|
19
|
-
|
|
20
|
-
- [core-handlebars](http://github.com/superhero/js.core.handlebars)
|
|
21
|
-
- [core-resource](http://github.com/superhero/js.core.resource)
|
|
22
|
-
- [core-websocket](http://github.com/superhero/js.core.websocket)
|
|
23
|
-
|
|
24
|
-
## Install
|
|
25
|
-
|
|
26
|
-
`npm install @superhero/core`
|
|
27
|
-
|
|
28
|
-
...or just set the dependency in your `package.json` file:
|
|
29
|
-
|
|
30
|
-
```json
|
|
31
|
-
{
|
|
32
|
-
"dependencies":
|
|
33
|
-
{
|
|
34
|
-
"@superhero/core": "*"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Example Application
|
|
40
|
-
|
|
41
|
-
An example application to get started, covering some recommended "best practices" regarding testing and docs generation.
|
|
42
|
-
|
|
43
|
-
The application is a calculator with very basic functionality. The aim with this application is not to make a good calculator. The aim is to show you, who is reading this, how different parts of the framework works, or are intended to work.
|
|
44
|
-
|
|
45
|
-
### Example Application › File structure
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
super-duper-app
|
|
49
|
-
├── docs
|
|
50
|
-
├── src
|
|
51
|
-
│ ├── api
|
|
52
|
-
│ │ ├── endpoint
|
|
53
|
-
│ │ │ ├── append-calculation.js
|
|
54
|
-
│ │ │ └── create-calculation.js
|
|
55
|
-
│ │ ├── middleware
|
|
56
|
-
│ │ │ └── authentication.js
|
|
57
|
-
│ │ └── config.js
|
|
58
|
-
│ ├── calculator
|
|
59
|
-
│ │ ├── error
|
|
60
|
-
│ │ | ├── calculation-could-not-be-found.js
|
|
61
|
-
│ │ | └── invalid-calculation-type.js
|
|
62
|
-
│ │ ├── calculation.js
|
|
63
|
-
│ │ ├── config.js
|
|
64
|
-
│ │ ├── index.js
|
|
65
|
-
│ │ └── locator.js
|
|
66
|
-
│ ├── logger
|
|
67
|
-
│ │ ├── config.js
|
|
68
|
-
│ │ ├── index.js
|
|
69
|
-
│ │ └── locator.js
|
|
70
|
-
│ └── index.js
|
|
71
|
-
├── test
|
|
72
|
-
│ ├── init.js
|
|
73
|
-
│ ├── mocha.opts
|
|
74
|
-
│ ├── test.calculations.js
|
|
75
|
-
│ └── test.logger.js
|
|
76
|
-
├── .gitignore
|
|
77
|
-
├── package.json
|
|
78
|
-
└── README.md
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
The file structure is here divided to only 3 modules
|
|
82
|
-
|
|
83
|
-
- One called `api` *- that's responsible for the endpoints.*
|
|
84
|
-
- A second one called `calculator` *- that is responsible for domain logic.*
|
|
85
|
-
- The third one called `logger` *- an infrastructure layer that will log events to the console.*
|
|
86
|
-
|
|
87
|
-
#### `.gitignore`
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
docs/generated
|
|
91
|
-
npm-debug.log
|
|
92
|
-
node_modules
|
|
93
|
-
package-lock.json
|
|
94
|
-
.nyc_output
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Set up a `.gitignore` file to ignore some auto-generated files to keep a clean repository.
|
|
98
|
-
|
|
99
|
-
#### `package.json`
|
|
100
|
-
|
|
101
|
-
```js
|
|
102
|
-
{
|
|
103
|
-
"name": "Super Duper App",
|
|
104
|
-
"version": "0.0.1",
|
|
105
|
-
"description": "An example application of the superhero/core framework",
|
|
106
|
-
"repository": "https://github.com/...",
|
|
107
|
-
"license": "MIT",
|
|
108
|
-
"main": "src/index.js",
|
|
109
|
-
"author": {
|
|
110
|
-
"name": "Padawan",
|
|
111
|
-
"email": "padawan@example.com"
|
|
112
|
-
},
|
|
113
|
-
"scripts": {
|
|
114
|
-
"docs-coverage": "nyc mocha './test/test.*.js' --opts ./test/mocha.opts && nyc report --reporter=html --report-dir=./docs/generated/coverage",
|
|
115
|
-
"docs-tests": "mocha './test/test.*.js' --opts ./test/mocha.opts --reporter mochawesome --reporter-options reportDir=docs/generated/test,reportFilename=index,showHooks=always",
|
|
116
|
-
"test": "nyc mocha './test/test.*.js' --opts ./test/mocha.opts",
|
|
117
|
-
"start": "node ./src/index.js"
|
|
118
|
-
},
|
|
119
|
-
"dependencies": {
|
|
120
|
-
"@superhero/core": "*"
|
|
121
|
-
},
|
|
122
|
-
"devDependencies": {
|
|
123
|
-
"mocha": "5.1.0",
|
|
124
|
-
"mochawesome": "3.0.2",
|
|
125
|
-
"chai": "4.1.2",
|
|
126
|
-
"nyc": "11.7.1"
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Our [`package.json`](https://docs.npmjs.com/files/package.json) file will dictate what dependencies we use. This example application will go through test cases, why we have a few `devDependencies` defined.
|
|
132
|
-
|
|
133
|
-
#### `index.js`
|
|
134
|
-
|
|
135
|
-
```js
|
|
136
|
-
const
|
|
137
|
-
CoreFactory = require('@superhero/core/factory'),
|
|
138
|
-
coreFactory = new CoreFactory,
|
|
139
|
-
core = coreFactory.create()
|
|
140
|
-
|
|
141
|
-
core.add('api')
|
|
142
|
-
core.add('calculator')
|
|
143
|
-
core.add('logger')
|
|
144
|
-
core.add('http/server')
|
|
145
|
-
|
|
146
|
-
core.load()
|
|
147
|
-
|
|
148
|
-
core.locate('bootstrap').bootstrap().then(() =>
|
|
149
|
-
core.locate('http/server').listen(process.env.HTTP_PORT))
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
We start of by creating a core factory that will create the core object, central to our application. The core is designed to keep track of a global state related to it's context. You can create multiple cores if necessary, but normally it makes sens to only use one. This example will only use one core.
|
|
153
|
-
|
|
154
|
-
The next step is to add services that we will use in relation to the core context. Here we add `api` and `calculator` that exists in the file tree previously defined. You also notice that we add the service `http/server` that does not exist in the file tree we defined. The `http/server` service is located in the core, but may not always be necessary to load depending on the scope of your application, so you need to add the `http/server` service when you want to set up an http server.
|
|
155
|
-
The framework will try to add services depending on a hierarchy of paths.
|
|
156
|
-
|
|
157
|
-
- First it will try to load in relation to your `main script`
|
|
158
|
-
- next it attempts by dependency defined in your `package.json` file
|
|
159
|
-
- and finally it will attempt to load related to the core library of existing services.
|
|
160
|
-
|
|
161
|
-
*This hierarchy allows you, as a developer, to overwrite anything in the framework with custom logic.*
|
|
162
|
-
|
|
163
|
-
Next we load the core! This will eager load all the services previously added to the context.
|
|
164
|
-
|
|
165
|
-
By bootstrapping the core, we run a few scripts that needs to run for some modules to function properly. As a developer you can hook into this process in the modules you write.
|
|
166
|
-
|
|
167
|
-
And in the end, after we have added, loaded and bootstrapped the modules related to the context, we tell the server to listen to a specific port for network activity.
|
|
168
|
-
|
|
169
|
-
### Api
|
|
170
1
|
|
|
171
|
-
|
|
2
|
+
# Core
|
|
172
3
|
|
|
173
|
-
|
|
174
|
-
module.exports =
|
|
175
|
-
{
|
|
176
|
-
http:
|
|
177
|
-
{
|
|
178
|
-
server:
|
|
179
|
-
{
|
|
180
|
-
routes:
|
|
181
|
-
{
|
|
182
|
-
'create-calculation':
|
|
183
|
-
{
|
|
184
|
-
url : '/calculations',
|
|
185
|
-
method : 'post',
|
|
186
|
-
endpoint: 'api/endpoint/create-calculation',
|
|
187
|
-
view : 'http/server/view/json'
|
|
188
|
-
},
|
|
189
|
-
'authentication':
|
|
190
|
-
{
|
|
191
|
-
middleware :
|
|
192
|
-
[
|
|
193
|
-
'api/middleware/authentication'
|
|
194
|
-
]
|
|
195
|
-
},
|
|
196
|
-
'append-calculation':
|
|
197
|
-
{
|
|
198
|
-
url : '/calculations/.+',
|
|
199
|
-
method : 'put',
|
|
200
|
-
endpoint: 'api/endpoint/append-calculation',
|
|
201
|
-
view : 'http/server/view/json',
|
|
202
|
-
dto :
|
|
203
|
-
{
|
|
204
|
-
'id' : { 'url' : 2 },
|
|
205
|
-
'type' : { 'body' : 'type' },
|
|
206
|
-
'value' : { 'body' : 'value' }
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
authentication:
|
|
213
|
-
{
|
|
214
|
-
apikey : 'ABC123456789'
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
```
|
|
4
|
+
A framework designed to support application clustering, configuration management, and service location.
|
|
218
5
|
|
|
219
|
-
|
|
6
|
+
### OBS!
|
|
220
7
|
|
|
221
|
-
|
|
8
|
+
_Current version is in beta release_
|
|
222
9
|
|
|
223
|
-
|
|
224
|
-
- The **method** attribute declares on what **url method** the route will be valid for
|
|
10
|
+
---
|
|
225
11
|
|
|
226
|
-
|
|
12
|
+
## Features
|
|
227
13
|
|
|
228
|
-
|
|
14
|
+
- **Cluster Support**: Scale horizontally using the `cluster` module with worker management.
|
|
15
|
+
- **Graceful Shutdown**: Handles system signals (`SIGINT`, `SIGTERM`) and unexpected errors (`unhandledRejection`, `uncaughtException`) to support a graceful shutdown.
|
|
16
|
+
- **Service Locator**: Locate and initialize services based on configuration.
|
|
17
|
+
- **Bootstrap Support**: Initialize resources and services based on configurations.
|
|
18
|
+
- **Configuration Manager**: Manage configurations for different environments or branches.
|
|
229
19
|
|
|
230
|
-
|
|
231
|
-
const Dispatcher = require('@superhero/core/http/server/dispatcher')
|
|
20
|
+
---
|
|
232
21
|
|
|
233
|
-
|
|
234
|
-
* @extends {@superhero/core/http/server/dispatcher}
|
|
235
|
-
*/
|
|
236
|
-
class CreateCalculationEndpoint extends Dispatcher
|
|
237
|
-
{
|
|
238
|
-
dispatch()
|
|
239
|
-
{
|
|
240
|
-
const
|
|
241
|
-
calculator = this.locator.locate('calculator'),
|
|
242
|
-
calculationId = calculator.createCalculation()
|
|
243
|
-
|
|
244
|
-
this.view.body.id = calculationId
|
|
245
|
-
}
|
|
246
|
-
}
|
|
22
|
+
## Installation
|
|
247
23
|
|
|
248
|
-
|
|
24
|
+
```bash
|
|
25
|
+
npm install @superhero/core
|
|
249
26
|
```
|
|
250
27
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
- First we locate the `calculator` service.
|
|
254
|
-
- Next we create a calculation
|
|
255
|
-
- And finally we populate the `view model` with the returning calculation id
|
|
256
|
-
|
|
257
|
-
***OBS! it's possible to define the `dispatch` method as `async`. The framework will `await` for the method to finish***
|
|
258
|
-
|
|
259
|
-
#### `src/api/endpoint/append-calculation.js`
|
|
260
|
-
|
|
261
|
-
```js
|
|
262
|
-
const
|
|
263
|
-
Dispatcher = require('@superhero/core/http/server/dispatcher'),
|
|
264
|
-
PageNotFoundError = require('@superhero/core/http/server/dispatcher/error/page-not-found'),
|
|
265
|
-
BadRequestError = require('@superhero/core/http/server/dispatcher/error/bad-request')
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* @extends {@superhero/core/http/server/dispatcher}
|
|
269
|
-
*/
|
|
270
|
-
class AppendCalculationEndpoint extends Dispatcher
|
|
271
|
-
{
|
|
272
|
-
dispatch()
|
|
273
|
-
{
|
|
274
|
-
const
|
|
275
|
-
calculator = this.locator.locate('calculator'),
|
|
276
|
-
composer = this.locator.locate('composer'),
|
|
277
|
-
calculation = composer.compose('calculation', this.route.dto),
|
|
278
|
-
result = calculator.appendToCalculation(calculation)
|
|
279
|
-
|
|
280
|
-
this.view.body.result = result
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
onError(error)
|
|
284
|
-
{
|
|
285
|
-
switch(error)
|
|
286
|
-
{
|
|
287
|
-
case 'E_CALCULATION_COULD_NOT_BE_FOUND':
|
|
288
|
-
throw new PageNotFoundError('Calculation could not be found')
|
|
289
|
-
|
|
290
|
-
case 'E_INVALID_CALCULATION_TYPE':
|
|
291
|
-
throw new BadRequestError(`Unrecognized type: "${this.route.dto.type}"`)
|
|
292
|
-
|
|
293
|
-
case 'E_COMPOSER_INVALID_ATTRIBUTE':
|
|
294
|
-
throw new BadRequestError(error.message)
|
|
295
|
-
|
|
296
|
-
default:
|
|
297
|
-
throw error
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
28
|
+
---
|
|
301
29
|
|
|
302
|
-
|
|
303
|
-
```
|
|
30
|
+
## Usage
|
|
304
31
|
|
|
305
|
-
|
|
32
|
+
### Basic Example
|
|
306
33
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
- Followed by appending a calculation to the stored calculated sum.
|
|
310
|
-
- And finally we populate the `view model` with the result of the calculation.
|
|
34
|
+
```javascript
|
|
35
|
+
import Core from '@superhero/core'
|
|
311
36
|
|
|
312
|
-
|
|
37
|
+
const core = new Core()
|
|
313
38
|
|
|
314
|
-
|
|
39
|
+
// Add configuration paths
|
|
40
|
+
await core.add('./path/to/config.json')
|
|
315
41
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
Dispatcher = require('@superhero/core/http/server/dispatcher'),
|
|
319
|
-
Unauthorized = require('@superhero/core/http/server/dispatcher/error/unauthorized')
|
|
42
|
+
// Bootstrap core
|
|
43
|
+
await core.bootstrap()
|
|
320
44
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
class AuthenticationMiddleware extends Dispatcher
|
|
325
|
-
{
|
|
326
|
-
async dispatch(next)
|
|
327
|
-
{
|
|
328
|
-
const
|
|
329
|
-
configuration = this.locator.locate('configuration'),
|
|
330
|
-
apikey = this.request.headers['api-key']
|
|
331
|
-
|
|
332
|
-
if(apikey === configuration.find('authentication.apikey'))
|
|
333
|
-
{
|
|
334
|
-
await next()
|
|
335
|
-
}
|
|
336
|
-
else
|
|
337
|
-
{
|
|
338
|
-
throw new Unauthorized('You are not authorized to access the requested resource')
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
45
|
+
// Locate a service
|
|
46
|
+
const myService = core.locate('myService')
|
|
47
|
+
console.log(myService)
|
|
342
48
|
|
|
343
|
-
|
|
49
|
+
// Graceful shutdown
|
|
50
|
+
await core.destruct()
|
|
344
51
|
```
|
|
345
52
|
|
|
346
|
-
|
|
53
|
+
### Clustering Example
|
|
347
54
|
|
|
348
|
-
|
|
55
|
+
```javascript
|
|
56
|
+
import Core from '@superhero/core'
|
|
349
57
|
|
|
350
|
-
|
|
351
|
-
Middleware
|
|
352
|
-
↓ ↑
|
|
353
|
-
Middleware
|
|
354
|
-
↓ ↑
|
|
355
|
-
Endpoint
|
|
356
|
-
```
|
|
58
|
+
const core = new Core()
|
|
357
59
|
|
|
358
|
-
|
|
60
|
+
// Cluster into 4 workers
|
|
61
|
+
await core.cluster(4)
|
|
359
62
|
|
|
360
|
-
|
|
63
|
+
// Add configuration paths
|
|
64
|
+
await core.add('./path/to/config.js')
|
|
361
65
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
* @typedef {Object} CalculatorCalculationDto
|
|
365
|
-
* @property {number} id
|
|
366
|
-
* @property {string} type
|
|
367
|
-
* @property {number} value
|
|
368
|
-
*/
|
|
369
|
-
const dto =
|
|
370
|
-
{
|
|
371
|
-
'id':
|
|
372
|
-
{
|
|
373
|
-
'type' : 'integer',
|
|
374
|
-
'unsigned': true
|
|
375
|
-
},
|
|
376
|
-
'type':
|
|
377
|
-
{
|
|
378
|
-
'type': 'string',
|
|
379
|
-
'enum':
|
|
380
|
-
[
|
|
381
|
-
'addition',
|
|
382
|
-
'subtraction'
|
|
383
|
-
]
|
|
384
|
-
},
|
|
385
|
-
'value':
|
|
386
|
-
{
|
|
387
|
-
'type': 'decimal'
|
|
388
|
-
}
|
|
389
|
-
}
|
|
66
|
+
// Bootstrap core
|
|
67
|
+
await core.bootstrap()
|
|
390
68
|
|
|
391
|
-
|
|
69
|
+
// Destruct core when done
|
|
70
|
+
await core.destruct()
|
|
392
71
|
```
|
|
393
72
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
A table over validation and filtration rules follows...
|
|
397
|
-
|
|
398
|
-
| | boolean | decimal | integer | json | schema | string | timestamp |
|
|
399
|
-
|-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
|
|
400
|
-
| default | * | * | * | * | * | * | * |
|
|
401
|
-
| collection | boolean | boolean | boolean | boolean | boolean | boolean | boolean |
|
|
402
|
-
| optional | boolean | boolean | boolean | boolean | boolean | boolean | boolean |
|
|
403
|
-
| nullable | boolean | boolean | boolean | boolean | boolean | boolean | boolean |
|
|
404
|
-
| unsigned | - | boolean | boolean | - | - | - | - |
|
|
405
|
-
| min | - | number | number | - | - | number | timestamp |
|
|
406
|
-
| max | - | number | number | - | - | number | timestamp |
|
|
407
|
-
| gt | - | number | number | - | - | number | timestamp |
|
|
408
|
-
| lt | - | number | number | - | - | number | timestamp |
|
|
409
|
-
| enum | array | array | array | - | - | array | array |
|
|
410
|
-
| uppercase | - | - | - | - | - | boolean | - |
|
|
411
|
-
| lowercase | - | - | - | - | - | boolean | - |
|
|
412
|
-
| not-empty | - | - | - | - | - | boolean | - |
|
|
413
|
-
| stringified | - | - | - | boolean | - | - | - |
|
|
414
|
-
| indentation | - | - | - | number | - | - | - |
|
|
415
|
-
| schema | - | - | - | - | string | - | - |
|
|
416
|
-
|
|
417
|
-
#### `src/calculator/config.js`
|
|
418
|
-
|
|
419
|
-
```js
|
|
420
|
-
module.exports =
|
|
421
|
-
{
|
|
422
|
-
composer:
|
|
423
|
-
{
|
|
424
|
-
schema:
|
|
425
|
-
{
|
|
426
|
-
'calculation' : __dirname + '/calculation'
|
|
427
|
-
}
|
|
428
|
-
},
|
|
429
|
-
locator:
|
|
430
|
-
{
|
|
431
|
-
'calculator' : __dirname
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
In the `calculator config` we define where a path to a module is located, and where the locator can find a constituent locator to locate the service through.
|
|
73
|
+
---
|
|
437
74
|
|
|
438
|
-
|
|
75
|
+
## Configuration
|
|
439
76
|
|
|
440
|
-
|
|
441
|
-
const
|
|
442
|
-
CalculationCouldNotBeFoundError = require('./error/calculation-could-not-be-found'),
|
|
443
|
-
InvalidCalculationTypeError = require('./error/invalid-calculation-type')
|
|
77
|
+
The core reads configurations from JSON files and supports environment-specific overrides. Example structure:
|
|
444
78
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
*/
|
|
448
|
-
class Calculator
|
|
79
|
+
`config.json`:
|
|
80
|
+
```json
|
|
449
81
|
{
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
*/
|
|
453
|
-
constructor(eventbus)
|
|
454
|
-
{
|
|
455
|
-
this.eventbus = eventbus
|
|
456
|
-
this.calculations = []
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* @returns {number} the id of the created calculation
|
|
461
|
-
*/
|
|
462
|
-
createCalculation()
|
|
463
|
-
{
|
|
464
|
-
const id = this.calculations.push(0)
|
|
465
|
-
this.eventbus.emit('calculator.calculation-created', { id })
|
|
466
|
-
return id
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* @throws {E_CALCULATION_COULD_NOT_BE_FOUND}
|
|
471
|
-
* @throws {E_INVALID_CALCULATION_TYPE}
|
|
472
|
-
*
|
|
473
|
-
* @param {CalculatorCalculation} dto
|
|
474
|
-
*
|
|
475
|
-
* @returns {number} the result of the calculation
|
|
476
|
-
*/
|
|
477
|
-
appendToCalculation({ id, type, value })
|
|
478
|
-
{
|
|
479
|
-
if(id < 1
|
|
480
|
-
|| id > this.calculations.length)
|
|
481
|
-
{
|
|
482
|
-
throw new CalculationCouldNotBeFoundError(`Id out of range: "${id}/${this.calculations.length}"`)
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
switch(type)
|
|
486
|
-
{
|
|
487
|
-
case 'addition':
|
|
488
|
-
{
|
|
489
|
-
const result = this.calculations[id - 1] += value
|
|
490
|
-
this.eventbus.emit('calculator.calculation-appended', { id, type, result })
|
|
491
|
-
return result
|
|
492
|
-
}
|
|
493
|
-
case 'subtraction':
|
|
494
|
-
{
|
|
495
|
-
const result = this.calculations[id - 1] -= value
|
|
496
|
-
this.eventbus.emit('calculator.calculation-appended', { id, type, result })
|
|
497
|
-
return result
|
|
498
|
-
}
|
|
499
|
-
default:
|
|
500
|
-
{
|
|
501
|
-
throw new InvalidCalculationTypeError(`Unrecognized type used for calculation: "${type}"`)
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
82
|
+
"bootstrap": { "myService": true },
|
|
83
|
+
"locator": { "myService": "./path/to/myService.js" }
|
|
505
84
|
}
|
|
506
|
-
|
|
507
|
-
module.exports = Calculator
|
|
508
85
|
```
|
|
509
86
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
It's a simple service that creates a calculation and allows to append an additional calculation to an already created calculation.
|
|
513
|
-
|
|
514
|
-
#### `src/calculator/locator.js`
|
|
515
|
-
|
|
516
|
-
```js
|
|
517
|
-
const
|
|
518
|
-
Calculator = require('.'),
|
|
519
|
-
LocatorConstituent = require('@superhero/core/locator/constituent')
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* @extends {@superhero/core/locator/constituent}
|
|
523
|
-
*/
|
|
524
|
-
class CalculatorLocator extends LocatorConstituent
|
|
87
|
+
`config-dev.json`:
|
|
88
|
+
```json
|
|
525
89
|
{
|
|
526
|
-
|
|
527
|
-
* @returns {Calculator}
|
|
528
|
-
*/
|
|
529
|
-
locate()
|
|
530
|
-
{
|
|
531
|
-
const eventbus = this.locator.locate('eventbus')
|
|
532
|
-
return new Calculator(eventbus)
|
|
533
|
-
}
|
|
90
|
+
"myService": { "debug": true }
|
|
534
91
|
}
|
|
535
|
-
|
|
536
|
-
module.exports = CalculatorLocator
|
|
537
92
|
```
|
|
538
93
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
#### `src/calculator/error/calculation-could-not-be-found.js`
|
|
542
|
-
|
|
543
|
-
```js
|
|
544
|
-
/**
|
|
545
|
-
* @extends {Error}
|
|
546
|
-
*/
|
|
547
|
-
class CalculationCouldNotBeFoundError extends Error
|
|
548
|
-
{
|
|
549
|
-
constructor(...args)
|
|
550
|
-
{
|
|
551
|
-
super(...args)
|
|
552
|
-
this.code = 'E_CALCULATION_COULD_NOT_BE_FOUND'
|
|
553
|
-
}
|
|
554
|
-
}
|
|
94
|
+
---
|
|
555
95
|
|
|
556
|
-
|
|
557
|
-
```
|
|
96
|
+
## Testing
|
|
558
97
|
|
|
559
|
-
|
|
98
|
+
### Prerequisites
|
|
560
99
|
|
|
561
|
-
|
|
100
|
+
Ensure the required dependencies are installed:
|
|
562
101
|
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
* @extends {Error}
|
|
566
|
-
*/
|
|
567
|
-
class InvalidCalculationTypeError extends Error
|
|
568
|
-
{
|
|
569
|
-
constructor(...args)
|
|
570
|
-
{
|
|
571
|
-
super(...args)
|
|
572
|
-
this.code = 'E_INVALID_CALCULATION_TYPE'
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
module.exports = InvalidCalculationTypeError
|
|
102
|
+
```bash
|
|
103
|
+
npm install
|
|
577
104
|
```
|
|
578
105
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
### Logger
|
|
106
|
+
### Run Tests
|
|
582
107
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
```js
|
|
586
|
-
module.exports =
|
|
587
|
-
{
|
|
588
|
-
eventbus:
|
|
589
|
-
{
|
|
590
|
-
observers:
|
|
591
|
-
{
|
|
592
|
-
'calculator.calculation-created' : [ 'logger' ],
|
|
593
|
-
'calculator.calculation-appended' : [ 'logger' ]
|
|
594
|
-
}
|
|
595
|
-
},
|
|
596
|
-
locator:
|
|
597
|
-
{
|
|
598
|
-
'logger' : __dirname
|
|
599
|
-
}
|
|
600
|
-
}
|
|
108
|
+
```bash
|
|
109
|
+
npm test
|
|
601
110
|
```
|
|
602
111
|
|
|
603
|
-
|
|
112
|
+
### Test Coverage
|
|
604
113
|
|
|
605
|
-
#### `src/logger/index.js`
|
|
606
|
-
|
|
607
|
-
```js
|
|
608
|
-
/**
|
|
609
|
-
* @implements {@superhero/eventbus/observer}
|
|
610
|
-
*/
|
|
611
|
-
class Logger
|
|
612
|
-
{
|
|
613
|
-
constructor(eventbus)
|
|
614
|
-
{
|
|
615
|
-
this.eventbus = eventbus
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
observe(event)
|
|
619
|
-
{
|
|
620
|
-
this.eventbus.emit('logger.logged-event', event)
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
module.exports = Logger
|
|
625
114
|
```
|
|
115
|
+
▶ @superhero/core
|
|
116
|
+
✔ Plain core bootstrap (2.792737ms)
|
|
117
|
+
✔ Bootstraps a service successfully (9.447829ms)
|
|
118
|
+
✔ Bootstraps a service with a branch variable (4.01927ms)
|
|
119
|
+
✔ Can cluster the core and bootstrap a service (479.701512ms)
|
|
120
|
+
✔ @superhero/core (511.980508ms)
|
|
626
121
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
After we have logged the event to the console, we emit an event broadcasting that we have done so. By doing so, we can hook up to this event in the future if we like. For instance, when you like to create a test for the method, we can listen to this event.
|
|
122
|
+
tests 4
|
|
123
|
+
pass 4
|
|
630
124
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
*/
|
|
641
|
-
class LoggerLocator extends LocatorConstituent
|
|
642
|
-
{
|
|
643
|
-
/**
|
|
644
|
-
* @returns {Logger}
|
|
645
|
-
*/
|
|
646
|
-
locate()
|
|
647
|
-
{
|
|
648
|
-
const eventbus = this.locator.locate('eventbus')
|
|
649
|
-
return new Logger(eventbus)
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
module.exports = LoggerLocator
|
|
125
|
+
---------------------------------------------------------------------------------------------------
|
|
126
|
+
file | line % | branch % | funcs % | uncovered lines
|
|
127
|
+
---------------------------------------------------------------------------------------------------
|
|
128
|
+
index.js | 74.64 | 67.42 | 76.00 | 103-106 125-127 135-140 143-145 189-194 205-210 2…
|
|
129
|
+
index.test.js | 100.00 | 100.00 | 100.00 |
|
|
130
|
+
worker.js | 100.00 | 100.00 | 100.00 |
|
|
131
|
+
---------------------------------------------------------------------------------------------------
|
|
132
|
+
all files | 77.97 | 70.41 | 78.95 |
|
|
133
|
+
---------------------------------------------------------------------------------------------------
|
|
654
134
|
```
|
|
655
135
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
### Test
|
|
659
|
-
|
|
660
|
-
#### `test/mocha.opts`
|
|
136
|
+
---
|
|
661
137
|
|
|
662
|
-
|
|
663
|
-
--require test/init.js
|
|
664
|
-
--ui bdd
|
|
665
|
-
--full-trace
|
|
666
|
-
--timeout 5000
|
|
667
|
-
```
|
|
138
|
+
## API
|
|
668
139
|
|
|
669
|
-
|
|
140
|
+
### Core
|
|
670
141
|
|
|
671
|
-
####
|
|
142
|
+
#### Constructor
|
|
672
143
|
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
require.main.dirname = __dirname + '/../src'
|
|
144
|
+
```javascript
|
|
145
|
+
new Core(branch: string = undefined)
|
|
676
146
|
```
|
|
147
|
+
- `branch`: The configuration branch to load additional configurations (e.g., `dev` for `config-dev.json`).
|
|
677
148
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
The port is by design set through the environment variable `HTTP_PORT`. While testing we can set the variable to what ever we like, and what ever is suitable for the local machine we are on.
|
|
681
|
-
|
|
682
|
-
#### `test/test.calculations.js`
|
|
149
|
+
#### Methods
|
|
683
150
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
{
|
|
687
|
-
const
|
|
688
|
-
expect = require('chai').expect,
|
|
689
|
-
context = require('mochawesome/addContext')
|
|
690
|
-
|
|
691
|
-
let core
|
|
692
|
-
|
|
693
|
-
before((done) =>
|
|
694
|
-
{
|
|
695
|
-
const
|
|
696
|
-
CoreFactory = require('@superhero/core/factory'),
|
|
697
|
-
coreFactory = new CoreFactory
|
|
698
|
-
|
|
699
|
-
core = coreFactory.create()
|
|
700
|
-
|
|
701
|
-
core.add('api')
|
|
702
|
-
core.add('calculator')
|
|
703
|
-
core.add('logger')
|
|
704
|
-
core.add('http/server')
|
|
705
|
-
|
|
706
|
-
core.load()
|
|
707
|
-
|
|
708
|
-
core.locate('bootstrap').bootstrap().then(() =>
|
|
709
|
-
{
|
|
710
|
-
core.locate('http/server').listen(9001)
|
|
711
|
-
core.locate('http/server').onListening(done)
|
|
712
|
-
})
|
|
713
|
-
})
|
|
714
|
-
|
|
715
|
-
after(() =>
|
|
716
|
-
{
|
|
717
|
-
core.locate('http/server').close()
|
|
718
|
-
})
|
|
719
|
-
|
|
720
|
-
it('A client can create a calculation', async function()
|
|
721
|
-
{
|
|
722
|
-
const configuration = core.locate('configuration')
|
|
723
|
-
const httpRequest = core.locate('http/request')
|
|
724
|
-
context(this, { title:'route', value:configuration.find('http.server.routes.create-calculation') })
|
|
725
|
-
const response = await httpRequest.post('http://localhost:9001/calculations')
|
|
726
|
-
expect(response.data.id).to.be.equal(1)
|
|
727
|
-
})
|
|
728
|
-
|
|
729
|
-
it('A client can append a calculation to the result of a former calculation if authentication Api-Key', async function()
|
|
730
|
-
{
|
|
731
|
-
const configuration = core.locate('configuration')
|
|
732
|
-
const httpRequest = core.locate('http/request')
|
|
733
|
-
context(this, { title:'route', value:configuration.find('http.server.routes.append-calculation') })
|
|
734
|
-
const url = 'http://localhost:9001/calculations/1'
|
|
735
|
-
const data = { id:1, type:'addition', value:100 }
|
|
736
|
-
const response_unauthorized = await httpRequest.put({ url, data })
|
|
737
|
-
expect(response_unauthorized.status).to.be.equal(401)
|
|
738
|
-
const headers = { 'Api-Key':'ABC123456789' }
|
|
739
|
-
const response_authorized = await httpRequest.put({ headers, url, data })
|
|
740
|
-
expect(response_authorized.data.result).to.be.equal(data.value)
|
|
741
|
-
})
|
|
742
|
-
})
|
|
743
|
-
```
|
|
151
|
+
- **`add(configPaths: string | string[] | object): Promise<Core>`**
|
|
152
|
+
Add configuration paths to the core.
|
|
744
153
|
|
|
745
|
-
|
|
154
|
+
- **`bootstrap(freeze: boolean = true): Promise<Core>`**
|
|
155
|
+
Initialize the core and its dependencies.
|
|
746
156
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
{
|
|
750
|
-
const
|
|
751
|
-
expect = require('chai').expect,
|
|
752
|
-
context = require('mochawesome/addContext')
|
|
753
|
-
|
|
754
|
-
let core
|
|
755
|
-
|
|
756
|
-
before((done) =>
|
|
757
|
-
{
|
|
758
|
-
const
|
|
759
|
-
CoreFactory = require('@superhero/core/factory'),
|
|
760
|
-
coreFactory = new CoreFactory
|
|
761
|
-
|
|
762
|
-
core = coreFactory.create()
|
|
763
|
-
|
|
764
|
-
core.add('api')
|
|
765
|
-
core.add('calculator')
|
|
766
|
-
core.add('logger')
|
|
767
|
-
core.add('http/server')
|
|
768
|
-
|
|
769
|
-
core.load()
|
|
770
|
-
|
|
771
|
-
core.locate('bootstrap').bootstrap().then(done)
|
|
772
|
-
})
|
|
773
|
-
|
|
774
|
-
it('Events are logged to the console', function(done)
|
|
775
|
-
{
|
|
776
|
-
const configuration = core.locate('configuration')
|
|
777
|
-
const eventbus = core.locate('eventbus')
|
|
778
|
-
context(this, { title:'observers', value:configuration.find('http.eventbus.observers') })
|
|
779
|
-
eventbus.once('logger.logged-event', () => done())
|
|
780
|
-
eventbus.emit('calculator.calculation-created', 'test')
|
|
781
|
-
})
|
|
782
|
-
})
|
|
783
|
-
```
|
|
157
|
+
- **`cluster(forks: number, branch?: number, version?: number): Promise<number>`**
|
|
158
|
+
Start clustering with the specified number of workers.
|
|
784
159
|
|
|
785
|
-
|
|
160
|
+
- **`destruct(): Promise<void>`**
|
|
161
|
+
Gracefully shutdown the core, its workers, and services.
|
|
786
162
|
|
|
787
|
-
|
|
163
|
+
#### Properties
|
|
788
164
|
|
|
789
|
-
|
|
165
|
+
- **`basePath: string`**
|
|
166
|
+
The base path used to resolve file paths.
|
|
790
167
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
npm start
|
|
794
|
-
```
|
|
168
|
+
- **`branch: string`**
|
|
169
|
+
The branch used for environment-specific configurations.
|
|
795
170
|
|
|
796
|
-
|
|
171
|
+
- **`workers: object`**
|
|
172
|
+
Access to clustered workers.
|
|
797
173
|
|
|
798
|
-
|
|
799
|
-
npm install
|
|
800
|
-
npm test
|
|
801
|
-
```
|
|
802
|
-
|
|
803
|
-
#### For an auto-generated coverage report in html:
|
|
174
|
+
---
|
|
804
175
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
```
|
|
176
|
+
## License
|
|
177
|
+
This project is licensed under the MIT License.
|
|
808
178
|
|
|
809
|
-
|
|
179
|
+
---
|
|
810
180
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
```
|
|
181
|
+
## Contributing
|
|
182
|
+
Feel free to submit issues or pull requests for improvements or additional features.
|