Skip to content
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

Scaffold the project with @loopback/cli #2

Merged
merged 1 commit into from
Nov 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@ typings/
# dotenv environment variables file
.env

dist
dist6

66 changes: 66 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# Generated apidocs
api-docs/

# Transpiled JavaScript files from Typescript
dist/
dist6/

1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package-lock=false
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
dist6
api-docs
*.json
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"bracketSpacing": false,
"singleQuote": true,
"printWidth": 80,
"trailingComma": "all"
}
1 change: 1 addition & 0 deletions .yo-rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Copyright (c) IBM Corp. 2017. All Rights Reserved.
Node module: loopback4-extension-starter
Node module: @loopback/mqtt
This project is licensed under the MIT License, full text below.

--------
Expand Down
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: @loopback/mqtt
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

export * from './dist';
8 changes: 8 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: @loopback/mqtt
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

const nodeMajorVersion = +process.versions.node.split('.')[0];
const dist = nodeMajorVersion >= 7 ? './dist' : './dist6';
module.exports = require(dist);
11 changes: 11 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: @loopback/mqtt
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

// NOTE(bajtos) This file is used by TypeScript compiler to resolve imports
// from "test" files against original TypeScript sources in "src" directory.
// As a side effect, `tsc` also produces "dist/index.{js,d.ts,map} files
// that allow test files to import paths pointing to {src,test} root directory,
// which is project root for TS sources but "dist" for transpiled sources.
export * from './src';
52 changes: 52 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@loopback/mqtt",
"version": "1.0.0",
"description": "MQTT extension for LoopBack 4",
"keywords": [
"loopback-extension",
"loopback"
],
"main": "index.js",
"engines": {
"node": ">=8"
},
"scripts": {
"build": "lb-tsc",
"build:watch": "lb-tsc --watch",
"clean": "lb-clean",
"lint": "npm run prettier:check && npm run tslint",
"lint:fix": "npm run prettier:fix && npm run tslint:fix",
"prettier:cli": "lb-prettier \"**/*.ts\" \"**/*.js\"",
"prettier:check": "npm run prettier:cli -- -l",
"prettier:fix": "npm run prettier:cli -- --write",
"tslint": "lb-tslint",
"tslint:fix": "npm run tslint -- --fix",
"pretest": "npm run clean && npm run build",
"test": "lb-dist mocha DIST/test",
"posttest": "npm run lint",
"prepare": "npm run build"
},
"repository": {
"type": "git",
"url": "https://github.com/strongloop/loopback4-extension-mqtt"
},
"author": "",
"license": "MIT",
"files": [
"README.md",
"index.js",
"index.d.ts",
"dist",
"dist6"
],
"dependencies": {
"@loopback/context": "^4.0.0-alpha.18",
"@loopback/core": "^4.0.0-alpha.20"
},
"devDependencies": {
"@loopback/build": "^4.0.0-alpha.4",
"@loopback/testlab": "^4.0.0-alpha.13",
"@types/mocha": "^2.2.43",
"mocha": "^4.0.1"
}
}
14 changes: 14 additions & 0 deletions src/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: @loopback/mqtt
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Component, ProviderMap} from '@loopback/core';

export class MqttComponent implements Component {
constructor() {}

providers?: ProviderMap = {
};

}
5 changes: 5 additions & 0 deletions src/controllers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Controllers

This directory contains source files for the controllers exported by this extension.

For more information, see http://loopback.io/doc/en/lb4/Controllers.html.
28 changes: 28 additions & 0 deletions src/decorators/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Decorators

## Overview

Decorators provide annotations for class methods and arguments. Decorators use the form `@decorator` where `decorator` is the name of the function that will be called at runtime.

## Basic Usage

### txIdFromHeader

This simple decorator allows you to annotate a `Controller` method argument. The decorator will annotate the method argument with the value of the header `X-Transaction-Id` from the request.

**Example**
```
class MyController {
@get('/')
getHandler(@txIdFromHeader() txId: string) {
return `Your transaction id is: ${txId}`;
}
}
```

## Related Resources

You can check out the following resource to learn more about decorators and how they are used in LoopBack Next.

- [TypeScript Handbook: Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
- [Decorators in LoopBack](http://loopback.io/doc/en/lb4/Decorators.html)
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: @loopback/mqtt
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

export * from './component';
160 changes: 160 additions & 0 deletions src/mixins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Mixins

This directory contains source files for the mixins exported by this extension.

## Overview

Sometimes it's helpful to write partial classes and then combining them together to build more powerful classes. This pattern is called Mixins (mixing in partial classes) and is supported by LoopBack 4.

LoopBack 4 supports mixins at an `Application` level. Your partial class can then be mixed into the `Application` class. A mixin class can modify or override existing methods of the class or add new ones! It is also possible to mixin multiple classes together as needed.

### High level example
```ts
class MyApplication extends MyMixinClass(Application) {
// Your code
};

// Multiple Classes mixed together
class MyApp extends MyMixinClass(MyMixinClass2(Application)) {
// Your code
}
```

## Getting Started

For hello-extensions we write a simple Mixin that allows the `Application` class to bind a `Logger` class from ApplicationOptions, Components, or `.logger()` method that is mixed in. `Logger` instances are bound to the key `loggers.${Logger.name}`. Once a Logger has been bound, the user can retrieve it by using [Dependency Injection](http://loopback.io/doc/en/lb4/Dependency-injection.html) and the key for the `Logger`.

### What is a Logger?
> A Logger class is provides a mechanism for logging messages of varying priority by providing an implementation for `Logger.info()` & `Logger.error()`. An example of a Logger is `console` which has `console.log()` and `console.error()`.

#### An example Logger
```ts
class ColorLogger implements Logger {
log(...args: LogArgs) {
console.log('log :', ...args);
}

error(...args: LogArgs) {
// log in red color
console.log('\x1b[31m error: ', ...args, '\x1b[0m');
}
}
```

## LoggerMixin
A complete & functional implementation can be found in `logger.mixin.ts`. *Here are some key things to keep in mind when writing your own Mixin*.

### constructor()
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.

It is also important for the constructor to call `super(args)` so `Application` continues to work as expected.
```ts
constructor(...args: any[]) {
super(args);
}
```

### Binding via `ApplicationOptions`
As mentioned earlier, since our `args` represents `ApplicationOptions`, we can make it possible for users to pass in their `Logger` implementations in a `loggers` array on `ApplicationOptions`. We can then read the array and automatically bind these for the user.

#### Example user experience
```ts
class MyApp extends LoggerMixin(Application){
constructor(...args: any[]) {
super(...args);
}
};

const app = new MyApp({
loggers: [ColorLogger]
});
```

#### Example Implementation
To implement this, we would check `this.options` to see if it has a `loggers` array and if so, bind it by calling the `.logger()` method. (More on that below).
```ts
if (this.options.loggers) {
for (const logger of this.options.loggers) {
this.logger(logger);
}
}
```

### Binding via `.logger()`
As mentioned earlier, we can add a new function to our `Application` class called `.logger()` into which a user would pass in their `Logger` implementation so we can bind it to the `loggers.*` key for them. We just add this new method on our partial Mixin class.
```ts
logger(logClass: Logger) {
const loggerKey = `loggers.${logClass.name}`;
this.bind(loggerKey).toClass(logClass);
}
```

### Binding a `Logger` from a `Component`
Our base class of `Application` already has a method that binds components. We can modify this method to continue binding a `Component` as usual but also binding any `Logger` instances provided by that `Component`. When modifying behavior of an existing method, we can ensure existing behavior by calling the `super.method()`. In our case the method is `.component()`.
```ts
component(component: Constructor<any>) {
super.component(component); // ensures existing behavior from Application
this.mountComponentLoggers(component);
}
```

We have now modified `.component()` to do it's thing and then call our method `mountComponentLoggers()`. In this method is where we check for `Logger` implementations declared by the component in a `loggers` array by retrieving the instance of the `Component`. Then if `loggers` array exists, we bind the `Logger` instances as normal (by leveraging our `.logger()` method).

```ts
mountComponentLoggers(component: Constructor<any>) {
const componentKey = `components.${component.name}`;
const compInstance = this.getSync(componentKey);

if (compInstance.loggers) {
for (const logger of compInstance.loggers) {
this.logger(logger);
}
}
}
```

## Retrieving the Logger instance
Now that we have bound a Logger to our Application via one of the many ways made possible by `LoggerMixin`, we need to be able to retrieve it so we can use it. Let's say we want to use it in a controller. Here's an example to retrieving it so we can use it.
```ts
class MyController {
constructor(@inject('loggers.ColorLogger') protected log: Logger) {}

helloWorld() {
this.log.log('hello log');
this.log.error('hello error');
}
}
```

## Examples for using LoggerMixin
### Using the app's `.logger()` method
```ts
class LoggingApplication extends LoggerMixin(Application) {
constructor(...args: any[]) {
super(...args);
this.logger(ColorLogger);
}
}
```

### Using the app's constructor
```ts
class LoggerApplication extends LoggerMixin(Application) {
constructor() {
super({
loggers: [ColorLogger],
});
}
}
```

### Binding a Logger provided by a component
```ts
class LoggingComponent implements Component{
loggers: [ColorLogger];
}

const app = new LoggingApplication({
components: [LoggingComponent] // Logger from MyComponent will be bound to loggers.ColorLogger
});
```
Loading