@loopback/cli 4.0.0-alpha.9 → 4.1.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/.yo-rc.json +1719 -0
- package/{generators/project/templates/LICENSE → LICENSE} +2 -1
- package/README.md +44 -43
- package/bin/cli-main.js +61 -0
- package/generators/app/index.js +109 -15
- package/generators/app/templates/.dockerignore +5 -0
- package/generators/app/templates/Dockerfile +28 -0
- package/generators/app/templates/README.md.ejs +130 -0
- package/generators/app/templates/public/index.html.ejs +88 -0
- package/generators/app/templates/{test → src/__tests__}/README.md +0 -1
- package/generators/app/templates/src/__tests__/acceptance/home-page.acceptance.ts.ejs +31 -0
- package/generators/app/templates/src/__tests__/acceptance/ping.controller.acceptance.ts.ejs +21 -0
- package/generators/app/templates/src/__tests__/acceptance/test-helper.ts.ejs +32 -0
- package/generators/app/templates/src/application.ts.ejs +70 -0
- package/generators/app/templates/src/controllers/README.md +6 -0
- package/generators/app/templates/src/controllers/index.ts.ejs +1 -0
- package/generators/app/templates/src/controllers/ping.controller.ts.ejs +55 -0
- package/generators/app/templates/src/datasources/README.md +3 -0
- package/generators/app/templates/src/index.ts.ejs +39 -0
- package/generators/app/templates/src/migrate.ts.ejs +20 -0
- package/generators/app/templates/src/models/README.md +3 -0
- package/generators/app/templates/src/openapi-spec.ts.ejs +23 -0
- package/generators/app/templates/src/sequence.ts.ejs +3 -0
- package/generators/controller/index.js +240 -23
- package/generators/controller/templates/src/controllers/controller-rest-template.ts.ejs +150 -0
- package/generators/controller/templates/src/controllers/{controller-template.ts → controller-template.ts.ejs} +2 -2
- package/generators/copyright/fs.js +46 -0
- package/generators/copyright/git.js +78 -0
- package/generators/copyright/header.js +306 -0
- package/generators/copyright/index.js +230 -0
- package/generators/copyright/license.js +105 -0
- package/generators/datasource/index.js +341 -0
- package/generators/datasource/templates/datasource.ts.ejs +22 -0
- package/generators/discover/import-discovered-model.js +70 -0
- package/generators/discover/index.js +411 -0
- package/generators/example/downloader.js +16 -0
- package/generators/example/index.js +176 -0
- package/generators/extension/index.js +34 -5
- package/generators/extension/templates/README.md.ejs +32 -0
- package/generators/extension/templates/{test → src/__tests__}/acceptance/README.md +0 -0
- package/generators/extension/templates/{test → src/__tests__}/integration/README.md +0 -0
- package/generators/extension/templates/{test → src/__tests__}/unit/README.md +0 -0
- package/generators/extension/templates/src/component.ts.ejs +22 -0
- package/generators/extension/templates/src/controllers/README.md +3 -2
- package/generators/extension/templates/src/decorators/README.md +10 -4
- package/generators/extension/templates/src/index.ts.ejs +3 -0
- package/generators/extension/templates/src/keys.ts.ejs +11 -0
- package/generators/extension/templates/src/mixins/README.md +77 -21
- package/generators/extension/templates/src/providers/README.md +51 -25
- package/generators/extension/templates/src/repositories/README.md +1 -1
- package/generators/extension/templates/src/types.ts.ejs +15 -0
- package/generators/import-lb3-models/index.js +197 -0
- package/generators/import-lb3-models/lb3app-loader.js +31 -0
- package/generators/import-lb3-models/migrate-model.js +249 -0
- package/generators/import-lb3-models/model-names.js +32 -0
- package/generators/interceptor/index.js +178 -0
- package/generators/interceptor/templates/interceptor-template.ts.ejs +62 -0
- package/generators/model/index.js +536 -0
- package/generators/model/property-definition.js +85 -0
- package/generators/model/templates/model.ts.ejs +49 -0
- package/generators/observer/index.js +132 -0
- package/generators/observer/templates/observer-template.ts.ejs +40 -0
- package/generators/openapi/README.md +211 -0
- package/generators/openapi/index.js +535 -0
- package/generators/openapi/schema-helper.js +447 -0
- package/generators/openapi/spec-helper.js +484 -0
- package/generators/openapi/spec-loader.js +75 -0
- package/generators/openapi/templates/src/controllers/controller-template.ts.ejs +43 -0
- package/generators/openapi/templates/src/datasources/datasource.ts.ejs +42 -0
- package/generators/openapi/templates/src/models/model-template.ts.ejs +71 -0
- package/generators/openapi/templates/src/models/type-template.ts.ejs +13 -0
- package/generators/openapi/templates/src/services/service-proxy-template.ts.ejs +55 -0
- package/generators/openapi/utils.js +322 -0
- package/generators/project/templates/.eslintignore +4 -0
- package/generators/project/templates/.eslintrc.js.ejs +3 -0
- package/generators/project/templates/.mocharc.json +5 -0
- package/generators/project/templates/.prettierignore +0 -2
- package/generators/project/templates/.prettierrc +2 -1
- package/generators/project/templates/.vscode/launch.json +38 -0
- package/generators/project/templates/.vscode/settings.json +32 -0
- package/generators/project/templates/.vscode/tasks.json +29 -0
- package/generators/project/templates/DEVELOPING.md +36 -0
- package/generators/project/templates/_.gitignore +3 -5
- package/generators/project/templates/package.json.ejs +175 -0
- package/generators/project/templates/package.plain.json.ejs +176 -0
- package/generators/project/templates/tsconfig.json.ejs +39 -0
- package/generators/relation/base-relation.generator.js +220 -0
- package/generators/relation/belongs-to-relation.generator.js +196 -0
- package/generators/relation/has-many-relation.generator.js +200 -0
- package/generators/relation/has-many-through-relation.generator.js +331 -0
- package/generators/relation/has-one-relation.generator.js +200 -0
- package/generators/relation/index.js +795 -0
- package/generators/relation/references-many-relation.generator.js +142 -0
- package/generators/relation/templates/controller-relation-template-belongs-to.ts.ejs +38 -0
- package/generators/relation/templates/controller-relation-template-has-many-through.ts.ejs +110 -0
- package/generators/relation/templates/controller-relation-template-has-many.ts.ejs +110 -0
- package/generators/relation/templates/controller-relation-template-has-one.ts.ejs +110 -0
- package/generators/relation/utils.generator.js +260 -0
- package/generators/repository/index.js +576 -0
- package/generators/repository/templates/src/repositories/repository-crud-default-template.ts.ejs +21 -0
- package/generators/repository/templates/src/repositories/repository-kv-template.ts.ejs +19 -0
- package/generators/rest-crud/crud-rest-component.js +63 -0
- package/generators/rest-crud/index.js +423 -0
- package/generators/rest-crud/templates/src/model-endpoints/model.rest-config-template.ts.ejs +11 -0
- package/generators/service/index.js +351 -0
- package/generators/service/templates/local-service-class-template.ts.ejs +10 -0
- package/generators/service/templates/local-service-provider-template.ts.ejs +19 -0
- package/generators/service/templates/remote-service-proxy-template.ts.ejs +21 -0
- package/generators/update/index.js +55 -0
- package/intl/cs/messages.json +204 -0
- package/intl/de/messages.json +204 -0
- package/intl/en/messages.json +204 -0
- package/intl/es/messages.json +204 -0
- package/intl/fr/messages.json +204 -0
- package/intl/it/messages.json +204 -0
- package/intl/ja/messages.json +204 -0
- package/intl/ko/messages.json +204 -0
- package/intl/nl/messages.json +204 -0
- package/intl/pl/messages.json +204 -0
- package/intl/pt/messages.json +204 -0
- package/intl/ru/messages.json +204 -0
- package/intl/tr/messages.json +204 -0
- package/intl/zh-Hans/messages.json +204 -0
- package/intl/zh-Hant/messages.json +204 -0
- package/lib/artifact-generator.js +138 -39
- package/lib/ast-helper.js +214 -0
- package/lib/base-generator.js +509 -0
- package/lib/cli.js +233 -0
- package/lib/connectors.json +894 -0
- package/lib/debug.js +16 -0
- package/lib/globalize.js +12 -0
- package/lib/model-discoverer.js +118 -0
- package/lib/project-generator.js +154 -57
- package/lib/tab-completion.js +127 -0
- package/lib/update-index.js +44 -0
- package/lib/utils.js +689 -20
- package/lib/version-helper.js +299 -0
- package/package.json +183 -39
- package/CHANGELOG.md +0 -86
- package/bin/cli.js +0 -66
- package/generators/app/templates/index.js +0 -14
- package/generators/app/templates/src/application.ts +0 -27
- package/generators/app/templates/src/controllers/ping-controller.ts +0 -25
- package/generators/app/templates/src/index.ts +0 -25
- package/generators/app/templates/test/ping-controller.test.ts +0 -46
- package/generators/extension/templates/index.js +0 -8
- package/generators/extension/templates/src/component.ts +0 -14
- package/generators/extension/templates/src/index.ts +0 -6
- package/generators/project/templates/.npmrc +0 -1
- package/generators/project/templates/.yo-rc.json +0 -1
- package/generators/project/templates/README.md +0 -4
- package/generators/project/templates/index.d.ts +0 -6
- package/generators/project/templates/index.ts +0 -11
- package/generators/project/templates/package.json +0 -79
- package/generators/project/templates/package.plain.json +0 -82
- package/generators/project/templates/test/mocha.opts +0 -1
- package/generators/project/templates/tsconfig.json +0 -29
- package/generators/project/templates/tslint.build.json +0 -17
- package/generators/project/templates/tslint.json +0 -33
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2017. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2017,2020. All Rights Reserved.
|
|
2
2
|
// Node module: @loopback/cli
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
|
-
const Generator = require('yeoman-generator');
|
|
8
7
|
const utils = require('../../lib/utils');
|
|
9
8
|
|
|
10
9
|
const ProjectGenerator = require('../../lib/project-generator');
|
|
10
|
+
const g = require('../../lib/globalize');
|
|
11
11
|
|
|
12
|
-
module.exports = class extends ProjectGenerator {
|
|
12
|
+
module.exports = class ExtensionGenerator extends ProjectGenerator {
|
|
13
13
|
// Note: arguments and options should be defined in the constructor.
|
|
14
14
|
constructor(args, opts) {
|
|
15
15
|
super(args, opts);
|
|
@@ -20,30 +20,41 @@ module.exports = class extends ProjectGenerator {
|
|
|
20
20
|
|
|
21
21
|
this.option('componentName', {
|
|
22
22
|
type: String,
|
|
23
|
-
description: 'Component name',
|
|
23
|
+
description: g.f('Component name'),
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
return super._setupGenerator();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
setOptions() {
|
|
30
|
+
if (this.shouldExit()) return;
|
|
30
31
|
return super.setOptions();
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
promptProjectName() {
|
|
35
|
+
if (this.shouldExit()) return;
|
|
34
36
|
return super.promptProjectName();
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
promptProjectDir() {
|
|
40
|
+
if (this.shouldExit()) return;
|
|
38
41
|
return super.promptProjectDir();
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
promptComponent() {
|
|
45
|
+
if (this.shouldExit()) return;
|
|
46
|
+
|
|
47
|
+
if (this.options.componentName) {
|
|
48
|
+
Object.assign(this.projectInfo, {
|
|
49
|
+
componentName: this.options.componentName,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
const prompts = [
|
|
43
54
|
{
|
|
44
55
|
type: 'input',
|
|
45
56
|
name: 'componentName',
|
|
46
|
-
message: 'Component class name:',
|
|
57
|
+
message: g.f('Component class name:'),
|
|
47
58
|
when: this.projectInfo.componentName == null,
|
|
48
59
|
default: utils.toClassName(this.projectInfo.name) + 'Component',
|
|
49
60
|
},
|
|
@@ -55,14 +66,32 @@ module.exports = class extends ProjectGenerator {
|
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
promptOptions() {
|
|
69
|
+
if (this.shouldExit()) return;
|
|
58
70
|
return super.promptOptions();
|
|
59
71
|
}
|
|
60
72
|
|
|
73
|
+
promptYarnInstall() {
|
|
74
|
+
if (this.shouldExit()) return;
|
|
75
|
+
return super.promptYarnInstall();
|
|
76
|
+
}
|
|
77
|
+
|
|
61
78
|
scaffold() {
|
|
79
|
+
if (this.projectInfo) {
|
|
80
|
+
this.projectInfo.optionsInterface = `${this.projectInfo.componentName}Options`;
|
|
81
|
+
this.projectInfo.bindingsNamespace = `${this.projectInfo.componentName}Bindings`;
|
|
82
|
+
const uppercaseUnderscore = this.projectInfo.name
|
|
83
|
+
.toUpperCase()
|
|
84
|
+
.replace(/\W/g, '_');
|
|
85
|
+
this.projectInfo.defaultOptions = `DEFAULT_${uppercaseUnderscore}_OPTIONS`;
|
|
86
|
+
}
|
|
62
87
|
return super.scaffold();
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
install() {
|
|
66
91
|
return super.install();
|
|
67
92
|
}
|
|
93
|
+
|
|
94
|
+
end() {
|
|
95
|
+
return super.end();
|
|
96
|
+
}
|
|
68
97
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# <%= project.name %>
|
|
2
|
+
|
|
3
|
+
[-@2x.png)](http://loopback.io/)
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install <%= project.componentName %> using `npm`;
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
$ [npm install | yarn add] <%= project.name %>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Basic Use
|
|
14
|
+
|
|
15
|
+
Configure and load <%= project.componentName %> in the application constructor
|
|
16
|
+
as shown below.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import {<%= project.componentName %>, <%= project.optionsInterface %>, <%= project.defaultOptions %>} from '<%= project.name %>';
|
|
20
|
+
// ...
|
|
21
|
+
export class MyApplication extends BootMixin(ServiceMixin(RepositoryMixin(RestApplication))) {
|
|
22
|
+
constructor(options: ApplicationConfig = {}) {
|
|
23
|
+
const opts: <%= project.optionsInterface %> = <%= project.defaultOptions %>;
|
|
24
|
+
this.configure(<%= project.bindingsNamespace %>.COMPONENT).to(opts);
|
|
25
|
+
// Put the configuration options here
|
|
26
|
+
});
|
|
27
|
+
this.component(<%= project.componentName %>);
|
|
28
|
+
// ...
|
|
29
|
+
}
|
|
30
|
+
// ...
|
|
31
|
+
}
|
|
32
|
+
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Application,
|
|
3
|
+
injectable,
|
|
4
|
+
Component,
|
|
5
|
+
config,
|
|
6
|
+
ContextTags,
|
|
7
|
+
CoreBindings,
|
|
8
|
+
inject,
|
|
9
|
+
} from '@loopback/core';
|
|
10
|
+
import {<%= project.bindingsNamespace %>} from './keys'
|
|
11
|
+
import {<%= project.defaultOptions %>, <%= project.optionsInterface %>} from './types';
|
|
12
|
+
|
|
13
|
+
// Configure the binding for <%= project.componentName %>
|
|
14
|
+
@injectable({tags: {[ContextTags.KEY]: <%= project.bindingsNamespace %>.COMPONENT}})
|
|
15
|
+
export class <%= project.componentName %> implements Component {
|
|
16
|
+
constructor(
|
|
17
|
+
@inject(CoreBindings.APPLICATION_INSTANCE)
|
|
18
|
+
private application: Application,
|
|
19
|
+
@config()
|
|
20
|
+
private options: <%= project.optionsInterface %> = <%= project.defaultOptions %>,
|
|
21
|
+
) {}
|
|
22
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Controllers
|
|
2
2
|
|
|
3
|
-
This directory contains source files for the controllers exported by this
|
|
3
|
+
This directory contains source files for the controllers exported by this
|
|
4
|
+
extension.
|
|
4
5
|
|
|
5
|
-
For more information, see http://loopback.io/doc/en/lb4/Controllers.html
|
|
6
|
+
For more information, see <http://loopback.io/doc/en/lb4/Controllers.html>.
|
|
@@ -2,16 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
Decorators provide annotations for class methods and arguments. Decorators use
|
|
5
|
+
Decorators provide annotations for class methods and arguments. Decorators use
|
|
6
|
+
the form `@decorator` where `decorator` is the name of the function that will be
|
|
7
|
+
called at runtime.
|
|
6
8
|
|
|
7
9
|
## Basic Usage
|
|
8
10
|
|
|
9
11
|
### txIdFromHeader
|
|
10
12
|
|
|
11
|
-
This simple decorator allows you to annotate a `Controller` method argument. The
|
|
13
|
+
This simple decorator allows you to annotate a `Controller` method argument. The
|
|
14
|
+
decorator will annotate the method argument with the value of the header
|
|
15
|
+
`X-Transaction-Id` from the request.
|
|
12
16
|
|
|
13
17
|
**Example**
|
|
14
|
-
|
|
18
|
+
|
|
19
|
+
```ts
|
|
15
20
|
class MyController {
|
|
16
21
|
@get('/')
|
|
17
22
|
getHandler(@txIdFromHeader() txId: string) {
|
|
@@ -22,7 +27,8 @@ class MyController {
|
|
|
22
27
|
|
|
23
28
|
## Related Resources
|
|
24
29
|
|
|
25
|
-
You can check out the following resource to learn more about decorators and how
|
|
30
|
+
You can check out the following resource to learn more about decorators and how
|
|
31
|
+
they are used in LoopBack Next.
|
|
26
32
|
|
|
27
33
|
- [TypeScript Handbook: Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
|
|
28
34
|
- [Decorators in LoopBack](http://loopback.io/doc/en/lb4/Decorators.html)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {BindingKey, CoreBindings} from '@loopback/core';
|
|
2
|
+
import {<%= project.componentName %>} from './component';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Binding keys used by this component.
|
|
6
|
+
*/
|
|
7
|
+
export namespace <%= project.bindingsNamespace %> {
|
|
8
|
+
export const COMPONENT = BindingKey.create<<%= project.componentName %>>(
|
|
9
|
+
`${CoreBindings.COMPONENTS}.<%= project.componentName %>`,
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -4,15 +4,21 @@ This directory contains source files for the mixins exported by this extension.
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
Sometimes it's helpful to write partial classes and then combining them together
|
|
7
|
+
Sometimes it's helpful to write partial classes and then combining them together
|
|
8
|
+
to build more powerful classes. This pattern is called Mixins (mixing in partial
|
|
9
|
+
classes) and is supported by LoopBack 4.
|
|
8
10
|
|
|
9
|
-
LoopBack 4 supports mixins at an `Application` level. Your partial class can
|
|
11
|
+
LoopBack 4 supports mixins at an `Application` level. Your partial class can
|
|
12
|
+
then be mixed into the `Application` class. A mixin class can modify or override
|
|
13
|
+
existing methods of the class or add new ones! It is also possible to mixin
|
|
14
|
+
multiple classes together as needed.
|
|
10
15
|
|
|
11
16
|
### High level example
|
|
17
|
+
|
|
12
18
|
```ts
|
|
13
19
|
class MyApplication extends MyMixinClass(Application) {
|
|
14
20
|
// Your code
|
|
15
|
-
}
|
|
21
|
+
}
|
|
16
22
|
|
|
17
23
|
// Multiple Classes mixed together
|
|
18
24
|
class MyApp extends MyMixinClass(MyMixinClass2(Application)) {
|
|
@@ -22,12 +28,23 @@ class MyApp extends MyMixinClass(MyMixinClass2(Application)) {
|
|
|
22
28
|
|
|
23
29
|
## Getting Started
|
|
24
30
|
|
|
25
|
-
For hello-extensions we write a simple Mixin that allows the `Application` class
|
|
31
|
+
For hello-extensions we write a simple Mixin that allows the `Application` class
|
|
32
|
+
to bind a `Logger` class from ApplicationOptions, Components, or `.logger()`
|
|
33
|
+
method that is mixed in. `Logger` instances are bound to the key
|
|
34
|
+
`loggers.${Logger.name}`. Once a Logger has been bound, the user can retrieve it
|
|
35
|
+
by using
|
|
36
|
+
[Dependency Injection](http://loopback.io/doc/en/lb4/Dependency-injection.html)
|
|
37
|
+
and the key for the `Logger`.
|
|
26
38
|
|
|
27
39
|
### What is a Logger?
|
|
28
|
-
|
|
40
|
+
|
|
41
|
+
> A Logger class is provides a mechanism for logging messages of varying
|
|
42
|
+
> priority by providing an implementation for `Logger.info()` &
|
|
43
|
+
> `Logger.error()`. An example of a Logger is `console` which has
|
|
44
|
+
> `console.log()` and `console.error()`.
|
|
29
45
|
|
|
30
46
|
#### An example Logger
|
|
47
|
+
|
|
31
48
|
```ts
|
|
32
49
|
class ColorLogger implements Logger {
|
|
33
50
|
log(...args: LogArgs) {
|
|
@@ -42,12 +59,19 @@ class ColorLogger implements Logger {
|
|
|
42
59
|
```
|
|
43
60
|
|
|
44
61
|
## LoggerMixin
|
|
45
|
-
|
|
62
|
+
|
|
63
|
+
A complete & functional implementation can be found in `logger.mixin.ts`. _Here
|
|
64
|
+
are some key things to keep in mind when writing your own Mixin_.
|
|
46
65
|
|
|
47
66
|
### constructor()
|
|
48
|
-
A Mixin constructor must take an array of any type as it's argument. This would represent `ApplicationOptions` for our base class `Application` as well as any properties we would like for our Mixin.
|
|
49
67
|
|
|
50
|
-
|
|
68
|
+
A Mixin constructor must take an array of any type as it's argument. This would
|
|
69
|
+
represent `ApplicationOptions` for our base class `Application` as well as any
|
|
70
|
+
properties we would like for our Mixin.
|
|
71
|
+
|
|
72
|
+
It is also important for the constructor to call `super(args)` so `Application`
|
|
73
|
+
continues to work as expected.
|
|
74
|
+
|
|
51
75
|
```ts
|
|
52
76
|
constructor(...args: any[]) {
|
|
53
77
|
super(args);
|
|
@@ -55,23 +79,32 @@ constructor(...args: any[]) {
|
|
|
55
79
|
```
|
|
56
80
|
|
|
57
81
|
### Binding via `ApplicationOptions`
|
|
58
|
-
|
|
82
|
+
|
|
83
|
+
As mentioned earlier, since our `args` represents `ApplicationOptions`, we can
|
|
84
|
+
make it possible for users to pass in their `Logger` implementations in a
|
|
85
|
+
`loggers` array on `ApplicationOptions`. We can then read the array and
|
|
86
|
+
automatically bind these for the user.
|
|
59
87
|
|
|
60
88
|
#### Example user experience
|
|
89
|
+
|
|
61
90
|
```ts
|
|
62
|
-
class MyApp extends LoggerMixin(Application){
|
|
91
|
+
class MyApp extends LoggerMixin(Application) {
|
|
63
92
|
constructor(...args: any[]) {
|
|
64
93
|
super(...args);
|
|
65
94
|
}
|
|
66
|
-
}
|
|
95
|
+
}
|
|
67
96
|
|
|
68
97
|
const app = new MyApp({
|
|
69
|
-
loggers: [ColorLogger]
|
|
98
|
+
loggers: [ColorLogger],
|
|
70
99
|
});
|
|
71
100
|
```
|
|
72
101
|
|
|
73
102
|
#### Example Implementation
|
|
74
|
-
|
|
103
|
+
|
|
104
|
+
To implement this, we would check `this.options` to see if it has a `loggers`
|
|
105
|
+
array and if so, bind it by calling the `.logger()` method. (More on that
|
|
106
|
+
below).
|
|
107
|
+
|
|
75
108
|
```ts
|
|
76
109
|
if (this.options.loggers) {
|
|
77
110
|
for (const logger of this.options.loggers) {
|
|
@@ -81,7 +114,12 @@ if (this.options.loggers) {
|
|
|
81
114
|
```
|
|
82
115
|
|
|
83
116
|
### Binding via `.logger()`
|
|
84
|
-
|
|
117
|
+
|
|
118
|
+
As mentioned earlier, we can add a new function to our `Application` class
|
|
119
|
+
called `.logger()` into which a user would pass in their `Logger` implementation
|
|
120
|
+
so we can bind it to the `loggers.*` key for them. We just add this new method
|
|
121
|
+
on our partial Mixin class.
|
|
122
|
+
|
|
85
123
|
```ts
|
|
86
124
|
logger(logClass: Logger) {
|
|
87
125
|
const loggerKey = `loggers.${logClass.name}`;
|
|
@@ -90,7 +128,13 @@ logger(logClass: Logger) {
|
|
|
90
128
|
```
|
|
91
129
|
|
|
92
130
|
### Binding a `Logger` from a `Component`
|
|
93
|
-
|
|
131
|
+
|
|
132
|
+
Our base class of `Application` already has a method that binds components. We
|
|
133
|
+
can modify this method to continue binding a `Component` as usual but also
|
|
134
|
+
binding any `Logger` instances provided by that `Component`. When modifying
|
|
135
|
+
behavior of an existing method, we can ensure existing behavior by calling the
|
|
136
|
+
`super.method()`. In our case the method is `.component()`.
|
|
137
|
+
|
|
94
138
|
```ts
|
|
95
139
|
component(component: Constructor<any>) {
|
|
96
140
|
super.component(component); // ensures existing behavior from Application
|
|
@@ -98,7 +142,11 @@ component(component: Constructor<any>) {
|
|
|
98
142
|
}
|
|
99
143
|
```
|
|
100
144
|
|
|
101
|
-
We have now modified `.component()` to do it's thing and then call our method
|
|
145
|
+
We have now modified `.component()` to do it's thing and then call our method
|
|
146
|
+
`mountComponentLoggers()`. In this method is where we check for `Logger`
|
|
147
|
+
implementations declared by the component in a `loggers` array by retrieving the
|
|
148
|
+
instance of the `Component`. Then if `loggers` array exists, we bind the
|
|
149
|
+
`Logger` instances as normal (by leveraging our `.logger()` method).
|
|
102
150
|
|
|
103
151
|
```ts
|
|
104
152
|
mountComponentLoggers(component: Constructor<any>) {
|
|
@@ -114,7 +162,12 @@ mountComponentLoggers(component: Constructor<any>) {
|
|
|
114
162
|
```
|
|
115
163
|
|
|
116
164
|
## Retrieving the Logger instance
|
|
117
|
-
|
|
165
|
+
|
|
166
|
+
Now that we have bound a Logger to our Application via one of the many ways made
|
|
167
|
+
possible by `LoggerMixin`, we need to be able to retrieve it so we can use it.
|
|
168
|
+
Let's say we want to use it in a controller. Here's an example to retrieving it
|
|
169
|
+
so we can use it.
|
|
170
|
+
|
|
118
171
|
```ts
|
|
119
172
|
class MyController {
|
|
120
173
|
constructor(@inject('loggers.ColorLogger') protected log: Logger) {}
|
|
@@ -127,7 +180,9 @@ class MyController {
|
|
|
127
180
|
```
|
|
128
181
|
|
|
129
182
|
## Examples for using LoggerMixin
|
|
183
|
+
|
|
130
184
|
### Using the app's `.logger()` method
|
|
185
|
+
|
|
131
186
|
```ts
|
|
132
187
|
class LoggingApplication extends LoggerMixin(Application) {
|
|
133
188
|
constructor(...args: any[]) {
|
|
@@ -138,6 +193,7 @@ class LoggingApplication extends LoggerMixin(Application) {
|
|
|
138
193
|
```
|
|
139
194
|
|
|
140
195
|
### Using the app's constructor
|
|
196
|
+
|
|
141
197
|
```ts
|
|
142
198
|
class LoggerApplication extends LoggerMixin(Application) {
|
|
143
199
|
constructor() {
|
|
@@ -149,12 +205,12 @@ class LoggerApplication extends LoggerMixin(Application) {
|
|
|
149
205
|
```
|
|
150
206
|
|
|
151
207
|
### Binding a Logger provided by a component
|
|
208
|
+
|
|
152
209
|
```ts
|
|
153
|
-
class LoggingComponent implements Component{
|
|
210
|
+
class LoggingComponent implements Component {
|
|
154
211
|
loggers: [ColorLogger];
|
|
155
212
|
}
|
|
156
213
|
|
|
157
|
-
const app = new LoggingApplication(
|
|
158
|
-
|
|
159
|
-
});
|
|
214
|
+
const app = new LoggingApplication();
|
|
215
|
+
app.component(LoggingComponent); // Logger from MyComponent will be bound to loggers.ColorLogger
|
|
160
216
|
```
|
|
@@ -1,61 +1,84 @@
|
|
|
1
1
|
# Providers
|
|
2
2
|
|
|
3
|
-
This directory contains providers contributing additional bindings, for example
|
|
3
|
+
This directory contains providers contributing additional bindings, for example
|
|
4
|
+
custom sequence actions.
|
|
4
5
|
|
|
5
6
|
## Overview
|
|
6
7
|
|
|
7
|
-
A [provider](http://loopback.io/doc/en/lb4/Creating-components.html#providers)
|
|
8
|
+
A [provider](http://loopback.io/doc/en/lb4/Creating-components.html#providers)
|
|
9
|
+
is a class that provides a `value()` function. This function is called `Context`
|
|
10
|
+
when another entity requests a value to be injected.
|
|
8
11
|
|
|
9
|
-
Here we create a provider for a logging function that can be used as a new
|
|
12
|
+
Here we create a provider for a logging function that can be used as a new
|
|
13
|
+
action in a custom [sequence](http://loopback.io/doc/en/lb4/Sequence.html).
|
|
10
14
|
|
|
11
|
-
The logger will log the URL, the parsed request parameters, and the result. The
|
|
15
|
+
The logger will log the URL, the parsed request parameters, and the result. The
|
|
16
|
+
logger is also capable of timing the sequence if you start a timer at the start
|
|
17
|
+
of the sequence using `this.logger.startTimer()`.
|
|
12
18
|
|
|
13
19
|
## Basic Usage
|
|
14
20
|
|
|
15
21
|
### TimerProvider
|
|
16
22
|
|
|
17
|
-
TimerProvider is automatically bound to your Application's
|
|
23
|
+
TimerProvider is automatically bound to your Application's
|
|
24
|
+
[Context](http://loopback.io/doc/en/lb4/Context.html) using the LogComponent
|
|
25
|
+
which exports this provider with a binding key of `extension-starter.timer`. You
|
|
26
|
+
can learn more about components in the
|
|
27
|
+
[related resources section](#related-resources).
|
|
18
28
|
|
|
19
|
-
This provider makes
|
|
29
|
+
This provider makes available to your application a timer function which given a
|
|
30
|
+
start time _(given as an array [seconds, nanoseconds])_ can give you a total
|
|
31
|
+
time elapsed since the start in milliseconds. The timer can also start timing if
|
|
32
|
+
no start time is given. This is used by LogComponent to allow a user to time a
|
|
33
|
+
Sequence.
|
|
20
34
|
|
|
21
|
-
|
|
35
|
+
_NOTE:_ _You can get the start time in the required format by using
|
|
36
|
+
`this.logger.startTimer()`._
|
|
37
|
+
|
|
38
|
+
You can provide your own implementation of the elapsed time function by binding
|
|
39
|
+
it to the binding key (accessible via `ExtensionStarterBindings`) as follows:
|
|
22
40
|
|
|
23
|
-
You can provide your own implementation of the elapsed time function by binding it to the binding key (accessible via `ExtensionStarterBindings`) as follows:
|
|
24
41
|
```ts
|
|
25
42
|
app.bind(ExtensionStarterBindings.TIMER).to(timerFn);
|
|
26
|
-
```
|
|
43
|
+
```
|
|
27
44
|
|
|
28
45
|
### LogProvider
|
|
29
46
|
|
|
30
|
-
LogProvider can automatically be bound to your Application's Context using the
|
|
47
|
+
LogProvider can automatically be bound to your Application's Context using the
|
|
48
|
+
LogComponent which exports the provider with a binding key of
|
|
49
|
+
`extension-starter.actions.log`.
|
|
31
50
|
|
|
32
51
|
The key can be accessed by importing `ExtensionStarterBindings` as follows:
|
|
33
52
|
|
|
34
53
|
**Example: Binding Keys**
|
|
54
|
+
|
|
35
55
|
```ts
|
|
36
56
|
import {ExtensionStarterBindings} from 'HelloExtensions';
|
|
37
57
|
// Key can be accessed as follows now
|
|
38
58
|
const key = ExtensionStarterBindings.LOG_ACTION;
|
|
39
59
|
```
|
|
40
60
|
|
|
41
|
-
LogProvider gives us a
|
|
61
|
+
LogProvider gives us a sequence action and a `startTimer` function. In order to
|
|
62
|
+
use the sequence action, you must define your own sequence as shown below.
|
|
42
63
|
|
|
43
64
|
**Example: Sequence**
|
|
65
|
+
|
|
44
66
|
```ts
|
|
45
67
|
class LogSequence implements SequenceHandler {
|
|
46
68
|
constructor(
|
|
47
69
|
@inject(coreSequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
|
|
48
70
|
@inject(coreSequenceActions.PARSE_PARAMS)
|
|
49
71
|
protected parseParams: ParseParams,
|
|
50
|
-
@inject(coreSequenceActions.INVOKE_METHOD)
|
|
51
|
-
protected invoke: InvokeMethod,
|
|
72
|
+
@inject(coreSequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
|
|
52
73
|
@inject(coreSequenceActions.SEND) protected send: Send,
|
|
53
74
|
@inject(coreSequenceActions.REJECT) protected reject: Reject,
|
|
54
75
|
// We get the logger injected by the LogProvider here
|
|
55
76
|
@inject(ExtensionStarterBindings.LOG_ACTION) protected logger: LogFn,
|
|
56
77
|
) {}
|
|
57
78
|
|
|
58
|
-
async handle(
|
|
79
|
+
async handle(context: RequestContext) {
|
|
80
|
+
const {request, response} = context;
|
|
81
|
+
|
|
59
82
|
// We define these variable outside so they can be accessed by logger.
|
|
60
83
|
let args: any = [];
|
|
61
84
|
let result: any;
|
|
@@ -65,39 +88,42 @@ class LogSequence implements SequenceHandler {
|
|
|
65
88
|
const start = this.logger.startTimer();
|
|
66
89
|
|
|
67
90
|
try {
|
|
68
|
-
const route = this.findRoute(
|
|
69
|
-
args = await this.parseParams(
|
|
91
|
+
const route = this.findRoute(request);
|
|
92
|
+
args = await this.parseParams(request, route);
|
|
70
93
|
result = await this.invoke(route, args);
|
|
71
|
-
this.send(
|
|
72
|
-
} catch (
|
|
73
|
-
result =
|
|
74
|
-
this.reject(
|
|
94
|
+
this.send(response, result);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
result = error; // so we can log the error message in the logger
|
|
97
|
+
this.reject(context, error);
|
|
75
98
|
}
|
|
76
99
|
|
|
77
100
|
// We call the logger function given to us by LogProvider
|
|
78
|
-
this.logger(
|
|
101
|
+
this.logger(request, args, result, start);
|
|
79
102
|
}
|
|
80
103
|
}
|
|
81
104
|
```
|
|
82
105
|
|
|
83
|
-
Once a sequence has been written, we can just use that in our Application as
|
|
106
|
+
Once a sequence has been written, we can just use that in our Application as
|
|
107
|
+
follows:
|
|
84
108
|
|
|
85
109
|
**Example: Application**
|
|
110
|
+
|
|
86
111
|
```ts
|
|
87
112
|
const app = new Application({
|
|
88
113
|
sequence: LogSequence,
|
|
89
|
-
components: [LogComponent]
|
|
90
114
|
});
|
|
115
|
+
app.component(LogComponent);
|
|
91
116
|
|
|
92
117
|
// Now all requests handled by our sequence will be logged.
|
|
93
118
|
```
|
|
94
119
|
|
|
95
120
|
## Related Resources
|
|
96
121
|
|
|
97
|
-
You can check out the following resource to learn more about providers,
|
|
122
|
+
You can check out the following resource to learn more about providers,
|
|
123
|
+
components, sequences, and binding keys.
|
|
98
124
|
|
|
99
125
|
- [Providers](http://loopback.io/doc/en/lb4/Creating-components.html#providers)
|
|
100
126
|
- [Creating Components](http://loopback.io/doc/en/lb4/Creating-components.html)
|
|
101
|
-
- [Using Components](http://loopback.io/doc/en/lb4/
|
|
127
|
+
- [Using Components](http://loopback.io/doc/en/lb4/Components.html)
|
|
102
128
|
- [Sequence](http://loopback.io/doc/en/lb4/Sequence.html)
|
|
103
129
|
- [Binding Keys](http://loopback.io/doc/en/lb4/Decorators.html)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface defining the component's options object
|
|
3
|
+
*/
|
|
4
|
+
export interface <%= project.optionsInterface %> {
|
|
5
|
+
// Add the definitions here
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Default options for the component
|
|
11
|
+
*/
|
|
12
|
+
export const <%= project.defaultOptions %>: <%= project.optionsInterface %> = {
|
|
13
|
+
// Specify the values here
|
|
14
|
+
|
|
15
|
+
};
|