diff --git a/.gitignore b/.gitignore index 8b880842..9e1c920c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,11 +16,12 @@ e2e/**/*.d.ts !e2e/protractor*.js !demo-apps/es5/index.js !demo-apps/es6-systemjs/index.js -test/**/*.d.ts -test/**/*.js.map -test/**/*.js -!test/index.js -!test/index.d.ts +test/specs/**/*.d.ts +test/specs/**/*.js.map +test/specs/**/*.js +test/util/**/*.d.ts +test/util/**/*.js.map +test/util/**/*.js bundles build build-stats.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 520601b9..2e238b49 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,10 +15,11 @@ "**/.git": true, "**/.DS_Store": true, "**/*.js": {"when": "$(basename).ts"}, + "**/*.js.map": true, + "*.d.ts": true, "src/**/*.d.ts": true, - "src/**/*.js.map": true, - "test/**/*.d.ts": true, - "test/**/*.js.map": true, + "test/specs/**/*.d.ts": true, + "test/util/**/*.d.ts": true, "bundles/": true, "demo-apps/**/build/": true, "demo-site/api-docs/": true, diff --git a/demo-apps/ts-webpack/package.json b/demo-apps/ts-webpack/package.json index de977802..f4a1e440 100644 --- a/demo-apps/ts-webpack/package.json +++ b/demo-apps/ts-webpack/package.json @@ -11,7 +11,7 @@ "build": "node ../../node_modules/webpack/bin/webpack.js --env.debug", "prebuild:prod": "npm run clean", "build:prod": "node ../../node_modules/webpack/bin/webpack.js --progress --env.prod", - "clean": "node ../../node_modules/shx/lib/cli.js rm -rf build build-stats.json src/**/*.js src/**/*.js.map", + "clean": "node ../../node_modules/shx/lib/cli.js rm -rf build build-stats.json src/**/*.{js,js.map}", "linklocal": "npm run _linklocal && npm prune", "serve": "node ../../node_modules/http-server/bin/http-server build -c-1 -o", "start": "node ../../node_modules/webpack-dev-server/bin/webpack-dev-server.js --progress --env.debug --open", diff --git a/karma.conf.js b/karma.conf.js index 59eecfe1..e191ae51 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -17,7 +17,7 @@ module.exports = function (config) { // list of files / patterns to load in the browser files: [ // libraries - 'node_modules/lodash/index.js', + 'node_modules/lodash/lodash.js', 'node_modules/angular/angular.js', 'node_modules/angular-mocks/angular-mocks.js', testGlob diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 1a9e3f0f..1b238b64 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -78,9 +78,9 @@ "dev": true }, "@types/jasmine": { - "version": "2.2.33", - "from": "@types/jasmine@>=2.2.33 <3.0.0", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.2.33.tgz", + "version": "2.5.38", + "from": "@types/jasmine@2.5.38", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.38.tgz", "dev": true }, "@types/jquery": { @@ -89,15 +89,15 @@ "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-1.10.31.tgz" }, "@types/karma-jasmine": { - "version": "0.0.27", - "from": "@types/karma-jasmine@0.0.27", - "resolved": "https://registry.npmjs.org/@types/karma-jasmine/-/karma-jasmine-0.0.27.tgz", + "version": "0.0.28", + "from": "@types/karma-jasmine@0.0.28", + "resolved": "https://registry.npmjs.org/@types/karma-jasmine/-/karma-jasmine-0.0.28.tgz", "dev": true }, "@types/lodash": { - "version": "4.14.34", - "from": "@types/lodash@>=4.14.34 <5.0.0", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.34.tgz", + "version": "4.14.43", + "from": "@types/lodash@4.14.43", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.43.tgz", "dev": true }, "@types/node": { @@ -150,6 +150,12 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.3.tgz", "dev": true }, + "acorn-dynamic-import": { + "version": "2.0.1", + "from": "acorn-dynamic-import@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.1.tgz", + "dev": true + }, "adm-zip": { "version": "0.4.7", "from": "adm-zip@0.4.7", @@ -177,15 +183,15 @@ } }, "ajv": { - "version": "4.9.0", + "version": "4.10.0", "from": "ajv@>=4.7.0 <5.0.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.9.0.tgz", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.10.0.tgz", "dev": true }, "ajv-keywords": { - "version": "1.1.1", + "version": "1.2.0", "from": "ajv-keywords@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.2.0.tgz", "dev": true }, "align-text": { @@ -449,18 +455,10 @@ "dev": true }, "awesome-typescript-loader": { - "version": "2.2.4", - "from": "awesome-typescript-loader@2.2.4", - "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-2.2.4.tgz", - "dev": true, - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.13.1 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz", - "dev": true - } - } + "version": "3.0.0-beta.9", + "from": "awesome-typescript-loader@3.0.0-beta.9", + "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-3.0.0-beta.9.tgz", + "dev": true }, "aws-sign2": { "version": "0.6.0", @@ -639,9 +637,9 @@ "dev": true }, "babel-loader": { - "version": "6.2.5", - "from": "babel-loader@6.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.2.5.tgz", + "version": "6.2.10", + "from": "babel-loader@latest", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.2.10.tgz", "dev": true }, "babel-messages": { @@ -1538,6 +1536,12 @@ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-0.1.1.tgz", "dev": true }, + "commondir": { + "version": "1.0.1", + "from": "commondir@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "dev": true + }, "component-bind": { "version": "1.0.0", "from": "component-bind@1.0.0", @@ -1557,10 +1561,18 @@ "dev": true }, "compressible": { - "version": "2.0.8", + "version": "2.0.9", "from": "compressible@>=2.0.8 <2.1.0", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.8.tgz", - "dev": true + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.9.tgz", + "dev": true, + "dependencies": { + "mime-db": { + "version": "1.25.0", + "from": "mime-db@>=1.24.0 <2.0.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz", + "dev": true + } + } }, "compression": { "version": "1.6.2", @@ -1668,6 +1680,12 @@ "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-0.0.17.tgz", "dev": true, "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.6.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "dev": true + }, "normalize-package-data": { "version": "1.0.3", "from": "normalize-package-data@>=1.0.3 <2.0.0", @@ -1743,9 +1761,9 @@ "dev": true }, "cross-env": { - "version": "3.1.2", + "version": "3.1.3", "from": "cross-env@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-3.1.2.tgz", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-3.1.3.tgz", "dev": true }, "cross-spawn": { @@ -2564,6 +2582,12 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz", "dev": true }, + "find-cache-dir": { + "version": "0.1.1", + "from": "find-cache-dir@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "dev": true + }, "find-node-modules": { "version": "1.0.3", "from": "find-node-modules@>=1.0.1 <2.0.0", @@ -3013,9 +3037,9 @@ "dev": true }, "highlight.js": { - "version": "9.7.0", + "version": "9.9.0", "from": "highlight.js@>=9.0.0 <10.0.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.7.0.tgz", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.9.0.tgz", "dev": true }, "hoek": { @@ -3151,15 +3175,21 @@ "dev": true }, "http-proxy-middleware": { - "version": "0.17.2", + "version": "0.17.3", "from": "http-proxy-middleware@>=0.17.1 <0.18.0", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.2.tgz", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.3.tgz", "dev": true, "dependencies": { + "http-proxy": { + "version": "1.16.2", + "from": "http-proxy@>=1.16.2 <2.0.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", + "dev": true + }, "is-extglob": { - "version": "2.1.0", + "version": "2.1.1", "from": "is-extglob@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "dev": true }, "is-glob": { @@ -3167,12 +3197,6 @@ "from": "is-glob@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "dev": true - }, - "lodash": { - "version": "4.16.4", - "from": "lodash@^4.16.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz", - "dev": true } } }, @@ -3581,11 +3605,97 @@ } }, "istanbul-instrumenter-loader": { - "version": "0.2.0", - "from": "istanbul-instrumenter-loader@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-0.2.0.tgz", + "version": "1.1.0", + "from": "istanbul-instrumenter-loader@latest", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-1.1.0.tgz", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "1.0.0", + "from": "istanbul-lib-coverage@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.0.tgz", "dev": true }, + "istanbul-lib-instrument": { + "version": "1.3.0", + "from": "istanbul-lib-instrument@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.3.0.tgz", + "dev": true, + "dependencies": { + "babel-code-frame": { + "version": "6.20.0", + "from": "babel-code-frame@>=6.20.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.20.0.tgz", + "dev": true + }, + "babel-generator": { + "version": "6.21.0", + "from": "babel-generator@>=6.18.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.21.0.tgz", + "dev": true + }, + "babel-runtime": { + "version": "6.20.0", + "from": "babel-runtime@>=6.20.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.20.0.tgz", + "dev": true + }, + "babel-traverse": { + "version": "6.21.0", + "from": "babel-traverse@>=6.18.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.21.0.tgz", + "dev": true + }, + "babel-types": { + "version": "6.21.0", + "from": "babel-types@>=6.18.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.21.0.tgz", + "dev": true + }, + "babylon": { + "version": "6.14.1", + "from": "babylon@>=6.13.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.14.1.tgz", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "from": "detect-indent@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "dev": true + }, + "globals": { + "version": "9.14.0", + "from": "globals@>=9.0.0 <10.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.14.0.tgz", + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "from": "jsesc@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "dev": true + }, + "regenerator-runtime": { + "version": "0.10.1", + "from": "regenerator-runtime@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz", + "dev": true + }, + "semver": { + "version": "5.3.0", + "from": "semver@>=5.3.0 <6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "dev": true + }, + "source-map": { + "version": "0.5.6", + "from": "source-map@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "dev": true + } + } + }, "items": { "version": "2.1.1", "from": "items@>=2.0.0 <3.0.0", @@ -3608,8 +3718,8 @@ }, "jasmine-core": { "version": "2.5.2", - "from": "jasmine-core@>=2.3.4 <3.0.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.5.2.tgz", + "from": "git+https://github.com/jasmine/jasmine.git#be6ff8b24cba355246df93d00d74a64de9e580ad", + "resolved": "git+https://github.com/jasmine/jasmine.git#be6ff8b24cba355246df93d00d74a64de9e580ad", "dev": true }, "jasmine-spec-reporter": { @@ -3676,6 +3786,12 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "dev": true }, + "json-loader": { + "version": "0.5.4", + "from": "json-loader@>=0.5.4 <0.6.0", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.4.tgz", + "dev": true + }, "json-schema": { "version": "0.2.3", "from": "json-schema@0.2.3", @@ -3789,9 +3905,9 @@ "dev": true }, "karma-jasmine": { - "version": "1.0.2", - "from": "karma-jasmine@1.0.2", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.0.2.tgz", + "version": "1.1.0", + "from": "karma-jasmine@1.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.0.tgz", "dev": true }, "karma-jasmine-diff-reporter": { @@ -3949,21 +4065,9 @@ "dev": true }, "lodash": { - "version": "3.7.0", - "from": "lodash@>=3.7.0 <3.8.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", - "dev": true - }, - "lodash._arraycopy": { - "version": "3.0.0", - "from": "lodash._arraycopy@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", - "dev": true - }, - "lodash._arrayeach": { - "version": "3.0.0", - "from": "lodash._arrayeach@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", + "version": "4.17.2", + "from": "lodash@4.17.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.2.tgz", "dev": true }, "lodash._baseassign": { @@ -3972,48 +4076,12 @@ "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", "dev": true }, - "lodash._basecallback": { - "version": "3.3.1", - "from": "lodash._basecallback@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basecallback/-/lodash._basecallback-3.3.1.tgz", - "dev": true - }, "lodash._basecopy": { "version": "3.0.1", "from": "lodash._basecopy@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", "dev": true }, - "lodash._baseeach": { - "version": "3.0.4", - "from": "lodash._baseeach@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._baseeach/-/lodash._baseeach-3.0.4.tgz", - "dev": true - }, - "lodash._basefind": { - "version": "3.0.0", - "from": "lodash._basefind@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basefind/-/lodash._basefind-3.0.0.tgz", - "dev": true - }, - "lodash._basefindindex": { - "version": "3.6.0", - "from": "lodash._basefindindex@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basefindindex/-/lodash._basefindindex-3.6.0.tgz", - "dev": true - }, - "lodash._basefor": { - "version": "3.0.3", - "from": "lodash._basefor@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", - "dev": true - }, - "lodash._baseisequal": { - "version": "3.0.7", - "from": "lodash._baseisequal@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz", - "dev": true - }, "lodash._bindcallback": { "version": "3.0.1", "from": "lodash._bindcallback@>=3.0.0 <4.0.0", @@ -4088,10 +4156,10 @@ } } }, - "lodash.find": { - "version": "3.2.1", - "from": "lodash.find@>=3.2.1 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-3.2.1.tgz", + "lodash.differencewith": { + "version": "4.5.0", + "from": "lodash.differencewith@>=4.5.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz", "dev": true }, "lodash.indexof": { @@ -4118,16 +4186,16 @@ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.4.0.tgz", "dev": true }, - "lodash.isplainobject": { - "version": "3.2.0", - "from": "lodash.isplainobject@>=3.2.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", + "lodash.isfunction": { + "version": "3.0.8", + "from": "lodash.isfunction@>=3.0.8 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz", "dev": true }, - "lodash.istypedarray": { - "version": "3.0.6", - "from": "lodash.istypedarray@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", + "lodash.isplainobject": { + "version": "4.0.6", + "from": "lodash.isplainobject@>=4.0.6 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "dev": true }, "lodash.keys": { @@ -4136,22 +4204,16 @@ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", "dev": true }, - "lodash.keysin": { - "version": "3.0.8", - "from": "lodash.keysin@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", - "dev": true - }, "lodash.map": { "version": "4.6.0", "from": "lodash.map@>=4.5.1 <5.0.0", "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", "dev": true }, - "lodash.merge": { - "version": "3.3.2", - "from": "lodash.merge@>=3.3.2 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", + "lodash.mergewith": { + "version": "4.6.0", + "from": "lodash.mergewith@>=4.6.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", "dev": true }, "lodash.pad": { @@ -4172,22 +4234,16 @@ "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", "dev": true }, - "lodash.pairs": { - "version": "3.0.1", - "from": "lodash.pairs@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz", - "dev": true - }, "lodash.restparam": { "version": "3.6.1", "from": "lodash.restparam@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "dev": true }, - "lodash.toplainobject": { - "version": "3.0.0", - "from": "lodash.toplainobject@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", + "lodash.unionwith": { + "version": "4.6.0", + "from": "lodash.unionwith@>=4.6.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.unionwith/-/lodash.unionwith-4.6.0.tgz", "dev": true }, "lodash.words": { @@ -4421,9 +4477,9 @@ } }, "moment": { - "version": "2.15.1", + "version": "2.17.1", "from": "moment@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.15.1.tgz", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz", "dev": true }, "ms": { @@ -4495,9 +4551,9 @@ } }, "node-libs-browser": { - "version": "1.1.1", - "from": "node-libs-browser@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-1.1.1.tgz", + "version": "2.0.0", + "from": "node-libs-browser@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz", "dev": true }, "node-sass": { @@ -5469,6 +5525,12 @@ "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-1.1.3.tgz", "dev": true }, + "pkg-dir": { + "version": "1.0.0", + "from": "pkg-dir@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "dev": true + }, "portfinder": { "version": "0.4.0", "from": "portfinder@>=0.4.0 <0.5.0", @@ -5795,7 +5857,15 @@ "version": "0.3.2", "from": "protractor-jasmine2-screenshot-reporter@>=0.3.2 <0.4.0", "resolved": "https://registry.npmjs.org/protractor-jasmine2-screenshot-reporter/-/protractor-jasmine2-screenshot-reporter-0.3.2.tgz", - "dev": true + "dev": true, + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "dev": true + } + } }, "proxy-addr": { "version": "1.1.2", @@ -6252,9 +6322,9 @@ } }, "sass-loader": { - "version": "4.0.2", - "from": "sass-loader@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-4.0.2.tgz", + "version": "4.1.0", + "from": "sass-loader@latest", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-4.1.0.tgz", "dev": true }, "saucelabs": { @@ -6395,6 +6465,12 @@ "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "dev": true }, + "setimmediate": { + "version": "1.0.5", + "from": "setimmediate@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "dev": true + }, "setprototypeof": { "version": "1.0.1", "from": "setprototypeof@1.0.1", @@ -6630,9 +6706,9 @@ "dev": true }, "spdy-transport": { - "version": "2.0.15", + "version": "2.0.18", "from": "spdy-transport@>=2.0.15 <3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.15.tgz", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.18.tgz", "dev": true }, "split": { @@ -6840,9 +6916,9 @@ } }, "timers-browserify": { - "version": "1.4.2", - "from": "timers-browserify@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "version": "2.0.2", + "from": "timers-browserify@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.2.tgz", "dev": true }, "title-case": { @@ -6962,10 +7038,10 @@ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.5.0.tgz", "dev": true, "dependencies": { - "lodash": { - "version": "4.16.4", - "from": "lodash@>=4.13.1 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz", + "typescript": { + "version": "2.0.3", + "from": "typescript@2.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.0.3.tgz", "dev": true } } @@ -6977,9 +7053,9 @@ "dev": true }, "typescript": { - "version": "2.0.3", + "version": "2.1.4", "from": "typescript@latest", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.0.3.tgz", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.1.4.tgz", "dev": true }, "uglify-js": { @@ -7111,9 +7187,9 @@ } }, "url-parse": { - "version": "1.1.6", + "version": "1.1.7", "from": "url-parse@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.6.tgz", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.7.tgz", "dev": true }, "url2": { @@ -7237,12 +7313,6 @@ "from": "async@2.0.0-rc.4", "resolved": "https://registry.npmjs.org/async/-/async-2.0.0-rc.4.tgz", "dev": true - }, - "lodash": { - "version": "4.17.2", - "from": "lodash@^4.3.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.2.tgz", - "dev": true } } }, @@ -7259,9 +7329,9 @@ "dev": true }, "webpack": { - "version": "2.1.0-beta.27", - "from": "git+https://github.com/webpack/webpack.git#fbb8920f2ec8366659bb04de7c2c044a308a0925", - "resolved": "git+https://github.com/webpack/webpack.git#fbb8920f2ec8366659bb04de7c2c044a308a0925", + "version": "2.1.0-beta.28", + "from": "webpack@2.1.0-beta.28", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-2.1.0-beta.28.tgz", "dev": true, "dependencies": { "async": { @@ -7282,12 +7352,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "dev": true }, - "lodash": { - "version": "4.17.2", - "from": "lodash@>=4.14.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.2.tgz", - "dev": true - }, "source-map": { "version": "0.5.6", "from": "source-map@>=0.5.3 <0.6.0", @@ -7307,15 +7371,15 @@ "dev": true }, "yargs": { - "version": "6.4.0", + "version": "6.5.0", "from": "yargs@>=6.0.0 <7.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.4.0.tgz", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.5.0.tgz", "dev": true }, "yargs-parser": { - "version": "4.1.0", - "from": "yargs-parser@>=4.1.0 <5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.1.0.tgz", + "version": "4.2.0", + "from": "yargs-parser@>=4.2.0 <5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.0.tgz", "dev": true } } @@ -7327,23 +7391,53 @@ "dev": true }, "webpack-dev-server": { - "version": "2.1.0-beta.9", - "from": "webpack-dev-server@2.1.0-beta.9", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.1.0-beta.9.tgz", + "version": "2.2.0-rc.0", + "from": "webpack-dev-server@beta", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.2.0-rc.0.tgz", "dev": true, "dependencies": { + "async": { + "version": "1.5.2", + "from": "async@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "from": "camelcase@^3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "dev": true + }, "cliui": { "version": "3.2.0", "from": "cliui@>=3.2.0 <4.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "dev": true }, + "memory-fs": { + "version": "0.4.1", + "from": "memory-fs@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "dev": true + }, + "portfinder": { + "version": "1.0.10", + "from": "portfinder@>=1.0.9 <2.0.0", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.10.tgz", + "dev": true + }, "supports-color": { "version": "3.1.2", "from": "supports-color@>=3.1.1 <4.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", "dev": true }, + "webpack-dev-middleware": { + "version": "1.9.0", + "from": "webpack-dev-middleware@>=1.9.0 <2.0.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.9.0.tgz", + "dev": true + }, "window-size": { "version": "0.2.0", "from": "window-size@>=0.2.0 <0.3.0", @@ -7351,17 +7445,23 @@ "dev": true }, "yargs": { - "version": "4.8.1", - "from": "yargs@>=4.7.1 <5.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "version": "6.5.0", + "from": "yargs@^6.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.5.0.tgz", + "dev": true + }, + "yargs-parser": { + "version": "4.2.0", + "from": "yargs-parser@^4.2.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.0.tgz", "dev": true } } }, "webpack-merge": { - "version": "0.14.1", - "from": "webpack-merge@>=0.14.1 <0.15.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-0.14.1.tgz", + "version": "1.1.1", + "from": "webpack-merge@latest", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-1.1.1.tgz", "dev": true }, "webpack-sources": { @@ -7379,9 +7479,9 @@ } }, "webpack-validator": { - "version": "2.2.9", - "from": "webpack-validator@2.2.9", - "resolved": "https://registry.npmjs.org/webpack-validator/-/webpack-validator-2.2.9.tgz", + "version": "2.3.0", + "from": "webpack-validator@latest", + "resolved": "https://registry.npmjs.org/webpack-validator/-/webpack-validator-2.3.0.tgz", "dev": true, "dependencies": { "camelcase": { diff --git a/package.json b/package.json index 84495d02..613f07b7 100644 --- a/package.json +++ b/package.json @@ -23,15 +23,15 @@ "@types/angular-mocks": "^1.5.4", "@types/angular-route": "^1.3.2", "@types/jasmine": "^2.2.33", - "@types/karma-jasmine": "0.0.27", - "@types/lodash": "^4.14.34", + "@types/karma-jasmine": "0.0.28", + "@types/lodash": "^4.14.43", "angular": "^1.5.8", "angular-mocks": "^1.5.8", "angular-route": "^1.5.8", "angular1-template-loader": "^0.1.0", - "awesome-typescript-loader": "^2.2.4", + "awesome-typescript-loader": "^3.0.0-beta.9", "babel-core": "^6.14.0", - "babel-loader": "^6.2.5", + "babel-loader": "^6.2.10", "babel-preset-es2015": "^6.13.2", "babel-preset-es2016": "^6.11.3", "babel-preset-stage-2": "^6.13.0", @@ -50,20 +50,20 @@ "http-server": "^0.9.0", "husky": "^0.11.9", "istanbul": "^0.4.4", - "istanbul-instrumenter-loader": "^0.2.0", - "jasmine-core": "^2.3.4", + "istanbul-instrumenter-loader": "^1.1.0", + "jasmine-core": "git+https://github.com/jasmine/jasmine.git#be6ff8b24cba355246df93d00d74a64de9e580ad", "jasmine-spec-reporter": "^2.7.0", "karma": "1.1.2", "karma-chrome-launcher": "1.0.1", "karma-coverage": "1.1.1", "karma-firefox-launcher": "1.0.0", - "karma-jasmine": "1.0.2", + "karma-jasmine": "^1.1.0", "karma-jasmine-diff-reporter": "^0.6.3", "karma-phantomjs-launcher": "1.0.1", "karma-spec-reporter": "0.0.26", "karma-webpack": "^1.8.0", "linklocal": "git+https://github.com/theoy/linklocal.git#3f939171c3c925f2af831d78a3f2fbf9caa3002e", - "lodash": "~3.7.0", + "lodash": "^4.17.2", "ngtemplate-loader": "git+https://github.com/wearymonkey/ngtemplate-loader.git#63e3461d8b1298de913e3528766068260915ae1f", "node-sass": "^3.8.0", "npm-run-all": "^2.3.0", @@ -72,7 +72,7 @@ "protractor": "^4.0.9", "protractor-jasmine2-screenshot-reporter": "^0.3.2", "resolve-url-loader": "^1.6.0", - "sass-loader": "^4.0.0", + "sass-loader": "^4.1.0", "semantic-release": "^4.3.5", "shx": "^0.1.4", "style-loader": "^0.13.1", @@ -80,13 +80,13 @@ "systemjs-plugin-babel": "0.0.15", "ts-node": "^1.3.0", "typedoc": "^0.5.0", - "typescript": "2.0.3", + "typescript": "^2.1.4", "url-loader": "^0.5.7", "validate-commit-msg": "^2.8.2", - "webpack": "git+https://github.com/webpack/webpack.git#fbb8920f2ec8366659bb04de7c2c044a308a0925", - "webpack-dev-server": "^2.1.0-beta.9", - "webpack-merge": "^0.14.1", - "webpack-validator": "^2.2.9" + "webpack": "^2.1.0-beta.28", + "webpack-dev-server": "^2.2.0-rc.0", + "webpack-merge": "^1.1.1", + "webpack-validator": "^2.3.0" }, "scripts": { "build:all": "run-s build:full build:demo-apps", @@ -99,7 +99,7 @@ "build:full": "run-p tsc \"webpack -- --progress --profile --env.prod --env.debug\"", "clean:demo-apps": "shx ls -d demo-apps/*/ | bulk -c \"npm run clean\"", "clean:all": "run-p clean clean:demo-apps", - "clean": "shx rm -rf bundles out demo-site/api-docs *.d.ts *.js.map src/**/*.js src/**/*.js.map src/**/*.d.ts test/**/*.spec.js test/**/*.spec.js.map test/**/*.spec.d.ts", + "clean": "shx rm -rf bundles out demo-site/api-docs index.{js,js.map,d.ts} src/**/*.{js,js.map,d.ts} test/specs/**/*.{js,js.map,d.ts} test/util/**/*.{js,js.map,d.ts}", "cm": "git add -A && git-cz", "commitmsg": "validate-commit-msg", "doc-deploy": "gh-pages -d demo-site", diff --git a/scripts/webpack/parts.js b/scripts/webpack/parts.js index be28a5c8..5c185f66 100644 --- a/scripts/webpack/parts.js +++ b/scripts/webpack/parts.js @@ -67,7 +67,10 @@ function createParts(rootDir, env) { }, // note: wanted to use eval-source-map to increase build times, but chrome would not stop on breakpoint // therefore instead using source-map - devtool: 'source-map' + devtool: 'source-map', + performance: { + hints: false + } }; } else if (env.test) { return { @@ -91,7 +94,10 @@ function createParts(rootDir, env) { /\.spec\.ts$/, /node_modules/ ], - loader: 'istanbul-instrumenter-loader' + loader: 'istanbul-instrumenter-loader', + query: { + esModules: true + } } ] } diff --git a/src/core/data/dataSettings.ts b/src/core/data/dataSettings.ts index 7aa794a0..dc8c6401 100644 --- a/src/core/data/dataSettings.ts +++ b/src/core/data/dataSettings.ts @@ -1,5 +1,7 @@ -export interface IDataSettings { - applyFilter?: boolean; - applyPaging?: boolean; - applySort?: boolean; +export type DataSettingsPartial = Partial; + +export class DataSettings { + applyFilter = true; + applyPaging = true; + applySort = true; } \ No newline at end of file diff --git a/src/core/data/ngTableDefaultGetData.ts b/src/core/data/ngTableDefaultGetData.ts index 918e4feb..837f96a0 100644 --- a/src/core/data/ngTableDefaultGetData.ts +++ b/src/core/data/ngTableDefaultGetData.ts @@ -65,8 +65,6 @@ export class NgTableDefaultGetDataProvider implements IServiceProvider { function ngTableDefaultGetData($filter: IFilterService, ngTableEventsChannel: NgTableEventsChannel): IDefaultGetData { - const defaultDataOptions = { applyFilter: true, applySort: true, applyPaging: true }; - (getData as IDefaultGetData).applyPaging = applyPaging; (getData as IDefaultGetData).getFilterFn = getFilterFn; (getData as IDefaultGetData).getOrderByFn = getOrderByFn; @@ -118,7 +116,7 @@ export class NgTableDefaultGetDataProvider implements IServiceProvider { return []; } - const options = ng1.extend({}, defaultDataOptions, params.settings().dataOptions); + const options = params.settings().dataOptions; const fData = options.applyFilter ? applyFilter(data, params) : data; ngTableEventsChannel.publishAfterDataFiltered(params, fData); diff --git a/src/core/filtering/filterSettings.ts b/src/core/filtering/filterSettings.ts index d5db2622..58d71322 100644 --- a/src/core/filtering/filterSettings.ts +++ b/src/core/filtering/filterSettings.ts @@ -3,7 +3,9 @@ import { IFilterFunc } from './filterFunc'; export type FilterLayout = 'stack' | 'horizontal'; -export interface IFilterSettings { +export type FilterSettingsPartial = Partial> + +export class FilterSettings { /** * Use this to determine how items are matched against the filter values. * This setting is identical to the `comparator` parameter supported by the angular @@ -13,31 +15,29 @@ export interface IFilterSettings { * `IDefaultGetData` service is supplying the implementation for the * `ISettings.getData` function */ - filterComparator?: FilterComparator; + filterComparator?: FilterComparator = undefined; // look for a substring match in case insensitive way /** * A duration to wait for the user to stop typing before applying the filter. - * - Defaults to 0 for small managed inmemory arrays ie where a `ISettings.dataset` argument is - * supplied to `NgTableParams.settings`. - * - Defaults to 500 milliseconds otherwise. + * Note: this delay will NOT be applied when *small* managed inmemory arrays are supplied as a + * `SettingsPartial.dataset` argument to `NgTableParams.settings`. */ - filterDelay?: number; + filterDelay = 500; /** - * The number of elements up to which a managed inmemory array is considered small. Defaults to 10000. + * The number of elements up to which a managed inmemory array is considered small */ - filterDelayThreshold?: number; + filterDelayThreshold: number | null = 10000; /** * Overrides `IDefaultGetDataProvider.filterFilterName`. * The value supplied should be the name of the angular `$filter` service that will be selected to perform * the actual filter logic. - * Defaults to 'filter'. */ - filterFilterName?: string; + filterFilterName?: string = undefined; /** * Tells `IDefaultGetData` to use this function supplied to perform the filtering instead of selecting an angular $filter. */ - filterFn?: IFilterFunc; + filterFn?: IFilterFunc = undefined; /** * The layout to use when multiple html templates are to rendered in a single table header column. */ - filterLayout?: FilterLayout + filterLayout: FilterLayout = 'stack'; } \ No newline at end of file diff --git a/src/core/grouping/groupSettings.ts b/src/core/grouping/groupSettings.ts index c32ef756..e1eee94b 100644 --- a/src/core/grouping/groupSettings.ts +++ b/src/core/grouping/groupSettings.ts @@ -1,16 +1,20 @@ import { SortDirection } from '../sorting'; +export type GroupSort = SortDirection | ''; + +export type GroupSettingsPartial = Partial + /** * Configuration that determines the data row grouping behaviour of a table */ -export interface IGroupSettings { +export class GroupSettings { /** * The default sort direction that will be used whenever a group is supplied that * does not define its own sort direction */ - defaultSort?: SortDirection; + defaultSort: SortDirection = 'asc'; /** * Determines whether groups should be displayed expanded to show their items. Defaults to true */ - isExpanded?: boolean; + isExpanded = true; } \ No newline at end of file diff --git a/src/core/grouping/groupingFunc.ts b/src/core/grouping/groupingFunc.ts index 2e9292ea..012387dd 100644 --- a/src/core/grouping/groupingFunc.ts +++ b/src/core/grouping/groupingFunc.ts @@ -1,9 +1,7 @@ -import { SortDirection } from '../sorting'; +import { GroupSort } from './groupSettings'; export type Grouping = IGroupValues | IGroupingFunc; -export type GroupSort = SortDirection | ''; - /** * Signature of a function that should return the name of the group * that the `item` should be placed within diff --git a/src/core/grouping/ngTableDefaultGetGroups.ts b/src/core/grouping/ngTableDefaultGetGroups.ts index c9a020d2..83e8f6d4 100644 --- a/src/core/grouping/ngTableDefaultGetGroups.ts +++ b/src/core/grouping/ngTableDefaultGetGroups.ts @@ -36,7 +36,7 @@ export function ngTableDefaultGetGroups($q: IQService, ngTableDefaultGetData: const settings = params.settings(); const originalDataOptions = settings.dataOptions; - settings.dataOptions = { applyPaging: false }; + settings.dataOptions = ng1.extend({}, originalDataOptions, { applyPaging: false }); const getData: IGetDataFunc = settings.getData; const gotData = $q.when(getData(params)); return gotData.then(data => { diff --git a/src/core/index.ts b/src/core/index.ts index e1270fab..bf410104 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1,8 +1,8 @@ import * as angular from 'angular'; import { NgTableDefaultGetDataProvider, IDefaultGetData } from './data'; -import { IGroupSettings, ngTableDefaultGetGroups } from './grouping'; +import { GroupSettingsPartial, ngTableDefaultGetGroups } from './grouping'; import { ngTableDefaults, IDefaults } from './ngTableDefaults'; -import { NgTableSettings, ISettings } from './ngTableSettings'; +import { NgTableSettings, SettingsPartial, Settings } from './ngTableSettings'; import { NgTableParams } from './ngTableParams'; import { NgTableEventsChannel } from './ngTableEventsChannel'; @@ -12,6 +12,7 @@ const ngTableCoreModule = angular.module('ngTable-core', []) .value('ngTableDefaults',ngTableDefaults) .service('ngTableEventsChannel', NgTableEventsChannel) .service('ngTableSettings', NgTableSettings) + .run(Settings.init) .run(NgTableParams.init); // note: if you are using ES6 or typescript prefer: @@ -22,7 +23,7 @@ export { ngTableCoreModule }; export { IDefaults } from './ngTableDefaults'; export * from './ngTableEventsChannel'; -export { ISettings } from './ngTableSettings'; +export { SettingsPartial, Settings }; export * from './ngTableParams'; export * from './data'; export * from './filtering'; diff --git a/src/core/ngTableDefaults.ts b/src/core/ngTableDefaults.ts index 771a995a..ae12a1f9 100644 --- a/src/core/ngTableDefaults.ts +++ b/src/core/ngTableDefaults.ts @@ -7,7 +7,7 @@ */ import { IParamValues } from './ngTableParams'; -import { ISettings } from './ngTableSettings'; +import { SettingsPartial } from './ngTableSettings'; /** @@ -16,7 +16,7 @@ import { ISettings } from './ngTableSettings'; */ export interface IDefaults { params?: IParamValues; - settings?: ISettings + settings?: SettingsPartial } /** diff --git a/src/core/ngTableParams.ts b/src/core/ngTableParams.ts index 435dd891..9bafdffd 100644 --- a/src/core/ngTableParams.ts +++ b/src/core/ngTableParams.ts @@ -7,11 +7,11 @@ */ import * as ng1 from 'angular'; -import { IPromise } from 'angular'; +import { ILogService, IPromise, IQService } from 'angular'; import { convertSortToOrderBy, isGroupingFun } from './util'; import { IDefaults } from './ngTableDefaults' import { NgTableEventsChannel } from './ngTableEventsChannel' -import { NgTableSettings, ISettings } from './ngTableSettings' +import { NgTableSettings, SettingsPartial, Settings } from './ngTableSettings' import { DataResult, IDataRowGroup, IGetDataFunc } from './data'; import { IFilterValues } from './filtering'; import { IGetGroupFunc, Grouping, IGroupingFunc, GroupSort, IGroupValues } from './grouping'; @@ -77,11 +77,14 @@ export class NgTableParams { */ data: T[] = []; reloadPages: () => void; - private defaultSettings = NgTableParams.ngTableSettings.createDefaults(); + private defaultSettings = this.ngTableSettings.createDefaults(); private errParamsMemento: Memento; private isCommittedDataset = false; isNullInstance: boolean; private initialEvents: Function[] = []; + private ngTableDefaults: IDefaults + private ngTableEventsChannel: NgTableEventsChannel; + private ngTableSettings: NgTableSettings; private prevParamsMemento: Memento; private _params: IParamValues = { page: 1, @@ -91,7 +94,9 @@ export class NgTableParams { group: {} }; private _settings = this.defaultSettings; - constructor(baseParameters?: IParamValues | boolean, baseSettings?: ISettings) { + private $q: IQService; + private $log: ILogService + constructor(baseParameters?: IParamValues | boolean, baseSettings?: SettingsPartial) { // the ngTableController "needs" to create a dummy/null instance and it's important to know whether an instance // is one of these @@ -106,17 +111,17 @@ export class NgTableParams { const newPages = this.generatePagesArray(this.page(), this.total(), this.count()); if (!ng1.equals(oldPages, newPages)) { currentPages = newPages; - NgTableParams.ngTableEventsChannel.publishPagesChanged(this, newPages, oldPages); + this.ngTableEventsChannel.publishPagesChanged(this, newPages, oldPages); } } })(); - ng1.extend(this._params, NgTableParams.ngTableDefaults.params); + ng1.extend(this._params, this.ngTableDefaults.params); this.settings(baseSettings); this.parameters(baseParameters, true); - NgTableParams.ngTableEventsChannel.publishAfterCreated(this); + this.ngTableEventsChannel.publishAfterCreated(this); // run events during construction after the initial create event. That way a consumer // can subscribe to all events for a table without "dropping" an event ng1.forEach(this.initialEvents, event => { @@ -424,10 +429,10 @@ export class NgTableParams { this.isCommittedDataset = true; if (this.hasGroup()) { - pData = this.runInterceptorPipeline(NgTableParams.$q.when(this._settings.getGroups(this))); + pData = this.runInterceptorPipeline(this.$q.when(this._settings.getGroups(this))); } else { const fn = this._settings.getData as IGetDataFunc; - pData = this.runInterceptorPipeline(NgTableParams.$q.when(fn(this))); + pData = this.runInterceptorPipeline(this.$q.when(fn(this))); } this.log('ngTable: reload data'); @@ -440,30 +445,30 @@ export class NgTableParams { this.data = data; // note: I think it makes sense to publish this event even when data === oldData // subscribers can always set a filter to only receive the event when data !== oldData - NgTableParams.ngTableEventsChannel.publishAfterReloadData(this, data, oldData); + this.ngTableEventsChannel.publishAfterReloadData(this, data, oldData); this.reloadPages(); return data; }).catch(reason => { this.errParamsMemento = this.prevParamsMemento; // "rethrow" - return NgTableParams.$q.reject(reason); + return this.$q.reject(reason); }); } /** * Returns the settings for the table. */ - settings(): ISettings + settings(): Settings /** * Sets the settings for the table; new setting values will be merged with the existing settings. * Supplying a new `dataset` will cause `isDataReloadRequired` to return true and the `ngTableEventsChannel` * to fire its `datasetChanged` event */ - settings(newSettings: ISettings): this - settings(newSettings?: ISettings): this | ISettings { + settings(newSettings: SettingsPartial): this + settings(newSettings?: SettingsPartial): this | Settings { if (ng1.isDefined(newSettings)) { - const settings = NgTableParams.ngTableSettings.merge(this._settings, newSettings); + const settings = this.ngTableSettings.merge(this._settings, newSettings); const originalDataset = this._settings.dataset; this._settings = settings; @@ -477,7 +482,7 @@ export class NgTableParams { this.isCommittedDataset = false; const fireEvent = () => { - NgTableParams.ngTableEventsChannel.publishDatasetChanged(this, newSettings.dataset, originalDataset); + this.ngTableEventsChannel.publishDatasetChanged(this, newSettings.dataset, originalDataset); }; if (this.initialEvents) { @@ -597,12 +602,12 @@ export class NgTableParams { return !ng1.equals(currentVal, previousVal); } private log(...args: any[]) { - if (this._settings.debugMode && NgTableParams.$log.debug) { - NgTableParams.$log.debug(...args); + if (this._settings.debugMode && this.$log.debug) { + this.$log.debug(...args); } } private parseGroup(group: string | Grouping) { - const defaultSort = this._settings.groupOptions && this._settings.groupOptions.defaultSort; + const defaultSort = this._settings.groupOptions.defaultSort; if (!group) { return group; } else if (isGroupingFun(group)) { @@ -623,12 +628,10 @@ export class NgTableParams { }; } } - private runInterceptorPipeline(fetchedData: ng1.IPromise) { - const interceptors = this._settings.interceptors || []; - - return interceptors.reduce((result, interceptor) => { - const thenFn = (interceptor.response && interceptor.response.bind(interceptor)) || NgTableParams.$q.when; - const rejectFn = (interceptor.responseError && interceptor.responseError.bind(interceptor)) || NgTableParams.$q.reject; + private runInterceptorPipeline(fetchedData: IPromise) { + return this._settings.interceptors.reduce((result, interceptor) => { + const thenFn = (interceptor.response && interceptor.response.bind(interceptor)) || this.$q.when; + const rejectFn = (interceptor.responseError && interceptor.responseError.bind(interceptor)) || this.$q.reject; return result.then(data => { return thenFn(data, this); }, reason => { @@ -637,22 +640,15 @@ export class NgTableParams { }, fetchedData); } - private static $q: ng1.IQService; - private static $log: ng1.ILogService; - private static ngTableDefaults: IDefaults; - private static ngTableEventsChannel: NgTableEventsChannel; - private static ngTableSettings: NgTableSettings; static init( - $q: ng1.IQService, - $log: ng1.ILogService, + $q: IQService, + $log: ILogService, ngTableDefaults: IDefaults, ngTableEventsChannel: NgTableEventsChannel, ngTableSettings: NgTableSettings) { - NgTableParams.$q = $q; - NgTableParams.$log = $log; - NgTableParams.ngTableDefaults = ngTableDefaults; - NgTableParams.ngTableEventsChannel = ngTableEventsChannel; - NgTableParams.ngTableSettings = ngTableSettings; + ng1.extend(NgTableParams.prototype, { + $q, $log, ngTableDefaults, ngTableEventsChannel, ngTableSettings + }); } } diff --git a/src/core/ngTableSettings.ts b/src/core/ngTableSettings.ts index f5e016b1..c951400e 100644 --- a/src/core/ngTableSettings.ts +++ b/src/core/ngTableSettings.ts @@ -1,140 +1,137 @@ import * as ng1 from 'angular'; +import { assignPartialDeep } from '../shared'; import { IPromise } from 'angular'; import { IDefaults } from './ngTableDefaults'; -import { IDataRowGroup, IDataSettings, IDefaultGetData, IGetDataFunc, IInterceptor, IInterceptableGetDataFunc } from './data'; -import { IFilterValues, IFilterSettings } from './filtering'; -import { IGetGroupFunc, IGroupSettings } from './grouping'; +import { IDataRowGroup, DataSettingsPartial, DataSettings, IDefaultGetData, IGetDataFunc, IInterceptor, IInterceptableGetDataFunc } from './data'; +import { IFilterValues, FilterSettingsPartial, FilterSettings } from './filtering'; +import { IGetGroupFunc, GroupSettingsPartial, GroupSettings } from './grouping'; import { SortDirection } from './sorting'; import { NgTableParams } from './ngTableParams'; /** * Configuration settings for {@link NgTableParams} */ -export interface ISettings { +export class Settings { /** * Returns true whenever a call to `getData` is in progress */ - $loading?: boolean; + $loading = false; + /** + * The page size buttons that should be displayed. Each value defined in the array + * determines the possible values that can be supplied to {@link NgTableParams} `page` + */ + counts = [10, 25, 50, 100]; /** * An array that contains all the data rows that table should manage. * The `gateData` function will be used to manage the data rows * that ultimately will be displayed. */ - dataset?: T[]; - dataOptions?: IDataSettings; - debugMode?: boolean; + dataset?: T[] = undefined; + dataOptions = new DataSettings(); + debugMode = false; /** * The total number of data rows before paging has been applied. * Typically you will not need to supply this yourself */ - total?: number; + total = 0; /** * The default sort direction that will be used whenever a sorting is supplied that * does not define its own sort direction */ - defaultSort?: SortDirection; - filterOptions?: IFilterSettings; - groupOptions?: IGroupSettings; + defaultSort: SortDirection = 'desc'; + filterOptions = new FilterSettings(); /** - * The page size buttons that should be displayed. Each value defined in the array - * determines the possible values that can be supplied to {@link NgTableParams} `page` + * The function that will be used fetch data rows. Leave undefined to let the {@link IDefaultGetData} + * service provide a default implementation that will work with the `dataset` array you supply. + * + * Typically you will supply a custom function when you need to execute filtering, paging and sorting + * on the server */ - counts?: number[]; + getData: IGetDataFunc | IInterceptableGetDataFunc = (params: NgTableParams) => { + return Settings.ngTableDefaultGetData(params.settings().dataset, params) as T[]; + }; + /** + * The function that will be used group data rows according to the groupings returned by {@link NgTableParams} `group` + */ + getGroups: IGetGroupFunc = Settings.ngTableDefaultGetGroups; + groupOptions = new GroupSettings(); /** * The collection of interceptors that should apply to the results of a call to * the `getData` function before the data rows are displayed in the table */ - interceptors?: IInterceptor[]; + interceptors = new Array>(); /** * Configuration for the template that will display the page size buttons */ - paginationMaxBlocks?: number; + paginationMaxBlocks = 11; /** * Configuration for the template that will display the page size buttons */ - paginationMinBlocks?: number; + paginationMinBlocks = 5; /** * The html tag that will be used to display the sorting indicator in the table header */ - sortingIndicator?: string; - /** - * The function that will be used fetch data rows. Leave undefined to let the {@link IDefaultGetData} - * service provide a default implementation that will work with the `dataset` array you supply. - * - * Typically you will supply a custom function when you need to execute filtering, paging and sorting - * on the server - */ - getData?: IGetDataFunc | IInterceptableGetDataFunc; - /** - * The function that will be used group data rows according to the groupings returned by {@link NgTableParams} `group` - */ - getGroups?: IGetGroupFunc; + sortingIndicator = 'span' + private static ngTableDefaultGetData: IDefaultGetData; + private static ngTableDefaultGetGroups: IGetGroupFunc; + static init(ngTableDefaultGetData: IDefaultGetData, + ngTableDefaultGetGroups: IGetGroupFunc) { + Settings.ngTableDefaultGetData = ngTableDefaultGetData; + Settings.ngTableDefaultGetGroups = ngTableDefaultGetGroups; + } } +Settings.init.$inject = ['ngTableDefaultGetData', 'ngTableDefaultGetGroups']; + +export type SettingsPartial = + Partial, + '$loading' | + 'counts' | + 'dataset' | + 'debugMode' | + 'total' | + 'defaultSort' | + 'getData' | + 'getGroups' | + 'interceptors' | + 'paginationMaxBlocks' | + 'paginationMinBlocks' | + 'sortingIndicator'>> + & { + dataOptions?: DataSettingsPartial; + filterOptions?: FilterSettingsPartial; + groupOptions?: GroupSettingsPartial; + } + /** * @private */ export class NgTableSettings { - static $inject = ['ngTableDefaults', 'ngTableDefaultGetData', 'ngTableDefaultGetGroups']; - private defaults: ISettings; + static $inject = ['ngTableDefaults']; + private defaults = new Settings(); constructor( - private ngTableDefaults: IDefaults, - private ngTableDefaultGetData: IDefaultGetData, - private ngTableDefaultGetGroups: IGetGroupFunc) { - - this.defaults = { - $loading: false, - dataset: null, //allows data to be set when table is initialized - total: 0, - defaultSort: 'desc', - counts: [10, 25, 50, 100], - filterOptions: { - filterComparator: undefined, // look for a substring match in case insensitive way - filterDelay: 500, - filterDelayThreshold: 10000, // size of dataset array that will trigger the filterDelay being applied - filterFilterName: undefined, // when defined overrides ngTableDefaultGetDataProvider.filterFilterName - filterFn: undefined, // when defined overrides the filter function that ngTableDefaultGetData uses - filterLayout: 'stack' - }, - getData: (params: NgTableParams) => { - return this.ngTableDefaultGetData(params.settings().dataset, params); - }, - getGroups: this.ngTableDefaultGetGroups, - groupOptions: { - defaultSort: 'asc', // set to 'asc' or 'desc' to apply sorting to groups - isExpanded: true - }, - interceptors: [], - paginationMaxBlocks: 11, - paginationMinBlocks: 5, - sortingIndicator: 'span' - }; + private ngTableDefaults: IDefaults) { } - createDefaults(): ISettings { + createDefaults(): Settings { return this.merge(this.defaults, this.ngTableDefaults.settings); } - merge(existing: ISettings, newSettings: ISettings): ISettings { + merge(existing: Settings, newSettings: SettingsPartial): Settings { - newSettings = ng1.extend({}, newSettings); + const results = assignPartialDeep(ng1.copy(existing), newSettings, (destValue: any, srcValue: any, key: keyof Settings) => { + // copy *reference* to dataset + if (key === 'dataset'){ + return srcValue; + } + return undefined; + }); - if (newSettings.filterOptions) { - newSettings.filterOptions = ng1.extend({}, existing.filterOptions || {}, newSettings.filterOptions); - } - if (newSettings.groupOptions) { - newSettings.groupOptions = ng1.extend({}, existing.groupOptions || {}, newSettings.groupOptions); - } - - if (ng1.isArray(newSettings.dataset)) { - //auto-set the total from passed in dataset - newSettings.total = newSettings.dataset.length; - } - const results = ng1.extend({}, existing, newSettings); - if (ng1.isArray(newSettings.dataset)) { + if (newSettings.dataset) { + results.total = newSettings.dataset.length; this.optimizeFilterDelay(results); } - return ng1.extend({}, existing, newSettings); + return results; } - private optimizeFilterDelay(settings: ISettings) { + private optimizeFilterDelay(settings: Settings) { // don't debounce by default filter input when working with small synchronous datasets if (settings.filterOptions.filterDelay === this.defaults.filterOptions.filterDelay && settings.total <= settings.filterOptions.filterDelayThreshold && diff --git a/src/shared/assign-partial-deep.ts b/src/shared/assign-partial-deep.ts new file mode 100644 index 00000000..f74db86a --- /dev/null +++ b/src/shared/assign-partial-deep.ts @@ -0,0 +1,29 @@ +import * as ng1 from 'angular'; + +/** + * @private + */ +export function assignPartialDeep( + destination: T, + partial: TPartial, + customizer: (destValue: any, srcValue: any, key: keyof TPartial) => any = () => undefined + ) { + const keys = Object.keys(partial); + for(const key of keys) { + let srcVal = partial[key]; + if (srcVal === undefined) continue; + + const destVal = destination[key]; + const customVal = customizer(destVal, srcVal, key as keyof TPartial); + if (customVal !== undefined){ + destination[key] = customVal; + } else if (ng1.isArray(srcVal)) { + destination[key] = [...srcVal]; + } else if (!ng1.isObject(srcVal)) { + destination[key] = srcVal; + } else { + destination[key] = assignPartialDeep(destVal, srcVal); + } + } + return destination; +} \ No newline at end of file diff --git a/src/shared/index.ts b/src/shared/index.ts new file mode 100644 index 00000000..fb519fb6 --- /dev/null +++ b/src/shared/index.ts @@ -0,0 +1 @@ +export * from './assign-partial-deep'; \ No newline at end of file diff --git a/test/custom-typings/jasmine-custom-matchers.d.ts b/test/custom-typings/jasmine-custom-matchers.d.ts new file mode 100644 index 00000000..4ecb8b5a --- /dev/null +++ b/test/custom-typings/jasmine-custom-matchers.d.ts @@ -0,0 +1,5 @@ +declare namespace jasmine { + interface Matchers { + toEqualPlainObject: (expected: any, expectationFailureOutput?: any) => boolean; + } +} \ No newline at end of file diff --git a/test/index.js b/test/index.js index 6eff0278..14a8ad91 100644 --- a/test/index.js +++ b/test/index.js @@ -1,5 +1,7 @@ // this file is only being used by karma +import './util/jasmine-extensions'; + /* * Ok, this is kinda crazy. We can use the the context method on * require that webpack created in order to tell webpack @@ -9,7 +11,7 @@ * any file that ends with Spec.ts and get its path. By passing in true * we say do this recursively */ -var testContext = require.context('./', true, /\.spec\.ts/); +var testContext = require.context('./specs', true, /\.spec\.ts/); /* * get all the files, for each file, call the context function diff --git a/test/filtersSpec.spec.ts b/test/specs/filters.spec.ts similarity index 98% rename from test/filtersSpec.spec.ts rename to test/specs/filters.spec.ts index 388c7c90..5c248e82 100644 --- a/test/filtersSpec.spec.ts +++ b/test/specs/filters.spec.ts @@ -1,4 +1,4 @@ -import { NgTableFilterConfig, NgTableFilterConfigProvider, ngTableBrowserModule } from '../src/browser'; +import { NgTableFilterConfig, NgTableFilterConfigProvider, ngTableBrowserModule } from '../../src/browser'; import * as ng1 from 'angular'; describe('ngTableFilterConfig', () => { diff --git a/test/ngTableDefaultGetDataSpec.spec.ts b/test/specs/ngTableDefaultGetData.spec.ts similarity index 99% rename from test/ngTableDefaultGetDataSpec.spec.ts rename to test/specs/ngTableDefaultGetData.spec.ts index b11c90e2..48ebd606 100644 --- a/test/ngTableDefaultGetDataSpec.spec.ts +++ b/test/specs/ngTableDefaultGetData.spec.ts @@ -2,7 +2,7 @@ import * as ng1 from 'angular'; import { NgTableDefaultGetDataProvider, IDefaultGetData, NgTableParams, ngTableCoreModule -} from '../src/core'; +} from '../../src/core'; describe('ngTableDefaultGetData', () => { diff --git a/test/selectFilterDsSpec.spec.ts b/test/specs/selectFilterDs.spec.ts similarity index 99% rename from test/selectFilterDsSpec.spec.ts rename to test/specs/selectFilterDs.spec.ts index ea6a57d0..85583062 100644 --- a/test/selectFilterDsSpec.spec.ts +++ b/test/specs/selectFilterDs.spec.ts @@ -1,6 +1,6 @@ import { ICompileService, IScope, ITimeoutService } from 'angular'; import * as ng1 from 'angular'; -import { SelectData, ISelectOption, ngTableBrowserModule } from '../src/browser'; +import { SelectData, ISelectOption, ngTableBrowserModule } from '../../src/browser'; describe('ngTableSelectFilterDs directive', () => { diff --git a/test/specs/settings.spec.ts b/test/specs/settings.spec.ts new file mode 100644 index 00000000..8cd185cc --- /dev/null +++ b/test/specs/settings.spec.ts @@ -0,0 +1,201 @@ +import * as ng1 from 'angular'; +import * as _ from 'lodash'; +import { areFunctions, areFunctionsEqual } from '../util/jasmine-extensions'; +import { + DataSettings, FilterSettings, IGetDataFunc, IGetGroupFunc, + GroupSettings, SettingsPartial, Settings, ngTableCoreModule +} from '../../src/core'; +import { NgTableSettings } from '../../src/core/ngTableSettings' + + +describe('NgTableSettings', () => { + + let ngTableSettings: NgTableSettings + + beforeAll(() => expect(ngTableCoreModule).toBeDefined()); + + let defaultOverrides: SettingsPartial; + let standardSettings: SettingsPartial; + + beforeEach(ng1.mock.module("ngTable-core")); + + beforeEach(() => { + + jasmine.addCustomEqualityTester(areFunctions); + + defaultOverrides = {}; + + ng1.mock.module(($provide: ng1.auto.IProvideService) => { + $provide.value('ngTableDefaults', { + settings: defaultOverrides + }) + }); + + const fakeGetData = () => { }; + const fakeGetGroups = () => { }; + standardSettings = { + $loading: false, + dataset: undefined, + total: 0, + dataOptions: { + applyFilter: true, + applyPaging: true, + applySort: true + }, + debugMode: false, + defaultSort: 'desc', + counts: [10, 25, 50, 100], + getData: fakeGetData as any, + getGroups: fakeGetGroups as any, + interceptors: [], + paginationMaxBlocks: 11, + paginationMinBlocks: 5, + sortingIndicator: 'span', + filterOptions: { + filterComparator: undefined, + filterDelay: 500, + filterDelayThreshold: 10000, + filterFilterName: undefined, + filterFn: undefined, + filterLayout: 'stack' + }, + groupOptions: { + defaultSort: 'asc', + isExpanded: true + } + }; + }); + + beforeEach(inject((_ngTableSettings_: NgTableSettings) => { + ngTableSettings = _ngTableSettings_; + })); + + it('should be injectable', () => { + expect(ngTableSettings).toBeDefined(); + }); + + describe('createDefaults', () => { + + it('should return standard defaults', () => { + const actual = ngTableSettings.createDefaults(); + expect(actual).toEqualPlainObject(standardSettings); + }); + + it('should merge setting overrides with standard defaults', () => { + const expected = standardSettings; + expected.defaultSort = defaultOverrides.defaultSort = 'asc'; + expected.counts = defaultOverrides.counts = [50]; + + const actual = ngTableSettings.createDefaults(); + expect(actual).toEqualPlainObject(expected); + }); + }); + + describe('merge', () => { + + function assertShallowClonedArray(actual: any[], expected: any[]) { + expect(actual).toEqual(expected); + expect(actual).not.toBe(expected); + expect(actual[0]).toBe(expected[0]); + } + + let allSettings: Settings; + beforeEach(() => { + allSettings = new Settings(); + }); + + it('should not modify arguments supplied', () => { + const newSettings: SettingsPartial = { + filterOptions: { + filterDelay: 20 + } + }; + const originalNewSettings = { ...newSettings, filterOptions: { ... newSettings.filterOptions } }; + + const actual = ngTableSettings.merge(allSettings, newSettings); + expect(actual).not.toBe(allSettings); + expect(allSettings.filterOptions.filterDelay).not.toEqual(20); + expect(newSettings).toEqual(originalNewSettings); + }); + + it('should merge shallow clone of new filterOptions', () => { + const newSettings: SettingsPartial = { + filterOptions: {} + }; + const expected = new Settings(); + expected.filterOptions.filterDelay = newSettings.filterOptions.filterDelay = 20; + + const actual = ngTableSettings.merge(allSettings, newSettings); + expect(actual).toEqualPlainObject(expected); + }); + + it('undefined values in new settings should be ignored', () => { + const newSettings = _.mapValues(allSettings, _.constant(undefined)); + + const actual = ngTableSettings.merge(allSettings, newSettings); + expect(actual).toEqualPlainObject(allSettings); + }); + + it('undefined nested values in new settings should be ignored', () => { + const newSettings: SettingsPartial = { + filterOptions: _.mapValues(allSettings.filterOptions, _.constant(undefined)), + dataOptions: _.mapValues(allSettings.dataOptions, _.constant(undefined)), + groupOptions: _.mapValues(allSettings.groupOptions, _.constant(undefined)) + }; + + const actual = ngTableSettings.merge(allSettings, newSettings); + expect(actual).toEqualPlainObject(allSettings); + }); + + it('interceptor array should be shallow cloned', () => { + const interceptor = { response: () => { } }; + const newSettings: SettingsPartial = { + interceptors: [interceptor] + }; + + const actual = ngTableSettings.merge(allSettings, newSettings); + assertShallowClonedArray(actual.interceptors, newSettings.interceptors); + }); + + it('counts array should be shallow cloned', () => { + const newSettings: SettingsPartial = { + counts: [10, 15] + }; + + const actual = ngTableSettings.merge(allSettings, newSettings); + assertShallowClonedArray(actual.counts, newSettings.counts); + }); + + it('dataset array reference should be copied', () => { + const item = {}; + const dataset = [item]; + const newSettings: SettingsPartial = { + dataset: dataset + }; + + const actual = ngTableSettings.merge(allSettings, newSettings); + expect(actual.dataset).toBe(dataset); + expect(actual.dataset[0]).toBe(item); + }); + + it('functions references should be copied', () => { + const fakeGetData = () => { }; + const fakeGetGroups = () => { }; + const fakeComparator = () => { }; + const fakeFilterFn = () => { }; + const newSettings: SettingsPartial = { + getData: fakeGetData, + getGroups: fakeGetGroups as any, + filterOptions: { + filterComparator: fakeComparator as any, + filterFn: fakeFilterFn as any + } + }; + + const actual = ngTableSettings.merge(allSettings, newSettings); + expect(actual.getData).toBe(fakeGetData); + expect(actual.filterOptions.filterComparator).toBe(fakeComparator); + expect(actual.filterOptions.filterFn).toBe(fakeFilterFn); + }); + }) +}); \ No newline at end of file diff --git a/test/tableSpec.spec.ts b/test/specs/table.spec.ts similarity index 99% rename from test/tableSpec.spec.ts rename to test/specs/table.spec.ts index 4243edbe..17504b40 100644 --- a/test/tableSpec.spec.ts +++ b/test/specs/table.spec.ts @@ -1,8 +1,8 @@ import { IAugmentedJQuery, ICompileService, IQService, IPromise, IScope, ITimeoutService } from 'angular'; import * as ng1 from 'angular'; -import { ngTableModule } from '../index'; -import { NgTableParams, IParamValues, ISettings, ISortingValues } from '../src/core'; -import { IColumnDef, IFilterTemplateDef, IFilterTemplateDefMap, ISelectOption } from '../src/browser' +import { ngTableModule } from '../../index'; +import { NgTableParams, IParamValues, SettingsPartial, ISortingValues } from '../../src/core'; +import { IColumnDef, IFilterTemplateDef, IFilterTemplateDefMap, ISelectOption } from '../../src/browser' describe('ng-table', () => { interface IPerson { @@ -72,8 +72,8 @@ describe('ng-table', () => { scope.model = {}; })); - function createNgTableParams(initialParams?: IParamValues, settings?: ISettings): NgTableParams; - function createNgTableParams(settings?: ISettings): NgTableParams; + function createNgTableParams(initialParams?: IParamValues, settings?: SettingsPartial): NgTableParams; + function createNgTableParams(settings?: SettingsPartial): NgTableParams; function createNgTableParams(settings?: any): NgTableParams { let initialParams: IParamValues; if (arguments.length === 2) { diff --git a/test/tableDynamicSpec.spec.ts b/test/specs/tableDynamic.spec.ts similarity index 99% rename from test/tableDynamicSpec.spec.ts rename to test/specs/tableDynamic.spec.ts index e38c75ac..9cb824e6 100644 --- a/test/tableDynamicSpec.spec.ts +++ b/test/specs/tableDynamic.spec.ts @@ -1,8 +1,9 @@ import { IAugmentedJQuery, ICompileService, IQService, IScope } from 'angular'; import * as ng1 from 'angular'; -import { ngTableModule } from '../index'; -import { NgTableParams } from '../src/core'; -import { ColumnFieldContext, IColumnDef, DynamicTableColField, IDynamicTableColDef, IFilterTemplateDefMap, ISelectOption } from '../src/browser'; +import * as _ from 'lodash'; +import { ngTableModule } from '../../index'; +import { NgTableParams } from '../../src/core'; +import { ColumnFieldContext, IColumnDef, DynamicTableColField, IDynamicTableColDef, IFilterTemplateDefMap, ISelectOption } from '../../src/browser'; describe('ng-table-dynamic', () => { diff --git a/test/tableParamsSpec.spec.ts b/test/specs/tableParams.spec.ts similarity index 97% rename from test/tableParamsSpec.spec.ts rename to test/specs/tableParams.spec.ts index 88b58883..b0eff08b 100644 --- a/test/tableParamsSpec.spec.ts +++ b/test/specs/tableParams.spec.ts @@ -1,9 +1,11 @@ import { IControllerService, IQService, IScope } from 'angular'; import * as ng1 from 'angular'; +import * as _ from 'lodash'; import { - IDataRowGroup, IDefaultGetData, IDefaults, NgTableEventsChannel, IGroupingFunc, IGroupValues, InternalTableParams, - NgTableParams, IPageButton, IParamValues, ISettings, ngTableCoreModule -} from '../src/core'; + IDataRowGroup, DataSettings, IDefaultGetData, IDefaults, NgTableEventsChannel, FilterSettings, + IGroupingFunc, GroupSettings, IGroupValues, InternalTableParams, NgTableParams, IPageButton, IParamValues, SettingsPartial, + ngTableCoreModule +} from '../../src/core'; describe('NgTableParams', () => { interface IScopeWithPrivates extends IScope { @@ -33,8 +35,8 @@ describe('NgTableParams', () => { scope = $rootScope.$new(); })); - function createNgTableParams(initialParams?: IParamValues, settings?: ISettings): NgTableParams; - function createNgTableParams(settings?: ISettings): NgTableParams; + function createNgTableParams(initialParams?: IParamValues, settings?: SettingsPartial): NgTableParams; + function createNgTableParams(settings?: SettingsPartial): NgTableParams; function createNgTableParams(settings?: any): NgTableParams { let initialParams: IParamValues; if (arguments.length === 2) { @@ -305,45 +307,6 @@ describe('NgTableParams', () => { describe('settings', () => { - it('defaults', () => { - let params = new NgTableParams({}); - - const expectedSettings: ISettings = { - $loading: false, - dataset: null, - total: 0, - defaultSort: 'desc', - counts: [10, 25, 50, 100], - interceptors: [], - paginationMaxBlocks: 11, - paginationMinBlocks: 5, - sortingIndicator: 'span', - filterOptions: { - filterComparator: undefined, - filterDelay: 500, - filterDelayThreshold: 10000, - filterFilterName: undefined, - filterFn: undefined, - filterLayout: 'stack' - }, - groupOptions: { defaultSort: 'asc', isExpanded: true } - }; - expect(params.settings()).toEqual(jasmine.objectContaining(expectedSettings)); - expect(params.settings().getData).toEqual(jasmine.any(Function)); - expect(params.settings().getGroups).toEqual(jasmine.any(Function)); - - params = new NgTableParams({}, { - total: 100, - counts: [1, 2], - groupOptions: { isExpanded: false } - }); - - expectedSettings.total = 100; - expectedSettings.counts = [1, 2]; - expectedSettings.groupOptions = { defaultSort: 'asc', isExpanded: false }; - expect(params.settings()).toEqual(jasmine.objectContaining(expectedSettings)); - }); - it('changing settings().dataset should reset page to 1', () => { // given const tableParams = createNgTableParams({ count: 1, page: 2 }, { dataset: [1, 2, 3] }); @@ -2072,7 +2035,7 @@ describe('NgTableParams', () => { // then expect(actualPublisher).toBe(params); - expect(actualEventArgs).toEqual([initialDs, null]); + expect(actualEventArgs).toEqual([initialDs, undefined]); }); it('should fire when a new dataset is supplied as a settings value', () => { diff --git a/test/util/jasmine-extensions.ts b/test/util/jasmine-extensions.ts new file mode 100644 index 00000000..bcfac465 --- /dev/null +++ b/test/util/jasmine-extensions.ts @@ -0,0 +1,53 @@ +import * as ng1 from 'angular'; +import * as _ from 'lodash'; + +function asPlainObjectDeep(origianl: T) { + const removePrototype = (srcVal: any, objVal: any) => { + if (ng1.isObject(objVal) && !ng1.isArray(objVal)) { + return _.toPlainObject(objVal); + } else { + return objVal; + } + }; + return _.mergeWith(Object.create(null), origianl, removePrototype); +} + +const customMatchers = { + toEqualPlainObject: function (util: jasmine.MatchersUtil, customEqualityTesters: jasmine.CustomEqualityTester[]) { + return { + compare: function (actual: any, expected: any) { + if (actual === undefined && expected === undefined) return { pass: true }; + + if (actual == null || expected == null) return { pass: false }; + + // we need to clone to remove type information (ie prototype) from objects before comparison + return { + pass: util.equals(asPlainObjectDeep(actual), asPlainObjectDeep(expected), customEqualityTesters) + }; + } + }; + } +}; + +function areFunctionsEqual(first: any, second: any): boolean | undefined { + if (typeof first === "function" && typeof second === "function") { + return first.toString() === second.toString(); + } + return undefined; +} + +function areFunctions(first: any, second: any): boolean | undefined { + if (typeof first === "function" && typeof second === "function") { + return true; + } + return undefined; +} + +beforeAll(() => { + jasmine.addCustomEqualityTester(areFunctions); + jasmine.addMatchers(customMatchers); +}); + + + +export { areFunctions, areFunctionsEqual }; \ No newline at end of file