-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: clean up extension generator #6158
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for starting the work in cleaning up the template for extensions. I find your implementation as very repetitive and easy to break if we don't remember to update all places repeating the same string manipulation logic. Please move the string manipulation to the generator.
This of the generator as a controller and the template as a view in MVC pattern. Views should be dump and deal only with rendering - converting data produced by the controller to the output format (HTML in MVC, TypeScript code in our case). Data manipulation and business logic belongs to the controller.
@@ -1,9 +1,13 @@ | |||
import {Component, ProviderMap} from '@loopback/core'; | |||
import {<%= project.name.charAt(0).toUpperCase() + project.name.slice(1) %>Bindings} from './keys' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not perform case manipulation in the template. Please move this code to the generator and make sure we use the same logic for all places (templates) that need to acces {ProjectName}Bindings
.
import {<%= project.name.charAt(0).toUpperCase() + project.name.slice(1) %>Bindings} from './keys' | |
import {<%= project.bindingsNamespace %>} from './keys' |
See how we lb4 app
is building appClassWithMixins
string for inspiration:
@@ -1,9 +1,13 @@ | |||
import {Component, ProviderMap} from '@loopback/core'; | |||
import {<%= project.name.charAt(0).toUpperCase() + project.name.slice(1) %>Bindings} from './keys' | |||
import {<%= project.name.toUpperCase() %>_OPTIONS} from './types'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly here.
import {<%= project.name.toUpperCase() %>_OPTIONS} from './types'; | |
import {<%= project.optionsConstant %>} from './types'; |
Thanks @bajtos I have applied your feedback. |
6c8bc9b
to
4fd36e3
Compare
4fd36e3
to
e45f386
Compare
@hacksparrow It would be nice to document the extension project layout as #6151 does for applications. |
More often than not, the component may want to offer different value providers | ||
depending on the configuration. For example, a component providing an email API | ||
may offer different transports (stub, SMTP, and so on). | ||
Components can be configured by an app by calling `this.configure()` in its |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHANGE NOTE
Let's keep examples as simple as possible and avoid using concepts and terms which can be overwhelming for beginners.
@@ -0,0 +1,7 @@ | |||
export interface <%= project.optionsInterface %> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add some comments here to explain the purpose of <Extension>Options
and describe specific properties should be added into the empty body.
@inject(CoreBindings.APPLICATION_INSTANCE) | ||
private application: Application, | ||
@config() | ||
options: <%= project.optionsInterface %> = <%= project.defaultOptions %>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private options
?
|
||
@bind({tags: {[ContextTags.KEY]: <%= project.bindingsNamespace %>.COMPONENT}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add some comments for the component.
docs/site/Extending-LoopBack-4.md
Outdated
@@ -190,7 +190,23 @@ An application-level component usually contributes: | |||
### Learn from existing ones | |||
|
|||
- [loopback4-example-log-extension](https://github.com/strongloop/loopback-next/tree/master/examples/log-extension) | |||
- [@loopback/apiconnect](https://github.com/strongloop/loopback-next/tree/master/extensions/apiconnect) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are going to have the list of extensions we created in Component.md
, it might be better to reference the list in here. It might be to keep both list updated as we're adding more extensions. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the acceptance criteria. Would like to hear from @bajtos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use your own judgment. The goal is to have a list of all extensions, to make it easier for our users to find them. I don't mind that much where the list is.
I agree with @dhmlau that we should have only one place where we are listing all components. Keeping multiple lists in sync is too much work and if we don't have automated checks in place, then we will almost certainly to forget to update all places sometime in the future.
docs/site/Component.md
Outdated
Here is a list of components officially created and maintained by the LoopBack | ||
team. | ||
|
||
- [@loopback/apiconnect](https://github.com/strongloop/loopback-next/tree/master/extensions/apiconnect) - An extension for IBM API Connect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- [@loopback/apiconnect](https://github.com/strongloop/loopback-next/tree/master/extensions/apiconnect) - An extension for IBM API Connect | |
- [@loopback/apiconnect](https://github.com/strongloop/loopback-next/tree/master/extensions/apiconnect) - An extension for integrating with [IBM API Connect](https://www.ibm.com/cloud/api-connect) |
docs/site/Component.md
Outdated
|
||
- [@loopback/apiconnect](https://github.com/strongloop/loopback-next/tree/master/extensions/apiconnect) - An extension for IBM API Connect | ||
- [@loopback/authentication](https://github.com/strongloop/loopback-next/tree/master/packages/authentication) - A LoopBack component for authentication support | ||
- [@loopback/authentication-jwt](https://github.com/strongloop/loopback-next/tree/master/extensions/authentication-jwt) - Extension for the prototype of JWT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe simply Extension for JWT authentication
?
@@ -83,6 +83,37 @@ const app = new RestApplication(); | |||
app.component(AuthenticationComponent); | |||
``` | |||
|
|||
## Official components | |||
|
|||
Here is a list of components officially created and maintained by the LoopBack |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the list below contains the components from the core (e.g. @loopback/rest
) and extensions (e.g. @loopback/apiconnect
). Perhaps it's better to separate the 2 categories?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bajtos what do you say?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind either way.
@raymondfeng let's do that in a follow up task, there are two more nice-to-haves in the acceptance criteria, I will club them together. |
ecf7037
to
7df1e9d
Compare
this.projectInfo.name.slice(1); | ||
this.projectInfo.optionsInterface = `${titleCase}Options`; | ||
this.projectInfo.bindingsNamespace = `${titleCase}Bindings`; | ||
this.projectInfo.defaultOptions = `DEFAULT_${this.projectInfo.name.toUpperCase()}_OPTIONS`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure we are handling multi-word names correctly and consistently with other places that are building PascalCase and camelCase identifiers.
A test case to consider: projectInfo.name
is todo-demo
. I expect the following strings to be used:
- options interface:
TodoDemoOptions
- bindings namespace:
TodoDemoBindings
- default options:
DEFAULT_TODO_DEMO_OPTIONS
Please check how is lb4 app
generator dealing with multi-word app names and apply the same solution for extensions. If the app generators behaves differently from what I described above, then please follow what the app generator is doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lb4 app
is not doing the upperase-underscore thing (eg: DEFAULT_TODO_DEMO_OPTIONS
), generating it this way for extension:
const uppercaseUnderscore = this.projectInfo.name
.toUpperCase()
.replace(/\W/g, '_');
this.projectInfo.defaultOptions = `DEFAULT_${uppercaseUnderscore}_OPTIONS`;
Rest, updated to be like lb4 app
.
|
||
## Installation | ||
|
||
Describe the installation steps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the generator can pre-fill this section, the typical instructions is to npm install
the package, right?
|
||
## Basic Use | ||
|
||
Describe the usage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the generator put the default example we are using in our components? Something along the following lines (replace MyComponent
with the real name):
this.configure(MyComponent.COMPONENT).to({
// put the configuration options here
});
this.component(MyComponent);
|
||
## License | ||
|
||
Specify the license. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect that many people won't bother to edit this section and push it to github & npmjs as-is. I think it's better to leave out the License section completely, rather than have content that's meaningless.
c89ee7f
to
56517ca
Compare
config, | ||
ContextTags, | ||
CoreBindings, | ||
createBindingFromClass, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import is not used. Please remove or leave it behind a comment.
as shown below. | ||
|
||
```ts | ||
... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use // ...
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to include import
statements here?
// Put the configuration options here | ||
}); | ||
this.component(<%= project.componentName %>); | ||
... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
|
||
```ts | ||
... | ||
this.configure(<%= project.componentName %>.COMPONENT).to({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be <%= project.bindingsNamespace %>.COMPONENT
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have something like:
const options: <%= project.optionsInterface %> = <%= project.defaultOptions %>;
this.configure(<%= project.bindingsNamespace %>.COMPONENT).to(options);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly good, please address @raymondfeng comments.
I am not sure if the algorithm for building defaultOptions
name will produce values consistent with other names (especially in app generator) in all edge cases. This should be easy to fix later, so I guess it's ok to wait until there is a bug report (if there is any problem ever).
{% include code-caption.html content="application.ts" %} | ||
|
||
```ts | ||
... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep code snippets a valid TypeScript please.
... | |
// ... |
Per Raymond's suggestions above. The same comment applies to all other places where you are using ...
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM from the documentation perspective. I had one suggestion to include the community extensions as well.
Resource pooling service for LoopBack 4 | ||
- [@loopback/typeorm](https://github.com/strongloop/loopback-next/tree/master/extensions/typeorm) - | ||
Adds support for TypeORM in LoopBack | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we want to add the link for community extensions as well? https://loopback.io/doc/en/lb4/Community-extensions.html
0e0ac32
to
6c80af3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please squash all commits into one before landing the PR.
Sure, thanks. |
Clean up the extension generator. Signed-off-by: Yaapa Hage <[email protected]>
6c80af3
to
c5e90b2
Compare
Addresses #5336.
Checklist
npm test
passes on your machinepackages/cli
were updatedexamples/*
were updated👉 Check out how to submit a PR 👈