ing
This commit is contained in:
commit
bc3f80b726
13
.editorconfig
Normal file
13
.editorconfig
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
39
.gitignore
vendored
Normal file
39
.gitignore
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
27
README.md
Normal file
27
README.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# LoaferNg
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.3.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
241
angular.json
Normal file
241
angular.json
Normal file
|
@ -0,0 +1,241 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"example": {
|
||||
"root": "example",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/example",
|
||||
"index": "example/index.html",
|
||||
"main": "example/main.ts",
|
||||
"polyfills": "example/polyfills.ts",
|
||||
"tsConfig": "example/tsconfig.app.json",
|
||||
"assets": [
|
||||
"example/favicon.ico",
|
||||
"example/assets"
|
||||
],
|
||||
"styles": [
|
||||
"example/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "example/environments/environment.ts",
|
||||
"with": "example/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "example:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "example:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "example:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "example/test.ts",
|
||||
"polyfills": "example/polyfills.ts",
|
||||
"tsConfig": "example/tsconfig.spec.json",
|
||||
"karmaConfig": "example/karma.conf.js",
|
||||
"styles": [
|
||||
"example/styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"example/favicon.ico",
|
||||
"example/assets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"example/tsconfig.app.json",
|
||||
"example/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"example-e2e": {
|
||||
"root": "e2e/",
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "example:serve"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@loafer/ng-logger": {
|
||||
"root": "projects/loafer/ng-logger",
|
||||
"sourceRoot": "projects/loafer/ng-logger/src",
|
||||
"projectType": "library",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"options": {
|
||||
"tsConfig": "projects/loafer/ng-logger/tsconfig.lib.json",
|
||||
"project": "projects/loafer/ng-logger/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"project": "projects/loafer/ng-logger/ng-package.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/loafer/ng-logger/src/test.ts",
|
||||
"tsConfig": "projects/loafer/ng-logger/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/loafer/ng-logger/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/loafer/ng-logger/tsconfig.lib.json",
|
||||
"projects/loafer/ng-logger/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@loafer/ng-rest": {
|
||||
"root": "projects/loafer/ng-rest",
|
||||
"sourceRoot": "projects/loafer/ng-rest/src",
|
||||
"projectType": "library",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"options": {
|
||||
"tsConfig": "projects/loafer/ng-rest/tsconfig.lib.json",
|
||||
"project": "projects/loafer/ng-rest/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"project": "projects/loafer/ng-rest/ng-package.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/loafer/ng-rest/src/test.ts",
|
||||
"tsConfig": "projects/loafer/ng-rest/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/loafer/ng-rest/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/loafer/ng-rest/tsconfig.lib.json",
|
||||
"projects/loafer/ng-rest/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@loafer/ng-rpc": {
|
||||
"root": "projects/loafer/ng-rpc",
|
||||
"sourceRoot": "projects/loafer/ng-rpc/src",
|
||||
"projectType": "library",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"options": {
|
||||
"tsConfig": "projects/loafer/ng-rpc/tsconfig.lib.json",
|
||||
"project": "projects/loafer/ng-rpc/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"project": "projects/loafer/ng-rpc/ng-package.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/loafer/ng-rpc/src/test.ts",
|
||||
"tsConfig": "projects/loafer/ng-rpc/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/loafer/ng-rpc/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/loafer/ng-rpc/tsconfig.lib.json",
|
||||
"projects/loafer/ng-rpc/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "example"
|
||||
}
|
28
e2e/protractor.conf.js
Normal file
28
e2e/protractor.conf.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.e2e.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
14
e2e/src/app.e2e-spec.ts
Normal file
14
e2e/src/app.e2e-spec.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { AppPage } from './app.po';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
11
e2e/src/app.po.ts
Normal file
11
e2e/src/app.po.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
13
e2e/tsconfig.e2e.json
Normal file
13
e2e/tsconfig.e2e.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
0
example/app/app.component.css
Normal file
0
example/app/app.component.css
Normal file
20
example/app/app.component.html
Normal file
20
example/app/app.component.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!--The content below is only a placeholder and can be replaced.-->
|
||||
<div style="text-align:center">
|
||||
<h1>
|
||||
Welcome to {{ title }}!
|
||||
</h1>
|
||||
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
|
||||
</div>
|
||||
<h2>Here are some links to help you start: </h2>
|
||||
<ul>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
|
27
example/app/app.component.spec.ts
Normal file
27
example/app/app.component.spec.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
it('should create the app', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
}));
|
||||
it(`should have as title 'app'`, async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('app');
|
||||
}));
|
||||
it('should render title in a h1 tag', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to loafer-ng!');
|
||||
}));
|
||||
});
|
10
example/app/app.component.ts
Normal file
10
example/app/app.component.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'app';
|
||||
}
|
16
example/app/app.module.ts
Normal file
16
example/app/app.module.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
0
example/assets/.gitkeep
Normal file
0
example/assets/.gitkeep
Normal file
9
example/browserslist
Normal file
9
example/browserslist
Normal file
|
@ -0,0 +1,9 @@
|
|||
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
# For IE 9-11 support, please uncomment the last line of the file and adjust as needed
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
# IE 9-11
|
3
example/environments/environment.prod.ts
Normal file
3
example/environments/environment.prod.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export const environment = {
|
||||
production: true
|
||||
};
|
15
example/environments/environment.ts
Normal file
15
example/environments/environment.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
||||
|
||||
/*
|
||||
* In development mode, to ignore zone related error stack frames such as
|
||||
* `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
|
||||
* import the following file, but please comment it out in production mode
|
||||
* because it will have performance impact when throw error
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
BIN
example/favicon.ico
Normal file
BIN
example/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
14
example/index.html
Normal file
14
example/index.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>LoaferNg</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
31
example/karma.conf.js
Normal file
31
example/karma.conf.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../coverage'),
|
||||
reports: ['html', 'lcovonly'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
12
example/main.ts
Normal file
12
example/main.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.log(err));
|
80
example/polyfills.ts
Normal file
80
example/polyfills.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
// import 'core-js/es6/symbol';
|
||||
// import 'core-js/es6/object';
|
||||
// import 'core-js/es6/function';
|
||||
// import 'core-js/es6/parse-int';
|
||||
// import 'core-js/es6/parse-float';
|
||||
// import 'core-js/es6/number';
|
||||
// import 'core-js/es6/math';
|
||||
// import 'core-js/es6/string';
|
||||
// import 'core-js/es6/date';
|
||||
// import 'core-js/es6/array';
|
||||
// import 'core-js/es6/regexp';
|
||||
// import 'core-js/es6/map';
|
||||
// import 'core-js/es6/weak-map';
|
||||
// import 'core-js/es6/set';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||
// import 'core-js/es6/reflect';
|
||||
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
**/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
*/
|
||||
|
||||
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
|
||||
/*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*/
|
||||
// (window as any).__Zone_enable_cross_context_check = true;
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
1
example/styles.css
Normal file
1
example/styles.css
Normal file
|
@ -0,0 +1 @@
|
|||
/* You can add global styles to this file, and also import other style files */
|
20
example/test.ts
Normal file
20
example/test.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
12
example/tsconfig.app.json
Normal file
12
example/tsconfig.app.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "es2015",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
19
example/tsconfig.spec.json
Normal file
19
example/tsconfig.spec.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts",
|
||||
"polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
17
example/tslint.json
Normal file
17
example/tslint.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
11550
package-lock.json
generated
Normal file
11550
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
56
package.json
Normal file
56
package.json
Normal file
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"name": "loafer-ng",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^6.0.2",
|
||||
"@angular/core": "^6.0.2",
|
||||
"@angular/compiler": "^6.0.2",
|
||||
"@angular/animations": "^6.0.2",
|
||||
"@angular/forms": "^6.0.2",
|
||||
"@angular/http": "^6.0.2",
|
||||
"@angular/platform-browser": "^6.0.2",
|
||||
"@angular/platform-browser-dynamic": "^6.0.2",
|
||||
"@angular/router": "^6.0.2",
|
||||
"@loafer/core": "^0.0.1",
|
||||
"@loafer/decorator": "^0.0.1",
|
||||
"@ngrx/store": "^5.2.0",
|
||||
"core-js": "^2.5.4",
|
||||
"rxjs": "^6.0.0",
|
||||
"rxjs-compat": "^6.0.0",
|
||||
"zone.js": "^0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/compiler-cli": "^6.0.2",
|
||||
"@angular-devkit/build-ng-packagr": "~0.6.3",
|
||||
"@angular-devkit/build-angular": "~0.6.3",
|
||||
"ng-packagr": "^3.0.0-rc.2",
|
||||
"tsickle": ">=0.25.5",
|
||||
"tslib": "^1.7.1",
|
||||
"typescript": "~2.7.2",
|
||||
"@angular/cli": "~6.0.3",
|
||||
"@angular/language-service": "^6.0.2",
|
||||
"@types/jasmine": "~2.8.6",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "~8.9.4",
|
||||
"codelyzer": "~4.2.1",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~1.7.1",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~1.4.2",
|
||||
"karma-jasmine": "~1.1.1",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.3.0",
|
||||
"ts-node": "~5.0.1",
|
||||
"tslint": "~5.9.1"
|
||||
}
|
||||
}
|
31
projects/loafer/ng-logger/karma.conf.js
Normal file
31
projects/loafer/ng-logger/karma.conf.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage'),
|
||||
reports: ['html', 'lcovonly'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
8
projects/loafer/ng-logger/ng-package.json
Normal file
8
projects/loafer/ng-logger/ng-package.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/loafer/ng-logger",
|
||||
"deleteDestPath": true,
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts"
|
||||
}
|
||||
}
|
7
projects/loafer/ng-logger/ng-package.prod.json
Normal file
7
projects/loafer/ng-logger/ng-package.prod.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/loafer/ng-logger",
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts"
|
||||
}
|
||||
}
|
15
projects/loafer/ng-logger/package.json
Normal file
15
projects/loafer/ng-logger/package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@loafer/ng-logger",
|
||||
"version": "0.0.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.loafle.net/loafer/ng.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-loafle/"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^6.0.0-rc.0 || ^6.0.0",
|
||||
"@angular/core": "^6.0.0-rc.0 || ^6.0.0"
|
||||
}
|
||||
}
|
6
projects/loafer/ng-logger/src/lib/ng-logger.config.ts
Normal file
6
projects/loafer/ng-logger/src/lib/ng-logger.config.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { LoggerLevel } from './ng-logger.type';
|
||||
|
||||
export class LoggerConfig {
|
||||
level: LoggerLevel;
|
||||
serverLogLevel?: LoggerLevel;
|
||||
}
|
65
projects/loafer/ng-logger/src/lib/ng-logger.module.ts
Normal file
65
projects/loafer/ng-logger/src/lib/ng-logger.module.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import {
|
||||
NgModule,
|
||||
ModuleWithProviders,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
LoggerConfig,
|
||||
} from './ng-logger.config';
|
||||
|
||||
import {
|
||||
LoggerService,
|
||||
} from './ng-logger.service';
|
||||
|
||||
export interface LoggerFeatureModuleConfig {
|
||||
url?: any;
|
||||
}
|
||||
|
||||
export interface LoggerRootModuleConfig {
|
||||
config: LoggerConfig;
|
||||
}
|
||||
|
||||
const SERVICES = [
|
||||
LoggerService,
|
||||
];
|
||||
|
||||
@NgModule({})
|
||||
export class LoggerRootModule {
|
||||
constructor(
|
||||
private loggerService: LoggerService,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class LoggerFeatureModule {
|
||||
constructor(
|
||||
private loggerService: LoggerService,
|
||||
private root: LoggerRootModule,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class LoggerModule {
|
||||
static forRoot(config: LoggerRootModuleConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: LoggerRootModule,
|
||||
providers: [
|
||||
{
|
||||
provide: LoggerConfig,
|
||||
useValue: config.config,
|
||||
},
|
||||
SERVICES,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
static forFeature(config: LoggerFeatureModuleConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: LoggerFeatureModule,
|
||||
providers: [
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
15
projects/loafer/ng-logger/src/lib/ng-logger.service.spec.ts
Normal file
15
projects/loafer/ng-logger/src/lib/ng-logger.service.spec.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { LoggerService } from './ng-logger.service';
|
||||
|
||||
describe('LoggerService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [LoggerService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([LoggerService], (service: LoggerService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
161
projects/loafer/ng-logger/src/lib/ng-logger.service.ts
Normal file
161
projects/loafer/ng-logger/src/lib/ng-logger.service.ts
Normal file
|
@ -0,0 +1,161 @@
|
|||
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
|
||||
import { isPlatformBrowser } from '@angular/common';
|
||||
|
||||
import {
|
||||
LoggerConfig,
|
||||
} from './ng-logger.config';
|
||||
|
||||
import {
|
||||
LoggerLevel,
|
||||
LoggerLevelName,
|
||||
} from './ng-logger.type';
|
||||
|
||||
|
||||
export type ConsoleFunc = (message?: any, ...optionalParams: any[]) => void;
|
||||
|
||||
@Injectable()
|
||||
export class LoggerService {
|
||||
private _isIE: boolean;
|
||||
|
||||
public constructor(
|
||||
private readonly config: LoggerConfig,
|
||||
@Inject(PLATFORM_ID) private readonly platformId,
|
||||
) {
|
||||
this._isIE = isPlatformBrowser(platformId) &&
|
||||
!!(navigator.userAgent.indexOf('MSIE') !== -1 || navigator.userAgent.match(/Trident\//) || navigator.userAgent.match(/Edge\//));
|
||||
|
||||
}
|
||||
|
||||
public get trace(): ConsoleFunc {
|
||||
return this.getConsoleMethod(LoggerLevel.TRACE);
|
||||
}
|
||||
public get debug(): ConsoleFunc {
|
||||
return this.getConsoleMethod(LoggerLevel.DEBUG);
|
||||
}
|
||||
public get info(): ConsoleFunc {
|
||||
return this.getConsoleMethod(LoggerLevel.INFO);
|
||||
}
|
||||
public get log(): ConsoleFunc {
|
||||
return this.getConsoleMethod(LoggerLevel.LOG);
|
||||
}
|
||||
public get warn(): ConsoleFunc {
|
||||
return this.getConsoleMethod(LoggerLevel.WARN);
|
||||
}
|
||||
public get error(): ConsoleFunc {
|
||||
return this.getConsoleMethod(LoggerLevel.ERROR);
|
||||
}
|
||||
|
||||
private _console_log: ConsoleFunc;
|
||||
|
||||
private getConsoleMethod(level: LoggerLevel): ConsoleFunc {
|
||||
if (level < this.config.level) {
|
||||
return (message, ...additional: any[]) => {};
|
||||
}
|
||||
|
||||
if (this._isIE) {
|
||||
switch (level) {
|
||||
case LoggerLevel.WARN:
|
||||
return console.warn.bind(console, ...this.getLogHeader(level));
|
||||
case LoggerLevel.ERROR:
|
||||
return console.error.bind(console, ...this.getLogHeader(level));
|
||||
case LoggerLevel.INFO:
|
||||
return console.info.bind(console, ...this.getLogHeader(level));
|
||||
default:
|
||||
return console.log.bind(console, ...this.getLogHeader(level));
|
||||
}
|
||||
} else {
|
||||
return console.log.bind(console, ...this.getLogHeader(level));
|
||||
}
|
||||
}
|
||||
|
||||
private getLogHeader(level: LoggerLevel): any[] {
|
||||
const params: any[] = [];
|
||||
params.push(`%c${this._timestamp()} [${LoggerLevelName[level]}]`);
|
||||
if (!this._isIE) {
|
||||
const color = this._getColor(level);
|
||||
params.push(`color:${color}`);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private _timestamp(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
private _log(level: LoggerLevel, message, additional: any[] = []): void {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow logging on server even if client log level is off
|
||||
// if (logOnServer) {
|
||||
// this._logOnServer(level, message, additional);
|
||||
// }
|
||||
|
||||
// if no message or the log level is less than the environ
|
||||
if (level < this.config.level) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
message = typeof message === 'string' ? message : JSON.stringify(message, null, 2);
|
||||
} catch (e) {
|
||||
additional = [message, ...additional];
|
||||
message = 'The provided "message" value could not be parsed with JSON.stringify().';
|
||||
}
|
||||
|
||||
// Coloring doesn't work in IE
|
||||
if (this._isIE) {
|
||||
return this._logIE(level, message, additional);
|
||||
}
|
||||
|
||||
const color = this._getColor(level);
|
||||
|
||||
const params: any[] = [];
|
||||
params.push(`%c${this._timestamp()} [${LoggerLevelName[level]}]`);
|
||||
params.push(`color:${color}`);
|
||||
params.push(message);
|
||||
params.push(...additional);
|
||||
|
||||
console.log.apply(console, params);
|
||||
}
|
||||
|
||||
private _logIE(level: LoggerLevel, message: string, additional: any[] = []): void {
|
||||
const params: any[] = [];
|
||||
params.push(`${this._timestamp()} [${LoggerLevelName[level]}] `);
|
||||
params.push(message);
|
||||
params.push(...additional);
|
||||
|
||||
switch (level) {
|
||||
case LoggerLevel.WARN:
|
||||
console.warn.apply(console, params);
|
||||
break;
|
||||
case LoggerLevel.ERROR:
|
||||
console.error.apply(console, params);
|
||||
break;
|
||||
case LoggerLevel.INFO:
|
||||
console.info.apply(console, params);
|
||||
break;
|
||||
default:
|
||||
console.log.apply(console, params);
|
||||
}
|
||||
}
|
||||
|
||||
private _getColor(level: LoggerLevel): 'blue' | 'teal' | 'gray' | 'red' | undefined {
|
||||
switch (level) {
|
||||
case LoggerLevel.TRACE:
|
||||
return 'blue';
|
||||
case LoggerLevel.DEBUG:
|
||||
return 'teal';
|
||||
case LoggerLevel.INFO:
|
||||
case LoggerLevel.LOG:
|
||||
return 'gray';
|
||||
case LoggerLevel.WARN:
|
||||
case LoggerLevel.ERROR:
|
||||
return 'red';
|
||||
case LoggerLevel.OFF:
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
26
projects/loafer/ng-logger/src/lib/ng-logger.type.ts
Normal file
26
projects/loafer/ng-logger/src/lib/ng-logger.type.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
export enum LoggerLevel {
|
||||
TRACE = 0,
|
||||
DEBUG,
|
||||
INFO,
|
||||
LOG,
|
||||
WARN,
|
||||
ERROR,
|
||||
OFF,
|
||||
}
|
||||
|
||||
export const LoggerLevelName = [
|
||||
'TRACE',
|
||||
'DEBUG',
|
||||
'INFO',
|
||||
'LOG',
|
||||
'WARN',
|
||||
'ERROR',
|
||||
'OFF'
|
||||
];
|
||||
|
||||
export interface ServerLoggingParameter {
|
||||
level: string;
|
||||
message: string;
|
||||
addtional?: string;
|
||||
timestamp: Date;
|
||||
}
|
8
projects/loafer/ng-logger/src/public_api.ts
Normal file
8
projects/loafer/ng-logger/src/public_api.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Public API Surface of ng-logger
|
||||
*/
|
||||
|
||||
export * from './lib/ng-logger.config';
|
||||
export * from './lib/ng-logger.type';
|
||||
export * from './lib/ng-logger.service';
|
||||
export * from './lib/ng-logger.module';
|
22
projects/loafer/ng-logger/src/test.ts
Normal file
22
projects/loafer/ng-logger/src/test.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
33
projects/loafer/ng-logger/tsconfig.lib.json
Normal file
33
projects/loafer/ng-logger/tsconfig.lib.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2015"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true,
|
||||
"flatModuleId": "AUTOGENERATED",
|
||||
"flatModuleOutFile": "AUTOGENERATED"
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
17
projects/loafer/ng-logger/tsconfig.spec.json
Normal file
17
projects/loafer/ng-logger/tsconfig.spec.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
17
projects/loafer/ng-logger/tslint.json
Normal file
17
projects/loafer/ng-logger/tslint.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"lib",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
31
projects/loafer/ng-rest/karma.conf.js
Normal file
31
projects/loafer/ng-rest/karma.conf.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage'),
|
||||
reports: ['html', 'lcovonly'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
8
projects/loafer/ng-rest/ng-package.json
Normal file
8
projects/loafer/ng-rest/ng-package.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/loafer/ng-rest",
|
||||
"deleteDestPath": true,
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts"
|
||||
}
|
||||
}
|
7
projects/loafer/ng-rest/ng-package.prod.json
Normal file
7
projects/loafer/ng-rest/ng-package.prod.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/loafer/ng-rest",
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts"
|
||||
}
|
||||
}
|
15
projects/loafer/ng-rest/package.json
Normal file
15
projects/loafer/ng-rest/package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@loafer/ng-rest",
|
||||
"version": "0.0.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.loafle.net/loafer/ng.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-loafle/"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^6.0.0-rc.0 || ^6.0.0",
|
||||
"@angular/core": "^6.0.0-rc.0 || ^6.0.0"
|
||||
}
|
||||
}
|
65
projects/loafer/ng-rest/src/lib/ng-rest.client.ts
Normal file
65
projects/loafer/ng-rest/src/lib/ng-rest.client.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { Injectable, Inject } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { HttpClient, HttpHeaders, HttpParams, HttpErrorResponse } from '@angular/common/http';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import 'rxjs/add/operator/timeout';
|
||||
import 'rxjs/add/observable/throw';
|
||||
|
||||
import {
|
||||
RESTError,
|
||||
RESTClientError,
|
||||
} from './ng-rest.error';
|
||||
|
||||
export class RESTClient {
|
||||
constructor(
|
||||
private _baseURL: string,
|
||||
private _httpClient: HttpClient,
|
||||
) {
|
||||
}
|
||||
|
||||
public get httpClient(): HttpClient {
|
||||
return this._httpClient;
|
||||
}
|
||||
|
||||
public request<T>(method: string, entry: string, options?: {
|
||||
body?: any;
|
||||
headers?: HttpHeaders | {
|
||||
[header: string]: string | string[];
|
||||
};
|
||||
observe?: 'body';
|
||||
params?: HttpParams | {
|
||||
[param: string]: string | string[];
|
||||
};
|
||||
responseType?: 'json';
|
||||
reportProgress?: boolean;
|
||||
withCredentials?: boolean;
|
||||
}): Observable<T> {
|
||||
return this._httpClient
|
||||
.request<T>(method, Location.joinWithSlash(this._baseURL, entry), options)
|
||||
.map(response => response)
|
||||
.catch((error: HttpErrorResponse) => {
|
||||
const restClientError: RESTClientError = {
|
||||
request: {
|
||||
method: method,
|
||||
entry: entry,
|
||||
options: options,
|
||||
},
|
||||
response: error.error,
|
||||
};
|
||||
|
||||
console.error(restClientError);
|
||||
// const aryMsg = error.error.message.split('|');
|
||||
// const resError: RESTError = {
|
||||
// code: error.error.code,
|
||||
// message: aryMsg[0],
|
||||
// data: aryMsg[1] === 'null' ? '' : aryMsg[1],
|
||||
// };
|
||||
return Observable.throw(restClientError);
|
||||
});
|
||||
}
|
||||
}
|
14
projects/loafer/ng-rest/src/lib/ng-rest.error.ts
Normal file
14
projects/loafer/ng-rest/src/lib/ng-rest.error.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
export interface RESTClientError {
|
||||
request: {
|
||||
method: string;
|
||||
entry: string;
|
||||
options?: any;
|
||||
};
|
||||
response: RESTError;
|
||||
}
|
||||
|
||||
export interface RESTError {
|
||||
code: number;
|
||||
message: string;
|
||||
data?: any;
|
||||
}
|
68
projects/loafer/ng-rest/src/lib/ng-rest.module.ts
Normal file
68
projects/loafer/ng-rest/src/lib/ng-rest.module.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import {
|
||||
NgModule,
|
||||
ModuleWithProviders,
|
||||
Type,
|
||||
Inject,
|
||||
InjectionToken,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
_REST_BASE_URL,
|
||||
} from './ng-rest.token';
|
||||
|
||||
import {
|
||||
RESTService,
|
||||
} from './ng-rest.service';
|
||||
|
||||
export interface RESTFeatureModuleConfig {
|
||||
url?: any;
|
||||
}
|
||||
|
||||
export interface RESTRootModuleConfig {
|
||||
baseURL: string;
|
||||
}
|
||||
|
||||
const SERVICES = [
|
||||
RESTService,
|
||||
];
|
||||
|
||||
@NgModule({})
|
||||
export class RESTRootModule {
|
||||
constructor(
|
||||
private restService: RESTService,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class RESTFeatureModule {
|
||||
constructor(
|
||||
private restService: RESTService,
|
||||
private root: RESTRootModule,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class RESTModule {
|
||||
static forRoot(config: RESTRootModuleConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: RESTRootModule,
|
||||
providers: [
|
||||
{
|
||||
provide: _REST_BASE_URL,
|
||||
useValue: config.baseURL,
|
||||
},
|
||||
SERVICES,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
static forFeature(config: RESTFeatureModuleConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: RESTFeatureModule,
|
||||
providers: [
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
16
projects/loafer/ng-rest/src/lib/ng-rest.service.spec.ts
Normal file
16
projects/loafer/ng-rest/src/lib/ng-rest.service.spec.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import {} from 'jasmine';
|
||||
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
import { RESTService } from './ng-rest.service';
|
||||
|
||||
describe('RESTService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [RESTService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([RESTService], (service: RESTService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
26
projects/loafer/ng-rest/src/lib/ng-rest.service.ts
Normal file
26
projects/loafer/ng-rest/src/lib/ng-rest.service.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { Injectable, Inject } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { Location } from '@angular/common';
|
||||
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import 'rxjs/add/operator/timeout';
|
||||
import 'rxjs/add/observable/throw';
|
||||
|
||||
import { _REST_BASE_URL } from './ng-rest.token';
|
||||
import { RESTClient } from './ng-rest.client';
|
||||
|
||||
@Injectable()
|
||||
export class RESTService extends RESTClient {
|
||||
|
||||
constructor(
|
||||
@Inject(_REST_BASE_URL) _baseURL: string,
|
||||
@Inject(HttpClient) _httpClient: HttpClient,
|
||||
) {
|
||||
super(_baseURL, _httpClient);
|
||||
}
|
||||
}
|
3
projects/loafer/ng-rest/src/lib/ng-rest.token.ts
Normal file
3
projects/loafer/ng-rest/src/lib/ng-rest.token.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
export const _REST_BASE_URL = new InjectionToken('@loafer/ng-rest Internal Base URL');
|
7
projects/loafer/ng-rest/src/public_api.ts
Normal file
7
projects/loafer/ng-rest/src/public_api.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Public API Surface of ng-rest
|
||||
*/
|
||||
|
||||
export * from './lib/ng-rest.error';
|
||||
export * from './lib/ng-rest.service';
|
||||
export * from './lib/ng-rest.module';
|
22
projects/loafer/ng-rest/src/test.ts
Normal file
22
projects/loafer/ng-rest/src/test.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
33
projects/loafer/ng-rest/tsconfig.lib.json
Normal file
33
projects/loafer/ng-rest/tsconfig.lib.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2015"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true,
|
||||
"flatModuleId": "AUTOGENERATED",
|
||||
"flatModuleOutFile": "AUTOGENERATED"
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
17
projects/loafer/ng-rest/tsconfig.spec.json
Normal file
17
projects/loafer/ng-rest/tsconfig.spec.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
17
projects/loafer/ng-rest/tslint.json
Normal file
17
projects/loafer/ng-rest/tslint.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"lib",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
31
projects/loafer/ng-rpc/karma.conf.js
Normal file
31
projects/loafer/ng-rpc/karma.conf.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage'),
|
||||
reports: ['html', 'lcovonly'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
8
projects/loafer/ng-rpc/ng-package.json
Normal file
8
projects/loafer/ng-rpc/ng-package.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/loafer/ng-rpc",
|
||||
"deleteDestPath": true,
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts"
|
||||
}
|
||||
}
|
7
projects/loafer/ng-rpc/ng-package.prod.json
Normal file
7
projects/loafer/ng-rpc/ng-package.prod.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/loafer/ng-rpc",
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts"
|
||||
}
|
||||
}
|
15
projects/loafer/ng-rpc/package.json
Normal file
15
projects/loafer/ng-rpc/package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@loafer/ng-rpc",
|
||||
"version": "0.0.6",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.loafle.net/loafer/ng.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-loafle/"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^6.0.0-rc.0 || ^6.0.0",
|
||||
"@angular/core": "^6.0.0-rc.0 || ^6.0.0"
|
||||
}
|
||||
}
|
146
projects/loafer/ng-rpc/src/lib/client/RPCClient.ts
Normal file
146
projects/loafer/ng-rpc/src/lib/client/RPCClient.ts
Normal file
|
@ -0,0 +1,146 @@
|
|||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
|
||||
import { RPCClientError } from '../protocol/RPCError';
|
||||
import { RPCClientRWC } from './RPCClientRWC';
|
||||
|
||||
import {
|
||||
RPCClientCodec,
|
||||
RPCClientResponseCodec,
|
||||
RPCClientNotificationCodec,
|
||||
} from '../protocol/RPCClientCodec';
|
||||
|
||||
export interface RPCRequestState {
|
||||
subject: Subject<any>;
|
||||
request: {
|
||||
method: string;
|
||||
params: any[];
|
||||
};
|
||||
}
|
||||
|
||||
export abstract class RPCClient<T> {
|
||||
private _requestID: number;
|
||||
|
||||
private _pendingRequestsCount: number;
|
||||
private _pendingRequests: Map<number, RPCRequestState>;
|
||||
|
||||
public constructor(
|
||||
private _codec: RPCClientCodec,
|
||||
private _rwc: RPCClientRWC<T>,
|
||||
) {
|
||||
this._requestID = 0;
|
||||
this._pendingRequestsCount = 0;
|
||||
this._pendingRequests = new Map();
|
||||
}
|
||||
|
||||
private getRequestID(): number {
|
||||
return ++this._requestID;
|
||||
}
|
||||
|
||||
/**
|
||||
* connect
|
||||
*/
|
||||
public connect(queryString?: string): void {
|
||||
this._rwc.connect(queryString);
|
||||
this._rwc.readResponse().subscribe(
|
||||
(value: T) => {
|
||||
this.onMessage(value);
|
||||
},
|
||||
(error: any) => {
|
||||
console.error(error);
|
||||
},
|
||||
() => {
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* close
|
||||
*/
|
||||
public disconnect() {
|
||||
this._rwc.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* notify
|
||||
*/
|
||||
public send(method: string, ...args: any[]): void {
|
||||
this.sendInternal(false, method, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* call
|
||||
*/
|
||||
public call<RT>(method: string, ...args: any[]): Observable<RT> {
|
||||
return this.sendInternal<RT>(true, method, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* callTimeout
|
||||
*/
|
||||
public callTimeout<RT>(ms: number, method: string, ...args: any[]): Observable<RT> {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private sendInternal<RT>(hasResponse: boolean, method: string, args?: any[]): Observable<RT> | undefined {
|
||||
let id: number;
|
||||
let resSubject: Subject<RT>;
|
||||
if (hasResponse) {
|
||||
id = this.getRequestID();
|
||||
resSubject = new Subject<RT>();
|
||||
const reqState: RPCRequestState = {
|
||||
subject: resSubject,
|
||||
request: {
|
||||
method: method,
|
||||
params: args,
|
||||
}
|
||||
};
|
||||
this._pendingRequests.set(id, reqState);
|
||||
this._pendingRequestsCount++;
|
||||
}
|
||||
|
||||
const req = this._codec.request(method, args, id);
|
||||
this._rwc.writeRequest(req);
|
||||
|
||||
if (undefined !== resSubject) {
|
||||
return resSubject.asObservable();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private onMessage(message: Object): void {
|
||||
const resCodec = this._codec.response(message);
|
||||
|
||||
if (resCodec.isNotification()) {
|
||||
this.onNotification(resCodec.notification());
|
||||
} else {
|
||||
this.onResponse(resCodec);
|
||||
}
|
||||
}
|
||||
|
||||
protected onResponse(resCodec: RPCClientResponseCodec): void {
|
||||
const id = resCodec.id();
|
||||
const result = resCodec.result();
|
||||
const error = resCodec.error();
|
||||
|
||||
const reqState: RPCRequestState = this._pendingRequests.get(id);
|
||||
|
||||
this._pendingRequests.delete(id);
|
||||
this._pendingRequestsCount--;
|
||||
|
||||
if (undefined !== result) {
|
||||
reqState.subject.next(result);
|
||||
} else if (undefined !== error) {
|
||||
const rpcClientError: RPCClientError = {
|
||||
request: reqState.request,
|
||||
response: error,
|
||||
};
|
||||
console.error(rpcClientError);
|
||||
reqState.subject.error(rpcClientError);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract onNotification(notiCodec: RPCClientNotificationCodec): void;
|
||||
}
|
11
projects/loafer/ng-rpc/src/lib/client/RPCClientRWC.ts
Normal file
11
projects/loafer/ng-rpc/src/lib/client/RPCClientRWC.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
export interface RPCClientRWC<T> {
|
||||
connect(queryString?: string): void;
|
||||
readResponse(): Observable<T>;
|
||||
writeRequest(data: any): void;
|
||||
disconnect(): void;
|
||||
connectionStatus(): Observable<boolean>;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import { map } from 'rxjs/operator/map';
|
||||
|
||||
import {
|
||||
RxWebsocketSubject,
|
||||
RxWebsocketSubjectConfig,
|
||||
} from './RxWebsocketSubject';
|
||||
|
||||
import { RPCClientRWC } from '../../RPCClientRWC';
|
||||
|
||||
export class RPCClientWebsocketRWC<T> implements RPCClientRWC<T> {
|
||||
private _wsSocketSubject: RxWebsocketSubject<T>;
|
||||
private _responseSubject: Subject<T>;
|
||||
|
||||
public constructor(
|
||||
private _config: RxWebsocketSubjectConfig,
|
||||
) {
|
||||
this._wsSocketSubject = new RxWebsocketSubject<T>(this._config);
|
||||
}
|
||||
|
||||
public connect(queryString?: string): void {
|
||||
if (undefined !== queryString) {
|
||||
this._wsSocketSubject.queryString = queryString;
|
||||
}
|
||||
this._wsSocketSubject.connect();
|
||||
this._wsSocketSubject.subscribe(
|
||||
(value: T) => {
|
||||
if (undefined !== this._responseSubject) {
|
||||
this._responseSubject.next(value);
|
||||
}
|
||||
},
|
||||
(error: any) => {
|
||||
if (undefined !== this._responseSubject) {
|
||||
this._responseSubject.error(error);
|
||||
}
|
||||
},
|
||||
() => {
|
||||
console.log('sss');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public disconnect(): void {
|
||||
this._wsSocketSubject.disconnect();
|
||||
}
|
||||
|
||||
public connectionStatus(): Observable<boolean> {
|
||||
return this._wsSocketSubject.connectionStatus;
|
||||
}
|
||||
|
||||
public readResponse(): Observable<T> {
|
||||
if (undefined === this._responseSubject) {
|
||||
this._responseSubject = new Subject<T>();
|
||||
}
|
||||
return this._responseSubject.asObservable();
|
||||
}
|
||||
|
||||
public writeRequest(data: any): void {
|
||||
this._wsSocketSubject.write(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
import { Observable } from 'rxjs/Observable';
|
||||
import { Observer } from 'rxjs/Observer';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import {
|
||||
WebSocketSubject,
|
||||
WebSocketSubjectConfig
|
||||
} from 'rxjs/observable/dom/WebSocketSubject';
|
||||
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/operator/share';
|
||||
import 'rxjs/add/operator/takeWhile';
|
||||
import 'rxjs/add/observable/interval';
|
||||
|
||||
export interface RxWebsocketSubjectConfig {
|
||||
url: string;
|
||||
protocol?: string | Array<string>;
|
||||
reconnectInterval?: 5000;
|
||||
reconnectRetry?: 10;
|
||||
}
|
||||
|
||||
export class RxWebsocketSubject<T> extends Subject<T> {
|
||||
private _reconnectionObservable: Observable<number>;
|
||||
private _wsSubjectConfig: WebSocketSubjectConfig<T>;
|
||||
private _socket: WebSocketSubject<any>;
|
||||
private _connectionObserver: Observer<boolean>;
|
||||
private _connectionStatus: Observable<boolean>;
|
||||
private _queryString: string;
|
||||
|
||||
public constructor(private _config: RxWebsocketSubjectConfig) {
|
||||
super();
|
||||
|
||||
this._connectionStatus = new Observable<boolean>((observer) => {
|
||||
this._connectionObserver = observer;
|
||||
}).share().distinctUntilChanged();
|
||||
|
||||
this._wsSubjectConfig = {
|
||||
url: _config.url,
|
||||
protocol: _config.protocol,
|
||||
serializer: (value: any) => value,
|
||||
closeObserver: {
|
||||
next: (e: CloseEvent) => {
|
||||
this._socket = null;
|
||||
this._connectionObserver.next(false);
|
||||
}
|
||||
},
|
||||
openObserver: {
|
||||
next: (e: Event) => {
|
||||
this._connectionObserver.next(true);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this._connectionStatus.subscribe((isConnected: boolean) => {
|
||||
if (!this._reconnectionObservable && typeof(isConnected) === 'boolean' && !isConnected) {
|
||||
this.reconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public set queryString(query: string) {
|
||||
this._queryString = query;
|
||||
}
|
||||
|
||||
public get queryString(): string | undefined {
|
||||
return this._queryString;
|
||||
}
|
||||
|
||||
public get connectionStatus(): Observable<boolean> {
|
||||
return this._connectionStatus;
|
||||
}
|
||||
|
||||
public connect(): void {
|
||||
const wsSubjectConfig = Object.assign({}, this._wsSubjectConfig);
|
||||
if (undefined !== this._queryString) {
|
||||
wsSubjectConfig.url = wsSubjectConfig.url + '?' + this._queryString;
|
||||
}
|
||||
|
||||
this._socket = new WebSocketSubject(wsSubjectConfig);
|
||||
this._socket.subscribe(
|
||||
(m) => {
|
||||
this.next(m);
|
||||
},
|
||||
(error: Event) => {
|
||||
if (!this._socket) {
|
||||
this.reconnect();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public disconnect(): void {
|
||||
this._socket.complete();
|
||||
}
|
||||
|
||||
private reconnect(): void {
|
||||
this._reconnectionObservable = Observable.interval(this._config.reconnectInterval)
|
||||
.takeWhile((v, index) => {
|
||||
return index < this._config.reconnectRetry && !this._socket;
|
||||
});
|
||||
this._reconnectionObservable.subscribe(
|
||||
() => {
|
||||
this.connect();
|
||||
},
|
||||
null,
|
||||
() => {
|
||||
this._reconnectionObservable = null;
|
||||
if (!this._socket) {
|
||||
this.complete();
|
||||
this._connectionObserver.complete();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public write(data: any): void {
|
||||
this._socket.next(data);
|
||||
}
|
||||
}
|
6
projects/loafer/ng-rpc/src/lib/core/error.ts
Normal file
6
projects/loafer/ng-rpc/src/lib/core/error.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export class SubscriberParameterError extends Error {
|
||||
public constructor(message?: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
}
|
||||
}
|
8
projects/loafer/ng-rpc/src/lib/core/token.ts
Normal file
8
projects/loafer/ng-rpc/src/lib/core/token.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
export const RPC_CODEC = new InjectionToken('@loafer/ng-rpc RPC codec');
|
||||
export const RPC_RWC = new InjectionToken('@loafer/ng-rpc RPC rwc');
|
||||
|
||||
export const _ROOT_SUBSCRIBERS = new InjectionToken('@loafer/ng-rpc RPC root subscribers');
|
||||
export const _FEATURE_SUBSCRIBERS = new InjectionToken('@loafer/ng-rpc RPC feature subscribers');
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import {
|
||||
Type,
|
||||
PropertyKeyType,
|
||||
} from '@loafer/core';
|
||||
|
||||
import {
|
||||
Annotation,
|
||||
} from '@loafer/core/reflect';
|
||||
|
||||
import {
|
||||
Decorator,
|
||||
} from '@loafer/decorator';
|
||||
|
||||
export class RPCSubscriberAnnotation extends Annotation {
|
||||
method: string;
|
||||
}
|
||||
|
||||
export function RPCSubscriber(config: RPCSubscriberAnnotation): MethodDecorator {
|
||||
return function<T>(target: Object, propertyKey: PropertyKeyType, descriptor: TypedPropertyDescriptor<T>)
|
||||
: TypedPropertyDescriptor<T> | void {
|
||||
|
||||
Decorator.register(RPCSubscriberAnnotation, config, target, propertyKey, descriptor);
|
||||
};
|
||||
}
|
106
projects/loafer/ng-rpc/src/lib/ng-rpc.module.ts
Normal file
106
projects/loafer/ng-rpc/src/lib/ng-rpc.module.ts
Normal file
|
@ -0,0 +1,106 @@
|
|||
import {
|
||||
NgModule,
|
||||
ModuleWithProviders,
|
||||
Type,
|
||||
Inject,
|
||||
InjectionToken,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
RPC_CODEC,
|
||||
RPC_RWC,
|
||||
|
||||
_ROOT_SUBSCRIBERS,
|
||||
_FEATURE_SUBSCRIBERS,
|
||||
} from './core/token';
|
||||
|
||||
import {
|
||||
RPCClientRWC,
|
||||
} from './client/RPCClientRWC';
|
||||
|
||||
import {
|
||||
RPCClientCodec,
|
||||
} from './protocol/RPCClientCodec';
|
||||
|
||||
import {
|
||||
RPCService,
|
||||
} from './service/rpc.service';
|
||||
|
||||
import {
|
||||
RPCSubscribeService,
|
||||
} from './subscribe/subscribe.service';
|
||||
|
||||
const SERVICES = [
|
||||
RPCService,
|
||||
];
|
||||
|
||||
const SUBSCRIBERS = [
|
||||
RPCSubscribeService,
|
||||
];
|
||||
|
||||
@NgModule({})
|
||||
export class RPCRootModule {
|
||||
constructor(
|
||||
private rpcService: RPCService,
|
||||
private rpcSubscribeService: RPCSubscribeService,
|
||||
@Inject(_ROOT_SUBSCRIBERS) rootSubscribers: any[],
|
||||
) {
|
||||
rootSubscribers.forEach((subscriber) => {
|
||||
rpcSubscribeService.addSubscriber(subscriber);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class RPCFeatureModule {
|
||||
constructor(
|
||||
private rpcService: RPCService,
|
||||
private rpcSubscribeService: RPCSubscribeService,
|
||||
@Inject(_FEATURE_SUBSCRIBERS) featureSubscribersGroups: any[][],
|
||||
private root: RPCRootModule,
|
||||
) {
|
||||
featureSubscribersGroups.forEach((featureSubscribers) => {
|
||||
featureSubscribers.forEach((subscriber) => {
|
||||
rpcSubscribeService.addSubscriber(subscriber);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class RPCModule {
|
||||
static forRoot(subscribers: Type<any>[]): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: RPCRootModule,
|
||||
providers: [
|
||||
subscribers,
|
||||
{
|
||||
provide: _ROOT_SUBSCRIBERS,
|
||||
deps: subscribers,
|
||||
useFactory: createSourceInstances,
|
||||
},
|
||||
SERVICES,
|
||||
SUBSCRIBERS,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
static forFeature(subscribers: Type<any>[]): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: RPCFeatureModule,
|
||||
providers: [
|
||||
subscribers,
|
||||
{
|
||||
provide: _FEATURE_SUBSCRIBERS,
|
||||
multi: true,
|
||||
deps: subscribers,
|
||||
useFactory: createSourceInstances,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function createSourceInstances(...instances: any[]) {
|
||||
return instances;
|
||||
}
|
20
projects/loafer/ng-rpc/src/lib/protocol/RPCClientCodec.ts
Normal file
20
projects/loafer/ng-rpc/src/lib/protocol/RPCClientCodec.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { RPCError } from './RPCError';
|
||||
|
||||
export interface RPCClientCodec {
|
||||
request(method: string, args: any[], id: number): any;
|
||||
response(res: any): RPCClientResponseCodec;
|
||||
}
|
||||
|
||||
export interface RPCClientResponseCodec {
|
||||
id(): number | undefined;
|
||||
error(): RPCError | undefined;
|
||||
result(): any | undefined;
|
||||
|
||||
isNotification(): boolean;
|
||||
notification(): RPCClientNotificationCodec | undefined;
|
||||
}
|
||||
|
||||
export interface RPCClientNotificationCodec {
|
||||
method(): string;
|
||||
params(): any | undefined;
|
||||
}
|
41
projects/loafer/ng-rpc/src/lib/protocol/RPCError.ts
Normal file
41
projects/loafer/ng-rpc/src/lib/protocol/RPCError.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
export interface RPCClientError {
|
||||
request: {
|
||||
method: string,
|
||||
params: any[],
|
||||
};
|
||||
response: RPCError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error object representation when a method invocation fails.
|
||||
*/
|
||||
export interface RPCError {
|
||||
/** Indicates the error type that occurred. */
|
||||
code: RPCErrorCode;
|
||||
|
||||
/** A short description of the error. */
|
||||
message: string;
|
||||
|
||||
/** Additional information about the error */
|
||||
data?: any;
|
||||
}/*
|
||||
|
||||
/** Error codes are same as xml-rpc codes. See http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php */
|
||||
export const enum RPCErrorCode {
|
||||
/** Parse error Invalid JSON was received by the Server. */
|
||||
ParseError = -32700,
|
||||
|
||||
/** Invalid Request The JSON sent is not a valid Request object. */
|
||||
InvalidRequest = -32600,
|
||||
|
||||
/** The method does not exist / is not available. */
|
||||
MethodNotFound = -32601,
|
||||
|
||||
/** Invalid method parameter(s). */
|
||||
InvalidParams = - -32602,
|
||||
|
||||
/** Internal JSON-RPC error. */
|
||||
InternalError = -32603
|
||||
|
||||
/** -32000 to -32099: Reserved for implementation-defined Server errors. */
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
import {
|
||||
RPCClientCodec,
|
||||
RPCClientResponseCodec,
|
||||
RPCClientNotificationCodec,
|
||||
} from '../RPCClientCodec';
|
||||
|
||||
import {
|
||||
RPCError,
|
||||
} from '../RPCError';
|
||||
|
||||
export interface ClientNotification {
|
||||
method: string;
|
||||
params?: string[];
|
||||
}
|
||||
|
||||
export interface ClientRequest {
|
||||
jsonrpc: string;
|
||||
method: string;
|
||||
params?: string[];
|
||||
id?: number;
|
||||
}
|
||||
|
||||
export interface ClientResponse {
|
||||
jsonrpc: string;
|
||||
result?: any;
|
||||
error?: RPCError;
|
||||
id?: number;
|
||||
}
|
||||
|
||||
export class JSONRPCClientCodec implements RPCClientCodec {
|
||||
public request(method: string, args: any[], id?: number): any {
|
||||
const params = convertParamsToStringArray(args);
|
||||
|
||||
const req: ClientRequest = {
|
||||
jsonrpc: '2.0',
|
||||
method: method,
|
||||
params: 0 === params.length ? null : params,
|
||||
id: id,
|
||||
};
|
||||
return JSON.stringify(req);
|
||||
}
|
||||
public response(res: any): RPCClientResponseCodec {
|
||||
const _res: ClientResponse = {
|
||||
id: res.id,
|
||||
jsonrpc: res.jsonrpc,
|
||||
result: res.result,
|
||||
error: res.error,
|
||||
};
|
||||
return new JSONRPCClientResponseCodec(_res);
|
||||
}
|
||||
}
|
||||
|
||||
function convertParamsToStringArray(args: any[]): string[] | undefined {
|
||||
const values: string[] = [];
|
||||
|
||||
if (undefined === args || null === args || 0 === args.length) {
|
||||
return values;
|
||||
}
|
||||
|
||||
for (let indexI = 0; indexI < args.length; indexI++) {
|
||||
const arg = args[indexI];
|
||||
|
||||
switch (typeof arg) {
|
||||
case 'boolean':
|
||||
case 'number': // enum
|
||||
values.push(String(arg));
|
||||
break;
|
||||
case 'string':
|
||||
values.push(arg);
|
||||
break;
|
||||
case 'object': // array, map
|
||||
values.push(JSON.stringify(arg));
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Not supported type[${typeof arg}]`);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
export class JSONRPCClientResponseCodec implements RPCClientResponseCodec {
|
||||
public constructor(private _res: ClientResponse) {
|
||||
}
|
||||
|
||||
public id(): number | undefined {
|
||||
return this._res.id;
|
||||
}
|
||||
public error(): RPCError | undefined {
|
||||
return this._res.error;
|
||||
}
|
||||
public result(): any | undefined {
|
||||
return this._res.result;
|
||||
}
|
||||
|
||||
public isNotification(): boolean {
|
||||
if (undefined !== this.id() || undefined === this.result()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public notification(): RPCClientNotificationCodec | undefined {
|
||||
if (undefined !== this.id() || undefined === this.result()) {
|
||||
return undefined;
|
||||
}
|
||||
const _noti: ClientNotification = {
|
||||
method: this._res.result.method,
|
||||
params: this._res.result.params,
|
||||
};
|
||||
return new JSONRPCClientNotificationCodec(_noti);
|
||||
}
|
||||
}
|
||||
|
||||
export class JSONRPCClientNotificationCodec implements RPCClientNotificationCodec {
|
||||
public constructor(private _noti: ClientNotification) {
|
||||
}
|
||||
|
||||
public method(): string {
|
||||
return this._noti.method;
|
||||
}
|
||||
public params(): any[] | undefined {
|
||||
return this._noti.params;
|
||||
}
|
||||
}
|
33
projects/loafer/ng-rpc/src/lib/service/rpc.service.ts
Normal file
33
projects/loafer/ng-rpc/src/lib/service/rpc.service.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { Injectable, Inject } from '@angular/core';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
|
||||
import {
|
||||
RPC_CODEC,
|
||||
RPC_RWC,
|
||||
} from '../core/token';
|
||||
|
||||
import { RPCClient } from '../client/RPCClient';
|
||||
import { RPCClientRWC } from '../client/RPCClientRWC';
|
||||
import { RPCClientCodec, RPCClientNotificationCodec } from '../protocol/RPCClientCodec';
|
||||
|
||||
import {
|
||||
RPCSubscribeService,
|
||||
} from '../subscribe/subscribe.service';
|
||||
|
||||
@Injectable()
|
||||
export class RPCService extends RPCClient<any> {
|
||||
constructor(
|
||||
@Inject(RPC_CODEC) rpcClientCodec: RPCClientCodec,
|
||||
@Inject(RPC_RWC) rpcClientRWC: RPCClientRWC<any>,
|
||||
private rpcSubscribeService: RPCSubscribeService,
|
||||
) {
|
||||
super(rpcClientCodec, rpcClientRWC);
|
||||
}
|
||||
|
||||
protected onNotification(notiCodec: RPCClientNotificationCodec): void {
|
||||
this.rpcSubscribeService.notify(notiCodec);
|
||||
}
|
||||
}
|
162
projects/loafer/ng-rpc/src/lib/subscribe/subscribe.service.ts
Normal file
162
projects/loafer/ng-rpc/src/lib/subscribe/subscribe.service.ts
Normal file
|
@ -0,0 +1,162 @@
|
|||
import { Injectable, Inject } from '@angular/core';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import {
|
||||
Type,
|
||||
PropertyKeyType,
|
||||
} from '@loafer/core';
|
||||
|
||||
import { TypeUtil } from '@loafer/core/util/TypeUtil';
|
||||
|
||||
import {
|
||||
Class,
|
||||
Method,
|
||||
Metadata,
|
||||
} from '@loafer/core/reflect';
|
||||
|
||||
import { RPCSubscriberAnnotation } from '../decorator/rpc-subscriber.decorator';
|
||||
|
||||
import {
|
||||
RPCClientNotificationCodec,
|
||||
} from '../protocol/RPCClientCodec';
|
||||
|
||||
import { SubscriberParameterError } from '../core/error';
|
||||
|
||||
export interface SubscriberMethod {
|
||||
className: PropertyKeyType;
|
||||
methodName: PropertyKeyType;
|
||||
parameterTypes: string[];
|
||||
|
||||
method: Method;
|
||||
instance: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class RPCSubscribeService {
|
||||
private subscriberTypes: Set<Type<any>>;
|
||||
private subscribers: Set<any>;
|
||||
private subscriberMethodMap: Map<string, SubscriberMethod[]>;
|
||||
|
||||
constructor(
|
||||
) {
|
||||
this.subscriberTypes = new Set();
|
||||
this.subscribers = new Set();
|
||||
this.subscriberMethodMap = new Map();
|
||||
}
|
||||
|
||||
public addSubscriber(subscriber: Type<any>): void {
|
||||
const type = TypeUtil.getType(subscriber);
|
||||
|
||||
if (this.subscriberTypes.has(type)) {
|
||||
// console.log(`Subscriber[${type.name}] has been added`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.subscriberTypes.add(type);
|
||||
|
||||
const clazz = Class.forType(type);
|
||||
if (undefined === clazz) {
|
||||
console.log(`Type[${subscriber.name}] is not decorated type`);
|
||||
return;
|
||||
}
|
||||
|
||||
const methods = clazz.getMethods();
|
||||
methods.forEach((method, propertyKey) => {
|
||||
const annon = method.getAnnotation(RPCSubscriberAnnotation);
|
||||
if (undefined === annon) {
|
||||
return;
|
||||
}
|
||||
|
||||
const subscriberMethodName = annon.method;
|
||||
let subscriberMethods: SubscriberMethod[] = this.subscriberMethodMap.get(subscriberMethodName);
|
||||
if (undefined === subscriberMethods) {
|
||||
subscriberMethods = [];
|
||||
this.subscriberMethodMap.set(subscriberMethodName, subscriberMethods);
|
||||
}
|
||||
|
||||
const paramTypes = this.getParamTypes(method);
|
||||
|
||||
const subscriberMethod: SubscriberMethod = {
|
||||
className: clazz.getName(),
|
||||
methodName: method.getName(),
|
||||
parameterTypes: paramTypes,
|
||||
method: method,
|
||||
instance: subscriber,
|
||||
};
|
||||
|
||||
subscriberMethods.push(subscriberMethod);
|
||||
});
|
||||
}
|
||||
|
||||
public notify(codec: RPCClientNotificationCodec): void {
|
||||
const method = codec.method();
|
||||
const params = codec.params();
|
||||
|
||||
const subscriberMethods: SubscriberMethod[] = this.subscriberMethodMap.get(method);
|
||||
if (undefined === subscriberMethods) {
|
||||
console.warn(`Subscriber for method[${method}] is not exist`);
|
||||
return;
|
||||
}
|
||||
subscriberMethods.forEach((subscriberMethod) => {
|
||||
try {
|
||||
const args = this.converParams(params, subscriberMethod.parameterTypes);
|
||||
subscriberMethod.method.invoke(subscriberMethod.instance, ...args);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getParamTypes(method: Method): string[] {
|
||||
if (undefined === method || null === method || 0 === method.getParameterCount()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parameters = method.getParameters();
|
||||
const results: string[] = [];
|
||||
for (let indexI = 0; indexI < parameters.length; indexI++) {
|
||||
const paramType = parameters[indexI].getType();
|
||||
results.push(paramType.name);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private converParams(params: string[], paramTypes: string[]): any[] {
|
||||
const results: any[] = [];
|
||||
|
||||
if (undefined === params || null === params || 0 === params.length) {
|
||||
return results;
|
||||
}
|
||||
if (undefined === paramTypes || null === paramTypes || 0 === paramTypes.length) {
|
||||
return results;
|
||||
}
|
||||
if (params.length !== paramTypes.length) {
|
||||
throw new SubscriberParameterError(`Count is not same from server[${params.length}] and method[${paramTypes.length}]`);
|
||||
}
|
||||
for (let indexI = 0; indexI < params.length; indexI++) {
|
||||
const param = params[indexI];
|
||||
const type = paramTypes[indexI];
|
||||
switch (type) {
|
||||
case 'Object':
|
||||
case 'Array':
|
||||
case 'Map':
|
||||
results.push(JSON.parse(param));
|
||||
break;
|
||||
case 'String':
|
||||
results.push(param);
|
||||
break;
|
||||
case 'Number':
|
||||
results.push(Number(param));
|
||||
break;
|
||||
case 'Boolean':
|
||||
results.push(Boolean(param));
|
||||
break;
|
||||
case 'Function':
|
||||
throw new SubscriberParameterError(`Function type [${indexI}] is not allowed`);
|
||||
default:
|
||||
throw new SubscriberParameterError(`${type} type parameter[${indexI}] is not allowed`);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
17
projects/loafer/ng-rpc/src/public_api.ts
Normal file
17
projects/loafer/ng-rpc/src/public_api.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Public API Surface of ng-rpc
|
||||
*/
|
||||
|
||||
export * from './lib/client/RPCClient';
|
||||
export * from './lib/client/RPCClientRWC';
|
||||
export * from './lib/client/rwc/websocket/RPCClientWebsocketRWC';
|
||||
export * from './lib/client/rwc/websocket/RxWebsocketSubject';
|
||||
export * from './lib/core/error';
|
||||
export * from './lib/core/token';
|
||||
export * from './lib/decorator/rpc-subscriber.decorator';
|
||||
export * from './lib/protocol/RPCClientCodec';
|
||||
export * from './lib/protocol/RPCError';
|
||||
export * from './lib/protocol/json/JSONRPCClientCodec';
|
||||
export * from './lib/service/rpc.service';
|
||||
export * from './lib/subscribe/subscribe.service';
|
||||
export * from './lib/ng-rpc.module';
|
22
projects/loafer/ng-rpc/src/test.ts
Normal file
22
projects/loafer/ng-rpc/src/test.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
33
projects/loafer/ng-rpc/tsconfig.lib.json
Normal file
33
projects/loafer/ng-rpc/tsconfig.lib.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2015"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true,
|
||||
"flatModuleId": "AUTOGENERATED",
|
||||
"flatModuleOutFile": "AUTOGENERATED"
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
17
projects/loafer/ng-rpc/tsconfig.spec.json
Normal file
17
projects/loafer/ng-rpc/tsconfig.spec.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
17
projects/loafer/ng-rpc/tslint.json
Normal file
17
projects/loafer/ng-rpc/tslint.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"lib",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
31
tsconfig.json
Normal file
31
tsconfig.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
],
|
||||
"paths": {
|
||||
"@loafer/ng-logger": [
|
||||
"dist/loafer/ng-logger"
|
||||
],
|
||||
"@loafer/ng-rest": [
|
||||
"dist/loafer/ng-rest"
|
||||
],
|
||||
"@loafer/ng-rpc": [
|
||||
"dist/loafer/ng-rpc"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
130
tslint.json
Normal file
130
tslint.json
Normal file
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"rulesDirectory": [
|
||||
"node_modules/codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warn"
|
||||
},
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-over-type-literal": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-misused-new": true,
|
||||
"no-non-null-assertion": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"unified-signatures": true,
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"no-output-on-prefix": true,
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user