├── .travis.yml
├── src
├── index.ts
├── tsconfig.spec.json
├── tsconfig.es5.json
├── package.json
├── module.ts
├── common.ts
└── ajax-angular-adapter.ts
├── .yo-rc.json
├── bs-config.json
├── tsconfig.json
├── playground
├── tsconfig.json
├── index.ts
├── index.html
├── systemjs-angular-loader.js
└── systemjs.config.js
├── .gitignore
├── .npmignore
├── package.json
├── tslint.json
├── README.md
├── tools
└── gulp
│ └── inline-resources.js
└── gulpfile.js
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - '4.2.1'
5 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './common';
2 | export * from './module';
3 | export * from './ajax-angular-adapter';
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-angular2-library": {
3 | "promptValues": {
4 | "gitRepositoryUrl": "https://github.com/Breeze/breeze.bridge.angular"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/bs-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "baseDir": "src",
4 | "routes": {
5 | "/": "playground",
6 | "/node_modules/": "node_modules",
7 | "/dist/": "dist",
8 | "/.playground": ".playground"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./src",
4 | "experimentalDecorators": true,
5 | "moduleResolution": "node",
6 | "rootDir": "./src",
7 | "lib": [
8 | "es2015",
9 | "dom"
10 | ],
11 | "skipLibCheck": true,
12 | "types": []
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/playground/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "../.playground",
4 | "target": "es5",
5 | "module": "commonjs",
6 | "moduleResolution": "node",
7 | "sourceMap": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "lib": [ "es2015", "dom" ],
11 | "noImplicitAny": true,
12 | "suppressImplicitAnyIndexErrors": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.es5.json",
3 | "compilerOptions": {
4 | "emitDecoratorMetadata": true,
5 | "experimentalDecorators": true,
6 | "outDir": "../out-tsc/spec",
7 | "module": "commonjs",
8 | "target": "es6",
9 | "baseUrl": "",
10 | "types": [
11 | "jest",
12 | "node"
13 | ]
14 | },
15 | "files": [
16 | "**/*.spec.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Node
2 | node_modules/*
3 | npm-debug.log
4 |
5 | # TypeScript
6 | src/*.js
7 | src/*.map
8 | src/*.d.ts
9 |
10 | # JetBrains
11 | .idea
12 | .project
13 | .settings
14 | .idea/*
15 | *.iml
16 |
17 | # VS Code
18 | .vscode/*
19 |
20 | # Windows
21 | Thumbs.db
22 | Desktop.ini
23 |
24 | # Mac
25 | .DS_Store
26 | **/.DS_Store
27 |
28 | # Ngc generated files
29 | **/*.ngfactory.ts
30 |
31 | # Build files
32 | dist/*
33 |
34 | # Playground tmp files
35 | .playground
36 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Node
2 | node_modules/*
3 | npm-debug.log
4 | docs/*
5 | # DO NOT IGNORE TYPESCRIPT FILES FOR NPM
6 | # TypeScript
7 | # *.js
8 | # *.map
9 | # *.d.ts
10 |
11 | # JetBrains
12 | .idea
13 | .project
14 | .settings
15 | .idea/*
16 | *.iml
17 |
18 | # VS Code
19 | .vscode/*
20 |
21 | # Windows
22 | Thumbs.db
23 | Desktop.ini
24 |
25 | # Mac
26 | .DS_Store
27 | **/.DS_Store
28 |
29 | # Ngc generated files
30 | **/*.ngfactory.ts
31 |
32 | # Library files
33 | src/*
34 | build/*
35 |
--------------------------------------------------------------------------------
/playground/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This is only for local test
3 | */
4 | import { BrowserModule } from '@angular/platform-browser';
5 | import { NgModule } from '@angular/core';
6 | import { Component } from '@angular/core';
7 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
8 |
9 | import { SampleModule } from 'breeze-bridge-angular';
10 |
11 | @Component({
12 | selector: 'app',
13 | template: ``
14 | })
15 | class AppComponent {}
16 |
17 | @NgModule({
18 | bootstrap: [ AppComponent ],
19 | declarations: [ AppComponent ],
20 | imports: [ BrowserModule, SampleModule ]
21 | })
22 | class AppModule {}
23 |
24 | platformBrowserDynamic().bootstrapModule(AppModule);
25 |
--------------------------------------------------------------------------------
/src/tsconfig.es5.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "module": "es2015",
5 | "target": "es5",
6 | "baseUrl": ".",
7 | "stripInternal": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "moduleResolution": "node",
11 | "outDir": "../build",
12 | "rootDir": ".",
13 | "lib": [
14 | "es2015",
15 | "dom"
16 | ],
17 | "skipLibCheck": true,
18 | "types": []
19 | },
20 | "angularCompilerOptions": {
21 | "annotateForClosureCompiler": true,
22 | "strictMetadataEmit": true,
23 | "skipTemplateCodegen": true,
24 | "flatModuleOutFile": "breeze-bridge-angular.js",
25 | "flatModuleId": "breeze-bridge-angular"
26 | },
27 | "files": [
28 | "./index.ts"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/playground/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | breeze-bridge-angular Playground
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 | Loading AppComponent content here ...
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "breeze-bridge-angular",
3 | "version": "4.0.2",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/Breeze/breeze.bridge.angular"
7 | },
8 | "author": {
9 | "name": "Marcel Good",
10 | "email": "marcelg@ideablade.com"
11 | },
12 | "keywords": [
13 | "breeze",
14 | "angular",
15 | "bridge"
16 | ],
17 | "license": "MIT",
18 | "bugs": {
19 | "url": "https://github.com/Breeze/breeze.bridge.angular/issues"
20 | },
21 | "main": "breeze-bridge-angular.umd.js",
22 | "module": "index.js",
23 | "jsnext:main": "index.js",
24 | "typings": "breeze-bridge-angular.d.ts",
25 | "peerDependencies": {
26 | "@angular/core": ">= 2.0.0",
27 | "@angular/http": ">= 2.0.0",
28 | "rxjs": ">= 5.1.0",
29 | "zone.js": ">= 0.8.4",
30 | "breeze-client": ">= 1.6.3"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { Http } from "@angular/http";
3 | import { config } from "breeze-client";
4 |
5 | import { AjaxAngularAdapter } from "./ajax-angular-adapter";
6 | import { Q } from "./common";
7 |
8 | @NgModule()
9 | export class BreezeBridgeAngularModule {
10 | constructor(public http: Http) {
11 | // Configure Breeze for Angular ... exactly once.
12 | // config breeze to use the native 'backingStore' modeling adapter appropriate for Ng
13 | // 'backingStore' is the Breeze default but we set it here to be explicit.
14 | config.initializeAdapterInstance('modelLibrary', 'backingStore', true);
15 | config.setQ(Q);
16 | config.registerAdapter('ajax', () => new AjaxAngularAdapter(http));
17 | config.initializeAdapterInstance('ajax', AjaxAngularAdapter.adapterName, true);
18 | }
19 | }
--------------------------------------------------------------------------------
/src/common.ts:
--------------------------------------------------------------------------------
1 | import { promises, HttpResponse } from "breeze-client";
2 |
3 | /**
4 | * Minimum for breeze breeze Q/ES6 Promise adapter
5 | */
6 | export var Q: promises.IPromiseService = {
7 | defer(): promises.IDeferred {
8 | let resolve: (value?: {} | PromiseLike<{}>) => void;
9 | let reject: (reason?: any) => void;
10 | let promise = new Promise((_resolve, _reject) => {
11 | resolve = _resolve;
12 | reject = _reject;
13 | });
14 | return {
15 | promise: promise,
16 | resolve(value: any) { resolve(value); },
17 | reject(reason: any) { reject(reason); }
18 | };
19 | },
20 |
21 | resolve(value?: {} | PromiseLike<{}>) {
22 | let deferred = Q.defer();
23 | deferred.resolve(value);
24 | return deferred.promise;
25 | },
26 |
27 |
28 | reject(reason?: any) {
29 | let deferred = Q.defer();
30 | deferred.reject(reason);
31 | return deferred.promise;
32 | }
33 | };
34 |
35 | /**
36 | * DataServiceAdapter Ajax request configuration
37 | */
38 | export interface DsaConfig {
39 | url: string;
40 | type?: string;
41 | dataType?: string;
42 | contentType?: string | boolean;
43 | crossDomain?: string;
44 | headers?: {};
45 | data?: any;
46 | params?: {};
47 | success: (res: HttpResponse) => void;
48 | error: (res: (HttpResponse | Error)) => void;
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/playground/systemjs-angular-loader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
4 | var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
5 | var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;
6 |
7 | module.exports.translate = function (load){
8 | if (load.source.indexOf('moduleId') !== -1) {
9 | return load;
10 | }
11 |
12 | // eslint-disable-next-line
13 | var url = document.createElement('a');
14 | url.href = load.address;
15 |
16 | var basePathParts = url.pathname.split('/');
17 |
18 | basePathParts.pop();
19 | var basePath = basePathParts.join('/');
20 |
21 | // eslint-disable-next-line
22 | var baseHref = document.createElement('a');
23 | baseHref.href = this.baseURL;
24 | baseHref = baseHref.pathname;
25 |
26 | if (!baseHref.startsWith('/base/')) { // it is not karma
27 | basePath = basePath.replace(baseHref, '');
28 | }
29 |
30 | load.source = load.source
31 | .replace(templateUrlRegex, function (match, quote, sourceUrl){
32 | var resolvedUrl = sourceUrl;
33 |
34 | if (sourceUrl.startsWith('.')) {
35 | resolvedUrl = basePath + sourceUrl.substr(1);
36 | }
37 |
38 | return 'templateUrl: "' + resolvedUrl + '"';
39 | })
40 | .replace(stylesRegex, function (match, relativeUrls) {
41 | var urls = [];
42 |
43 | while ((match = stringRegex.exec(relativeUrls)) !== null) {
44 | if (match[2].startsWith('.')) {
45 | urls.push('"' + basePath + match[2].substr(1) + '"');
46 | } else {
47 | urls.push('"' + match[2] + '"');
48 | }
49 | }
50 |
51 | return 'styleUrls: [' + urls.join(', ') + ']';
52 | });
53 |
54 | return load;
55 | };
56 |
--------------------------------------------------------------------------------
/playground/systemjs.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * System configuration for Angular samples
4 | * Adjust as necessary for your application needs.
5 | */
6 | (function () {
7 | System.config({
8 | paths: {
9 | // paths serve as alias
10 | 'npm:': '../node_modules/'
11 | },
12 | // map tells the System loader where to look for things
13 | map: {
14 | // our app is within the app folder
15 | app: 'app',
16 |
17 | // angular bundles
18 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
19 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
20 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
21 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
22 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
23 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
24 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
25 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
26 |
27 | // other libraries
28 | rxjs: 'npm:rxjs',
29 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
30 | 'breeze-bridge-angular': '../dist'
31 | },
32 | // packages tells the System loader how to load when no filename and/or no extension
33 | packages: {
34 | app: {
35 | defaultExtension: 'js',
36 | meta: {
37 | './*.js': {
38 | loader: 'systemjs-angular-loader.js'
39 | }
40 | }
41 | },
42 | rxjs: {
43 | defaultExtension: 'js'
44 | },
45 | 'breeze-bridge-angular': {
46 | main: 'breeze-bridge-angular.umd.js',
47 | defaultExtension: 'js'
48 | }
49 | }
50 | });
51 | })(this);
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "breeze-bridge-angular",
3 | "version": "4.0.2",
4 | "scripts": {
5 | "build": "gulp build",
6 | "build:watch": "gulp",
7 | "docs": "npm run docs:build",
8 | "docs:build": "compodoc -p tsconfig.json -n breeze-bridge-angular -d docs --hideGenerator",
9 | "docs:serve": "npm run docs:build -- -s",
10 | "docs:watch": "npm run docs:build -- -s -w",
11 | "lint": "tslint --type-check --project tsconfig.json src/**/*.ts",
12 | "lite": "lite-server",
13 | "playground:build": "tsc -p playground -w",
14 | "playground": "concurrently \"npm run build:watch\" \"npm run playground:build\" \"npm run lite\"",
15 | "test": "tsc && karma start"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/Breeze/breeze.bridge.angular"
20 | },
21 | "author": {
22 | "name": "Marcel Good",
23 | "email": "marcelg@ideablade.com"
24 | },
25 | "keywords": [
26 | "breeze",
27 | "angular",
28 | "bridge"
29 | ],
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/Breeze/breeze.bridge.angular/issues"
33 | },
34 | "devDependencies": {
35 | "@angular/common": "^4.0.0",
36 | "@angular/compiler": "^4.0.0",
37 | "@angular/compiler-cli": "^4.0.0",
38 | "@angular/core": "^4.0.0",
39 | "@angular/http": "^4.0.0",
40 | "@angular/platform-browser": "^4.0.0",
41 | "@angular/platform-browser-dynamic": "^4.0.0",
42 | "@compodoc/compodoc": "^1.0.0-beta.10",
43 | "@types/jasmine": "2.5.38",
44 | "@types/node": "~6.0.60",
45 | "angular-in-memory-web-api": "^0.3.2",
46 | "breeze-client": "^1.6.3",
47 | "codelyzer": "~2.0.0",
48 | "concurrently": "^3.4.0",
49 | "core-js": "^2.4.1",
50 | "del": "^2.2.2",
51 | "gulp": "^3.9.1",
52 | "gulp-rename": "^1.2.2",
53 | "gulp-rollup": "^2.15.0",
54 | "jasmine-core": "~2.5.2",
55 | "jasmine-spec-reporter": "~3.2.0",
56 | "karma": "~1.4.1",
57 | "karma-chrome-launcher": "~2.0.0",
58 | "karma-cli": "~1.0.1",
59 | "karma-coverage-istanbul-reporter": "^0.2.0",
60 | "karma-jasmine": "~1.1.0",
61 | "karma-jasmine-html-reporter": "^0.2.2",
62 | "lite-server": "^2.3.0",
63 | "node-sass": "^4.5.2",
64 | "node-sass-tilde-importer": "^1.0.0",
65 | "node-watch": "^0.5.2",
66 | "protractor": "~5.1.0",
67 | "rollup": "^0.49.3",
68 | "run-sequence": "^1.2.2",
69 | "rxjs": "^5.1.0",
70 | "systemjs": "^0.20.12",
71 | "ts-node": "~2.0.0",
72 | "tslint": "~4.5.0",
73 | "typescript": "~2.2.0",
74 | "zone.js": "^0.8.4"
75 | },
76 | "engines": {
77 | "node": ">=6.0.0"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "class-name": true,
7 | "comment-format": [
8 | true,
9 | "check-space"
10 | ],
11 | "curly": true,
12 | "eofline": true,
13 | "forin": true,
14 | "indent": [
15 | true,
16 | "spaces"
17 | ],
18 | "label-position": true,
19 | "max-line-length": [
20 | true,
21 | 140
22 | ],
23 | "member-access": false,
24 | "member-ordering": [
25 | true,
26 | "static-before-instance",
27 | "variables-before-functions"
28 | ],
29 | "no-arg": true,
30 | "no-bitwise": true,
31 | "no-console": [
32 | true,
33 | "debug",
34 | "info",
35 | "time",
36 | "timeEnd",
37 | "trace"
38 | ],
39 | "no-construct": true,
40 | "no-debugger": true,
41 | "no-duplicate-variable": true,
42 | "no-empty": false,
43 | "no-eval": true,
44 | "no-inferrable-types": true,
45 | "no-shadowed-variable": true,
46 | "no-string-literal": false,
47 | "no-switch-case-fall-through": true,
48 | "no-trailing-whitespace": true,
49 | "no-unused-expression": true,
50 | "no-unused-variable": true,
51 | "no-use-before-declare": true,
52 | "no-var-keyword": true,
53 | "object-literal-sort-keys": false,
54 | "one-line": [
55 | true,
56 | "check-open-brace",
57 | "check-catch",
58 | "check-else",
59 | "check-whitespace"
60 | ],
61 | "quotemark": [
62 | true,
63 | "single"
64 | ],
65 | "radix": true,
66 | "semicolon": [
67 | "always"
68 | ],
69 | "triple-equals": [
70 | true,
71 | "allow-null-check"
72 | ],
73 | "typedef-whitespace": [
74 | true,
75 | {
76 | "call-signature": "nospace",
77 | "index-signature": "nospace",
78 | "parameter": "nospace",
79 | "property-declaration": "nospace",
80 | "variable-declaration": "nospace"
81 | }
82 | ],
83 | "variable-name": false,
84 | "whitespace": [
85 | true,
86 | "check-branch",
87 | "check-decl",
88 | "check-operator",
89 | "check-separator",
90 | "check-type"
91 | ],
92 | "directive-selector": [true, "attribute", "", "camelCase"],
93 | "component-selector": [true, "element", "", "kebab-case"],
94 | "use-input-property-decorator": true,
95 | "use-output-property-decorator": true,
96 | "use-host-property-decorator": true,
97 | "no-input-rename": true,
98 | "no-output-rename": true,
99 | "use-life-cycle-interface": true,
100 | "use-pipe-transform-interface": true,
101 | "component-class-suffix": true,
102 | "directive-class-suffix": true
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to the Breeze-Angular bridge #
2 |
3 | A bridge that configures Breeze to work with Angular out of the box.
4 |
5 | This package is effectively obsolete. For Angular 4.3 and up it is recommended to use the new HttpClient service. An updated bridge which uses the HttpClient can be found [here](https://github.com/Breeze/breeze.bridge2.angular).
6 |
7 | # Change Log #
8 |
9 | ### 4.0.2 November 20, 2017 ###
10 |
11 | #### Features ####
12 | - Restructed package and minor code tweaks
13 |
14 | ### 4.0.0 April 19, 2017 ###
15 |
16 | #### Features ####
17 | - Update to to support Angular 4
18 |
19 | ### 2.4.2 March 5, 2017 ###
20 |
21 | #### Features ####
22 | - Update to breeze-client 1.6.3
23 |
24 | ### 2.4.1 March 1, 2017 ###
25 |
26 | #### Breaking Changes ####
27 | - Renamed package to `breeze-bridge-angular` and synchronzied major/minor version with Angular
28 | - Renamed `BreezeBridgeAngular2Module` to `BreezeBridgeAngularModule`
29 | - Renamed `AjaxAngular2Adapter` to `AjaxAngularAdapter`
30 |
31 | ### 0.3.5 December 1, 2016 ###
32 |
33 | #### Features ####
34 | - Export AjaxAngular2Adapter class, [making it easier to add auth headers](https://github.com/Breeze/breeze.js/issues/173#issuecomment-263797223).
35 |
36 | ### 0.3.4 October 20, 2016 ###
37 |
38 | #### Fixed Bugs ####
39 | - Fix error response payload not being passed up
40 |
41 | ### 0.3.3 September 28, 2016 ###
42 |
43 | #### Fixed Bugs ####
44 | - Removed post install scripts from package.json
45 |
46 | ### 0.3.2 September 23, 2016 ###
47 |
48 | #### Features ####
49 | - Update to Angular 2 final
50 | - Add support for AoT compilation
51 |
52 | ### 0.3.1 August 25, 2016 ###
53 |
54 | #### Fixed Bugs ####
55 | - Fix errant rejected promise in failure case
56 |
57 | ### 0.3.0 August 24, 2016 ###
58 |
59 | #### Breaking Changes ####
60 | - The Breeze Angular bridge is no longer an injectable service. It has been changed to an NgModule
61 |
62 | # Prerequisites #
63 |
64 | - Breeze client npm package 1.6.3 or higher
65 | - Angular 2.0.0 or higher
66 |
67 | # Installation #
68 |
69 | 1. Install breeze-client
70 |
71 | `npm install breeze-client --save`
72 |
73 | 2. Install breeze-bridge-angular
74 |
75 | `npm install breeze-bridge-angular --save`
76 |
77 | # Usage #
78 |
79 | A comprehensive example app that makes use of the bridge can be found here: [https://github.com/Breeze/temphire.angular](https://github.com/Breeze/temphire.angular).
80 |
81 | To use the bridge in your own application, the following steps are required.
82 |
83 | Import `BreezeBridgeAngularModule` and `HttpModule` and add it to the app module's imports.
84 |
85 | ```
86 | import { BreezeBridgeAngularModule } from 'breeze-bridge-angular';
87 | import { Http } from '@angular/http';
88 | ```
89 |
90 | ```
91 | @NgModule({
92 | imports: [
93 | BreezeBridgeAngularModule,
94 | HttpModule
95 | ],
96 | bootstrap: [ AppComponent ]
97 | })
98 | export class AppModule { }
99 | ```
100 |
101 | Now we can use Breeze normally from something like a data service for example.
102 |
103 | ```
104 | import { Injectable } from '@angular/core';
105 | import { EntityManager, EntityQuery } from 'breeze-client';
106 | import { Customer } from './entities';
107 |
108 | @Injectable()
109 | export class DataService {
110 |
111 | private _em: EntityManager;
112 |
113 | constructor() {
114 | this._em = new EntityManager();
115 | }
116 |
117 | getAllCustomers(): Promise {
118 | let query = EntityQuery.from('Customers').orderBy('companyName');
119 |
120 | return this._em.executeQuery(query)
121 | .then(res => res.results)
122 | .catch((error) => {
123 | console.log(error);
124 | return Promise.reject(error);
125 | });
126 | }
127 | }
128 | ```
129 |
--------------------------------------------------------------------------------
/tools/gulp/inline-resources.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // https://github.com/filipesilva/angular-quickstart-lib/blob/master/inline-resources.js
3 | 'use strict';
4 |
5 | const fs = require('fs');
6 | const path = require('path');
7 | const glob = require('glob');
8 | const sass = require('node-sass');
9 | const tildeImporter = require('node-sass-tilde-importer');
10 |
11 | /**
12 | * Simple Promiseify function that takes a Node API and return a version that supports promises.
13 | * We use promises instead of synchronized functions to make the process less I/O bound and
14 | * faster. It also simplifies the code.
15 | */
16 | function promiseify(fn) {
17 | return function () {
18 | const args = [].slice.call(arguments, 0);
19 | return new Promise((resolve, reject) => {
20 | fn.apply(this, args.concat([function (err, value) {
21 | if (err) {
22 | reject(err);
23 | } else {
24 | resolve(value);
25 | }
26 | }]));
27 | });
28 | };
29 | }
30 |
31 | const readFile = promiseify(fs.readFile);
32 | const writeFile = promiseify(fs.writeFile);
33 |
34 | /**
35 | * Inline resources in a tsc/ngc compilation.
36 | * @param projectPath {string} Path to the project.
37 | */
38 | function inlineResources(projectPath) {
39 |
40 | // Match only TypeScript files in projectPath.
41 | const files = glob.sync('**/*.ts', {cwd: projectPath});
42 |
43 | // For each file, inline the templates and styles under it and write the new file.
44 | return Promise.all(files.map(filePath => {
45 | const fullFilePath = path.join(projectPath, filePath);
46 | return readFile(fullFilePath, 'utf-8')
47 | .then(content => inlineResourcesFromString(content, url => {
48 | // Resolve the template url.
49 | return path.join(path.dirname(fullFilePath), url);
50 | }))
51 | .then(content => writeFile(fullFilePath, content))
52 | .catch(err => {
53 | console.error('An error occured: ', err);
54 | });
55 | }));
56 | }
57 |
58 | /**
59 | * Inline resources from a string content.
60 | * @param content {string} The source file's content.
61 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
62 | * @returns {string} The content with resources inlined.
63 | */
64 | function inlineResourcesFromString(content, urlResolver) {
65 | // Curry through the inlining functions.
66 | return [
67 | inlineTemplate,
68 | inlineStyle,
69 | removeModuleId
70 | ].reduce((content, fn) => fn(content, urlResolver), content);
71 | }
72 |
73 | /**
74 | * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and
75 | * replace with `template: ...` (with the content of the file included).
76 | * @param content {string} The source file's content.
77 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
78 | * @return {string} The content with all templates inlined.
79 | */
80 | function inlineTemplate(content, urlResolver) {
81 | return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function (m, templateUrl) {
82 | const templateFile = urlResolver(templateUrl);
83 | const templateContent = fs.readFileSync(templateFile, 'utf-8');
84 | const shortenedTemplate = templateContent
85 | .replace(/([\n\r]\s*)+/gm, ' ')
86 | .replace(/"/g, '\\"');
87 | return `template: "${shortenedTemplate}"`;
88 | });
89 | }
90 |
91 |
92 | /**
93 | * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and
94 | * replace with `styles: [...]` (with the content of the file included).
95 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
96 | * @param content {string} The source file's content.
97 | * @return {string} The content with all styles inlined.
98 | */
99 | function inlineStyle(content, urlResolver) {
100 | return content.replace(/styleUrls\s*:\s*(\[[\s\S]*?\])/gm, function (m, styleUrls) {
101 | const urls = eval(styleUrls);
102 | return 'styles: ['
103 | + urls.map(styleUrl => {
104 | const styleFile = urlResolver(styleUrl);
105 | const originContent = fs.readFileSync(styleFile, 'utf-8');
106 | const styleContent = styleFile.endsWith('.scss') ? buildSass(originContent, styleFile) : originContent;
107 | const shortenedStyle = styleContent
108 | .replace(/([\n\r]\s*)+/gm, ' ')
109 | .replace(/"/g, '\\"');
110 | return `"${shortenedStyle}"`;
111 | })
112 | .join(',\n')
113 | + ']';
114 | });
115 | }
116 |
117 | /**
118 | * build sass content to css
119 | * @param content {string} the css content
120 | * @param sourceFile {string} the scss file sourceFile
121 | * @return {string} the generated css, empty string if error occured
122 | */
123 | function buildSass(content, sourceFile) {
124 | try {
125 | const result = sass.renderSync({
126 | data: content,
127 | file: sourceFile,
128 | importer: tildeImporter
129 | });
130 | return result.css.toString()
131 | } catch (e) {
132 | console.error('\x1b[41m');
133 | console.error('at ' + sourceFile + ':' + e.line + ":" + e.column);
134 | console.error(e.formatted);
135 | console.error('\x1b[0m');
136 | return "";
137 | }
138 | }
139 |
140 | /**
141 | * Remove every mention of `moduleId: module.id`.
142 | * @param content {string} The source file's content.
143 | * @returns {string} The content with all moduleId: mentions removed.
144 | */
145 | function removeModuleId(content) {
146 | return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
147 | }
148 |
149 | module.exports = inlineResources;
150 | module.exports.inlineResourcesFromString = inlineResourcesFromString;
151 |
152 | // Run inlineResources if module is being called directly from the CLI with arguments.
153 | if (require.main === module && process.argv.length > 2) {
154 | console.log('Inlining resources from project:', process.argv[2]);
155 | return inlineResources(process.argv[2]);
156 | }
157 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var gulp = require('gulp'),
3 | path = require('path'),
4 | ngc = require('@angular/compiler-cli/src/main').main,
5 | rollup = require('gulp-rollup'),
6 | rename = require('gulp-rename'),
7 | del = require('del'),
8 | runSequence = require('run-sequence'),
9 | inlineResources = require('./tools/gulp/inline-resources');
10 |
11 | const rootFolder = path.join(__dirname);
12 | const srcFolder = path.join(rootFolder, 'src');
13 | const tmpFolder = path.join(rootFolder, '.tmp');
14 | const buildFolder = path.join(rootFolder, 'build');
15 | const distFolder = path.join(rootFolder, 'dist');
16 |
17 | /**
18 | * 1. Delete /dist folder
19 | */
20 | gulp.task('clean:dist', function () {
21 |
22 | // Delete contents but not dist folder to avoid broken npm links
23 | // when dist directory is removed while npm link references it.
24 | return deleteFolders([distFolder + '/**', '!' + distFolder]);
25 | });
26 |
27 | /**
28 | * 2. Clone the /src folder into /.tmp. If an npm link inside /src has been made,
29 | * then it's likely that a node_modules folder exists. Ignore this folder
30 | * when copying to /.tmp.
31 | */
32 | gulp.task('copy:source', function () {
33 | return gulp.src([`${srcFolder}/**/*`, `!${srcFolder}/node_modules`])
34 | .pipe(gulp.dest(tmpFolder));
35 | });
36 |
37 | /**
38 | * 3. Inline template (.html) and style (.css) files into the the component .ts files.
39 | * We do this on the /.tmp folder to avoid editing the original /src files
40 | */
41 | gulp.task('inline-resources', function () {
42 | return Promise.resolve()
43 | .then(() => inlineResources(tmpFolder));
44 | });
45 |
46 |
47 | /**
48 | * 4. Run the Angular compiler, ngc, on the /.tmp folder. This will output all
49 | * compiled modules to the /build folder.
50 | */
51 | gulp.task('ngc', function () {
52 | return ngc({
53 | project: `${tmpFolder}/tsconfig.es5.json`
54 | })
55 | .then((exitCode) => {
56 | if (exitCode === 1) {
57 | // This error is caught in the 'compile' task by the runSequence method callback
58 | // so that when ngc fails to compile, the whole compile process stops running
59 | throw new Error('ngc compilation failed');
60 | }
61 | });
62 | });
63 |
64 | /**
65 | * 5. Run rollup inside the /build folder to generate our Flat ES module and place the
66 | * generated file into the /dist folder
67 | */
68 | gulp.task('rollup:fesm', function () {
69 | return gulp.src(`${buildFolder}/**/*.js`)
70 | // transform the files here.
71 | .pipe(rollup({
72 |
73 | // Bundle's entry point
74 | // See "input" in https://rollupjs.org/#core-functionality
75 | input: `${buildFolder}/index.js`,
76 |
77 | // Allow mixing of hypothetical and actual files. "Actual" files can be files
78 | // accessed by Rollup or produced by plugins further down the chain.
79 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system
80 | // when subdirectories are used in the `src` directory.
81 | allowRealFiles: true,
82 |
83 | // A list of IDs of modules that should remain external to the bundle
84 | // See "external" in https://rollupjs.org/#core-functionality
85 | external: [
86 | '@angular/core',
87 | '@angular/common'
88 | ],
89 |
90 | // Format of generated bundle
91 | // See "format" in https://rollupjs.org/#core-functionality
92 | format: 'es'
93 | }))
94 | .pipe(gulp.dest(distFolder));
95 | });
96 |
97 | /**
98 | * 6. Run rollup inside the /build folder to generate our UMD module and place the
99 | * generated file into the /dist folder
100 | */
101 | gulp.task('rollup:umd', function () {
102 | return gulp.src(`${buildFolder}/**/*.js`)
103 | // transform the files here.
104 | .pipe(rollup({
105 |
106 | // Bundle's entry point
107 | // See "input" in https://rollupjs.org/#core-functionality
108 | input: `${buildFolder}/index.js`,
109 |
110 | // Allow mixing of hypothetical and actual files. "Actual" files can be files
111 | // accessed by Rollup or produced by plugins further down the chain.
112 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system
113 | // when subdirectories are used in the `src` directory.
114 | allowRealFiles: true,
115 |
116 | // A list of IDs of modules that should remain external to the bundle
117 | // See "external" in https://rollupjs.org/#core-functionality
118 | external: [
119 | '@angular/core',
120 | '@angular/common'
121 | ],
122 |
123 | // Format of generated bundle
124 | // See "format" in https://rollupjs.org/#core-functionality
125 | format: 'umd',
126 |
127 | // Export mode to use
128 | // See "exports" in https://rollupjs.org/#danger-zone
129 | exports: 'named',
130 |
131 | // The name to use for the module for UMD/IIFE bundles
132 | // (required for bundles with exports)
133 | // See "name" in https://rollupjs.org/#core-functionality
134 | name: 'breeze-bridge-angular',
135 |
136 | // See "globals" in https://rollupjs.org/#core-functionality
137 | globals: {
138 | typescript: 'ts'
139 | }
140 |
141 | }))
142 | .pipe(rename('breeze-bridge-angular.umd.js'))
143 | .pipe(gulp.dest(distFolder));
144 | });
145 |
146 | /**
147 | * 7. Copy all the files from /build to /dist, except .js files. We ignore all .js from /build
148 | * because with don't need individual modules anymore, just the Flat ES module generated
149 | * on step 5.
150 | */
151 | gulp.task('copy:build', function () {
152 | return gulp.src([`${buildFolder}/**/*`, `!${buildFolder}/**/*.js`])
153 | .pipe(gulp.dest(distFolder));
154 | });
155 |
156 | /**
157 | * 8. Copy package.json from /src to /dist
158 | */
159 | gulp.task('copy:manifest', function () {
160 | return gulp.src([`${srcFolder}/package.json`])
161 | .pipe(gulp.dest(distFolder));
162 | });
163 |
164 | /**
165 | * 9. Copy README.md from / to /dist
166 | */
167 | gulp.task('copy:readme', function () {
168 | return gulp.src([path.join(rootFolder, 'README.MD')])
169 | .pipe(gulp.dest(distFolder));
170 | });
171 |
172 | /**
173 | * 10. Delete /.tmp folder
174 | */
175 | gulp.task('clean:tmp', function () {
176 | return deleteFolders([tmpFolder]);
177 | });
178 |
179 | /**
180 | * 11. Delete /build folder
181 | */
182 | gulp.task('clean:build', function () {
183 | return deleteFolders([buildFolder]);
184 | });
185 |
186 | gulp.task('compile', function () {
187 | runSequence(
188 | 'clean:dist',
189 | 'copy:source',
190 | 'inline-resources',
191 | 'ngc',
192 | 'rollup:fesm',
193 | 'rollup:umd',
194 | 'copy:build',
195 | 'copy:manifest',
196 | 'copy:readme',
197 | 'clean:build',
198 | 'clean:tmp',
199 | function (err) {
200 | if (err) {
201 | console.log('ERROR:', err.message);
202 | deleteFolders([distFolder, tmpFolder, buildFolder]);
203 | } else {
204 | console.log('Compilation finished succesfully');
205 | }
206 | });
207 | });
208 |
209 | /**
210 | * Watch for any change in the /src folder and compile files
211 | */
212 | gulp.task('watch', function () {
213 | gulp.watch(`${srcFolder}/**/*`, ['compile']);
214 | });
215 |
216 | gulp.task('clean', ['clean:dist', 'clean:tmp', 'clean:build']);
217 |
218 | gulp.task('build', ['clean', 'compile']);
219 | gulp.task('build:watch', ['build', 'watch']);
220 | gulp.task('default', ['build:watch']);
221 |
222 | /**
223 | * Deletes the specified folder
224 | */
225 | function deleteFolders(folders) {
226 | return del(folders);
227 | }
228 |
--------------------------------------------------------------------------------
/src/ajax-angular-adapter.ts:
--------------------------------------------------------------------------------
1 | import { Http, Headers, Request, RequestOptions, Response } from '@angular/http';
2 | import { core, HttpResponse } from "breeze-client";
3 | import { map } from "rxjs/operators/map";
4 |
5 | import { DsaConfig } from "./common";
6 |
7 | export class AjaxAngularAdapter {
8 | static adapterName = 'angular';
9 | name = AjaxAngularAdapter.adapterName;
10 | defaultSettings = {};
11 | requestInterceptor: (info: {}) => {};
12 |
13 | constructor(public http: Http) { }
14 |
15 | initialize() { }
16 |
17 | ajax(config: DsaConfig) {
18 | if (!this.http) {
19 | throw new Error('Unable to locate angular http module for ajax adapter');
20 | }
21 |
22 | // merge default DataSetAdapter Settings with config arg
23 | if (!core.isEmpty(this.defaultSettings)) {
24 | let compositeConfig = core.extend({}, this.defaultSettings);
25 | config = core.extend(compositeConfig, config);
26 | // extend is shallow; extend headers separately
27 | let headers = core.extend({}, this.defaultSettings['headers']); // copy default headers 1st
28 | config['headers'] = core.extend(headers, config.headers);
29 | }
30 |
31 | if (config.crossDomain) {
32 | throw new Error(this.name + ' does not support JSONP (jQuery.ajax:crossDomain) requests');
33 | }
34 |
35 | let url = config.url;
36 | if (!core.isEmpty(config.params)) {
37 | // Hack: Not sure how Angular handles writing 'search' parameters to the url.
38 | // so this approach takes over the url param writing completely.
39 | let delim = (url.indexOf('?') >= 0) ? '&' : '?';
40 | url = url + delim + encodeParams(config.params);
41 | }
42 |
43 | let headers = new Headers(config.headers || {});
44 | if (!headers.has('Content-Type')) {
45 | if (config.type != 'GET' && config.type != 'DELETE' && config.contentType !== false) {
46 | headers.set('Content-Type',
47 | config.contentType || 'application/json; charset=utf-8');
48 | }
49 | }
50 |
51 | // Create the http request body which must be stringified
52 | let body: any = config.data;
53 | if (body && typeof body !== 'string') {
54 | body = JSON.stringify(body);
55 | };
56 |
57 | let reqOptions = new RequestOptions({
58 | url: url,
59 | method: (config.type || 'GET').toUpperCase(),
60 | headers: headers,
61 | body: body,
62 | });
63 |
64 | let request = new Request(reqOptions);
65 |
66 | let requestInfo = {
67 | adapter: this, // this adapter
68 | requestOptions: reqOptions, // angular's http requestOptions
69 | request: request, // the http request from the requestOptions
70 | dsaConfig: config, // the config arg from the calling Breeze DataServiceAdapter
71 | success: successFn, // adapter's success callback
72 | error: errorFn // adapter's error callback
73 | };
74 |
75 | if (core.isFunction(this.requestInterceptor)) {
76 | this.requestInterceptor(requestInfo);
77 | if (this.requestInterceptor['oneTime']) {
78 | this.requestInterceptor = null;
79 | }
80 | }
81 |
82 | if (requestInfo.request) { // exists unless requestInterceptor killed it.
83 | const fmap = map(extractData);
84 |
85 | fmap(this.http.request(requestInfo.request))
86 | .forEach(requestInfo.success)
87 | .catch(requestInfo.error);
88 | }
89 |
90 | function extractData(response: Response) {
91 | let data: any;
92 | let dt = requestInfo.dsaConfig.dataType;
93 | // beware:`res.json` and `res.text` will be async some day
94 | if (dt && dt !== 'json') {
95 | data = response.text ? response.text() : null;
96 | } else {
97 | data = response.json ? response.json() : null;
98 | }
99 | return { data, response };
100 | }
101 |
102 | function successFn(arg: { data: any, response: Response }) {
103 | if (arg.response.status < 200 || arg.response.status >= 300) {
104 | throw { data: arg.data, response: arg.response };
105 | }
106 |
107 | let httpResponse: HttpResponse = {
108 | config: requestInfo.request,
109 | data: arg.data,
110 | getHeaders: makeGetHeaders(arg.response),
111 | status: arg.response.status
112 | };
113 | httpResponse['ngConfig'] = requestInfo.request;
114 | httpResponse['statusText'] = arg.response.statusText;
115 | httpResponse['response'] = arg.response;
116 | config.success(httpResponse);
117 | }
118 |
119 | function errorFn(arg: { data: any, response: Response } | Error | Response) {
120 | if (arg instanceof Error) {
121 | throw arg; // program error; nothing we can do
122 | } else {
123 | var data: any;
124 | var response: Response;
125 | if (arg instanceof Response) {
126 | response = arg;
127 | try {
128 | data = arg.json();
129 | } catch (e) {
130 | data = arg.text();
131 | }
132 | } else {
133 | data = arg.data;
134 | response = arg.response;
135 | }
136 |
137 | // Timeout appears as an error with status===0 and no data.
138 | if (response.status === 0 && data == null) {
139 | data = 'timeout';
140 | }
141 |
142 | let errorMessage = response.status + ": " + response.statusText;
143 | if (data && typeof data === 'object') {
144 | data["message"] = data["message"] || errorMessage; // breeze looks at the message property
145 | }
146 | if (!data) {
147 | data = errorMessage; // Return the error message as data
148 | }
149 | let httpResponse: HttpResponse = {
150 | config: requestInfo.request,
151 | data: data,
152 | getHeaders: makeGetHeaders(response),
153 | status: response.status
154 | };
155 | httpResponse['ngConfig'] = requestInfo.request;
156 | httpResponse['statusText'] = response.statusText;
157 | httpResponse['response'] = response;
158 |
159 | config.error(httpResponse); // send error to breeze error handler
160 | }
161 | }
162 | };
163 |
164 | }
165 |
166 | ///// Helpers ////
167 |
168 | function encodeParams(obj: {}) {
169 | let query = '';
170 | let subValue: any, innerObj: any, fullSubName: any;
171 |
172 | for (let name in obj) {
173 | if (!obj.hasOwnProperty(name)) { continue; }
174 |
175 | let value = obj[name];
176 |
177 | if (value instanceof Array) {
178 | for (let i = 0; i < value.length; ++i) {
179 | subValue = value[i];
180 | fullSubName = name + '[' + i + ']';
181 | innerObj = {};
182 | innerObj[fullSubName] = subValue;
183 | query += encodeParams(innerObj) + '&';
184 | }
185 | } else if (value && value.toISOString) { // a feature of Date-like things
186 | query += encodeURIComponent(name) + '=' + encodeURIComponent(value.toISOString()) + '&';
187 | } else if (value instanceof Object) {
188 | for (let subName in value) {
189 | if (obj.hasOwnProperty(name)) {
190 | subValue = value[subName];
191 | fullSubName = name + '[' + subName + ']';
192 | innerObj = {};
193 | innerObj[fullSubName] = subValue;
194 | query += encodeParams(innerObj) + '&';
195 | }
196 | }
197 | } else if (value === null) {
198 | query += encodeURIComponent(name) + '=&';
199 | } else if (value !== undefined) {
200 | query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
201 | }
202 | }
203 |
204 | return query.length ? query.substr(0, query.length - 1) : query;
205 | }
206 |
207 | function makeGetHeaders(res: Response) {
208 | let headers = res.headers;
209 | return function getHeaders(headerName?: string) { return headers.getAll(headerName).join('\r\n'); };
210 | }
--------------------------------------------------------------------------------