diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 0000000000..b512c09d47 --- /dev/null +++ b/.bazelignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index 71a350b97e..3aeb1fdc58 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ version: 2 # See https://blog.daemonl.com/2016/02/yaml.html # To validate changes, use an online parser, eg. # https://yaml-online-parser.appspot.com/ -var_1: &cache_key yarn-cache-{{ checksum "yarn.lock" }}-0.8.0 +var_1: &cache_key yarn-cache-{{ checksum "yarn.lock" }}-0.9.1 var_2: &run_in_node docker: - image: circleci/node:10.12 @@ -18,8 +18,25 @@ var_3: &set_bazel_options run: command: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc var_4: &docs_cache_key yarn-docs-cache-{{ checksum "~/docs/projects/ngrx.io/yarn.lock" }}-0.1 +var_5: &run_in_browser + docker: + - image: circleci/node:10.12-browsers jobs: + install: + <<: *run_in_node + steps: + - checkout + - restore_cache: + key: *cache_key + - run: yarn --frozen-lockfile --non-interactive + - save_cache: + key: *cache_key + paths: + - ~/.cache/yarn + - ~/.cache/Cypress + - node_modules + # Enforce some static analysis invariants. # Note that generally, these should be checked only on the delta in each change, # otherwise any change to the static analysis config requires updating all the @@ -30,20 +47,19 @@ jobs: steps: - checkout - *set_bazel_options - - restore_cache: key: *cache_key - # Enforce that BUILD files are formatted. - # Note that this uses the version of buildifier from the docker image - - # take care that you use the same version when you run - # buildifier locally on your change. - - run: yarn - - run: - 'yarn buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) || - (echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)' + # Run the Buildifier to check our Bazel rules for format issues. + - run: 'yarn bazel:format --mode=check || + (echo "BUILD files not formatted. Please run ''yarn bazel:format --mode=fix''" ; exit 1)' + + # Run the Buildifier to check our Bazel rules for lint issues. + # Note: The `--lint=warn` will auto fixe (re-write) the affected files. + - run: 'yarn bazel:format --lint=warn || + (echo "BUILD files contain unresolved lint errors. Please fix manually the remaining errors." ; exit 1)' - bazel: + test: <<: *run_in_node steps: - checkout @@ -52,42 +68,55 @@ jobs: - restore_cache: key: *cache_key - # Helpful for debugging, so you can check you have the same bazel version when you need - # to reproduce a failure. - - run: yarn - - run: yarn bazel info release - - # Install the dependencies from NPM, using the node and yarn binaries managed by Bazel - - run: yarn bazel run @nodejs//:yarn - # Build and Test - # Use bazel query so that we explicitly ask for all buildable targets to - # be built even though we run `bazel test` - # See https://github.com/bazelbuild/bazel/issues/4257 - run: yarn bazel test //... # Store artifacts from build - persist_to_workspace: root: dist paths: - bin/* - test: - docker: - - image: circleci/node:10.12-browsers + - save_cache: + key: *cache_key + paths: + - ~/.cache/yarn + - ~/.cache/Cypress + - node_modules + + schematics-core-check: + <<: *run_in_browser steps: - checkout - restore_cache: key: *cache_key - - run: yarn - run: yarn copy:schematics - run: git diff --name-only --exit-code ./modules - - run: yarn run ci - - run: yarn run example:build:prod + + example-tests: + <<: *run_in_browser + steps: + - checkout + - restore_cache: + key: *cache_key - run: yarn run example:test --watch=false - - save_cache: + + example-e2e-tests: + <<: *run_in_browser + steps: + - checkout + - restore_cache: key: *cache_key - paths: - - ~/.cache/yarn - - node_modules + - run: yarn run example:build:prod + - run: yarn run example:cypress:ci + + docs-tests: + <<: *run_in_browser + working_directory: ~/docs/projects/ngrx.io + steps: + - checkout: + path: ~/docs + - restore_cache: + key: *docs_cache_key + - run: yarn test --watch=false docs: <<: *run_in_node @@ -109,7 +138,6 @@ jobs: - save_cache: key: *docs_cache_key paths: - - ~/.cache/yarn - ~/docs/projects/ngrx.io/node_modules docs-preview: @@ -118,7 +146,7 @@ jobs: steps: - add_ssh_keys: fingerprints: - - 'c9:c2:b4:5e:13:23:b6:6d:d8:29:3e:68:c6:40:9c:ec' + - "c9:c2:b4:5e:13:23:b6:6d:d8:29:3e:68:c6:40:9c:ec" - checkout: path: ~/docs - restore_cache: @@ -132,40 +160,81 @@ jobs: echo 'export SHORT_GIT_HASH=$(git rev-parse --short $CIRCLE_SHA1)' >> $BASH_ENV echo 'export CIRCLE_PULL_REQUEST_NUMBER=$(echo "$CIRCLE_PULL_REQUEST" | cut -d"/" -f7)' >> $BASH_ENV source $BASH_ENV - - run: yarn setup - run: npm rebuild node-sass - run: yarn build-for next --progress false --base-href /pr$CIRCLE_PULL_REQUEST_NUMBER-$SHORT_GIT_HASH/ --output-path dist/ngrx.io/pr$CIRCLE_PULL_REQUEST_NUMBER-$SHORT_GIT_HASH/ && yarn copy-404-page - run: cp -rf src/extra-files/next/. dist/ngrx.io/pr$CIRCLE_PULL_REQUEST_NUMBER-$SHORT_GIT_HASH/ - run: yarn --cwd ../../ install && yarn --cwd ../../ run deploy:preview + - save_cache: + key: *docs_cache_key + paths: + - ~/docs/projects/ngrx.io/node_modules deploy: <<: *run_in_node steps: - add_ssh_keys: fingerprints: - - 'c9:c2:b4:5e:13:23:b6:6d:d8:29:3e:68:c6:40:9c:ec' + - "c9:c2:b4:5e:13:23:b6:6d:d8:29:3e:68:c6:40:9c:ec" - checkout - restore_cache: key: *cache_key - - run: yarn - attach_workspace: at: dist - run: yarn run deploy:builds + cleanup-previews: + <<: *run_in_node + steps: + - add_ssh_keys: + fingerprints: + - "c9:c2:b4:5e:13:23:b6:6d:d8:29:3e:68:c6:40:9c:ec" + - checkout + - restore_cache: + key: *cache_key + - run: yarn run cleanup:previews + workflows: version: 2 build-test-deploy: jobs: - - lint - - bazel - - test - - docs - - docs-preview + - install + - lint: + requires: + - install + - test: + requires: + - install + - example-tests: + requires: + - install + - example-e2e-tests: + requires: + - install + - docs-tests: + requires: + - install + - docs: + requires: + - install + - docs-preview: + requires: + - install + - schematics-core-check: + requires: + - install - deploy: requires: - docs + - example-tests + - example-e2e-tests + - docs-tests - test - - bazel + filters: + branches: + only: master + - cleanup-previews: + requires: + - install filters: branches: only: master diff --git a/BUILD.bazel b/BUILD.bazel index 534f36ad23..a7c39c14e2 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -5,8 +5,3 @@ exports_files([ "tsconfig.json", "LICENSE", ]) - -alias( - name = "install", - actual = "@nodejs//:yarn", -) diff --git a/CHANGELOG.md b/CHANGELOG.md index 321f2070eb..ec8ba827fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,126 +1,143 @@ - -# [7.2.0](https://github.com/ngrx/platform/compare/7.1.0...7.2.0) (2019-01-29) + +# [7.4.0](https://github.com/ngrx/platform/compare/7.3.0...7.4.0) (2019-03-29) ### Bug Fixes -* **Entity:** add schematics to bazel build ([88d0ad5](https://github.com/ngrx/platform/commit/88d0ad5)) -* **RouterStore:** add schematics to bazel build ([7465af9](https://github.com/ngrx/platform/commit/7465af9)) -* **StoreDevTools:** out of bounds when actions are filtered ([#1532](https://github.com/ngrx/platform/issues/1532)) ([d532979](https://github.com/ngrx/platform/commit/d532979)), closes [#1522](https://github.com/ngrx/platform/issues/1522) - +- **Example:** linter problems ([#1597](https://github.com/ngrx/platform/issues/1597)) ([4cfcc08](https://github.com/ngrx/platform/commit/4cfcc08)) ### Features -* **schematics:** add api success/failure effects/actions to ng generate feature ([#1530](https://github.com/ngrx/platform/issues/1530)) ([e17a787](https://github.com/ngrx/platform/commit/e17a787)) -* **schematics:** bump platformVersion to ^7.0.0 per issue [#1489](https://github.com/ngrx/platform/issues/1489) ([#1527](https://github.com/ngrx/platform/issues/1527)) ([a71aa71](https://github.com/ngrx/platform/commit/a71aa71)) +- **example-app:** add visual testing with Applitools ([#1605](https://github.com/ngrx/platform/issues/1605)) ([8856210](https://github.com/ngrx/platform/commit/8856210)) +- **schematics:** use plural for entity schematics reducer key ([#1596](https://github.com/ngrx/platform/issues/1596)) ([1e49530](https://github.com/ngrx/platform/commit/1e49530)), closes [#1412](https://github.com/ngrx/platform/issues/1412) +- **store:** add action creator functions ([#1654](https://github.com/ngrx/platform/issues/1654)) ([e7fe28b](https://github.com/ngrx/platform/commit/e7fe28b)), closes [#1480](https://github.com/ngrx/platform/issues/1480) [#1634](https://github.com/ngrx/platform/issues/1634) + +# [7.3.0](https://github.com/ngrx/platform/compare/7.2.0...7.3.0) (2019-03-29) - -# [7.1.0](https://github.com/ngrx/platform/compare/7.0.0...7.1.0) (2019-01-21) +### Bug Fixes +- **Example:** linter problems ([#1597](https://github.com/ngrx/platform/issues/1597)) ([4cfcc08](https://github.com/ngrx/platform/commit/4cfcc08)) +- **schematics:** type actions and avoid endless loop in effect schematic ([#1576](https://github.com/ngrx/platform/issues/1576)) ([5fbcb3c](https://github.com/ngrx/platform/commit/5fbcb3c)), closes [#1573](https://github.com/ngrx/platform/issues/1573) +- **store:** deprecate signature for selector with only a projector ([#1580](https://github.com/ngrx/platform/issues/1580)) ([e86c5f6](https://github.com/ngrx/platform/commit/e86c5f6)) -### Bug Fixes +### Features + +- **example-app:** add visual testing with Applitools ([#1605](https://github.com/ngrx/platform/issues/1605)) ([8856210](https://github.com/ngrx/platform/commit/8856210)) +- **schematics:** Add ng-add support with prompt for making our schematics default ([#1552](https://github.com/ngrx/platform/issues/1552)) ([01ff157](https://github.com/ngrx/platform/commit/01ff157)) +- **schematics:** use plural for entity schematics reducer key ([#1596](https://github.com/ngrx/platform/issues/1596)) ([1e49530](https://github.com/ngrx/platform/commit/1e49530)), closes [#1412](https://github.com/ngrx/platform/issues/1412) +- **store:** add action creator functions ([#1654](https://github.com/ngrx/platform/issues/1654)) ([e7fe28b](https://github.com/ngrx/platform/commit/e7fe28b)), closes [#1480](https://github.com/ngrx/platform/issues/1480) [#1634](https://github.com/ngrx/platform/issues/1634) + + -* **store:** call metareducer with the user's config initial state ([#1498](https://github.com/ngrx/platform/issues/1498)) ([2aabe0f](https://github.com/ngrx/platform/commit/2aabe0f)), closes [#1464](https://github.com/ngrx/platform/issues/1464) -* **store:** don't call the projector function if there are no selectors and props ([#1515](https://github.com/ngrx/platform/issues/1515)) ([e0ad3c3](https://github.com/ngrx/platform/commit/e0ad3c3)), closes [#1501](https://github.com/ngrx/platform/issues/1501) +# [7.2.0](https://github.com/ngrx/platform/compare/7.1.0...7.2.0) (2019-01-29) +### Bug Fixes + +- **Entity:** add schematics to bazel build ([88d0ad5](https://github.com/ngrx/platform/commit/88d0ad5)) +- **RouterStore:** add schematics to bazel build ([7465af9](https://github.com/ngrx/platform/commit/7465af9)) +- **StoreDevTools:** out of bounds when actions are filtered ([#1532](https://github.com/ngrx/platform/issues/1532)) ([d532979](https://github.com/ngrx/platform/commit/d532979)), closes [#1522](https://github.com/ngrx/platform/issues/1522) ### Features -* **example:** make the example app more user friendly ([#1508](https://github.com/ngrx/platform/issues/1508)) ([ac4fb88](https://github.com/ngrx/platform/commit/ac4fb88)) -* **router-store:** add routerState to action payload ([#1511](https://github.com/ngrx/platform/issues/1511)) ([283424f](https://github.com/ngrx/platform/commit/283424f)) -* **schematics:** add ng add support for [@ngrx](https://github.com/ngrx)/entity ([#1503](https://github.com/ngrx/platform/issues/1503)) ([da1c955](https://github.com/ngrx/platform/commit/da1c955)) -* **schematics:** implement router store ng-add ([#1487](https://github.com/ngrx/platform/issues/1487)) ([9da4aac](https://github.com/ngrx/platform/commit/9da4aac)), closes [#1479](https://github.com/ngrx/platform/issues/1479) -* **store:** support store config factory for feature ([#1445](https://github.com/ngrx/platform/issues/1445)) ([6aa5645](https://github.com/ngrx/platform/commit/6aa5645)), closes [#1414](https://github.com/ngrx/platform/issues/1414) +- **schematics:** add api success/failure effects/actions to ng generate feature ([#1530](https://github.com/ngrx/platform/issues/1530)) ([e17a787](https://github.com/ngrx/platform/commit/e17a787)) +- **schematics:** bump platformVersion to ^7.0.0 per issue [#1489](https://github.com/ngrx/platform/issues/1489) ([#1527](https://github.com/ngrx/platform/issues/1527)) ([a71aa71](https://github.com/ngrx/platform/commit/a71aa71)) + +# [7.1.0](https://github.com/ngrx/platform/compare/7.0.0...7.1.0) (2019-01-21) - -# [7.0.0](https://github.com/ngrx/platform/compare/7.0.0-beta.1...7.0.0) (2018-12-20) +### Bug Fixes +- **store:** call metareducer with the user's config initial state ([#1498](https://github.com/ngrx/platform/issues/1498)) ([2aabe0f](https://github.com/ngrx/platform/commit/2aabe0f)), closes [#1464](https://github.com/ngrx/platform/issues/1464) +- **store:** don't call the projector function if there are no selectors and props ([#1515](https://github.com/ngrx/platform/issues/1515)) ([e0ad3c3](https://github.com/ngrx/platform/commit/e0ad3c3)), closes [#1501](https://github.com/ngrx/platform/issues/1501) ### Features -* **Effects:** add OnInitEffects interface to dispatch an action on initialization ([e921cd9](https://github.com/ngrx/platform/commit/e921cd9)) -* **RouterStore:** make the router store key selector generic ([a30a514](https://github.com/ngrx/platform/commit/a30a514)), closes [#1457](https://github.com/ngrx/platform/issues/1457) -* **schematics:** add project flag support to specify apps or libs ([#1477](https://github.com/ngrx/platform/issues/1477)) ([af39fd2](https://github.com/ngrx/platform/commit/af39fd2)), closes [#1455](https://github.com/ngrx/platform/issues/1455) +- **example:** make the example app more user friendly ([#1508](https://github.com/ngrx/platform/issues/1508)) ([ac4fb88](https://github.com/ngrx/platform/commit/ac4fb88)) +- **router-store:** add routerState to action payload ([#1511](https://github.com/ngrx/platform/issues/1511)) ([283424f](https://github.com/ngrx/platform/commit/283424f)) +- **schematics:** add ng add support for [@ngrx](https://github.com/ngrx)/entity ([#1503](https://github.com/ngrx/platform/issues/1503)) ([da1c955](https://github.com/ngrx/platform/commit/da1c955)) +- **schematics:** implement router store ng-add ([#1487](https://github.com/ngrx/platform/issues/1487)) ([9da4aac](https://github.com/ngrx/platform/commit/9da4aac)), closes [#1479](https://github.com/ngrx/platform/issues/1479) +- **store:** support store config factory for feature ([#1445](https://github.com/ngrx/platform/issues/1445)) ([6aa5645](https://github.com/ngrx/platform/commit/6aa5645)), closes [#1414](https://github.com/ngrx/platform/issues/1414) + -### Reverts +# [7.0.0](https://github.com/ngrx/platform/compare/7.0.0-beta.1...7.0.0) (2018-12-20) -* **Effects:** dispatch init feature effects action on init [#1305](https://github.com/ngrx/platform/issues/1305) ([e9cc9ae](https://github.com/ngrx/platform/commit/e9cc9ae)) +### Features +- **Effects:** add OnInitEffects interface to dispatch an action on initialization ([e921cd9](https://github.com/ngrx/platform/commit/e921cd9)) +- **RouterStore:** make the router store key selector generic ([a30a514](https://github.com/ngrx/platform/commit/a30a514)), closes [#1457](https://github.com/ngrx/platform/issues/1457) +- **schematics:** add project flag support to specify apps or libs ([#1477](https://github.com/ngrx/platform/issues/1477)) ([af39fd2](https://github.com/ngrx/platform/commit/af39fd2)), closes [#1455](https://github.com/ngrx/platform/issues/1455) + +### Reverts +- **Effects:** dispatch init feature effects action on init [#1305](https://github.com/ngrx/platform/issues/1305) ([e9cc9ae](https://github.com/ngrx/platform/commit/e9cc9ae)) -# [7.0.0-beta.1](https://github.com/ngrx/platform/compare/7.0.0-beta.0...7.0.0-beta.1) (2018-12-04) +# [7.0.0-beta.1](https://github.com/ngrx/platform/compare/7.0.0-beta.0...7.0.0-beta.1) (2018-12-04) ### Features -* **effects:** add OnIdentifyEffects interface to register multiple effect instances ([#1448](https://github.com/ngrx/platform/issues/1448)) ([b553ce7](https://github.com/ngrx/platform/commit/b553ce7)) -* **store-devtools:** catch and log redux devtools errors ([#1450](https://github.com/ngrx/platform/issues/1450)) ([4ed16cd](https://github.com/ngrx/platform/commit/4ed16cd)) - - +- **effects:** add OnIdentifyEffects interface to register multiple effect instances ([#1448](https://github.com/ngrx/platform/issues/1448)) ([b553ce7](https://github.com/ngrx/platform/commit/b553ce7)) +- **store-devtools:** catch and log redux devtools errors ([#1450](https://github.com/ngrx/platform/issues/1450)) ([4ed16cd](https://github.com/ngrx/platform/commit/4ed16cd)) -# [7.0.0-beta.0](https://github.com/ngrx/platform/compare/6.1.0...7.0.0-beta.0) (2018-11-03) +# [7.0.0-beta.0](https://github.com/ngrx/platform/compare/6.1.0...7.0.0-beta.0) (2018-11-03) ### Bug Fixes -* **docs-infra:** ARIA roles used must conform to valid values ([8a4b2de](https://github.com/ngrx/platform/commit/8a4b2de)) -* **docs-infra:** elements must have sufficient color contrast ([c5dfaef](https://github.com/ngrx/platform/commit/c5dfaef)) -* **docs-infra:** html element must have a lang attribute ([32256de](https://github.com/ngrx/platform/commit/32256de)) -* **docs-infra:** Images must have alternate text ([8241f99](https://github.com/ngrx/platform/commit/8241f99)) -* **docs-infra:** notification must have sufficient color contrast ([ac24cc3](https://github.com/ngrx/platform/commit/ac24cc3)) -* **example:** close side nav when escape key is pressed ([#1244](https://github.com/ngrx/platform/issues/1244)) ([b3fc5dd](https://github.com/ngrx/platform/commit/b3fc5dd)), closes [#1172](https://github.com/ngrx/platform/issues/1172) -* **router-store:** Added new imports to index.ts, codestyle ([293f960](https://github.com/ngrx/platform/commit/293f960)) -* **router-store:** allow compilation with strictFunctionTypes ([#1385](https://github.com/ngrx/platform/issues/1385)) ([0e38673](https://github.com/ngrx/platform/commit/0e38673)), closes [#1344](https://github.com/ngrx/platform/issues/1344) -* **router-store:** Avoiding [@ngrx](https://github.com/ngrx)/effects dependency inside tests ([11d3b9f](https://github.com/ngrx/platform/commit/11d3b9f)) -* **router-store:** handle internal navigation error, dispatch cancel/error action with previous state ([#1294](https://github.com/ngrx/platform/issues/1294)) ([5300e7d](https://github.com/ngrx/platform/commit/5300e7d)) -* **schematics:** correct spec description in reducer template ([#1269](https://github.com/ngrx/platform/issues/1269)) ([b7ab4f8](https://github.com/ngrx/platform/commit/b7ab4f8)) -* **schematics:** fix effects code generated by schematics:feature ([#1357](https://github.com/ngrx/platform/issues/1357)) ([458e2b4](https://github.com/ngrx/platform/commit/458e2b4)) -* **store:** add typing to allow props with store.select ([#1387](https://github.com/ngrx/platform/issues/1387)) ([a9e7cbd](https://github.com/ngrx/platform/commit/a9e7cbd)) -* **store:** memoize selector arguments ([#1393](https://github.com/ngrx/platform/issues/1393)) ([7cc9702](https://github.com/ngrx/platform/commit/7cc9702)), closes [#1389](https://github.com/ngrx/platform/issues/1389) -* **store:** remove deprecation from Store.select ([#1382](https://github.com/ngrx/platform/issues/1382)) ([626784e](https://github.com/ngrx/platform/commit/626784e)) - +- **docs-infra:** ARIA roles used must conform to valid values ([8a4b2de](https://github.com/ngrx/platform/commit/8a4b2de)) +- **docs-infra:** elements must have sufficient color contrast ([c5dfaef](https://github.com/ngrx/platform/commit/c5dfaef)) +- **docs-infra:** html element must have a lang attribute ([32256de](https://github.com/ngrx/platform/commit/32256de)) +- **docs-infra:** Images must have alternate text ([8241f99](https://github.com/ngrx/platform/commit/8241f99)) +- **docs-infra:** notification must have sufficient color contrast ([ac24cc3](https://github.com/ngrx/platform/commit/ac24cc3)) +- **example:** close side nav when escape key is pressed ([#1244](https://github.com/ngrx/platform/issues/1244)) ([b3fc5dd](https://github.com/ngrx/platform/commit/b3fc5dd)), closes [#1172](https://github.com/ngrx/platform/issues/1172) +- **router-store:** Added new imports to index.ts, codestyle ([293f960](https://github.com/ngrx/platform/commit/293f960)) +- **router-store:** allow compilation with strictFunctionTypes ([#1385](https://github.com/ngrx/platform/issues/1385)) ([0e38673](https://github.com/ngrx/platform/commit/0e38673)), closes [#1344](https://github.com/ngrx/platform/issues/1344) +- **router-store:** Avoiding [@ngrx](https://github.com/ngrx)/effects dependency inside tests ([11d3b9f](https://github.com/ngrx/platform/commit/11d3b9f)) +- **router-store:** handle internal navigation error, dispatch cancel/error action with previous state ([#1294](https://github.com/ngrx/platform/issues/1294)) ([5300e7d](https://github.com/ngrx/platform/commit/5300e7d)) +- **schematics:** correct spec description in reducer template ([#1269](https://github.com/ngrx/platform/issues/1269)) ([b7ab4f8](https://github.com/ngrx/platform/commit/b7ab4f8)) +- **schematics:** fix effects code generated by schematics:feature ([#1357](https://github.com/ngrx/platform/issues/1357)) ([458e2b4](https://github.com/ngrx/platform/commit/458e2b4)) +- **store:** add typing to allow props with store.select ([#1387](https://github.com/ngrx/platform/issues/1387)) ([a9e7cbd](https://github.com/ngrx/platform/commit/a9e7cbd)) +- **store:** memoize selector arguments ([#1393](https://github.com/ngrx/platform/issues/1393)) ([7cc9702](https://github.com/ngrx/platform/commit/7cc9702)), closes [#1389](https://github.com/ngrx/platform/issues/1389) +- **store:** remove deprecation from Store.select ([#1382](https://github.com/ngrx/platform/issues/1382)) ([626784e](https://github.com/ngrx/platform/commit/626784e)) ### Code Refactoring -* **routerstore:** change default state key to router ([#1258](https://github.com/ngrx/platform/issues/1258)) ([e8173d9](https://github.com/ngrx/platform/commit/e8173d9)) -* **RouterStore:** normalize actions ([#1302](https://github.com/ngrx/platform/issues/1302)) ([466e2cd](https://github.com/ngrx/platform/commit/466e2cd)) - +- **routerstore:** change default state key to router ([#1258](https://github.com/ngrx/platform/issues/1258)) ([e8173d9](https://github.com/ngrx/platform/commit/e8173d9)) +- **RouterStore:** normalize actions ([#1302](https://github.com/ngrx/platform/issues/1302)) ([466e2cd](https://github.com/ngrx/platform/commit/466e2cd)) ### Features -* **effects:** add smarter type inference for ofType operator. ([#1183](https://github.com/ngrx/platform/issues/1183)) ([8d56a6f](https://github.com/ngrx/platform/commit/8d56a6f)) -* **effects:** add support for effects of different instances of same class ([#1249](https://github.com/ngrx/platform/issues/1249)) ([518e561](https://github.com/ngrx/platform/commit/518e561)), closes [#1246](https://github.com/ngrx/platform/issues/1246) -* **effects:** dispatch feature effects action on init ([#1305](https://github.com/ngrx/platform/issues/1305)) ([15a4b58](https://github.com/ngrx/platform/commit/15a4b58)), closes [#683](https://github.com/ngrx/platform/issues/683) -* **entity:** add support for predicate to removeMany ([#900](https://github.com/ngrx/platform/issues/900)) ([d7daa2f](https://github.com/ngrx/platform/commit/d7daa2f)) -* **entity:** add support for predicate to updateMany ([#907](https://github.com/ngrx/platform/issues/907)) ([4e4c50f](https://github.com/ngrx/platform/commit/4e4c50f)) -* **example:** add logout confirmation ([#1287](https://github.com/ngrx/platform/issues/1287)) ([ba8d300](https://github.com/ngrx/platform/commit/ba8d300)), closes [#1271](https://github.com/ngrx/platform/issues/1271) -* **router-store:** Add custom serializer to config object ([5c814a9](https://github.com/ngrx/platform/commit/5c814a9)), closes [#1262](https://github.com/ngrx/platform/issues/1262) -* **router-store:** Add support for serializers with injected values ([959cfac](https://github.com/ngrx/platform/commit/959cfac)) -* **router-store:** config option to dispatch ROUTER_NAVIGATION later ([fe71ffb](https://github.com/ngrx/platform/commit/fe71ffb)), closes [#1263](https://github.com/ngrx/platform/issues/1263) -* **router-store:** New router Actions ROUTER_REQUEST and ROUTER_NAVIGATED ([9f731c3](https://github.com/ngrx/platform/commit/9f731c3)), closes [#1010](https://github.com/ngrx/platform/issues/1010) [#1263](https://github.com/ngrx/platform/issues/1263) -* **router-store:** serialize routeConfig inside the default serializer ([#1384](https://github.com/ngrx/platform/issues/1384)) ([18a16d4](https://github.com/ngrx/platform/commit/18a16d4)) -* **router-store:** update stateKey definition to take a string or selector ([4ad9a94](https://github.com/ngrx/platform/commit/4ad9a94)), closes [#1300](https://github.com/ngrx/platform/issues/1300) -* **store:** add testing package ([#1027](https://github.com/ngrx/platform/issues/1027)) ([ab56aac](https://github.com/ngrx/platform/commit/ab56aac)), closes [#915](https://github.com/ngrx/platform/issues/915) -* **store:** dispatch one update action when features are added or removed ([#1240](https://github.com/ngrx/platform/issues/1240)) ([0b90f91](https://github.com/ngrx/platform/commit/0b90f91)) -* **Store:** export SelectorWithProps and MemoizedSelectorWithProps ([#1341](https://github.com/ngrx/platform/issues/1341)) ([df8fc60](https://github.com/ngrx/platform/commit/df8fc60)) -* **store-devtools:** add support for persist, lock, pause ([#955](https://github.com/ngrx/platform/issues/955)) ([93fcf56](https://github.com/ngrx/platform/commit/93fcf56)), closes [#853](https://github.com/ngrx/platform/issues/853) [#919](https://github.com/ngrx/platform/issues/919) -* **store-devtools:** use different action when recomputing state history ([#1353](https://github.com/ngrx/platform/issues/1353)) ([1448a0e](https://github.com/ngrx/platform/commit/1448a0e)), closes [#1255](https://github.com/ngrx/platform/issues/1255) -* **StoreDevtools:** implement actionsBlacklist/Whitelist & predicate ([#970](https://github.com/ngrx/platform/issues/970)) ([7ee46d2](https://github.com/ngrx/platform/commit/7ee46d2)), closes [#938](https://github.com/ngrx/platform/issues/938) -* update angular dependencies to V7 ([e6048bd](https://github.com/ngrx/platform/commit/e6048bd)), closes [#1340](https://github.com/ngrx/platform/issues/1340) - +- **effects:** add smarter type inference for ofType operator. ([#1183](https://github.com/ngrx/platform/issues/1183)) ([8d56a6f](https://github.com/ngrx/platform/commit/8d56a6f)) +- **effects:** add support for effects of different instances of same class ([#1249](https://github.com/ngrx/platform/issues/1249)) ([518e561](https://github.com/ngrx/platform/commit/518e561)), closes [#1246](https://github.com/ngrx/platform/issues/1246) +- **effects:** dispatch feature effects action on init ([#1305](https://github.com/ngrx/platform/issues/1305)) ([15a4b58](https://github.com/ngrx/platform/commit/15a4b58)), closes [#683](https://github.com/ngrx/platform/issues/683) +- **entity:** add support for predicate to removeMany ([#900](https://github.com/ngrx/platform/issues/900)) ([d7daa2f](https://github.com/ngrx/platform/commit/d7daa2f)) +- **entity:** add support for predicate to updateMany ([#907](https://github.com/ngrx/platform/issues/907)) ([4e4c50f](https://github.com/ngrx/platform/commit/4e4c50f)) +- **example:** add logout confirmation ([#1287](https://github.com/ngrx/platform/issues/1287)) ([ba8d300](https://github.com/ngrx/platform/commit/ba8d300)), closes [#1271](https://github.com/ngrx/platform/issues/1271) +- **router-store:** Add custom serializer to config object ([5c814a9](https://github.com/ngrx/platform/commit/5c814a9)), closes [#1262](https://github.com/ngrx/platform/issues/1262) +- **router-store:** Add support for serializers with injected values ([959cfac](https://github.com/ngrx/platform/commit/959cfac)) +- **router-store:** config option to dispatch ROUTER_NAVIGATION later ([fe71ffb](https://github.com/ngrx/platform/commit/fe71ffb)), closes [#1263](https://github.com/ngrx/platform/issues/1263) +- **router-store:** New router Actions ROUTER_REQUEST and ROUTER_NAVIGATED ([9f731c3](https://github.com/ngrx/platform/commit/9f731c3)), closes [#1010](https://github.com/ngrx/platform/issues/1010) [#1263](https://github.com/ngrx/platform/issues/1263) +- **router-store:** serialize routeConfig inside the default serializer ([#1384](https://github.com/ngrx/platform/issues/1384)) ([18a16d4](https://github.com/ngrx/platform/commit/18a16d4)) +- **router-store:** update stateKey definition to take a string or selector ([4ad9a94](https://github.com/ngrx/platform/commit/4ad9a94)), closes [#1300](https://github.com/ngrx/platform/issues/1300) +- **store:** add testing package ([#1027](https://github.com/ngrx/platform/issues/1027)) ([ab56aac](https://github.com/ngrx/platform/commit/ab56aac)), closes [#915](https://github.com/ngrx/platform/issues/915) +- **store:** dispatch one update action when features are added or removed ([#1240](https://github.com/ngrx/platform/issues/1240)) ([0b90f91](https://github.com/ngrx/platform/commit/0b90f91)) +- **Store:** export SelectorWithProps and MemoizedSelectorWithProps ([#1341](https://github.com/ngrx/platform/issues/1341)) ([df8fc60](https://github.com/ngrx/platform/commit/df8fc60)) +- **store-devtools:** add support for persist, lock, pause ([#955](https://github.com/ngrx/platform/issues/955)) ([93fcf56](https://github.com/ngrx/platform/commit/93fcf56)), closes [#853](https://github.com/ngrx/platform/issues/853) [#919](https://github.com/ngrx/platform/issues/919) +- **store-devtools:** use different action when recomputing state history ([#1353](https://github.com/ngrx/platform/issues/1353)) ([1448a0e](https://github.com/ngrx/platform/commit/1448a0e)), closes [#1255](https://github.com/ngrx/platform/issues/1255) +- **StoreDevtools:** implement actionsBlacklist/Whitelist & predicate ([#970](https://github.com/ngrx/platform/issues/970)) ([7ee46d2](https://github.com/ngrx/platform/commit/7ee46d2)), closes [#938](https://github.com/ngrx/platform/issues/938) +- update angular dependencies to V7 ([e6048bd](https://github.com/ngrx/platform/commit/e6048bd)), closes [#1340](https://github.com/ngrx/platform/issues/1340) ### BREAKING CHANGES -* **router-store:** The default router serializer now returns a `null` value for -`routeConfig` when `routeConfig` doesn't exist on the -`ActivatedRouteSnapshot` instead of an empty object. +- **router-store:** The default router serializer now returns a `null` value for + `routeConfig` when `routeConfig` doesn't exist on the + `ActivatedRouteSnapshot` instead of an empty object. BEFORE: @@ -137,10 +154,12 @@ AFTER: "routeConfig": null } ``` -* **effects:** Removes .ofType method on Actions. Instead use the provided 'ofType' -rxjs operator. + +- **effects:** Removes .ofType method on Actions. Instead use the provided 'ofType' + rxjs operator. BEFORE: + ``` this.actions.ofType('INCREMENT') ``` @@ -152,9 +171,11 @@ import { ofType } from '@ngrx/store'; ... this.action.pipe(ofType('INCREMENT')) ``` -* **RouterStore:** Normalize router store actions to be consistent with the other modules + +- **RouterStore:** Normalize router store actions to be consistent with the other modules BEFORE: + - ROUTER_REQUEST - ROUTER_NAVIGATION - ROUTER_CANCEL @@ -162,148 +183,139 @@ BEFORE: - ROUTER_NAVIGATED AFTER + - @ngrx/router-store/request - @ngrx/router-store/navigation - @ngrx/router-store/cancel - @ngrx/router-store/error - @ngrx/router-store/navigated + * **router-store:** StoreRouterConfigFunction is removed. It is no longer possible to pass a function returning a StoreRouterConfig to StoreRouterConnectingModule.forRoot If you still need this, pass a provider like this: { - provide: ROUTER_CONFIG, - useFactory: _createRouterConfig // you function +provide: ROUTER_CONFIG, +useFactory: \_createRouterConfig // you function } -* **routerstore:** The default state key is changed from routerReducer to router -* **store:** BEFORE: + +- **routerstore:** The default state key is changed from routerReducer to router +- **store:** BEFORE: + ```ts {type: '@ngrx/store/update-reducers', feature: 'feature1'} {type: '@ngrx/store/update-reducers', feature: 'feature2'} ``` AFTER: + ```ts {type: '@ngrx/store/update-reducers', features: ['feature1', 'feature2']} ``` - - -# [6.1.0](https://github.com/ngrx/platform/compare/6.0.1...6.1.0) (2018-08-02) +# [6.1.0](https://github.com/ngrx/platform/compare/6.0.1...6.1.0) (2018-08-02) ### Bug Fixes -* **effects:** Add deprecation notice for ofType instance operator ([830c8fa](https://github.com/ngrx/platform/commit/830c8fa)) -* **Effects:** Added defaults for ng-add schematic ([9d36016](https://github.com/ngrx/platform/commit/9d36016)) -* **example:** adjust styles to display spinner correctly ([#1203](https://github.com/ngrx/platform/issues/1203)) ([4a0b580](https://github.com/ngrx/platform/commit/4a0b580)) -* **example:** remove custom router state serializer ([#1129](https://github.com/ngrx/platform/issues/1129)) ([389cd78](https://github.com/ngrx/platform/commit/389cd78)) -* **schematics:** correct a type of action class generated ([#1140](https://github.com/ngrx/platform/issues/1140)) ([bbb7e8c](https://github.com/ngrx/platform/commit/bbb7e8c)) -* **schematics:** exclude environment imports for libraries ([#1213](https://github.com/ngrx/platform/issues/1213)) ([541de02](https://github.com/ngrx/platform/commit/541de02)), closes [#1205](https://github.com/ngrx/platform/issues/1205) [#1197](https://github.com/ngrx/platform/issues/1197) -* **schematics:** Remove peer dependencies on Angular DevKit ([#1222](https://github.com/ngrx/platform/issues/1222)) ([fd3da16](https://github.com/ngrx/platform/commit/fd3da16)), closes [#1206](https://github.com/ngrx/platform/issues/1206) -* **Schematics:** correct resolution of environments path for module ([#1094](https://github.com/ngrx/platform/issues/1094)) ([d24ed10](https://github.com/ngrx/platform/commit/d24ed10)), closes [#1090](https://github.com/ngrx/platform/issues/1090) -* **store:** Add deprecation notice for select instance operator ([232ca7a](https://github.com/ngrx/platform/commit/232ca7a)) -* **store:** Compare results in addition to arguments change in memoizer ([#1175](https://github.com/ngrx/platform/issues/1175)) ([99e1313](https://github.com/ngrx/platform/commit/99e1313)) -* **Store:** bootstrap store with partial initial state ([#1163](https://github.com/ngrx/platform/issues/1163)) ([11bd465](https://github.com/ngrx/platform/commit/11bd465)), closes [#906](https://github.com/ngrx/platform/issues/906) [#909](https://github.com/ngrx/platform/issues/909) -* **Store:** Fix import bug with ng-add and added defaults ([ff7dc72](https://github.com/ngrx/platform/commit/ff7dc72)) - +- **effects:** Add deprecation notice for ofType instance operator ([830c8fa](https://github.com/ngrx/platform/commit/830c8fa)) +- **Effects:** Added defaults for ng-add schematic ([9d36016](https://github.com/ngrx/platform/commit/9d36016)) +- **example:** adjust styles to display spinner correctly ([#1203](https://github.com/ngrx/platform/issues/1203)) ([4a0b580](https://github.com/ngrx/platform/commit/4a0b580)) +- **example:** remove custom router state serializer ([#1129](https://github.com/ngrx/platform/issues/1129)) ([389cd78](https://github.com/ngrx/platform/commit/389cd78)) +- **schematics:** correct a type of action class generated ([#1140](https://github.com/ngrx/platform/issues/1140)) ([bbb7e8c](https://github.com/ngrx/platform/commit/bbb7e8c)) +- **schematics:** exclude environment imports for libraries ([#1213](https://github.com/ngrx/platform/issues/1213)) ([541de02](https://github.com/ngrx/platform/commit/541de02)), closes [#1205](https://github.com/ngrx/platform/issues/1205) [#1197](https://github.com/ngrx/platform/issues/1197) +- **schematics:** Remove peer dependencies on Angular DevKit ([#1222](https://github.com/ngrx/platform/issues/1222)) ([fd3da16](https://github.com/ngrx/platform/commit/fd3da16)), closes [#1206](https://github.com/ngrx/platform/issues/1206) +- **Schematics:** correct resolution of environments path for module ([#1094](https://github.com/ngrx/platform/issues/1094)) ([d24ed10](https://github.com/ngrx/platform/commit/d24ed10)), closes [#1090](https://github.com/ngrx/platform/issues/1090) +- **store:** Add deprecation notice for select instance operator ([232ca7a](https://github.com/ngrx/platform/commit/232ca7a)) +- **store:** Compare results in addition to arguments change in memoizer ([#1175](https://github.com/ngrx/platform/issues/1175)) ([99e1313](https://github.com/ngrx/platform/commit/99e1313)) +- **Store:** bootstrap store with partial initial state ([#1163](https://github.com/ngrx/platform/issues/1163)) ([11bd465](https://github.com/ngrx/platform/commit/11bd465)), closes [#906](https://github.com/ngrx/platform/issues/906) [#909](https://github.com/ngrx/platform/issues/909) +- **Store:** Fix import bug with ng-add and added defaults ([ff7dc72](https://github.com/ngrx/platform/commit/ff7dc72)) ### Features -* **effects:** stringify action when reporting as invalid ([#1219](https://github.com/ngrx/platform/issues/1219)) ([73d32eb](https://github.com/ngrx/platform/commit/73d32eb)) -* **entity:** log a warning message when selectId returns undefined in dev mode ([#1169](https://github.com/ngrx/platform/issues/1169)) ([8f05f1f](https://github.com/ngrx/platform/commit/8f05f1f)), closes [#1133](https://github.com/ngrx/platform/issues/1133) -* **Entity:** expose Dictionary as part of the public API ([#1118](https://github.com/ngrx/platform/issues/1118)) ([2a267b6](https://github.com/ngrx/platform/commit/2a267b6)), closes [#865](https://github.com/ngrx/platform/issues/865) -* **schematics:** display provided path when displaying an error ([#1208](https://github.com/ngrx/platform/issues/1208)) ([91cc6ed](https://github.com/ngrx/platform/commit/91cc6ed)), closes [#1200](https://github.com/ngrx/platform/issues/1200) -* **schematics:** use ofType operator function instead of Actions#ofType ([#1154](https://github.com/ngrx/platform/issues/1154)) ([cb58ff1](https://github.com/ngrx/platform/commit/cb58ff1)) -* **store:** add an overload to createFeatureSelector to provide better type checking ([#1171](https://github.com/ngrx/platform/issues/1171)) ([03db76f](https://github.com/ngrx/platform/commit/03db76f)), closes [#1136](https://github.com/ngrx/platform/issues/1136) -* **store:** provide props to createSelector projector function ([#1210](https://github.com/ngrx/platform/issues/1210)) ([b1f9b34](https://github.com/ngrx/platform/commit/b1f9b34)) -* **Store:** createSelector allow props in selector ([53832a1](https://github.com/ngrx/platform/commit/53832a1)) -* **Store:** createSelector with only a props selector ([35a4848](https://github.com/ngrx/platform/commit/35a4848)) -* **StoreDevtools:** Add ng-add support ([be28d8d](https://github.com/ngrx/platform/commit/be28d8d)) -* **StoreDevtools:** Allow custom serializer options ([#1121](https://github.com/ngrx/platform/issues/1121)) ([55a0488](https://github.com/ngrx/platform/commit/55a0488)) - +- **effects:** stringify action when reporting as invalid ([#1219](https://github.com/ngrx/platform/issues/1219)) ([73d32eb](https://github.com/ngrx/platform/commit/73d32eb)) +- **entity:** log a warning message when selectId returns undefined in dev mode ([#1169](https://github.com/ngrx/platform/issues/1169)) ([8f05f1f](https://github.com/ngrx/platform/commit/8f05f1f)), closes [#1133](https://github.com/ngrx/platform/issues/1133) +- **Entity:** expose Dictionary as part of the public API ([#1118](https://github.com/ngrx/platform/issues/1118)) ([2a267b6](https://github.com/ngrx/platform/commit/2a267b6)), closes [#865](https://github.com/ngrx/platform/issues/865) +- **schematics:** display provided path when displaying an error ([#1208](https://github.com/ngrx/platform/issues/1208)) ([91cc6ed](https://github.com/ngrx/platform/commit/91cc6ed)), closes [#1200](https://github.com/ngrx/platform/issues/1200) +- **schematics:** use ofType operator function instead of Actions#ofType ([#1154](https://github.com/ngrx/platform/issues/1154)) ([cb58ff1](https://github.com/ngrx/platform/commit/cb58ff1)) +- **store:** add an overload to createFeatureSelector to provide better type checking ([#1171](https://github.com/ngrx/platform/issues/1171)) ([03db76f](https://github.com/ngrx/platform/commit/03db76f)), closes [#1136](https://github.com/ngrx/platform/issues/1136) +- **store:** provide props to createSelector projector function ([#1210](https://github.com/ngrx/platform/issues/1210)) ([b1f9b34](https://github.com/ngrx/platform/commit/b1f9b34)) +- **Store:** createSelector allow props in selector ([53832a1](https://github.com/ngrx/platform/commit/53832a1)) +- **Store:** createSelector with only a props selector ([35a4848](https://github.com/ngrx/platform/commit/35a4848)) +- **StoreDevtools:** Add ng-add support ([be28d8d](https://github.com/ngrx/platform/commit/be28d8d)) +- **StoreDevtools:** Allow custom serializer options ([#1121](https://github.com/ngrx/platform/issues/1121)) ([55a0488](https://github.com/ngrx/platform/commit/55a0488)) ### Performance Improvements -* **Effects:** remove path filters in ng-add ([5318913](https://github.com/ngrx/platform/commit/5318913)) -* **Schematics:** remove path filters in effects schematics ([6d3f5a1](https://github.com/ngrx/platform/commit/6d3f5a1)) -* **Schematics:** remove path filters in reducer schematics ([055f6ef](https://github.com/ngrx/platform/commit/055f6ef)) -* **Schematics:** remove path filters in store schematics ([762cf2e](https://github.com/ngrx/platform/commit/762cf2e)) -* **Store:** remove path filters in ng-add ([ec6adb5](https://github.com/ngrx/platform/commit/ec6adb5)) -* **StoreDevtools:** remove path filters in ng-add ([3ba463f](https://github.com/ngrx/platform/commit/3ba463f)) - - +- **Effects:** remove path filters in ng-add ([5318913](https://github.com/ngrx/platform/commit/5318913)) +- **Schematics:** remove path filters in effects schematics ([6d3f5a1](https://github.com/ngrx/platform/commit/6d3f5a1)) +- **Schematics:** remove path filters in reducer schematics ([055f6ef](https://github.com/ngrx/platform/commit/055f6ef)) +- **Schematics:** remove path filters in store schematics ([762cf2e](https://github.com/ngrx/platform/commit/762cf2e)) +- **Store:** remove path filters in ng-add ([ec6adb5](https://github.com/ngrx/platform/commit/ec6adb5)) +- **StoreDevtools:** remove path filters in ng-add ([3ba463f](https://github.com/ngrx/platform/commit/3ba463f)) -## [6.0.1](https://github.com/ngrx/platform/compare/6.0.0...6.0.1) (2018-05-23) - +## [6.0.1](https://github.com/ngrx/platform/compare/6.0.0...6.0.1) (2018-05-23) -# [6.0.0](https://github.com/ngrx/platform/compare/v6.0.0-beta.3...6.0.0) (2018-05-23) +# [6.0.0](https://github.com/ngrx/platform/compare/v6.0.0-beta.3...6.0.0) (2018-05-23) ### Bug Fixes -* **Schematics:** remove ts extension when importing reducer in container ([#1061](https://github.com/ngrx/platform/issues/1061)) ([d1ed9e5](https://github.com/ngrx/platform/commit/d1ed9e5)), closes [#1056](https://github.com/ngrx/platform/issues/1056) -* **Schematics:** Update parsed path logic to split path and name ([a1e9530](https://github.com/ngrx/platform/commit/a1e9530)), closes [#1064](https://github.com/ngrx/platform/issues/1064) -* **Store:** Resolve environment path when generating a new store ([#1071](https://github.com/ngrx/platform/issues/1071)) ([599cfb6](https://github.com/ngrx/platform/commit/599cfb6)) - +- **Schematics:** remove ts extension when importing reducer in container ([#1061](https://github.com/ngrx/platform/issues/1061)) ([d1ed9e5](https://github.com/ngrx/platform/commit/d1ed9e5)), closes [#1056](https://github.com/ngrx/platform/issues/1056) +- **Schematics:** Update parsed path logic to split path and name ([a1e9530](https://github.com/ngrx/platform/commit/a1e9530)), closes [#1064](https://github.com/ngrx/platform/issues/1064) +- **Store:** Resolve environment path when generating a new store ([#1071](https://github.com/ngrx/platform/issues/1071)) ([599cfb6](https://github.com/ngrx/platform/commit/599cfb6)) ### Features -* implement ng add for store and effects packages ([db94db7](https://github.com/ngrx/platform/commit/db94db7)) - - +- implement ng add for store and effects packages ([db94db7](https://github.com/ngrx/platform/commit/db94db7)) -# [6.0.0-beta.3](https://github.com/ngrx/platform/compare/v6.0.0-beta.2...v6.0.0-beta.3) (2018-05-12) +# [6.0.0-beta.3](https://github.com/ngrx/platform/compare/v6.0.0-beta.2...v6.0.0-beta.3) (2018-05-12) ### Bug Fixes -* **build:** Use default build for schematics ([#1057](https://github.com/ngrx/platform/issues/1057)) ([355b12f](https://github.com/ngrx/platform/commit/355b12f)) - - +- **build:** Use default build for schematics ([#1057](https://github.com/ngrx/platform/issues/1057)) ([355b12f](https://github.com/ngrx/platform/commit/355b12f)) -# [6.0.0-beta.2](https://github.com/ngrx/platform/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2018-05-11) +# [6.0.0-beta.2](https://github.com/ngrx/platform/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2018-05-11) ### Bug Fixes -* Update minimum node version to 8.9.0 ([#989](https://github.com/ngrx/platform/issues/989)) ([0baaad8](https://github.com/ngrx/platform/commit/0baaad8)) -* **build:** Fix UMD global names ([#1005](https://github.com/ngrx/platform/issues/1005)) ([413efd4](https://github.com/ngrx/platform/commit/413efd4)), closes [#1004](https://github.com/ngrx/platform/issues/1004) -* **RouterStore:** Reset dispatch-tracking booleans after navigation end ([#968](https://github.com/ngrx/platform/issues/968)) ([48305aa](https://github.com/ngrx/platform/commit/48305aa)) -* **Schematics:** Add check for app/lib to project helper function ([5942885](https://github.com/ngrx/platform/commit/5942885)) -* **Schematics:** Add smart default to blueprint schemas ([cdd247e](https://github.com/ngrx/platform/commit/cdd247e)) -* **Schematics:** Remove aliases for state and stateInterface options ([f4520a2](https://github.com/ngrx/platform/commit/f4520a2)) -* **Schematics:** Update upsert actions for entity blueprint ([#1042](https://github.com/ngrx/platform/issues/1042)) ([0d1d309](https://github.com/ngrx/platform/commit/0d1d309)), closes [#1039](https://github.com/ngrx/platform/issues/1039) -* **Schematics:** Upgrade schematics to new CLI structure ([b99d9ff](https://github.com/ngrx/platform/commit/b99d9ff)) -* **Store:** Fix type annotations for select methods ([#953](https://github.com/ngrx/platform/issues/953)) ([4d74bd2](https://github.com/ngrx/platform/commit/4d74bd2)) -* **StoreDevtools:** Refresh devtools when extension is started ([#1017](https://github.com/ngrx/platform/issues/1017)) ([c6e33d9](https://github.com/ngrx/platform/commit/c6e33d9)), closes [#508](https://github.com/ngrx/platform/issues/508) - +- Update minimum node version to 8.9.0 ([#989](https://github.com/ngrx/platform/issues/989)) ([0baaad8](https://github.com/ngrx/platform/commit/0baaad8)) +- **build:** Fix UMD global names ([#1005](https://github.com/ngrx/platform/issues/1005)) ([413efd4](https://github.com/ngrx/platform/commit/413efd4)), closes [#1004](https://github.com/ngrx/platform/issues/1004) +- **RouterStore:** Reset dispatch-tracking booleans after navigation end ([#968](https://github.com/ngrx/platform/issues/968)) ([48305aa](https://github.com/ngrx/platform/commit/48305aa)) +- **Schematics:** Add check for app/lib to project helper function ([5942885](https://github.com/ngrx/platform/commit/5942885)) +- **Schematics:** Add smart default to blueprint schemas ([cdd247e](https://github.com/ngrx/platform/commit/cdd247e)) +- **Schematics:** Remove aliases for state and stateInterface options ([f4520a2](https://github.com/ngrx/platform/commit/f4520a2)) +- **Schematics:** Update upsert actions for entity blueprint ([#1042](https://github.com/ngrx/platform/issues/1042)) ([0d1d309](https://github.com/ngrx/platform/commit/0d1d309)), closes [#1039](https://github.com/ngrx/platform/issues/1039) +- **Schematics:** Upgrade schematics to new CLI structure ([b99d9ff](https://github.com/ngrx/platform/commit/b99d9ff)) +- **Store:** Fix type annotations for select methods ([#953](https://github.com/ngrx/platform/issues/953)) ([4d74bd2](https://github.com/ngrx/platform/commit/4d74bd2)) +- **StoreDevtools:** Refresh devtools when extension is started ([#1017](https://github.com/ngrx/platform/issues/1017)) ([c6e33d9](https://github.com/ngrx/platform/commit/c6e33d9)), closes [#508](https://github.com/ngrx/platform/issues/508) ### Features -* **Schematics:** Rename default action type for action blueprint ([#1047](https://github.com/ngrx/platform/issues/1047)) ([4c4e6a9](https://github.com/ngrx/platform/commit/4c4e6a9)), closes [#1040](https://github.com/ngrx/platform/issues/1040) -* **Store:** Add support ng update ([#1032](https://github.com/ngrx/platform/issues/1032)) ([5b4f067](https://github.com/ngrx/platform/commit/5b4f067)) -* Add ng update support to ngrx packages ([#1053](https://github.com/ngrx/platform/issues/1053)) ([4f91e9e](https://github.com/ngrx/platform/commit/4f91e9e)) - +- **Schematics:** Rename default action type for action blueprint ([#1047](https://github.com/ngrx/platform/issues/1047)) ([4c4e6a9](https://github.com/ngrx/platform/commit/4c4e6a9)), closes [#1040](https://github.com/ngrx/platform/issues/1040) +- **Store:** Add support ng update ([#1032](https://github.com/ngrx/platform/issues/1032)) ([5b4f067](https://github.com/ngrx/platform/commit/5b4f067)) +- Add ng update support to ngrx packages ([#1053](https://github.com/ngrx/platform/issues/1053)) ([4f91e9e](https://github.com/ngrx/platform/commit/4f91e9e)) ### BREAKING CHANGES -* **Schematics:** The action blueprint has been updated to be less generic, with associated reducer and effects updated for the feature blueprint +- **Schematics:** The action blueprint has been updated to be less generic, with associated reducer and effects updated for the feature blueprint BEFORE: export enum UserActionTypes { - UserAction = '[User] Action' +UserAction = '[User] Action' } export class User implements Action { - readonly type = UserActionTypes.UserAction; +readonly type = UserActionTypes.UserAction; } export type UserActions = User; @@ -311,57 +323,52 @@ export type UserActions = User; AFTER: export enum UserActionTypes { - LoadUsers = '[User] Load Users' +LoadUsers = '[User] Load Users' } export class LoadUsers implements Action { - readonly type = UserActionTypes.LoadUsers; +readonly type = UserActionTypes.LoadUsers; } export type UserActions = LoadUsers; -* **Schematics:** Aliases for `state` and `stateInterface` were removed due to conflicts with component aliases without reasonable alternatives. -* **Schematics:** Minimum dependency for @ngrx/schematics has changed: + +- **Schematics:** Aliases for `state` and `stateInterface` were removed due to conflicts with component aliases without reasonable alternatives. +- **Schematics:** Minimum dependency for @ngrx/schematics has changed: @angular-devkit/core: ^0.5.0 @angular-devkit/schematics: ^0.5.0 - - -# [6.0.0-beta.1](https://github.com/ngrx/platform/compare/v6.0.0-beta.0...v6.0.0-beta.1) (2018-04-02) +# [6.0.0-beta.1](https://github.com/ngrx/platform/compare/v6.0.0-beta.0...v6.0.0-beta.1) (2018-04-02) ### Bug Fixes -* Declare global NgRx packages for UMD bundles ([#952](https://github.com/ngrx/platform/issues/952)) ([ba2139d](https://github.com/ngrx/platform/commit/ba2139d)), closes [#949](https://github.com/ngrx/platform/issues/949) - - +- Declare global NgRx packages for UMD bundles ([#952](https://github.com/ngrx/platform/issues/952)) ([ba2139d](https://github.com/ngrx/platform/commit/ba2139d)), closes [#949](https://github.com/ngrx/platform/issues/949) -# [6.0.0-beta.0](https://github.com/ngrx/platform/compare/v5.2.0...v6.0.0-beta.0) (2018-03-31) +# [6.0.0-beta.0](https://github.com/ngrx/platform/compare/v5.2.0...v6.0.0-beta.0) (2018-03-31) ### Bug Fixes -* Add support for Angular 6 and RxJS 6 ([d1286d2](https://github.com/ngrx/platform/commit/d1286d2)) -* **Entity:** Change EntityAdapter upsertOne/upsertMany to accept an entity ([a0f45ff](https://github.com/ngrx/platform/commit/a0f45ff)) -* **RouterStore:** Allow strict mode with router reducer ([#903](https://github.com/ngrx/platform/issues/903)) ([f17a032](https://github.com/ngrx/platform/commit/f17a032)) -* **RouterStore:** change the default serializer to work around cycles in RouterStateSnapshot ([7917a27](https://github.com/ngrx/platform/commit/7917a27)) -* **RouterStore:** Replace RouterStateSnapshot with SerializedRouterStateSnapshot ([bd415a1](https://github.com/ngrx/platform/commit/bd415a1)) -* **StoreDevtools:** pass timestamp to actions ([df2411f](https://github.com/ngrx/platform/commit/df2411f)) -* **StoreDevtools:** report errors to ErrorHandler instead of console ([32df3f0](https://github.com/ngrx/platform/commit/32df3f0)) - +- Add support for Angular 6 and RxJS 6 ([d1286d2](https://github.com/ngrx/platform/commit/d1286d2)) +- **Entity:** Change EntityAdapter upsertOne/upsertMany to accept an entity ([a0f45ff](https://github.com/ngrx/platform/commit/a0f45ff)) +- **RouterStore:** Allow strict mode with router reducer ([#903](https://github.com/ngrx/platform/issues/903)) ([f17a032](https://github.com/ngrx/platform/commit/f17a032)) +- **RouterStore:** change the default serializer to work around cycles in RouterStateSnapshot ([7917a27](https://github.com/ngrx/platform/commit/7917a27)) +- **RouterStore:** Replace RouterStateSnapshot with SerializedRouterStateSnapshot ([bd415a1](https://github.com/ngrx/platform/commit/bd415a1)) +- **StoreDevtools:** pass timestamp to actions ([df2411f](https://github.com/ngrx/platform/commit/df2411f)) +- **StoreDevtools:** report errors to ErrorHandler instead of console ([32df3f0](https://github.com/ngrx/platform/commit/32df3f0)) ### Features -* **Schematcis:** Extend from [@schematics](https://github.com/schematics)/angular ([0e17aad](https://github.com/ngrx/platform/commit/0e17aad)) -* **Schematics:** Add support for custom store interface name ([#810](https://github.com/ngrx/platform/issues/810)) ([1352d83](https://github.com/ngrx/platform/commit/1352d83)) - +- **Schematcis:** Extend from [@schematics](https://github.com/schematics)/angular ([0e17aad](https://github.com/ngrx/platform/commit/0e17aad)) +- **Schematics:** Add support for custom store interface name ([#810](https://github.com/ngrx/platform/issues/810)) ([1352d83](https://github.com/ngrx/platform/commit/1352d83)) ### BREAKING CHANGES -* **StoreDevtools:** Errors in reducers are no longer hidden from ErrorHandler by -StoreDevtools +- **StoreDevtools:** Errors in reducers are no longer hidden from ErrorHandler by + StoreDevtools BEFORE: @@ -370,9 +377,10 @@ Errors in reducers are caught by StoreDevtools and logged to the console AFTER: Errors in reducers are reported to ErrorHandler -* **Schematcis:** NgRx Schematics now has a minimum version dependency on @angular-devkit/core + +- **Schematcis:** NgRx Schematics now has a minimum version dependency on @angular-devkit/core and @angular-devkit/schematics of v0.4.0. -* **RouterStore:** Default router state is serialized to a shape that removes cycles +- **RouterStore:** Default router state is serialized to a shape that removes cycles BEFORE: @@ -381,7 +389,8 @@ Full RouterStateSnapshot is returned AFTER: Router state snapshot is returned as a SerializedRouterStateSnapshot with cyclical dependencies removed -* **Entity:** The signature of the upsertOne/upsertMany functions in the EntityAdapter + +- **Entity:** The signature of the upsertOne/upsertMany functions in the EntityAdapter has been changed to accept a fully qualified entity instead of an update object that implements the Update interface. @@ -402,123 +411,115 @@ Router state snapshot is returned as a SerializedRouterStateSnapshot with cyclic name: 'Entity Name', }, state); ``` -* NgRx now has a minimum version requirement on Angular 6 and RxJS 6. - +- NgRx now has a minimum version requirement on Angular 6 and RxJS 6. -# [5.2.0](https://github.com/ngrx/platform/compare/v5.1.0...v5.2.0) (2018-03-07) +# [5.2.0](https://github.com/ngrx/platform/compare/v5.1.0...v5.2.0) (2018-03-07) ### Bug Fixes -* **Schematics:** Correct usage of upsert actions for entity blueprint ([#821](https://github.com/ngrx/platform/issues/821)) ([1ffb5a9](https://github.com/ngrx/platform/commit/1ffb5a9)) -* **Store:** only default to initialValue when store value is undefined ([#886](https://github.com/ngrx/platform/issues/886)) ([51a1547](https://github.com/ngrx/platform/commit/51a1547)) -* **StoreDevtools:** Fix bug when exporting/importing state history ([#855](https://github.com/ngrx/platform/issues/855)) ([a5dcdb1](https://github.com/ngrx/platform/commit/a5dcdb1)) -* **StoreDevtools:** Recompute state history when reducers are updated ([#844](https://github.com/ngrx/platform/issues/844)) ([10debcc](https://github.com/ngrx/platform/commit/10debcc)) - +- **Schematics:** Correct usage of upsert actions for entity blueprint ([#821](https://github.com/ngrx/platform/issues/821)) ([1ffb5a9](https://github.com/ngrx/platform/commit/1ffb5a9)) +- **Store:** only default to initialValue when store value is undefined ([#886](https://github.com/ngrx/platform/issues/886)) ([51a1547](https://github.com/ngrx/platform/commit/51a1547)) +- **StoreDevtools:** Fix bug when exporting/importing state history ([#855](https://github.com/ngrx/platform/issues/855)) ([a5dcdb1](https://github.com/ngrx/platform/commit/a5dcdb1)) +- **StoreDevtools:** Recompute state history when reducers are updated ([#844](https://github.com/ngrx/platform/issues/844)) ([10debcc](https://github.com/ngrx/platform/commit/10debcc)) ### Features -* **Entity:** Add 'selectId' and 'sortComparer' to state adapter ([#889](https://github.com/ngrx/platform/issues/889)) ([69a62f2](https://github.com/ngrx/platform/commit/69a62f2)) -* **Store:** Added feature name to Update Reducers action ([730361e](https://github.com/ngrx/platform/commit/730361e)) - - +- **Entity:** Add 'selectId' and 'sortComparer' to state adapter ([#889](https://github.com/ngrx/platform/issues/889)) ([69a62f2](https://github.com/ngrx/platform/commit/69a62f2)) +- **Store:** Added feature name to Update Reducers action ([730361e](https://github.com/ngrx/platform/commit/730361e)) -# [5.1.0](https://github.com/ngrx/platform/compare/v5.0.1...v5.1.0) (2018-02-13) +# [5.1.0](https://github.com/ngrx/platform/compare/v5.0.1...v5.1.0) (2018-02-13) ### Bug Fixes -* **Devtools:** Ensure Store is loaded eagerly ([#801](https://github.com/ngrx/platform/issues/801)) ([ecf1ebf](https://github.com/ngrx/platform/commit/ecf1ebf)), closes [#624](https://github.com/ngrx/platform/issues/624) [#741](https://github.com/ngrx/platform/issues/741) -* **Effects:** Make ofType operator strictFunctionTypes safe ([#789](https://github.com/ngrx/platform/issues/789)) ([c8560e4](https://github.com/ngrx/platform/commit/c8560e4)), closes [#753](https://github.com/ngrx/platform/issues/753) -* **Entity:** Avoid for..in iteration in sorted state adapter ([#805](https://github.com/ngrx/platform/issues/805)) ([4192645](https://github.com/ngrx/platform/commit/4192645)) -* **Entity:** Do not add Array.prototype properties to store ([#782](https://github.com/ngrx/platform/issues/782)) ([d537758](https://github.com/ngrx/platform/commit/d537758)), closes [#781](https://github.com/ngrx/platform/issues/781) -* **Entity:** Properly iterate over array in upsert ([#802](https://github.com/ngrx/platform/issues/802)) ([779d689](https://github.com/ngrx/platform/commit/779d689)) -* **Schematics:** Add store import to container blueprint ([#763](https://github.com/ngrx/platform/issues/763)) ([a140fa9](https://github.com/ngrx/platform/commit/a140fa9)), closes [#760](https://github.com/ngrx/platform/issues/760) -* **Schematics:** Remove extra braces from constructor for container blueprint ([#791](https://github.com/ngrx/platform/issues/791)) ([945bf40](https://github.com/ngrx/platform/commit/945bf40)), closes [#778](https://github.com/ngrx/platform/issues/778) -* **Schematics:** Use correct paths for nested and grouped feature blueprint ([#756](https://github.com/ngrx/platform/issues/756)) ([c219770](https://github.com/ngrx/platform/commit/c219770)) -* **StoreDevtools:** Add internal support for ActionSanitizer and StateSanitizer ([#795](https://github.com/ngrx/platform/issues/795)) ([a7de2a6](https://github.com/ngrx/platform/commit/a7de2a6)) -* **StoreDevtools:** Do not send full liftedState for application actions ([#790](https://github.com/ngrx/platform/issues/790)) ([c11504f](https://github.com/ngrx/platform/commit/c11504f)) - +- **Devtools:** Ensure Store is loaded eagerly ([#801](https://github.com/ngrx/platform/issues/801)) ([ecf1ebf](https://github.com/ngrx/platform/commit/ecf1ebf)), closes [#624](https://github.com/ngrx/platform/issues/624) [#741](https://github.com/ngrx/platform/issues/741) +- **Effects:** Make ofType operator strictFunctionTypes safe ([#789](https://github.com/ngrx/platform/issues/789)) ([c8560e4](https://github.com/ngrx/platform/commit/c8560e4)), closes [#753](https://github.com/ngrx/platform/issues/753) +- **Entity:** Avoid for..in iteration in sorted state adapter ([#805](https://github.com/ngrx/platform/issues/805)) ([4192645](https://github.com/ngrx/platform/commit/4192645)) +- **Entity:** Do not add Array.prototype properties to store ([#782](https://github.com/ngrx/platform/issues/782)) ([d537758](https://github.com/ngrx/platform/commit/d537758)), closes [#781](https://github.com/ngrx/platform/issues/781) +- **Entity:** Properly iterate over array in upsert ([#802](https://github.com/ngrx/platform/issues/802)) ([779d689](https://github.com/ngrx/platform/commit/779d689)) +- **Schematics:** Add store import to container blueprint ([#763](https://github.com/ngrx/platform/issues/763)) ([a140fa9](https://github.com/ngrx/platform/commit/a140fa9)), closes [#760](https://github.com/ngrx/platform/issues/760) +- **Schematics:** Remove extra braces from constructor for container blueprint ([#791](https://github.com/ngrx/platform/issues/791)) ([945bf40](https://github.com/ngrx/platform/commit/945bf40)), closes [#778](https://github.com/ngrx/platform/issues/778) +- **Schematics:** Use correct paths for nested and grouped feature blueprint ([#756](https://github.com/ngrx/platform/issues/756)) ([c219770](https://github.com/ngrx/platform/commit/c219770)) +- **StoreDevtools:** Add internal support for ActionSanitizer and StateSanitizer ([#795](https://github.com/ngrx/platform/issues/795)) ([a7de2a6](https://github.com/ngrx/platform/commit/a7de2a6)) +- **StoreDevtools:** Do not send full liftedState for application actions ([#790](https://github.com/ngrx/platform/issues/790)) ([c11504f](https://github.com/ngrx/platform/commit/c11504f)) ### Features -* **Entity:** Add upsertOne and upsertMany functions to entity adapters ([#780](https://github.com/ngrx/platform/issues/780)) ([f871540](https://github.com/ngrx/platform/commit/f871540)), closes [#421](https://github.com/ngrx/platform/issues/421) -* **Schematics:** Add group option to entity blueprint ([#792](https://github.com/ngrx/platform/issues/792)) ([0429276](https://github.com/ngrx/platform/commit/0429276)), closes [#779](https://github.com/ngrx/platform/issues/779) -* **Schematics:** Add upsert methods to entity blueprint ([#809](https://github.com/ngrx/platform/issues/809)) ([7acdc79](https://github.com/ngrx/platform/commit/7acdc79)), closes [#592](https://github.com/ngrx/platform/issues/592) - - +- **Entity:** Add upsertOne and upsertMany functions to entity adapters ([#780](https://github.com/ngrx/platform/issues/780)) ([f871540](https://github.com/ngrx/platform/commit/f871540)), closes [#421](https://github.com/ngrx/platform/issues/421) +- **Schematics:** Add group option to entity blueprint ([#792](https://github.com/ngrx/platform/issues/792)) ([0429276](https://github.com/ngrx/platform/commit/0429276)), closes [#779](https://github.com/ngrx/platform/issues/779) +- **Schematics:** Add upsert methods to entity blueprint ([#809](https://github.com/ngrx/platform/issues/809)) ([7acdc79](https://github.com/ngrx/platform/commit/7acdc79)), closes [#592](https://github.com/ngrx/platform/issues/592) -## [5.0.1](https://github.com/ngrx/platform/compare/v5.0.0...v5.0.1) (2018-01-25) +## [5.0.1](https://github.com/ngrx/platform/compare/v5.0.0...v5.0.1) (2018-01-25) ### Bug Fixes -* **Effects:** Provide instance from actions to ofType lettable operator ([#751](https://github.com/ngrx/platform/issues/751)) ([33d48e7](https://github.com/ngrx/platform/commit/33d48e7)), closes [#739](https://github.com/ngrx/platform/issues/739) - - +- **Effects:** Provide instance from actions to ofType lettable operator ([#751](https://github.com/ngrx/platform/issues/751)) ([33d48e7](https://github.com/ngrx/platform/commit/33d48e7)), closes [#739](https://github.com/ngrx/platform/issues/739) -# [5.0.0](https://github.com/ngrx/platform/compare/v4.1.1...v5.0.0) (2018-01-22) +# [5.0.0](https://github.com/ngrx/platform/compare/v4.1.1...v5.0.0) (2018-01-22) ### Bug Fixes -* **Effects:** Ensure Store modules are loaded eagerly ([#658](https://github.com/ngrx/platform/issues/658)) ([0a3398d](https://github.com/ngrx/platform/commit/0a3398d)), closes [#642](https://github.com/ngrx/platform/issues/642) -* **Effects:** Remove toPayload utility function ([#738](https://github.com/ngrx/platform/issues/738)) ([b390ef5](https://github.com/ngrx/platform/commit/b390ef5)) -* **Entity:** updateOne/updateMany should not change ids state on existing entity ([#581](https://github.com/ngrx/platform/issues/581)) ([b989e4b](https://github.com/ngrx/platform/commit/b989e4b)), closes [#571](https://github.com/ngrx/platform/issues/571) -* **RouterStore:** Fix usage of config object if provided ([#575](https://github.com/ngrx/platform/issues/575)) ([4125914](https://github.com/ngrx/platform/commit/4125914)) -* **RouterStore:** Match RouterAction type parameters ([#562](https://github.com/ngrx/platform/issues/562)) ([980a653](https://github.com/ngrx/platform/commit/980a653)) -* **Schematics:** Add group folder after feature name folder ([#737](https://github.com/ngrx/platform/issues/737)) ([317fb94](https://github.com/ngrx/platform/commit/317fb94)) -* **Schematics:** Add handling of flat option to entity blueprint ([fb8d2c6](https://github.com/ngrx/platform/commit/fb8d2c6)) -* **Schematics:** Distinguish between root and feature effect arrays when registering ([#718](https://github.com/ngrx/platform/issues/718)) ([95ff6c8](https://github.com/ngrx/platform/commit/95ff6c8)) -* **Schematics:** Don't add state import if not provided ([#697](https://github.com/ngrx/platform/issues/697)) ([e5c2aed](https://github.com/ngrx/platform/commit/e5c2aed)) -* **Schematics:** Make variable naming consistent for entity blueprint ([#716](https://github.com/ngrx/platform/issues/716)) ([765b15a](https://github.com/ngrx/platform/commit/765b15a)) -* **Store:** Compose provided metareducers for a feature reducer ([#704](https://github.com/ngrx/platform/issues/704)) ([1454620](https://github.com/ngrx/platform/commit/1454620)), closes [#701](https://github.com/ngrx/platform/issues/701) -* **StoreDevtools:** Only recompute current state when reducers are updated ([#570](https://github.com/ngrx/platform/issues/570)) ([247ae1a](https://github.com/ngrx/platform/commit/247ae1a)), closes [#229](https://github.com/ngrx/platform/issues/229) [#487](https://github.com/ngrx/platform/issues/487) -* **typo:** update login error to use correct css font color property ([41723fc](https://github.com/ngrx/platform/commit/41723fc)) - +- **Effects:** Ensure Store modules are loaded eagerly ([#658](https://github.com/ngrx/platform/issues/658)) ([0a3398d](https://github.com/ngrx/platform/commit/0a3398d)), closes [#642](https://github.com/ngrx/platform/issues/642) +- **Effects:** Remove toPayload utility function ([#738](https://github.com/ngrx/platform/issues/738)) ([b390ef5](https://github.com/ngrx/platform/commit/b390ef5)) +- **Entity:** updateOne/updateMany should not change ids state on existing entity ([#581](https://github.com/ngrx/platform/issues/581)) ([b989e4b](https://github.com/ngrx/platform/commit/b989e4b)), closes [#571](https://github.com/ngrx/platform/issues/571) +- **RouterStore:** Fix usage of config object if provided ([#575](https://github.com/ngrx/platform/issues/575)) ([4125914](https://github.com/ngrx/platform/commit/4125914)) +- **RouterStore:** Match RouterAction type parameters ([#562](https://github.com/ngrx/platform/issues/562)) ([980a653](https://github.com/ngrx/platform/commit/980a653)) +- **Schematics:** Add group folder after feature name folder ([#737](https://github.com/ngrx/platform/issues/737)) ([317fb94](https://github.com/ngrx/platform/commit/317fb94)) +- **Schematics:** Add handling of flat option to entity blueprint ([fb8d2c6](https://github.com/ngrx/platform/commit/fb8d2c6)) +- **Schematics:** Distinguish between root and feature effect arrays when registering ([#718](https://github.com/ngrx/platform/issues/718)) ([95ff6c8](https://github.com/ngrx/platform/commit/95ff6c8)) +- **Schematics:** Don't add state import if not provided ([#697](https://github.com/ngrx/platform/issues/697)) ([e5c2aed](https://github.com/ngrx/platform/commit/e5c2aed)) +- **Schematics:** Make variable naming consistent for entity blueprint ([#716](https://github.com/ngrx/platform/issues/716)) ([765b15a](https://github.com/ngrx/platform/commit/765b15a)) +- **Store:** Compose provided metareducers for a feature reducer ([#704](https://github.com/ngrx/platform/issues/704)) ([1454620](https://github.com/ngrx/platform/commit/1454620)), closes [#701](https://github.com/ngrx/platform/issues/701) +- **StoreDevtools:** Only recompute current state when reducers are updated ([#570](https://github.com/ngrx/platform/issues/570)) ([247ae1a](https://github.com/ngrx/platform/commit/247ae1a)), closes [#229](https://github.com/ngrx/platform/issues/229) [#487](https://github.com/ngrx/platform/issues/487) +- **typo:** update login error to use correct css font color property ([41723fc](https://github.com/ngrx/platform/commit/41723fc)) ### Features -* **Effects:** Add lettable ofType operator ([d5e1814](https://github.com/ngrx/platform/commit/d5e1814)) -* **ErrorHandler:** Use the Angular ErrorHandler for reporting errors ([#667](https://github.com/ngrx/platform/issues/667)) ([8f297d1](https://github.com/ngrx/platform/commit/8f297d1)), closes [#626](https://github.com/ngrx/platform/issues/626) -* **material:** Upgrade [@angular](https://github.com/angular)/material to v 2.0.0-beta.12 ([#482](https://github.com/ngrx/platform/issues/482)) ([aedf20e](https://github.com/ngrx/platform/commit/aedf20e)), closes [#448](https://github.com/ngrx/platform/issues/448) -* **Schematics:** Add alias for container, store and action blueprints ([#685](https://github.com/ngrx/platform/issues/685)) ([dc64ac9](https://github.com/ngrx/platform/commit/dc64ac9)) -* **Schematics:** Add alias for reducer blueprint ([#684](https://github.com/ngrx/platform/issues/684)) ([ea98fb7](https://github.com/ngrx/platform/commit/ea98fb7)) -* **Schematics:** Add effect to registered effects array ([#717](https://github.com/ngrx/platform/issues/717)) ([f1082fe](https://github.com/ngrx/platform/commit/f1082fe)) -* **Schematics:** Add option to group feature blueprints in respective folders ([#736](https://github.com/ngrx/platform/issues/736)) ([b82c35d](https://github.com/ngrx/platform/commit/b82c35d)) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics ([#631](https://github.com/ngrx/platform/issues/631)) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) -* **Store:** Add support for generating custom createSelector functions ([#734](https://github.com/ngrx/platform/issues/734)) ([cb0d185](https://github.com/ngrx/platform/commit/cb0d185)), closes [#478](https://github.com/ngrx/platform/issues/478) [#724](https://github.com/ngrx/platform/issues/724) -* **StoreDevtools:** Add option to configure extension in log-only mode ([#712](https://github.com/ngrx/platform/issues/712)) ([1ecd658](https://github.com/ngrx/platform/commit/1ecd658)), closes [#643](https://github.com/ngrx/platform/issues/643) [#374](https://github.com/ngrx/platform/issues/374) -* **StoreDevtools:** Add support for custom instance name ([#517](https://github.com/ngrx/platform/issues/517)) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) -* **StoreDevtools:** Add support for extension sanitizers ([#544](https://github.com/ngrx/platform/issues/544)) ([6ed92b0](https://github.com/ngrx/platform/commit/6ed92b0)), closes [#494](https://github.com/ngrx/platform/issues/494) -* **StoreDevtools:** Add support for jumping to a specific action ([#703](https://github.com/ngrx/platform/issues/703)) ([b9f6442](https://github.com/ngrx/platform/commit/b9f6442)), closes [#681](https://github.com/ngrx/platform/issues/681) - +- **Effects:** Add lettable ofType operator ([d5e1814](https://github.com/ngrx/platform/commit/d5e1814)) +- **ErrorHandler:** Use the Angular ErrorHandler for reporting errors ([#667](https://github.com/ngrx/platform/issues/667)) ([8f297d1](https://github.com/ngrx/platform/commit/8f297d1)), closes [#626](https://github.com/ngrx/platform/issues/626) +- **material:** Upgrade [@angular](https://github.com/angular)/material to v 2.0.0-beta.12 ([#482](https://github.com/ngrx/platform/issues/482)) ([aedf20e](https://github.com/ngrx/platform/commit/aedf20e)), closes [#448](https://github.com/ngrx/platform/issues/448) +- **Schematics:** Add alias for container, store and action blueprints ([#685](https://github.com/ngrx/platform/issues/685)) ([dc64ac9](https://github.com/ngrx/platform/commit/dc64ac9)) +- **Schematics:** Add alias for reducer blueprint ([#684](https://github.com/ngrx/platform/issues/684)) ([ea98fb7](https://github.com/ngrx/platform/commit/ea98fb7)) +- **Schematics:** Add effect to registered effects array ([#717](https://github.com/ngrx/platform/issues/717)) ([f1082fe](https://github.com/ngrx/platform/commit/f1082fe)) +- **Schematics:** Add option to group feature blueprints in respective folders ([#736](https://github.com/ngrx/platform/issues/736)) ([b82c35d](https://github.com/ngrx/platform/commit/b82c35d)) +- **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics ([#631](https://github.com/ngrx/platform/issues/631)) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) +- **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) +- **Store:** Add support for generating custom createSelector functions ([#734](https://github.com/ngrx/platform/issues/734)) ([cb0d185](https://github.com/ngrx/platform/commit/cb0d185)), closes [#478](https://github.com/ngrx/platform/issues/478) [#724](https://github.com/ngrx/platform/issues/724) +- **StoreDevtools:** Add option to configure extension in log-only mode ([#712](https://github.com/ngrx/platform/issues/712)) ([1ecd658](https://github.com/ngrx/platform/commit/1ecd658)), closes [#643](https://github.com/ngrx/platform/issues/643) [#374](https://github.com/ngrx/platform/issues/374) +- **StoreDevtools:** Add support for custom instance name ([#517](https://github.com/ngrx/platform/issues/517)) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) +- **StoreDevtools:** Add support for extension sanitizers ([#544](https://github.com/ngrx/platform/issues/544)) ([6ed92b0](https://github.com/ngrx/platform/commit/6ed92b0)), closes [#494](https://github.com/ngrx/platform/issues/494) +- **StoreDevtools:** Add support for jumping to a specific action ([#703](https://github.com/ngrx/platform/issues/703)) ([b9f6442](https://github.com/ngrx/platform/commit/b9f6442)), closes [#681](https://github.com/ngrx/platform/issues/681) ### BREAKING CHANGES -* **Effects:** The utility function `toPayload`, deprecated in @ngrx/effects v4.0, has been removed. +- **Effects:** The utility function `toPayload`, deprecated in @ngrx/effects v4.0, has been removed. + + Before: + + ```ts + import { toPayload } from '@ngrx/effects'; - Before: - - ```ts - import { toPayload } from '@ngrx/effects'; - - actions$.ofType('SOME_ACTION').map(toPayload); - ``` + actions$.ofType('SOME_ACTION').map(toPayload); + ``` - After: + After: - ```ts - actions$.ofType('SOME_ACTION').map((action: SomeActionWithPayload) => action.payload) - ``` -* **ErrorHandler:** The ErrorReporter has been replaced with ErrorHandler -from angular/core. + ```ts + actions$ + .ofType('SOME_ACTION') + .map((action: SomeActionWithPayload) => action.payload); + ``` + +- **ErrorHandler:** The ErrorReporter has been replaced with ErrorHandler + from angular/core. BEFORE: @@ -528,7 +529,8 @@ ErrorReporter would log to the console by default. AFTER: Errors are now reported to the @angular/core ErrorHandler. -* **Store:** Updates minimum version of RxJS dependency. + +- **Store:** Updates minimum version of RxJS dependency. BEFORE: @@ -537,7 +539,8 @@ Minimum peer dependency of RxJS ^5.0.0 AFTER: Minimum peer dependency of RxJS ^5.5.0 -* **Effects:** Updates minimum version of RxJS dependency. + +- **Effects:** Updates minimum version of RxJS dependency. BEFORE: @@ -547,216 +550,179 @@ AFTER: Minimum peer dependency of RxJS ^5.5.0 - - -## [4.1.1](https://github.com/ngrx/platform/compare/v4.1.0...v4.1.1) (2017-11-07) +## [4.1.1](https://github.com/ngrx/platform/compare/v4.1.0...v4.1.1) (2017-11-07) ### Bug Fixes -* **Entity:** Fix type error for id selectors ([#533](https://github.com/ngrx/platform/issues/533)) ([88f672c](https://github.com/ngrx/platform/commit/88f672c)), closes [#525](https://github.com/ngrx/platform/issues/525) -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - +- **Entity:** Fix type error for id selectors ([#533](https://github.com/ngrx/platform/issues/533)) ([88f672c](https://github.com/ngrx/platform/commit/88f672c)), closes [#525](https://github.com/ngrx/platform/issues/525) +- Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) ### Features -* **Codegen:** Add base code and build for [@ngrx](https://github.com/ngrx)/codegen ([#534](https://github.com/ngrx/platform/issues/534)) ([2a22211](https://github.com/ngrx/platform/commit/2a22211)) -* **RouterStore:** Add configurable option for router reducer name ([#417](https://github.com/ngrx/platform/issues/417)) ([ab7de5c](https://github.com/ngrx/platform/commit/ab7de5c)), closes [#410](https://github.com/ngrx/platform/issues/410) - - +- **Codegen:** Add base code and build for [@ngrx](https://github.com/ngrx)/codegen ([#534](https://github.com/ngrx/platform/issues/534)) ([2a22211](https://github.com/ngrx/platform/commit/2a22211)) +- **RouterStore:** Add configurable option for router reducer name ([#417](https://github.com/ngrx/platform/issues/417)) ([ab7de5c](https://github.com/ngrx/platform/commit/ab7de5c)), closes [#410](https://github.com/ngrx/platform/issues/410) -# [4.1.0](https://github.com/ngrx/platform/compare/v4.0.5...v4.1.0) (2017-10-19) +# [4.1.0](https://github.com/ngrx/platform/compare/v4.0.5...v4.1.0) (2017-10-19) ### Bug Fixes -* **Build:** Fix build with space in path ([#331](https://github.com/ngrx/platform/issues/331)) ([257fc9d](https://github.com/ngrx/platform/commit/257fc9d)) -* **combineSelectors:** Remove default parameter from function signature for Closure ([ae7d5e1](https://github.com/ngrx/platform/commit/ae7d5e1)) -* **decorator:** add ExportDecoratedItems jsdoc for g3 ([#456](https://github.com/ngrx/platform/issues/456)) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) -* **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) -* **Entity:** Change type for EntityState to interface ([#454](https://github.com/ngrx/platform/issues/454)) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) -* **Example:** Add missing import for catch operator ([#409](https://github.com/ngrx/platform/issues/409)) ([193e8b3](https://github.com/ngrx/platform/commit/193e8b3)) -* **RouterStore:** Fix cancelled navigation with async guard (fixes [#354](https://github.com/ngrx/platform/issues/354)) ([#355](https://github.com/ngrx/platform/issues/355)) ([920c0ba](https://github.com/ngrx/platform/commit/920c0ba)), closes [#201](https://github.com/ngrx/platform/issues/201) -* **RouterStore:** Stringify error from navigation error event ([#357](https://github.com/ngrx/platform/issues/357)) ([0528d2d](https://github.com/ngrx/platform/commit/0528d2d)), closes [#356](https://github.com/ngrx/platform/issues/356) -* **Store:** Fix typing for feature to accept InjectionToken ([#375](https://github.com/ngrx/platform/issues/375)) ([38b2f95](https://github.com/ngrx/platform/commit/38b2f95)) -* **Store:** Refactor parameter initialization in combineReducers for Closure ([5c60cba](https://github.com/ngrx/platform/commit/5c60cba)) -* **Store:** Set initial value for state action pair to object ([#480](https://github.com/ngrx/platform/issues/480)) ([100a8ef](https://github.com/ngrx/platform/commit/100a8ef)), closes [#477](https://github.com/ngrx/platform/issues/477) - +- **Build:** Fix build with space in path ([#331](https://github.com/ngrx/platform/issues/331)) ([257fc9d](https://github.com/ngrx/platform/commit/257fc9d)) +- **combineSelectors:** Remove default parameter from function signature for Closure ([ae7d5e1](https://github.com/ngrx/platform/commit/ae7d5e1)) +- **decorator:** add ExportDecoratedItems jsdoc for g3 ([#456](https://github.com/ngrx/platform/issues/456)) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) +- **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) +- **Entity:** Change type for EntityState to interface ([#454](https://github.com/ngrx/platform/issues/454)) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) +- **Example:** Add missing import for catch operator ([#409](https://github.com/ngrx/platform/issues/409)) ([193e8b3](https://github.com/ngrx/platform/commit/193e8b3)) +- **RouterStore:** Fix cancelled navigation with async guard (fixes [#354](https://github.com/ngrx/platform/issues/354)) ([#355](https://github.com/ngrx/platform/issues/355)) ([920c0ba](https://github.com/ngrx/platform/commit/920c0ba)), closes [#201](https://github.com/ngrx/platform/issues/201) +- **RouterStore:** Stringify error from navigation error event ([#357](https://github.com/ngrx/platform/issues/357)) ([0528d2d](https://github.com/ngrx/platform/commit/0528d2d)), closes [#356](https://github.com/ngrx/platform/issues/356) +- **Store:** Fix typing for feature to accept InjectionToken ([#375](https://github.com/ngrx/platform/issues/375)) ([38b2f95](https://github.com/ngrx/platform/commit/38b2f95)) +- **Store:** Refactor parameter initialization in combineReducers for Closure ([5c60cba](https://github.com/ngrx/platform/commit/5c60cba)) +- **Store:** Set initial value for state action pair to object ([#480](https://github.com/ngrx/platform/issues/480)) ([100a8ef](https://github.com/ngrx/platform/commit/100a8ef)), closes [#477](https://github.com/ngrx/platform/issues/477) ### Features -* **createSelector:** Expose projector function on selectors to improve testability ([56cb21f](https://github.com/ngrx/platform/commit/56cb21f)), closes [#290](https://github.com/ngrx/platform/issues/290) -* **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) -* **Effects:** Add root effects init action ([#473](https://github.com/ngrx/platform/issues/473)) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) -* **Entity:** Add default selectId function for EntityAdapter ([#405](https://github.com/ngrx/platform/issues/405)) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Entity:** Add support for string or number type for ID ([#441](https://github.com/ngrx/platform/issues/441)) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) -* **Entity:** Enable creating entity selectors without composing a state selector ([#490](https://github.com/ngrx/platform/issues/490)) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) -* **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) -* **Store:** createSelector with an array of selectors ([#340](https://github.com/ngrx/platform/issues/340)) ([2f6a035](https://github.com/ngrx/platform/commit/2f6a035)), closes [#192](https://github.com/ngrx/platform/issues/192) - - +- **createSelector:** Expose projector function on selectors to improve testability ([56cb21f](https://github.com/ngrx/platform/commit/56cb21f)), closes [#290](https://github.com/ngrx/platform/issues/290) +- **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) +- **Effects:** Add root effects init action ([#473](https://github.com/ngrx/platform/issues/473)) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) +- **Entity:** Add default selectId function for EntityAdapter ([#405](https://github.com/ngrx/platform/issues/405)) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) +- **Entity:** Add support for string or number type for ID ([#441](https://github.com/ngrx/platform/issues/441)) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) +- **Entity:** Enable creating entity selectors without composing a state selector ([#490](https://github.com/ngrx/platform/issues/490)) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) +- **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) +- **Store:** createSelector with an array of selectors ([#340](https://github.com/ngrx/platform/issues/340)) ([2f6a035](https://github.com/ngrx/platform/commit/2f6a035)), closes [#192](https://github.com/ngrx/platform/issues/192) -## [4.0.5](https://github.com/ngrx/platform/compare/v4.0.4...v4.0.5) (2017-08-18) +## [4.0.5](https://github.com/ngrx/platform/compare/v4.0.4...v4.0.5) (2017-08-18) ### Bug Fixes -* **Effects:** Do not complete effects if one source errors or completes ([#297](https://github.com/ngrx/platform/issues/297)) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) -* **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) -* **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) - - +- **Effects:** Do not complete effects if one source errors or completes ([#297](https://github.com/ngrx/platform/issues/297)) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) +- **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) +- **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) -## [4.0.4](https://github.com/ngrx/platform/compare/v4.0.3...v4.0.4) (2017-08-17) +## [4.0.4](https://github.com/ngrx/platform/compare/v4.0.3...v4.0.4) (2017-08-17) ### Bug Fixes -* **Effects:** Use factory provide for console ([#288](https://github.com/ngrx/platform/issues/288)) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) -* **RouterStore:** Add generic type to RouterReducerState ([#292](https://github.com/ngrx/platform/issues/292)) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) -* **RouterStore:** Only serialize snapshot in preactivation hook ([#287](https://github.com/ngrx/platform/issues/287)) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) - - +- **Effects:** Use factory provide for console ([#288](https://github.com/ngrx/platform/issues/288)) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) +- **RouterStore:** Add generic type to RouterReducerState ([#292](https://github.com/ngrx/platform/issues/292)) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) +- **RouterStore:** Only serialize snapshot in preactivation hook ([#287](https://github.com/ngrx/platform/issues/287)) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) -## [4.0.3](https://github.com/ngrx/platform/compare/v4.0.2...v4.0.3) (2017-08-16) +## [4.0.3](https://github.com/ngrx/platform/compare/v4.0.2...v4.0.3) (2017-08-16) ### Bug Fixes -* **Effects:** Deprecate toPayload utility function ([#266](https://github.com/ngrx/platform/issues/266)) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects ([#230](https://github.com/ngrx/platform/issues/230)) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface ([#231](https://github.com/ngrx/platform/issues/231)) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) -* **Store:** Add type signature for metareducer ([#270](https://github.com/ngrx/platform/issues/270)) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) -* **Store:** Set initial state for feature modules ([#235](https://github.com/ngrx/platform/issues/235)) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) -* **Store:** Update usage of compose for reducer factory ([#252](https://github.com/ngrx/platform/issues/252)) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) -* **Store:** Use existing reducers when providing reducers without an InjectionToken ([#254](https://github.com/ngrx/platform/issues/254)) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) -* **Store:** Use injector to get reducers provided via InjectionTokens ([#259](https://github.com/ngrx/platform/issues/259)) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)), closes [#189](https://github.com/ngrx/platform/issues/189) - +- **Effects:** Deprecate toPayload utility function ([#266](https://github.com/ngrx/platform/issues/266)) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) +- **Effects:** Ensure StoreModule is loaded before effects ([#230](https://github.com/ngrx/platform/issues/230)) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) +- **Effects:** Export EffectsNotification interface ([#231](https://github.com/ngrx/platform/issues/231)) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) +- **Store:** Add type signature for metareducer ([#270](https://github.com/ngrx/platform/issues/270)) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) +- **Store:** Set initial state for feature modules ([#235](https://github.com/ngrx/platform/issues/235)) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) +- **Store:** Update usage of compose for reducer factory ([#252](https://github.com/ngrx/platform/issues/252)) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) +- **Store:** Use existing reducers when providing reducers without an InjectionToken ([#254](https://github.com/ngrx/platform/issues/254)) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) +- **Store:** Use injector to get reducers provided via InjectionTokens ([#259](https://github.com/ngrx/platform/issues/259)) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)), closes [#189](https://github.com/ngrx/platform/issues/189) ### Features -* **RouterStore:** Add serializer for router state snapshot ([#188](https://github.com/ngrx/platform/issues/188)) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - +- **RouterStore:** Add serializer for router state snapshot ([#188](https://github.com/ngrx/platform/issues/188)) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) -## [4.0.2](https://github.com/ngrx/platform/compare/v4.0.1...v4.0.2) (2017-08-02) +## [4.0.2](https://github.com/ngrx/platform/compare/v4.0.1...v4.0.2) (2017-08-02) ### Bug Fixes -* **createSelector:** memoize projector function ([#228](https://github.com/ngrx/platform/issues/228)) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) -* **docs:** update angular-cli variable ([eeb7d5d](https://github.com/ngrx/platform/commit/eeb7d5d)) -* **Docs:** update effects description ([#164](https://github.com/ngrx/platform/issues/164)) ([c77b2d9](https://github.com/ngrx/platform/commit/c77b2d9)) -* **Effects:** Wrap testing source in an Actions observable ([#121](https://github.com/ngrx/platform/issues/121)) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) -* **RouterStore:** Add support for cancellation with CanLoad guard ([#223](https://github.com/ngrx/platform/issues/223)) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) -* **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) - +- **createSelector:** memoize projector function ([#228](https://github.com/ngrx/platform/issues/228)) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) +- **docs:** update angular-cli variable ([eeb7d5d](https://github.com/ngrx/platform/commit/eeb7d5d)) +- **Docs:** update effects description ([#164](https://github.com/ngrx/platform/issues/164)) ([c77b2d9](https://github.com/ngrx/platform/commit/c77b2d9)) +- **Effects:** Wrap testing source in an Actions observable ([#121](https://github.com/ngrx/platform/issues/121)) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) +- **RouterStore:** Add support for cancellation with CanLoad guard ([#223](https://github.com/ngrx/platform/issues/223)) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) +- **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) ### Features -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity ([#207](https://github.com/ngrx/platform/issues/207)) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) -* **Store:** Add injection token option for feature modules ([#153](https://github.com/ngrx/platform/issues/153)) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) -* **Store:** Added initial state function support for features. Added more tests ([#85](https://github.com/ngrx/platform/issues/85)) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) - - +- **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) +- **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity ([#207](https://github.com/ngrx/platform/issues/207)) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) +- **Store:** Add injection token option for feature modules ([#153](https://github.com/ngrx/platform/issues/153)) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) +- **Store:** Added initial state function support for features. Added more tests ([#85](https://github.com/ngrx/platform/issues/85)) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) -## [4.0.1](https://github.com/ngrx/platform/compare/v4.0.0...v4.0.1) (2017-07-18) +## [4.0.1](https://github.com/ngrx/platform/compare/v4.0.0...v4.0.1) (2017-07-18) ### Bug Fixes -* **effects:** allow downleveled annotations ([#98](https://github.com/ngrx/platform/issues/98)) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **effects:** make correct export path for testing module ([#96](https://github.com/ngrx/platform/issues/96)) ([a5aad22](https://github.com/ngrx/platform/commit/a5aad22)), closes [#94](https://github.com/ngrx/platform/issues/94) - - +- **effects:** allow downleveled annotations ([#98](https://github.com/ngrx/platform/issues/98)) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) +- **effects:** make correct export path for testing module ([#96](https://github.com/ngrx/platform/issues/96)) ([a5aad22](https://github.com/ngrx/platform/commit/a5aad22)), closes [#94](https://github.com/ngrx/platform/issues/94) -# [4.0.0](https://github.com/ngrx/platform/compare/68bd9df...v4.0.0) (2017-07-18) +# [4.0.0](https://github.com/ngrx/platform/compare/68bd9df...v4.0.0) (2017-07-18) ### Bug Fixes -* **build:** Fixed deployment of latest master as commit ([#18](https://github.com/ngrx/platform/issues/18)) ([5d0ecf9](https://github.com/ngrx/platform/commit/5d0ecf9)) -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **build:** Limit concurrency for lerna bootstrap ([7e7a7d8](https://github.com/ngrx/platform/commit/7e7a7d8)) -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers ([#57](https://github.com/ngrx/platform/issues/57)) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **Effects:** Start child effects after running root effects ([#43](https://github.com/ngrx/platform/issues/43)) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) -* **Example:** Fix Book State interface parent ([#90](https://github.com/ngrx/platform/issues/90)) ([6982952](https://github.com/ngrx/platform/commit/6982952)) -* **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **Store:** Exported initial state tokens ([#65](https://github.com/ngrx/platform/issues/65)) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector ([#74](https://github.com/ngrx/platform/issues/74)) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove parameter destructuring for strict mode ([#33](https://github.com/ngrx/platform/issues/33)) ([#77](https://github.com/ngrx/platform/issues/77)) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type ([#72](https://github.com/ngrx/platform/issues/72)) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) -* **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) - +- **build:** Fixed deployment of latest master as commit ([#18](https://github.com/ngrx/platform/issues/18)) ([5d0ecf9](https://github.com/ngrx/platform/commit/5d0ecf9)) +- **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) +- **build:** Limit concurrency for lerna bootstrap ([7e7a7d8](https://github.com/ngrx/platform/commit/7e7a7d8)) +- **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers ([#57](https://github.com/ngrx/platform/issues/57)) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) +- **Effects:** Start child effects after running root effects ([#43](https://github.com/ngrx/platform/issues/43)) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) +- **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) +- **Example:** Fix Book State interface parent ([#90](https://github.com/ngrx/platform/issues/90)) ([6982952](https://github.com/ngrx/platform/commit/6982952)) +- **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) +- **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) +- **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) +- **Store:** Exported initial state tokens ([#65](https://github.com/ngrx/platform/issues/65)) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) +- **Store:** pass all required arguments to projector ([#74](https://github.com/ngrx/platform/issues/74)) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) +- **Store:** Remove parameter destructuring for strict mode ([#33](https://github.com/ngrx/platform/issues/33)) ([#77](https://github.com/ngrx/platform/issues/77)) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) +- **Store:** Removed readonly from type ([#72](https://github.com/ngrx/platform/issues/72)) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) +- **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) ### Code Refactoring -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - +- **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) ### Features -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module ([#70](https://github.com/ngrx/platform/issues/70)) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **router-store:** Added action types ([#47](https://github.com/ngrx/platform/issues/47)) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils ([#10](https://github.com/ngrx/platform/issues/10)) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Allow initial state function for AoT compatibility ([#59](https://github.com/ngrx/platform/issues/59)) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens ([#36](https://github.com/ngrx/platform/issues/36)) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers ([#87](https://github.com/ngrx/platform/issues/87)) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - +- **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) +- **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) +- **Effects:** Introduce new Effects testing module ([#70](https://github.com/ngrx/platform/issues/70)) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) +- **router-store:** Added action types ([#47](https://github.com/ngrx/platform/issues/47)) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) +- **store:** Add 'createSelector' and 'createFeatureSelector' utils ([#10](https://github.com/ngrx/platform/issues/10)) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) +- **Store:** Allow initial state function for AoT compatibility ([#59](https://github.com/ngrx/platform/issues/59)) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) +- **Store:** Allow parent modules to provide reducers with tokens ([#36](https://github.com/ngrx/platform/issues/36)) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) +- **Store:** Simplify API for adding meta-reducers ([#87](https://github.com/ngrx/platform/issues/87)) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) ### BREAKING CHANGES -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. +- **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. BEFORE: + ```ts @NgModule({ - imports: [ - EffectsModule.run(SourceA), - EffectsModule.run(SourceB) - ] + imports: [EffectsModule.run(SourceA), EffectsModule.run(SourceB)], }) -export class AppModule { } +export class AppModule {} ``` AFTER: + ```ts @NgModule({ - imports: [ - EffectsModule.forRoot([ - SourceA, - SourceB, - SourceC, - ]) - ] + imports: [EffectsModule.forRoot([SourceA, SourceB, SourceC])], }) -export class AppModule { } +export class AppModule {} @NgModule({ imports: [ - EffectsModule.forFeature([ - FeatureSourceA, - FeatureSourceB, - FeatureSourceC, - ]) - ] + EffectsModule.forFeature([FeatureSourceA, FeatureSourceB, FeatureSourceC]), + ], }) -export class SomeFeatureModule { } +export class SomeFeatureModule {} ``` - - - diff --git a/WORKSPACE b/WORKSPACE index 1d932d1f0f..1ef1e33bb2 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -7,85 +7,35 @@ # imports also make sense when referencing the published package. workspace(name = "ngrx") -# The Bazel buildtools repo contains tools like the BUILD file formatter, buildifier -# This commit matches the version of buildifier in angular/ngcontainer -# If you change this, also check if it matches the version in the angular/ngcontainer -# version in /.circleci/config.yml -BAZEL_BUILDTOOLS_VERSION = "49a6c199e3fbf5d94534b2771868677d3f9c6de9" +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( - name = "com_github_bazelbuild_buildtools", - url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION, - strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION, - sha256 = "edf39af5fc257521e4af4c40829fffe8fba6d0ebff9f4dd69a6f8f1223ae047b", + name = "build_bazel_rules_nodejs", + sha256 = "88e5e579fb9edfbd19791b8a3c6bfbe16ae3444dba4b428e5efd36856db7cf16", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.27.8/rules_nodejs-0.27.8.tar.gz"], ) -# The @angular repo contains rule for building Angular applications http_archive( - name = "angular", - url = "https://github.com/angular/angular/archive/7.0.1.zip", - strip_prefix = "angular-7.0.1", -) - -# The @rxjs repo contains targets for building rxjs with bazel -http_archive( - name = "rxjs", - url = "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz", - strip_prefix = "package/src", - sha256 = "72b0b4e517f43358f554c125e40e39f67688cd2738a8998b4a266981ed32f403", + name = "io_bazel_rules_webtesting", + sha256 = "1c0900547bdbe33d22aa258637dc560ce6042230e41e9ea9dad5d7d2fca8bc42", + urls = ["https://github.com/bazelbuild/rules_webtesting/releases/download/0.3.0/rules_webtesting.tar.gz"], ) # Rules for compiling sass http_archive( name = "io_bazel_rules_sass", - url = "https://github.com/bazelbuild/rules_sass/archive/1.14.1.zip", + sha256 = "d8b89e47b05092a6eed3fa199f2de7cf671a4b9165d0bf38f12a0363dda928d3", strip_prefix = "rules_sass-1.14.1", -) - -# This local_repository rule is needed to prevent `bazel build ...` from -# drilling down into the @rxjs workspace BUILD files in node_modules/rxjs/src. -# In the future this will no longer be needed. -local_repository( - name = "ignore_node_modules_rxjs", - path = "node_modules/rxjs/src", -) - -local_repository( - name = "rxjs_ignore_nested_1", - path = "node_modules/@angular-devkit/core/node_modules/rxjs/src", -) - -local_repository( - name = "rxjs_ignore_nested_2", - path = "node_modules/@angular-devkit/schematics/node_modules/rxjs/src", -) - -local_repository( - name = "rxjs_ignore_nested_3", - path = "node_modules/@angular/cli/node_modules/rxjs/src", -) - -local_repository( - name = "rxjs_ignore_nested_4", - path = "node_modules/@angular/cli/node_modules/inquirer/node_modules/rxjs/src", -) - -local_repository( - name = "rxjs_ignore_nested_5", - path = "node_modules/listr/node_modules/rxjs/src", + url = "https://github.com/bazelbuild/rules_sass/archive/1.14.1.zip", ) #################################### # Load and install our dependencies downloaded above. -load("@angular//packages/bazel:package.bzl", "rules_angular_dependencies") - -rules_angular_dependencies() - load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install") -# The minimum bazel version to use is 0.17.1 -check_bazel_version("0.17.1") +check_bazel_version(minimum_bazel_version = "0.24.0") + node_repositories( node_version = "10.9.0", yarn_version = "1.9.2", @@ -93,32 +43,28 @@ node_repositories( yarn_install( name = "npm", + data = ["//:angular-metadata.tsconfig.json"], package_json = "//:package.json", yarn_lock = "//:yarn.lock", - # data = ["//:postinstall.tsconfig.json"], ) -load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains") +load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies") -go_rules_dependencies() -go_register_toolchains() +install_bazel_dependencies() load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories") web_test_repositories() + browser_repositories( chromium = True, firefox = True, ) -load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace", "check_rules_typescript_version") +load("@npm_bazel_typescript//:defs.bzl", "ts_setup_workspace") ts_setup_workspace() load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories") sass_repositories() - -load("@angular//:index.bzl", "ng_setup_workspace") - -ng_setup_workspace() diff --git a/angular-metadata.tsconfig.json b/angular-metadata.tsconfig.json new file mode 100644 index 0000000000..8417fb295d --- /dev/null +++ b/angular-metadata.tsconfig.json @@ -0,0 +1,19 @@ +// WORKAROUND https://github.com/angular/angular/issues/18810 +// +// This file is required to run ngc on 3rd party libraries such as @angular/core +// to write files like node_modules/@angular/core/core.ngsummary.json. +// +{ + "compilerOptions": { + "lib": ["dom", "es2015"], + "experimentalDecorators": true, + "types": [], + "module": "amd", + "moduleResolution": "node" + }, + "angularCompilerOptions": { + "enableSummariesForJit": true + }, + "include": ["node_modules/@angular/core/*"], + "exclude": ["node_modules/@angular/**/testing/**"] +} diff --git a/angular.json b/angular.json index 0ec236b0ad..6898937e20 100644 --- a/angular.json +++ b/angular.json @@ -92,31 +92,6 @@ } } } - }, - "example-app-e2e": { - "root": "projects/example-app-e2e/", - "projectType": "application", - "architect": { - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "projects/example-app-e2e/protractor.conf.js", - "devServerTarget": "example-app:serve" - }, - "configurations": { - "production": { - "devServerTarget": "example-app:serve:production" - } - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": "projects/example-app-e2e/tsconfig.e2e.json", - "exclude": ["**/node_modules/**"] - } - } - } } }, "schematics": { diff --git a/build/cleanup-previews.ts b/build/cleanup-previews.ts new file mode 100644 index 0000000000..0c94a9a33b --- /dev/null +++ b/build/cleanup-previews.ts @@ -0,0 +1,15 @@ +import * as tasks from './tasks'; +import { createBuilder } from './util'; +import { packages } from './config'; + +const cleanup = createBuilder([ + ['Cleanup docs previews', tasks.cleanupDocsPreviews], +]); + +cleanup({ + scope: '', + packages, +}).catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/build/example-app-server.js b/build/example-app-server.js new file mode 100644 index 0000000000..b26fdc42bf --- /dev/null +++ b/build/example-app-server.js @@ -0,0 +1,14 @@ +const express = require('express'); +const path = require('path'); + +const CONTEXT = `/${process.env.CONTEXT || 'platform/example-app'}`; +const PORT = process.env.PORT || 4000; +const DIST = path.join(__dirname, '../projects/example-app/dist'); + +const app = express(); + +app.use(CONTEXT, express.static(DIST)); +app.use('/', express.static(DIST)); +app.listen(PORT, () => + console.log(`App running on http://localhost:${PORT}${CONTEXT}`) +); diff --git a/build/tasks.ts b/build/tasks.ts index 712aeba059..19baef559a 100644 --- a/build/tasks.ts +++ b/build/tasks.ts @@ -149,3 +149,49 @@ export async function postGithubComment() { }); } } + +export async function cleanupDocsPreviews() { + const repoUrl = 'git@github.com:ngrx/ngrx-io-previews.git'; + const repoDir = `./tmp/docs-preview-cleanup`; + const token = process.env.GITHUB_API_KEY; + const octokit = require('@octokit/rest')(); + + octokit.authenticate({ type: 'token', token }); + + const q = 'repo:ngrx/platform is:pr is:closed'; + + const { data }: { data: { items: any[] } } = await octokit.search.issues({ + q, + per_page: 100, + }); + + await util.cmd('rm -rf', [`${repoDir}`]); + await util.cmd('mkdir ', [`-p ${repoDir}`]); + await process.chdir(`${repoDir}`); + await util.git([`init`]); + await util.git([`remote add origin ${repoUrl}`]); + await util.git([`fetch origin master --depth=1`]); + await util.git(['checkout origin/master -b master']); + + const prsToRemove = data.items.reduce( + (prev: string[], curr: { number: number }) => { + prev.push(`pr${curr.number}*`); + + return prev; + }, + [] + ); + + await util.cmd('rm -rf', [`${prsToRemove.join(' ')}`]); + await util.git([`config user.name "ngrxbot"`]); + await util.git([`config user.email "${process.env.GITHUB_BOT_EMAIL}"`]); + await util.git(['add --all']); + + try { + await util.git([ + `commit -m "chore: cleanup previews for closed pull requests"`, + ]); + } catch (e) {} + + await util.git(['push origin master --force']); +} diff --git a/docs/effects/testing.md b/docs/effects/testing.md index a4e5aac190..b3f9f4cb7d 100644 --- a/docs/effects/testing.md +++ b/docs/effects/testing.md @@ -19,8 +19,7 @@ Usage: ```ts import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; -import { ReplaySubject } from 'rxjs/ReplaySubject'; -import { hot, cold } from 'jasmine-marbles'; +import { cold, hot } from 'jasmine-marbles'; import { Observable } from 'rxjs'; import { MyEffects } from './my-effects'; @@ -28,7 +27,7 @@ import * as MyActions from '../actions/my-actions'; describe('My Effects', () => { let effects: MyEffects; - let actions: Subject; + let actions: Observable; beforeEach(() => { TestBed.configureTestingModule({ @@ -55,14 +54,44 @@ describe('My Effects', () => { expect(effects.someSource$).toBeObservable(expected); }); +}); +``` - it('should work also', () => { - actions = new ReplaySubject(1); +It is also possible to use `ReplaySubject` as an alternative for marble tests: + +```ts +import { TestBed } from '@angular/core/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { ReplaySubject } from 'rxjs'; + +import { MyEffects } from './my-effects'; +import * as MyActions from '../actions/my-actions'; + +describe('My Effects', () => { + let effects: MyEffects; + let actions: ReplaySubject<any>; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + // any modules needed + ], + providers: [ + MyEffects, + provideMockActions(() => actions), + // other providers + ], + }); - actions.next(SomeAction); + effects = TestBed.get(MyEffects); + }); + + it('should work', () => { + actions = new ReplaySubject(1); + actions.next(new MyActions.ExampleAction()); effects.someSource$.subscribe(result => { - expect(result).toEqual(AnotherAction); + expect(result).toEqual(new MyActions.ExampleActionSuccess()); }); }); }); diff --git a/modules/effects/BUILD b/modules/effects/BUILD index f20436e01c..de7dd03ab5 100644 --- a/modules/effects/BUILD +++ b/modules/effects/BUILD @@ -11,8 +11,8 @@ ng_module( module_name = "@ngrx/effects", deps = [ "//modules/store", - "@angular//packages/core", - "@rxjs", + "@npm//@angular/core", + "@npm//rxjs", ], ) diff --git a/modules/effects/CHANGELOG.md b/modules/effects/CHANGELOG.md index a6674615b2..3b9c4d91aa 100644 --- a/modules/effects/CHANGELOG.md +++ b/modules/effects/CHANGELOG.md @@ -1,1507 +1,3 @@ # Change Log -All notable changes to this project will be documented in this file. -See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - - -# 5.2.0 (2018-03-07) - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Effects:** Make ofType operator strictFunctionTypes safe (#789) ([c8560e4](https://github.com/ngrx/platform/commit/c8560e4)), closes [#753](https://github.com/ngrx/platform/issues/753) - - - - -## 5.0.1 (2018-01-25) - - -### Bug Fixes - -* **Effects:** Provide instance from actions to ofType lettable operator (#751) ([33d48e7](https://github.com/ngrx/platform/commit/33d48e7)), closes [#739](https://github.com/ngrx/platform/issues/739) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Effects:** Ensure Store modules are loaded eagerly (#658) ([0a3398d](https://github.com/ngrx/platform/commit/0a3398d)), closes [#642](https://github.com/ngrx/platform/issues/642) -* **Effects:** Remove toPayload utility function (#738) ([b390ef5](https://github.com/ngrx/platform/commit/b390ef5)) - - -### Features - -* **Effects:** Add lettable ofType operator ([d5e1814](https://github.com/ngrx/platform/commit/d5e1814)) -* **ErrorHandler:** Use the Angular ErrorHandler for reporting errors (#667) ([8f297d1](https://github.com/ngrx/platform/commit/8f297d1)), closes [#626](https://github.com/ngrx/platform/issues/626) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) - - -### BREAKING CHANGES - -* **Effects:** The utility function `toPayload`, deprecated in @ngrx/effects v4.0, has been removed. - - Before: - - ```ts - import { toPayload } from '@ngrx/effects'; - - actions$.ofType('SOME_ACTION').map(toPayload); - ``` - - After: - - ```ts - actions$.ofType('SOME_ACTION').map((action: SomeActionWithPayload) => action.payload) - ``` -* **ErrorHandler:** The ErrorReporter has been replaced with ErrorHandler -from angular/core. - -BEFORE: - -Errors were reported to the ngrx/effects ErrorReporter. The -ErrorReporter would log to the console by default. - -AFTER: - -Errors are now reported to the @angular/core ErrorHandler. -* **Effects:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **decorator:** add ExportDecoratedItems jsdoc for g3 (#456) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) -* **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) - - -### Features - -* **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) -* **Effects:** Add root effects init action (#473) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) - - - - -## 4.0.5 (2017-08-18) - - -### Bug Fixes - -* **Effects:** Do not complete effects if one source errors or completes (#297) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ - imports: [ - EffectsModule.run(SourceA), - EffectsModule.run(SourceB) - ] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ - imports: [ - EffectsModule.forRoot([ - SourceA, - SourceB, - SourceC, - ]) - ] -}) -export class AppModule { } - -@NgModule({ - imports: [ - EffectsModule.forFeature([ - FeatureSourceA, - FeatureSourceB, - FeatureSourceC, - ]) - ] -}) -export class SomeFeatureModule { } -``` - - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Effects:** Make ofType operator strictFunctionTypes safe (#789) ([c8560e4](https://github.com/ngrx/platform/commit/c8560e4)), closes [#753](https://github.com/ngrx/platform/issues/753) - - - - -## 5.0.1 (2018-01-25) - - -### Bug Fixes - -* **Effects:** Provide instance from actions to ofType lettable operator (#751) ([33d48e7](https://github.com/ngrx/platform/commit/33d48e7)), closes [#739](https://github.com/ngrx/platform/issues/739) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Effects:** Ensure Store modules are loaded eagerly (#658) ([0a3398d](https://github.com/ngrx/platform/commit/0a3398d)), closes [#642](https://github.com/ngrx/platform/issues/642) -* **Effects:** Remove toPayload utility function (#738) ([b390ef5](https://github.com/ngrx/platform/commit/b390ef5)) - - -### Features - -* **Effects:** Add lettable ofType operator ([d5e1814](https://github.com/ngrx/platform/commit/d5e1814)) -* **ErrorHandler:** Use the Angular ErrorHandler for reporting errors (#667) ([8f297d1](https://github.com/ngrx/platform/commit/8f297d1)), closes [#626](https://github.com/ngrx/platform/issues/626) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) - - -### BREAKING CHANGES - -* **Effects:** The utility function `toPayload`, deprecated in @ngrx/effects v4.0, has been removed. - - Before: - - ```ts - import { toPayload } from '@ngrx/effects'; - - actions$.ofType('SOME_ACTION').map(toPayload); - ``` - - After: - - ```ts - actions$.ofType('SOME_ACTION').map((action: SomeActionWithPayload) => action.payload) - ``` -* **ErrorHandler:** The ErrorReporter has been replaced with ErrorHandler -from angular/core. - -BEFORE: - -Errors were reported to the ngrx/effects ErrorReporter. The -ErrorReporter would log to the console by default. - -AFTER: - -Errors are now reported to the @angular/core ErrorHandler. -* **Effects:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **decorator:** add ExportDecoratedItems jsdoc for g3 (#456) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) -* **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) - - -### Features - -* **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) -* **Effects:** Add root effects init action (#473) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) - - - - -## 4.0.5 (2017-08-18) - - -### Bug Fixes - -* **Effects:** Do not complete effects if one source errors or completes (#297) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ - EffectsModule.run(SourceA), - EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ - EffectsModule.forRoot([ - SourceA, - SourceB, - SourceC, - ]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ - EffectsModule.forFeature([ - FeatureSourceA, - FeatureSourceB, - FeatureSourceC, - ]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -## 5.0.1 (2018-01-25) - - -### Bug Fixes - -* **Effects:** Provide instance from actions to ofType lettable operator (#751) ([33d48e7](https://github.com/ngrx/platform/commit/33d48e7)), closes [#739](https://github.com/ngrx/platform/issues/739) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Effects:** Ensure Store modules are loaded eagerly (#658) ([0a3398d](https://github.com/ngrx/platform/commit/0a3398d)), closes [#642](https://github.com/ngrx/platform/issues/642) -* **Effects:** Remove toPayload utility function (#738) ([b390ef5](https://github.com/ngrx/platform/commit/b390ef5)) - - -### Features - -* **Effects:** Add lettable ofType operator ([d5e1814](https://github.com/ngrx/platform/commit/d5e1814)) -* **ErrorHandler:** Use the Angular ErrorHandler for reporting errors (#667) ([8f297d1](https://github.com/ngrx/platform/commit/8f297d1)), closes [#626](https://github.com/ngrx/platform/issues/626) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) - - -### BREAKING CHANGES - -* **Effects:** The utility function `toPayload`, deprecated in @ngrx/effects v4.0, has been removed. - -Before: - - ```ts - import { toPayload } from '@ngrx/effects'; - - actions$.ofType('SOME_ACTION').map(toPayload); - ``` - - After: - - ```ts - actions$.ofType('SOME_ACTION').map((action: SomeActionWithPayload) => action.payload) - ``` -* **ErrorHandler:** The ErrorReporter has been replaced with ErrorHandler -from angular/core. - -BEFORE: - -Errors were reported to the ngrx/effects ErrorReporter. The -ErrorReporter would log to the console by default. - -AFTER: - -Errors are now reported to the @angular/core ErrorHandler. -* **Effects:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **decorator:** add ExportDecoratedItems jsdoc for g3 (#456) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) -* **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) - - -### Features - -* **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) -* **Effects:** Add root effects init action (#473) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) - - - - -## 4.0.5 (2017-08-18) - - -### Bug Fixes - -* **Effects:** Do not complete effects if one source errors or completes (#297) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ - EffectsModule.run(SourceA), - EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ - EffectsModule.forRoot([ - SourceA, - SourceB, - SourceC, - ]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ - EffectsModule.forFeature([ - FeatureSourceA, - FeatureSourceB, - FeatureSourceC, - ]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Effects:** Ensure Store modules are loaded eagerly (#658) ([0a3398d](https://github.com/ngrx/platform/commit/0a3398d)), closes [#642](https://github.com/ngrx/platform/issues/642) -* **Effects:** Remove toPayload utility function (#738) ([b390ef5](https://github.com/ngrx/platform/commit/b390ef5)) - - -### Features - -* **Effects:** Add lettable ofType operator ([d5e1814](https://github.com/ngrx/platform/commit/d5e1814)) -* **ErrorHandler:** Use the Angular ErrorHandler for reporting errors (#667) ([8f297d1](https://github.com/ngrx/platform/commit/8f297d1)), closes [#626](https://github.com/ngrx/platform/issues/626) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) - - -### BREAKING CHANGES - -* **Effects:** The utility function `toPayload`, deprecated in @ngrx/effects v4.0, has been removed. - -Before: - -```ts -import { toPayload } from '@ngrx/effects'; - -actions$.ofType('SOME_ACTION').map(toPayload); -``` - -After: - -```ts -actions$.ofType('SOME_ACTION').map((action: SomeActionWithPayload) => action.payload) -``` -* **ErrorHandler:** The ErrorReporter has been replaced with ErrorHandler -from angular/core. - -BEFORE: - -Errors were reported to the ngrx/effects ErrorReporter. The -ErrorReporter would log to the console by default. - -AFTER: - -Errors are now reported to the @angular/core ErrorHandler. -* **Effects:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **decorator:** add ExportDecoratedItems jsdoc for g3 (#456) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) -* **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) - - -### Features - -* **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) -* **Effects:** Add root effects init action (#473) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) - - - - -## 4.0.5 (2017-08-18) - - -### Bug Fixes - -* **Effects:** Do not complete effects if one source errors or completes (#297) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ - SourceA, - SourceB, - SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ - FeatureSourceA, - FeatureSourceB, - FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **decorator:** add ExportDecoratedItems jsdoc for g3 (#456) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) -* **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) - - -### Features - -* **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) -* **Effects:** Add root effects init action (#473) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) - - - - -## 4.0.5 (2017-08-18) - - -### Bug Fixes - -* **Effects:** Do not complete effects if one source errors or completes (#297) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **decorator:** add ExportDecoratedItems jsdoc for g3 (#456) ([2b0e0cf](https://github.com/ngrx/platform/commit/2b0e0cf)) -* **Effects:** Simplify decorator handling for Closure compatibility ([ad30d40](https://github.com/ngrx/platform/commit/ad30d40)) - - -### Features - -* **Effects:** Add getEffectsMetadata() helper for verifying metadata ([628b865](https://github.com/ngrx/platform/commit/628b865)), closes [#491](https://github.com/ngrx/platform/issues/491) -* **Effects:** Add root effects init action (#473) ([838ba17](https://github.com/ngrx/platform/commit/838ba17)), closes [#246](https://github.com/ngrx/platform/issues/246) - - - - -## 4.0.5 (2017-08-18) - - -### Bug Fixes - -* **Effects:** Do not complete effects if one source errors or completes (#297) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -## 4.0.5 (2017-08-18) - - -### Bug Fixes - -* **Effects:** Do not complete effects if one source errors or completes (#297) ([54747cf](https://github.com/ngrx/platform/commit/54747cf)), closes [#232](https://github.com/ngrx/platform/issues/232) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **Effects:** Use factory provide for console (#288) ([bf7f70c](https://github.com/ngrx/platform/commit/bf7f70c)), closes [#276](https://github.com/ngrx/platform/issues/276) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Effects:** Deprecate toPayload utility function (#266) ([1cbb2c9](https://github.com/ngrx/platform/commit/1cbb2c9)) -* **Effects:** Ensure StoreModule is loaded before effects (#230) ([065d33e](https://github.com/ngrx/platform/commit/065d33e)), closes [#184](https://github.com/ngrx/platform/issues/184) [#219](https://github.com/ngrx/platform/issues/219) -* **Effects:** Export EffectsNotification interface (#231) ([2b1a076](https://github.com/ngrx/platform/commit/2b1a076)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **Effects:** Wrap testing source in an Actions observable (#121) ([bfdb83b](https://github.com/ngrx/platform/commit/bfdb83b)), closes [#117](https://github.com/ngrx/platform/issues/117) - - -### Features - -* **Effects:** Add generic type to the "ofType" operator ([55c13b2](https://github.com/ngrx/platform/commit/55c13b2)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) - - - - -## 4.0.1 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **effects:** allow downleveled annotations (#98) ([875b326](https://github.com/ngrx/platform/commit/875b326)), closes [#93](https://github.com/ngrx/platform/issues/93) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -# 4.0.0 (2017-07-18) - - -### Bug Fixes - -* **build:** Get tests running for each project ([c4a1054](https://github.com/ngrx/platform/commit/c4a1054)) -* **Effects:** Start child effects after running root effects (#43) ([931adb1](https://github.com/ngrx/platform/commit/931adb1)) -* **Effects:** Use Actions generic type for the return of the ofType operator ([d176a11](https://github.com/ngrx/platform/commit/d176a11)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Ensure effects are only subscribed to once ([089abdc](https://github.com/ngrx/platform/commit/089abdc)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` +See [CHANGELOG.md](https://github.com/ngrx/platform/blob/master/CHANGELOG.md) diff --git a/modules/effects/schematics-core/index.ts b/modules/effects/schematics-core/index.ts index 36cc0abbcf..9608baec44 100644 --- a/modules/effects/schematics-core/index.ts +++ b/modules/effects/schematics-core/index.ts @@ -15,6 +15,7 @@ export { getDecoratorMetadata, getContentOfKeyLiteral, insertAfterLastOccurrence, + insertImport, addBootstrapToModule, addDeclarationToModule, addExportToModule, @@ -49,7 +50,6 @@ export { } from './utility/ngrx-utils'; export { getProjectPath, getProject, isLib } from './utility/project'; -export { insertImport } from './utility/route-utils'; export const stringUtils = { dasherize, diff --git a/modules/effects/schematics-core/utility/ast-utils.ts b/modules/effects/schematics-core/utility/ast-utils.ts index b1f263974e..f6174fc4b1 100644 --- a/modules/effects/schematics-core/utility/ast-utils.ts +++ b/modules/effects/schematics-core/utility/ast-utils.ts @@ -7,8 +7,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import { Change, InsertChange } from './change'; -import { insertImport } from './route-utils'; +import { Change, InsertChange, NoopChange } from './change'; /** * Find all nodes from the AST in the subtree of node of SyntaxKind kind. @@ -537,3 +536,103 @@ export function addBootstrapToModule( importPath ); } + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ + +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + const rootNode = source; + const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + + // get nodes that map to import statements from the file fileName + const relevantImports = allImports.filter(node => { + // StringLiteral of the ImportDeclaration is the import file (fileName in this case). + const importFiles = node + .getChildren() + .filter(child => child.kind === ts.SyntaxKind.StringLiteral) + .map(n => (n as ts.StringLiteral).text); + + return importFiles.filter(file => file === fileName).length === 1; + }); + + if (relevantImports.length > 0) { + let importsAsterisk = false; + // imports from import file + const imports: ts.Node[] = []; + relevantImports.forEach(n => { + Array.prototype.push.apply( + imports, + findNodes(n, ts.SyntaxKind.Identifier) + ); + if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + importsAsterisk = true; + } + }); + + // if imports * from fileName, don't add symbolName + if (importsAsterisk) { + return new NoopChange(); + } + + const importTextNodes = imports.filter( + n => (n as ts.Identifier).text === symbolName + ); + + // insert import if it's not there + if (importTextNodes.length === 0) { + const fallbackPos = + findNodes( + relevantImports[0], + ts.SyntaxKind.CloseBraceToken + )[0].getStart() || + findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + + return insertAfterLastOccurrence( + imports, + `, ${symbolName}`, + fileToEdit, + fallbackPos + ); + } + + return new NoopChange(); + } + + // no such import declaration exists + const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( + n => n.getText() === 'use strict' + ); + let fallbackPos = 0; + if (useStrict.length > 0) { + fallbackPos = useStrict[0].end; + } + const open = isDefault ? '' : '{ '; + const close = isDefault ? '' : ' }'; + // if there are no imports or 'use strict' statement, insert import at beginning of file + const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; + const separator = insertAtBeginning ? '' : ';\n'; + const toInsert = + `${separator}import ${open}${symbolName}${close}` + + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; + + return insertAfterLastOccurrence( + allImports, + toInsert, + fileToEdit, + fallbackPos, + ts.SyntaxKind.StringLiteral + ); +} diff --git a/modules/effects/schematics-core/utility/ngrx-utils.ts b/modules/effects/schematics-core/utility/ngrx-utils.ts index 28294e1110..d856f79346 100644 --- a/modules/effects/schematics-core/utility/ngrx-utils.ts +++ b/modules/effects/schematics-core/utility/ngrx-utils.ts @@ -4,8 +4,7 @@ import { InsertChange, Change, NoopChange } from './change'; import { Tree, SchematicsException, Rule } from '@angular-devkit/schematics'; import { normalize } from '@angular-devkit/core'; import { buildRelativePath } from './find-module'; -import { insertImport } from './route-utils'; -import { addImportToModule } from './ast-utils'; +import { addImportToModule, insertImport } from './ast-utils'; export function addReducerToState(options: any): Rule { return (host: Tree) => { @@ -79,7 +78,7 @@ export function addReducerToState(options: any): Rule { export function addReducerToStateInterface( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { const stateInterface = source.statements.find( stm => stm.kind === ts.SyntaxKind.InterfaceDeclaration @@ -90,11 +89,12 @@ export function addReducerToStateInterface( return new NoopChange(); } + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.State;'; + state + ': from' + stringUtils.classify(options.name) + '.State;'; const expr = node as any; let position; let toInsert; @@ -125,7 +125,7 @@ export function addReducerToStateInterface( export function addReducerToActionReducerMap( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { let initializer: any; const actionReducerMap: any = source.statements @@ -152,11 +152,12 @@ export function addReducerToActionReducerMap( let node = actionReducerMap.initializer; + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.reducer,'; + state + ': from' + stringUtils.classify(options.name) + '.reducer,'; const expr = node as any; let position; let toInsert; diff --git a/modules/effects/schematics-core/utility/project.ts b/modules/effects/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/effects/schematics-core/utility/project.ts +++ b/modules/effects/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/effects/schematics-core/utility/route-utils.ts b/modules/effects/schematics-core/utility/route-utils.ts deleted file mode 100644 index d25cc059a8..0000000000 --- a/modules/effects/schematics-core/utility/route-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as ts from 'typescript'; -import { findNodes, insertAfterLastOccurrence } from './ast-utils'; -import { Change, NoopChange } from './change'; - -/** - * Add Import `import { symbolName } from fileName` if the import doesn't exit - * already. Assumes fileToEdit can be resolved and accessed. - * @param fileToEdit (file we want to add import to) - * @param symbolName (item to import) - * @param fileName (path to the file) - * @param isDefault (if true, import follows style for importing default exports) - * @return Change - */ - -export function insertImport( - source: ts.SourceFile, - fileToEdit: string, - symbolName: string, - fileName: string, - isDefault = false -): Change { - const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); - - // get nodes that map to import statements from the file fileName - const relevantImports = allImports.filter(node => { - // StringLiteral of the ImportDeclaration is the import file (fileName in this case). - const importFiles = node - .getChildren() - .filter(child => child.kind === ts.SyntaxKind.StringLiteral) - .map(n => (n as ts.StringLiteral).text); - - return importFiles.filter(file => file === fileName).length === 1; - }); - - if (relevantImports.length > 0) { - let importsAsterisk = false; - // imports from import file - const imports: ts.Node[] = []; - relevantImports.forEach(n => { - Array.prototype.push.apply( - imports, - findNodes(n, ts.SyntaxKind.Identifier) - ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { - importsAsterisk = true; - } - }); - - // if imports * from fileName, don't add symbolName - if (importsAsterisk) { - return new NoopChange(); - } - - const importTextNodes = imports.filter( - n => (n as ts.Identifier).text === symbolName - ); - - // insert import if it's not there - if (importTextNodes.length === 0) { - const fallbackPos = - findNodes( - relevantImports[0], - ts.SyntaxKind.CloseBraceToken - )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); - - return insertAfterLastOccurrence( - imports, - `, ${symbolName}`, - fileToEdit, - fallbackPos - ); - } - - return new NoopChange(); - } - - // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - n => n.getText() === 'use strict' - ); - let fallbackPos = 0; - if (useStrict.length > 0) { - fallbackPos = useStrict[0].end; - } - const open = isDefault ? '' : '{ '; - const close = isDefault ? '' : ' }'; - // if there are no imports or 'use strict' statement, insert import at beginning of file - const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; - const separator = insertAtBeginning ? '' : ';\n'; - const toInsert = - `${separator}import ${open}${symbolName}${close}` + - ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; - - return insertAfterLastOccurrence( - allImports, - toInsert, - fileToEdit, - fallbackPos, - ts.SyntaxKind.StringLiteral - ); -} diff --git a/modules/effects/schematics-core/utility/strings.ts b/modules/effects/schematics-core/utility/strings.ts index dae37e563c..5ebec70706 100644 --- a/modules/effects/schematics-core/utility/strings.ts +++ b/modules/effects/schematics-core/utility/strings.ts @@ -110,6 +110,25 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.substr(1); } +/** + Returns the plural form of a string + + ```javascript + 'innerHTML'.pluralize() // 'InnerHTMLs' + 'action_name'.pluralize() // 'actionNames' + 'css-class-name'.pluralize() // 'cssClassNames' + 'regex'.pluralize() // 'regexes' + 'user'.pluralize() // 'users' + ``` + */ +export function pluralize(str: string): string { + return camelize( + [/([^aeiou])y$/, /()fe?$/, /([^aeiou]o|[sxz]|[cs]h)$/].map( + (c, i) => (str = str.replace(c, `$1${'iv'[i] || ''}e`)) + ) && str + 's' + ); +} + export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } diff --git a/modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects__dot__spec.ts b/modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects.spec.ts.template similarity index 100% rename from modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects__dot__spec.ts rename to modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects.spec.ts.template diff --git a/modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts b/modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts.template similarity index 100% rename from modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts rename to modules/effects/schematics/ng-add/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts.template diff --git a/modules/effects/schematics/ng-add/index.ts b/modules/effects/schematics/ng-add/index.ts index 6c7b1cdecc..e0853a1034 100644 --- a/modules/effects/schematics/ng-add/index.ts +++ b/modules/effects/schematics/ng-add/index.ts @@ -4,6 +4,7 @@ import { SchematicsException, Tree, apply, + applyTemplates, branchAndMerge, chain, filter, @@ -121,8 +122,10 @@ export default function(options: RootEffectOptions): Rule { options.path = parsedPath.path; const templateSource = apply(url('./files'), [ - options.spec ? noop() : filter(path => !path.endsWith('__spec.ts')), - template({ + options.spec + ? noop() + : filter(path => !path.endsWith('.spec.ts.template')), + applyTemplates({ ...stringUtils, 'if-flat': (s: string) => stringUtils.group( @@ -130,7 +133,6 @@ export default function(options: RootEffectOptions): Rule { options.group ? 'effects' : '' ), ...(options as object), - dot: () => '.', } as any), move(parsedPath.path), ]); diff --git a/modules/effects/spec/BUILD b/modules/effects/spec/BUILD index bedc249a7f..5de8af0822 100644 --- a/modules/effects/spec/BUILD +++ b/modules/effects/spec/BUILD @@ -11,8 +11,7 @@ ts_test_library( deps = [ "//modules/effects", "//modules/store", - "@rxjs", - "@rxjs//operators", + "@npm//rxjs", ], ) diff --git a/modules/effects/spec/actions.spec.ts b/modules/effects/spec/actions.spec.ts index 3896590a6f..e66f65331e 100644 --- a/modules/effects/spec/actions.spec.ts +++ b/modules/effects/spec/actions.spec.ts @@ -1,4 +1,4 @@ -import { ReflectiveInjector } from '@angular/core'; +import { Injector } from '@angular/core'; import { Action, StoreModule, @@ -37,9 +37,14 @@ describe('Actions', function() { } beforeEach(function() { - const injector = ReflectiveInjector.resolveAndCreate([ - StoreModule.forRoot(reducer).providers || [], - Actions, + const injector = Injector.create([ + { + provide: ScannedActionsSubject, + useClass: ScannedActionsSubject, + deps: [], + }, + { provide: ActionsSubject, useClass: ActionsSubject, deps: [] }, + { provide: Actions, useClass: Actions, deps: [ScannedActionsSubject] }, ]); actions$ = injector.get(Actions); diff --git a/modules/effects/src/actions.ts b/modules/effects/src/actions.ts index dfb2debf93..7d24ed9a2d 100644 --- a/modules/effects/src/actions.ts +++ b/modules/effects/src/actions.ts @@ -25,8 +25,9 @@ export class Actions extends Observable { * 'ofType' filters an Observable of Actions into an observable of the actions * whose type strings are passed to it. * - * For example, `actions.pipe(ofType('add'))` returns an - * `Observable` + * For example, if `actions` has type `Actions`, and + * the type of the `Addition` action is `add`, then + * `actions.pipe(ofType('add'))` returns an `Observable`. * * Properly typing this function is hard and requires some advanced TS tricks * below. diff --git a/modules/effects/testing/BUILD b/modules/effects/testing/BUILD index 89fa302cdf..a857d9ad96 100644 --- a/modules/effects/testing/BUILD +++ b/modules/effects/testing/BUILD @@ -14,6 +14,7 @@ ng_module( visibility = ["//visibility:public"], deps = [ "//modules/effects", - "@rxjs", + "@npm//@angular/core", + "@npm//rxjs", ], ) diff --git a/modules/entity/BUILD b/modules/entity/BUILD index da0256ae0d..6f08dc13f2 100644 --- a/modules/entity/BUILD +++ b/modules/entity/BUILD @@ -12,6 +12,7 @@ ng_module( deps = [ "//modules/store", "@npm//@angular-devkit/schematics", + "@npm//@angular/core", ], ) diff --git a/modules/entity/CHANGELOG.md b/modules/entity/CHANGELOG.md index 812d089dbb..3b9c4d91aa 100644 --- a/modules/entity/CHANGELOG.md +++ b/modules/entity/CHANGELOG.md @@ -1,341 +1,3 @@ # Change Log -All notable changes to this project will be documented in this file. -See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - - -# 5.2.0 (2018-03-07) - - -### Features - -* **Entity:** Add 'selectId' and 'sortComparer' to state adapter (#889) ([69a62f2](https://github.com/ngrx/platform/commit/69a62f2)) - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Entity:** Avoid for..in iteration in sorted state adapter (#805) ([4192645](https://github.com/ngrx/platform/commit/4192645)) -* **Entity:** Do not add Array.prototype properties to store (#782) ([d537758](https://github.com/ngrx/platform/commit/d537758)), closes [#781](https://github.com/ngrx/platform/issues/781) -* **Entity:** Properly iterate over array in upsert (#802) ([779d689](https://github.com/ngrx/platform/commit/779d689)) - - -### Features - -* **Entity:** Add upsertOne and upsertMany functions to entity adapters (#780) ([f871540](https://github.com/ngrx/platform/commit/f871540)), closes [#421](https://github.com/ngrx/platform/issues/421) - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Entity:** updateOne/updateMany should not change ids state on existing entity (#581) ([b989e4b](https://github.com/ngrx/platform/commit/b989e4b)), closes [#571](https://github.com/ngrx/platform/issues/571) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Entity:** Fix type error for id selectors (#533) ([88f672c](https://github.com/ngrx/platform/commit/88f672c)), closes [#533](https://github.com/ngrx/platform/issues/533) [#525](https://github.com/ngrx/platform/issues/525) -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **Entity:** Change type for EntityState to interface (#454) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) -* **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) -* **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) - - -### Features - -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Entity:** Add support for string or number type for ID (#441) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) -* **Entity:** Enable creating entity selectors without composing a state selector (#490) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) -* **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) - - - - -## 4.0.2 (2017-08-02) - - -### Features - -* **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity (#207) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) - - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Entity:** Avoid for..in iteration in sorted state adapter (#805) ([4192645](https://github.com/ngrx/platform/commit/4192645)) -* **Entity:** Do not add Array.prototype properties to store (#782) ([d537758](https://github.com/ngrx/platform/commit/d537758)), closes [#781](https://github.com/ngrx/platform/issues/781) -* **Entity:** Properly iterate over array in upsert (#802) ([779d689](https://github.com/ngrx/platform/commit/779d689)) - - -### Features - -* **Entity:** Add upsertOne and upsertMany functions to entity adapters (#780) ([f871540](https://github.com/ngrx/platform/commit/f871540)), closes [#421](https://github.com/ngrx/platform/issues/421) - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Entity:** updateOne/updateMany should not change ids state on existing entity (#581) ([b989e4b](https://github.com/ngrx/platform/commit/b989e4b)), closes [#571](https://github.com/ngrx/platform/issues/571) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Entity:** Fix type error for id selectors (#533) ([88f672c](https://github.com/ngrx/platform/commit/88f672c)), closes [#533](https://github.com/ngrx/platform/issues/533) [#525](https://github.com/ngrx/platform/issues/525) -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **Entity:** Change type for EntityState to interface (#454) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) -* **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) -* **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) - - -### Features - -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Entity:** Add support for string or number type for ID (#441) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) -* **Entity:** Enable creating entity selectors without composing a state selector (#490) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) -* **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) - - - - -## 4.0.2 (2017-08-02) - - -### Features - -* **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity (#207) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) - - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Entity:** updateOne/updateMany should not change ids state on existing entity (#581) ([b989e4b](https://github.com/ngrx/platform/commit/b989e4b)), closes [#571](https://github.com/ngrx/platform/issues/571) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Entity:** Fix type error for id selectors (#533) ([88f672c](https://github.com/ngrx/platform/commit/88f672c)), closes [#533](https://github.com/ngrx/platform/issues/533) [#525](https://github.com/ngrx/platform/issues/525) -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **Entity:** Change type for EntityState to interface (#454) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) -* **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) -* **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) - - -### Features - -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Entity:** Add support for string or number type for ID (#441) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) -* **Entity:** Enable creating entity selectors without composing a state selector (#490) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) -* **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) - - - - -## 4.0.2 (2017-08-02) - - -### Features - -* **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity (#207) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) - - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Entity:** updateOne/updateMany should not change ids state on existing entity (#581) ([b989e4b](https://github.com/ngrx/platform/commit/b989e4b)), closes [#571](https://github.com/ngrx/platform/issues/571) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Entity:** Fix type error for id selectors (#533) ([88f672c](https://github.com/ngrx/platform/commit/88f672c)), closes [#533](https://github.com/ngrx/platform/issues/533) [#525](https://github.com/ngrx/platform/issues/525) -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **Entity:** Change type for EntityState to interface (#454) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) -* **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) -* **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) - - -### Features - -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Entity:** Add support for string or number type for ID (#441) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) -* **Entity:** Enable creating entity selectors without composing a state selector (#490) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) -* **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) - - - - -## 4.0.2 (2017-08-02) - - -### Features - -* **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity (#207) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) - - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Entity:** Fix type error for id selectors (#533) ([88f672c](https://github.com/ngrx/platform/commit/88f672c)), closes [#533](https://github.com/ngrx/platform/issues/533) [#525](https://github.com/ngrx/platform/issues/525) -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **Entity:** Change type for EntityState to interface (#454) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) -* **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) -* **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) - - -### Features - -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Entity:** Add support for string or number type for ID (#441) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) -* **Entity:** Enable creating entity selectors without composing a state selector (#490) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) -* **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) - - - - -## 4.0.2 (2017-08-02) - - -### Features - -* **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity (#207) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) - - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **Entity:** Change type for EntityState to interface (#454) ([d5640ec](https://github.com/ngrx/platform/commit/d5640ec)), closes [#458](https://github.com/ngrx/platform/issues/458) -* **Entity:** Return a referentially equal state if state did not change ([fbd6a66](https://github.com/ngrx/platform/commit/fbd6a66)) -* **Entity:** Simplify target index finder for sorted entities ([335d255](https://github.com/ngrx/platform/commit/335d255)) - - -### Features - -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Entity:** Add support for string or number type for ID (#441) ([46d6f2f](https://github.com/ngrx/platform/commit/46d6f2f)) -* **Entity:** Enable creating entity selectors without composing a state selector (#490) ([aae4064](https://github.com/ngrx/platform/commit/aae4064)) -* **Entity:** Rename 'sort' to 'sortComparer' ([274554b](https://github.com/ngrx/platform/commit/274554b)), closes [#370](https://github.com/ngrx/platform/issues/370) - - - - -## 4.0.2 (2017-08-02) - - -### Features - -* **Platform:** Introduce [@ngrx](https://github.com/ngrx)/entity (#207) ([9bdfd70](https://github.com/ngrx/platform/commit/9bdfd70)) +See [CHANGELOG.md](https://github.com/ngrx/platform/blob/master/CHANGELOG.md) diff --git a/modules/entity/schematics-core/index.ts b/modules/entity/schematics-core/index.ts index 36cc0abbcf..9608baec44 100644 --- a/modules/entity/schematics-core/index.ts +++ b/modules/entity/schematics-core/index.ts @@ -15,6 +15,7 @@ export { getDecoratorMetadata, getContentOfKeyLiteral, insertAfterLastOccurrence, + insertImport, addBootstrapToModule, addDeclarationToModule, addExportToModule, @@ -49,7 +50,6 @@ export { } from './utility/ngrx-utils'; export { getProjectPath, getProject, isLib } from './utility/project'; -export { insertImport } from './utility/route-utils'; export const stringUtils = { dasherize, diff --git a/modules/entity/schematics-core/utility/ast-utils.ts b/modules/entity/schematics-core/utility/ast-utils.ts index b1f263974e..f6174fc4b1 100644 --- a/modules/entity/schematics-core/utility/ast-utils.ts +++ b/modules/entity/schematics-core/utility/ast-utils.ts @@ -7,8 +7,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import { Change, InsertChange } from './change'; -import { insertImport } from './route-utils'; +import { Change, InsertChange, NoopChange } from './change'; /** * Find all nodes from the AST in the subtree of node of SyntaxKind kind. @@ -537,3 +536,103 @@ export function addBootstrapToModule( importPath ); } + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ + +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + const rootNode = source; + const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + + // get nodes that map to import statements from the file fileName + const relevantImports = allImports.filter(node => { + // StringLiteral of the ImportDeclaration is the import file (fileName in this case). + const importFiles = node + .getChildren() + .filter(child => child.kind === ts.SyntaxKind.StringLiteral) + .map(n => (n as ts.StringLiteral).text); + + return importFiles.filter(file => file === fileName).length === 1; + }); + + if (relevantImports.length > 0) { + let importsAsterisk = false; + // imports from import file + const imports: ts.Node[] = []; + relevantImports.forEach(n => { + Array.prototype.push.apply( + imports, + findNodes(n, ts.SyntaxKind.Identifier) + ); + if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + importsAsterisk = true; + } + }); + + // if imports * from fileName, don't add symbolName + if (importsAsterisk) { + return new NoopChange(); + } + + const importTextNodes = imports.filter( + n => (n as ts.Identifier).text === symbolName + ); + + // insert import if it's not there + if (importTextNodes.length === 0) { + const fallbackPos = + findNodes( + relevantImports[0], + ts.SyntaxKind.CloseBraceToken + )[0].getStart() || + findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + + return insertAfterLastOccurrence( + imports, + `, ${symbolName}`, + fileToEdit, + fallbackPos + ); + } + + return new NoopChange(); + } + + // no such import declaration exists + const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( + n => n.getText() === 'use strict' + ); + let fallbackPos = 0; + if (useStrict.length > 0) { + fallbackPos = useStrict[0].end; + } + const open = isDefault ? '' : '{ '; + const close = isDefault ? '' : ' }'; + // if there are no imports or 'use strict' statement, insert import at beginning of file + const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; + const separator = insertAtBeginning ? '' : ';\n'; + const toInsert = + `${separator}import ${open}${symbolName}${close}` + + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; + + return insertAfterLastOccurrence( + allImports, + toInsert, + fileToEdit, + fallbackPos, + ts.SyntaxKind.StringLiteral + ); +} diff --git a/modules/entity/schematics-core/utility/ngrx-utils.ts b/modules/entity/schematics-core/utility/ngrx-utils.ts index 28294e1110..d856f79346 100644 --- a/modules/entity/schematics-core/utility/ngrx-utils.ts +++ b/modules/entity/schematics-core/utility/ngrx-utils.ts @@ -4,8 +4,7 @@ import { InsertChange, Change, NoopChange } from './change'; import { Tree, SchematicsException, Rule } from '@angular-devkit/schematics'; import { normalize } from '@angular-devkit/core'; import { buildRelativePath } from './find-module'; -import { insertImport } from './route-utils'; -import { addImportToModule } from './ast-utils'; +import { addImportToModule, insertImport } from './ast-utils'; export function addReducerToState(options: any): Rule { return (host: Tree) => { @@ -79,7 +78,7 @@ export function addReducerToState(options: any): Rule { export function addReducerToStateInterface( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { const stateInterface = source.statements.find( stm => stm.kind === ts.SyntaxKind.InterfaceDeclaration @@ -90,11 +89,12 @@ export function addReducerToStateInterface( return new NoopChange(); } + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.State;'; + state + ': from' + stringUtils.classify(options.name) + '.State;'; const expr = node as any; let position; let toInsert; @@ -125,7 +125,7 @@ export function addReducerToStateInterface( export function addReducerToActionReducerMap( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { let initializer: any; const actionReducerMap: any = source.statements @@ -152,11 +152,12 @@ export function addReducerToActionReducerMap( let node = actionReducerMap.initializer; + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.reducer,'; + state + ': from' + stringUtils.classify(options.name) + '.reducer,'; const expr = node as any; let position; let toInsert; diff --git a/modules/entity/schematics-core/utility/project.ts b/modules/entity/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/entity/schematics-core/utility/project.ts +++ b/modules/entity/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/entity/schematics-core/utility/route-utils.ts b/modules/entity/schematics-core/utility/route-utils.ts deleted file mode 100644 index d25cc059a8..0000000000 --- a/modules/entity/schematics-core/utility/route-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as ts from 'typescript'; -import { findNodes, insertAfterLastOccurrence } from './ast-utils'; -import { Change, NoopChange } from './change'; - -/** - * Add Import `import { symbolName } from fileName` if the import doesn't exit - * already. Assumes fileToEdit can be resolved and accessed. - * @param fileToEdit (file we want to add import to) - * @param symbolName (item to import) - * @param fileName (path to the file) - * @param isDefault (if true, import follows style for importing default exports) - * @return Change - */ - -export function insertImport( - source: ts.SourceFile, - fileToEdit: string, - symbolName: string, - fileName: string, - isDefault = false -): Change { - const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); - - // get nodes that map to import statements from the file fileName - const relevantImports = allImports.filter(node => { - // StringLiteral of the ImportDeclaration is the import file (fileName in this case). - const importFiles = node - .getChildren() - .filter(child => child.kind === ts.SyntaxKind.StringLiteral) - .map(n => (n as ts.StringLiteral).text); - - return importFiles.filter(file => file === fileName).length === 1; - }); - - if (relevantImports.length > 0) { - let importsAsterisk = false; - // imports from import file - const imports: ts.Node[] = []; - relevantImports.forEach(n => { - Array.prototype.push.apply( - imports, - findNodes(n, ts.SyntaxKind.Identifier) - ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { - importsAsterisk = true; - } - }); - - // if imports * from fileName, don't add symbolName - if (importsAsterisk) { - return new NoopChange(); - } - - const importTextNodes = imports.filter( - n => (n as ts.Identifier).text === symbolName - ); - - // insert import if it's not there - if (importTextNodes.length === 0) { - const fallbackPos = - findNodes( - relevantImports[0], - ts.SyntaxKind.CloseBraceToken - )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); - - return insertAfterLastOccurrence( - imports, - `, ${symbolName}`, - fileToEdit, - fallbackPos - ); - } - - return new NoopChange(); - } - - // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - n => n.getText() === 'use strict' - ); - let fallbackPos = 0; - if (useStrict.length > 0) { - fallbackPos = useStrict[0].end; - } - const open = isDefault ? '' : '{ '; - const close = isDefault ? '' : ' }'; - // if there are no imports or 'use strict' statement, insert import at beginning of file - const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; - const separator = insertAtBeginning ? '' : ';\n'; - const toInsert = - `${separator}import ${open}${symbolName}${close}` + - ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; - - return insertAfterLastOccurrence( - allImports, - toInsert, - fileToEdit, - fallbackPos, - ts.SyntaxKind.StringLiteral - ); -} diff --git a/modules/entity/schematics-core/utility/strings.ts b/modules/entity/schematics-core/utility/strings.ts index dae37e563c..5ebec70706 100644 --- a/modules/entity/schematics-core/utility/strings.ts +++ b/modules/entity/schematics-core/utility/strings.ts @@ -110,6 +110,25 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.substr(1); } +/** + Returns the plural form of a string + + ```javascript + 'innerHTML'.pluralize() // 'InnerHTMLs' + 'action_name'.pluralize() // 'actionNames' + 'css-class-name'.pluralize() // 'cssClassNames' + 'regex'.pluralize() // 'regexes' + 'user'.pluralize() // 'users' + ``` + */ +export function pluralize(str: string): string { + return camelize( + [/([^aeiou])y$/, /()fe?$/, /([^aeiou]o|[sxz]|[cs]h)$/].map( + (c, i) => (str = str.replace(c, `$1${'iv'[i] || ''}e`)) + ) && str + 's' + ); +} + export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } diff --git a/modules/entity/spec/BUILD b/modules/entity/spec/BUILD index feec9d2d00..299a089798 100644 --- a/modules/entity/spec/BUILD +++ b/modules/entity/spec/BUILD @@ -9,8 +9,7 @@ ts_test_library( ), deps = [ "//modules/entity", - "@rxjs", - "@rxjs//operators", + "@npm//rxjs", ], ) diff --git a/modules/router-store/BUILD b/modules/router-store/BUILD index b13067f9e0..ef487bedcc 100644 --- a/modules/router-store/BUILD +++ b/modules/router-store/BUILD @@ -11,8 +11,8 @@ ng_module( module_name = "@ngrx/router-store", deps = [ "//modules/store", - "@angular//packages/router", - "@rxjs", + "@npm//@angular/router", + "@npm//rxjs", ], ) diff --git a/modules/router-store/CHANGELOG.md b/modules/router-store/CHANGELOG.md index 367513383c..3b9c4d91aa 100644 --- a/modules/router-store/CHANGELOG.md +++ b/modules/router-store/CHANGELOG.md @@ -1,492 +1,3 @@ # Change Log -All notable changes to this project will be documented in this file. -See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - - -# 5.2.0 (2018-03-07) - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **RouterStore:** Fix usage of config object if provided (#575) ([4125914](https://github.com/ngrx/platform/commit/4125914)), closes [#575](https://github.com/ngrx/platform/issues/575) -* **RouterStore:** Match RouterAction type parameters (#562) ([980a653](https://github.com/ngrx/platform/commit/980a653)) - - -### Features - -* **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) -* **StoreDevtools:** Add support for custom instance name (#517) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) - - -### BREAKING CHANGES - -* **Store:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - -### Features - -* **RouterStore:** Add configurable option for router reducer name (#417) ([ab7de5c](https://github.com/ngrx/platform/commit/ab7de5c)), closes [#410](https://github.com/ngrx/platform/issues/410) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **RouterStore:** Fix cancelled navigation with async guard (fixes #354) (#355) ([920c0ba](https://github.com/ngrx/platform/commit/920c0ba)), closes [#354](https://github.com/ngrx/platform/issues/354) [#355](https://github.com/ngrx/platform/issues/355) [#354](https://github.com/ngrx/platform/issues/354) [#201](https://github.com/ngrx/platform/issues/201) -* **RouterStore:** Stringify error from navigation error event (#357) ([0528d2d](https://github.com/ngrx/platform/commit/0528d2d)), closes [#356](https://github.com/ngrx/platform/issues/356) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **RouterStore:** Add generic type to RouterReducerState (#292) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) -* **RouterStore:** Only serialize snapshot in preactivation hook (#287) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) - - - - -## 4.0.3 (2017-08-16) - - -### Features - -* **RouterStore:** Add serializer for router state snapshot (#188) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **RouterStore:** Add support for cancellation with CanLoad guard (#223) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) - - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **RouterStore:** Fix usage of config object if provided (#575) ([4125914](https://github.com/ngrx/platform/commit/4125914)), closes [#575](https://github.com/ngrx/platform/issues/575) -* **RouterStore:** Match RouterAction type parameters (#562) ([980a653](https://github.com/ngrx/platform/commit/980a653)) - - -### Features - -* **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) -* **StoreDevtools:** Add support for custom instance name (#517) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) - - -### BREAKING CHANGES - -* **Store:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - -### Features - -* **RouterStore:** Add configurable option for router reducer name (#417) ([ab7de5c](https://github.com/ngrx/platform/commit/ab7de5c)), closes [#410](https://github.com/ngrx/platform/issues/410) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **RouterStore:** Fix cancelled navigation with async guard (fixes #354) (#355) ([920c0ba](https://github.com/ngrx/platform/commit/920c0ba)), closes [#354](https://github.com/ngrx/platform/issues/354) [#355](https://github.com/ngrx/platform/issues/355) [#354](https://github.com/ngrx/platform/issues/354) [#201](https://github.com/ngrx/platform/issues/201) -* **RouterStore:** Stringify error from navigation error event (#357) ([0528d2d](https://github.com/ngrx/platform/commit/0528d2d)), closes [#356](https://github.com/ngrx/platform/issues/356) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **RouterStore:** Add generic type to RouterReducerState (#292) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) -* **RouterStore:** Only serialize snapshot in preactivation hook (#287) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) - - - - -## 4.0.3 (2017-08-16) - - -### Features - -* **RouterStore:** Add serializer for router state snapshot (#188) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **RouterStore:** Add support for cancellation with CanLoad guard (#223) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) - - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **RouterStore:** Fix usage of config object if provided (#575) ([4125914](https://github.com/ngrx/platform/commit/4125914)), closes [#575](https://github.com/ngrx/platform/issues/575) -* **RouterStore:** Match RouterAction type parameters (#562) ([980a653](https://github.com/ngrx/platform/commit/980a653)) - - -### Features - -* **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) -* **StoreDevtools:** Add support for custom instance name (#517) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) - - -### BREAKING CHANGES - -* **Store:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - -### Features - -* **RouterStore:** Add configurable option for router reducer name (#417) ([ab7de5c](https://github.com/ngrx/platform/commit/ab7de5c)), closes [#410](https://github.com/ngrx/platform/issues/410) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **RouterStore:** Fix cancelled navigation with async guard (fixes #354) (#355) ([920c0ba](https://github.com/ngrx/platform/commit/920c0ba)), closes [#354](https://github.com/ngrx/platform/issues/354) [#355](https://github.com/ngrx/platform/issues/355) [#354](https://github.com/ngrx/platform/issues/354) [#201](https://github.com/ngrx/platform/issues/201) -* **RouterStore:** Stringify error from navigation error event (#357) ([0528d2d](https://github.com/ngrx/platform/commit/0528d2d)), closes [#356](https://github.com/ngrx/platform/issues/356) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **RouterStore:** Add generic type to RouterReducerState (#292) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) -* **RouterStore:** Only serialize snapshot in preactivation hook (#287) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) - - - - -## 4.0.3 (2017-08-16) - - -### Features - -* **RouterStore:** Add serializer for router state snapshot (#188) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **RouterStore:** Add support for cancellation with CanLoad guard (#223) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) - - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - -### Features - -* **RouterStore:** Add configurable option for router reducer name (#417) ([ab7de5c](https://github.com/ngrx/platform/commit/ab7de5c)), closes [#410](https://github.com/ngrx/platform/issues/410) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **RouterStore:** Fix cancelled navigation with async guard (fixes #354) (#355) ([920c0ba](https://github.com/ngrx/platform/commit/920c0ba)), closes [#354](https://github.com/ngrx/platform/issues/354) [#355](https://github.com/ngrx/platform/issues/355) [#354](https://github.com/ngrx/platform/issues/354) [#201](https://github.com/ngrx/platform/issues/201) -* **RouterStore:** Stringify error from navigation error event (#357) ([0528d2d](https://github.com/ngrx/platform/commit/0528d2d)), closes [#356](https://github.com/ngrx/platform/issues/356) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **RouterStore:** Add generic type to RouterReducerState (#292) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) -* **RouterStore:** Only serialize snapshot in preactivation hook (#287) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) - - - - -## 4.0.3 (2017-08-16) - - -### Features - -* **RouterStore:** Add serializer for router state snapshot (#188) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **RouterStore:** Add support for cancellation with CanLoad guard (#223) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) - - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **RouterStore:** Fix cancelled navigation with async guard (fixes #354) (#355) ([920c0ba](https://github.com/ngrx/platform/commit/920c0ba)), closes [#354](https://github.com/ngrx/platform/issues/354) [#355](https://github.com/ngrx/platform/issues/355) [#354](https://github.com/ngrx/platform/issues/354) [#201](https://github.com/ngrx/platform/issues/201) -* **RouterStore:** Stringify error from navigation error event (#357) ([0528d2d](https://github.com/ngrx/platform/commit/0528d2d)), closes [#356](https://github.com/ngrx/platform/issues/356) - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **RouterStore:** Add generic type to RouterReducerState (#292) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) -* **RouterStore:** Only serialize snapshot in preactivation hook (#287) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) - - - - -## 4.0.3 (2017-08-16) - - -### Features - -* **RouterStore:** Add serializer for router state snapshot (#188) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **RouterStore:** Add support for cancellation with CanLoad guard (#223) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) - - - - - -## 4.0.4 (2017-08-17) - - -### Bug Fixes - -* **RouterStore:** Add generic type to RouterReducerState (#292) ([6da3ec5](https://github.com/ngrx/platform/commit/6da3ec5)), closes [#289](https://github.com/ngrx/platform/issues/289) -* **RouterStore:** Only serialize snapshot in preactivation hook (#287) ([bbb7c99](https://github.com/ngrx/platform/commit/bbb7c99)), closes [#286](https://github.com/ngrx/platform/issues/286) - - - - -## 4.0.3 (2017-08-16) - - -### Features - -* **RouterStore:** Add serializer for router state snapshot (#188) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **RouterStore:** Add support for cancellation with CanLoad guard (#223) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) - - - - - -## 4.0.3 (2017-08-16) - - -### Features - -* **RouterStore:** Add serializer for router state snapshot (#188) ([0fc1bcc](https://github.com/ngrx/platform/commit/0fc1bcc)), closes [#97](https://github.com/ngrx/platform/issues/97) [#104](https://github.com/ngrx/platform/issues/104) [#237](https://github.com/ngrx/platform/issues/237) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) -* **RouterStore:** Add support for cancellation with CanLoad guard (#223) ([2c006e8](https://github.com/ngrx/platform/commit/2c006e8)), closes [#213](https://github.com/ngrx/platform/issues/213) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) - - - - - -# 4.0.0 (2017-07-18) - - -### Bug Fixes - -* **router-store:** NavigationCancel and NavigationError creates a cycle when used with routerReducer ([a085730](https://github.com/ngrx/platform/commit/a085730)), closes [#68](https://github.com/ngrx/platform/issues/68) - - -### Features - -* **router-store:** Added action types (#47) ([1f67cb3](https://github.com/ngrx/platform/commit/1f67cb3)), closes [#44](https://github.com/ngrx/platform/issues/44) +See [CHANGELOG.md](https://github.com/ngrx/platform/blob/master/CHANGELOG.md) diff --git a/modules/router-store/schematics-core/index.ts b/modules/router-store/schematics-core/index.ts index 36cc0abbcf..9608baec44 100644 --- a/modules/router-store/schematics-core/index.ts +++ b/modules/router-store/schematics-core/index.ts @@ -15,6 +15,7 @@ export { getDecoratorMetadata, getContentOfKeyLiteral, insertAfterLastOccurrence, + insertImport, addBootstrapToModule, addDeclarationToModule, addExportToModule, @@ -49,7 +50,6 @@ export { } from './utility/ngrx-utils'; export { getProjectPath, getProject, isLib } from './utility/project'; -export { insertImport } from './utility/route-utils'; export const stringUtils = { dasherize, diff --git a/modules/router-store/schematics-core/utility/ast-utils.ts b/modules/router-store/schematics-core/utility/ast-utils.ts index b1f263974e..f6174fc4b1 100644 --- a/modules/router-store/schematics-core/utility/ast-utils.ts +++ b/modules/router-store/schematics-core/utility/ast-utils.ts @@ -7,8 +7,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import { Change, InsertChange } from './change'; -import { insertImport } from './route-utils'; +import { Change, InsertChange, NoopChange } from './change'; /** * Find all nodes from the AST in the subtree of node of SyntaxKind kind. @@ -537,3 +536,103 @@ export function addBootstrapToModule( importPath ); } + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ + +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + const rootNode = source; + const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + + // get nodes that map to import statements from the file fileName + const relevantImports = allImports.filter(node => { + // StringLiteral of the ImportDeclaration is the import file (fileName in this case). + const importFiles = node + .getChildren() + .filter(child => child.kind === ts.SyntaxKind.StringLiteral) + .map(n => (n as ts.StringLiteral).text); + + return importFiles.filter(file => file === fileName).length === 1; + }); + + if (relevantImports.length > 0) { + let importsAsterisk = false; + // imports from import file + const imports: ts.Node[] = []; + relevantImports.forEach(n => { + Array.prototype.push.apply( + imports, + findNodes(n, ts.SyntaxKind.Identifier) + ); + if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + importsAsterisk = true; + } + }); + + // if imports * from fileName, don't add symbolName + if (importsAsterisk) { + return new NoopChange(); + } + + const importTextNodes = imports.filter( + n => (n as ts.Identifier).text === symbolName + ); + + // insert import if it's not there + if (importTextNodes.length === 0) { + const fallbackPos = + findNodes( + relevantImports[0], + ts.SyntaxKind.CloseBraceToken + )[0].getStart() || + findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + + return insertAfterLastOccurrence( + imports, + `, ${symbolName}`, + fileToEdit, + fallbackPos + ); + } + + return new NoopChange(); + } + + // no such import declaration exists + const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( + n => n.getText() === 'use strict' + ); + let fallbackPos = 0; + if (useStrict.length > 0) { + fallbackPos = useStrict[0].end; + } + const open = isDefault ? '' : '{ '; + const close = isDefault ? '' : ' }'; + // if there are no imports or 'use strict' statement, insert import at beginning of file + const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; + const separator = insertAtBeginning ? '' : ';\n'; + const toInsert = + `${separator}import ${open}${symbolName}${close}` + + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; + + return insertAfterLastOccurrence( + allImports, + toInsert, + fileToEdit, + fallbackPos, + ts.SyntaxKind.StringLiteral + ); +} diff --git a/modules/router-store/schematics-core/utility/ngrx-utils.ts b/modules/router-store/schematics-core/utility/ngrx-utils.ts index 28294e1110..d856f79346 100644 --- a/modules/router-store/schematics-core/utility/ngrx-utils.ts +++ b/modules/router-store/schematics-core/utility/ngrx-utils.ts @@ -4,8 +4,7 @@ import { InsertChange, Change, NoopChange } from './change'; import { Tree, SchematicsException, Rule } from '@angular-devkit/schematics'; import { normalize } from '@angular-devkit/core'; import { buildRelativePath } from './find-module'; -import { insertImport } from './route-utils'; -import { addImportToModule } from './ast-utils'; +import { addImportToModule, insertImport } from './ast-utils'; export function addReducerToState(options: any): Rule { return (host: Tree) => { @@ -79,7 +78,7 @@ export function addReducerToState(options: any): Rule { export function addReducerToStateInterface( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { const stateInterface = source.statements.find( stm => stm.kind === ts.SyntaxKind.InterfaceDeclaration @@ -90,11 +89,12 @@ export function addReducerToStateInterface( return new NoopChange(); } + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.State;'; + state + ': from' + stringUtils.classify(options.name) + '.State;'; const expr = node as any; let position; let toInsert; @@ -125,7 +125,7 @@ export function addReducerToStateInterface( export function addReducerToActionReducerMap( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { let initializer: any; const actionReducerMap: any = source.statements @@ -152,11 +152,12 @@ export function addReducerToActionReducerMap( let node = actionReducerMap.initializer; + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.reducer,'; + state + ': from' + stringUtils.classify(options.name) + '.reducer,'; const expr = node as any; let position; let toInsert; diff --git a/modules/router-store/schematics-core/utility/project.ts b/modules/router-store/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/router-store/schematics-core/utility/project.ts +++ b/modules/router-store/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/router-store/schematics-core/utility/route-utils.ts b/modules/router-store/schematics-core/utility/route-utils.ts deleted file mode 100644 index d25cc059a8..0000000000 --- a/modules/router-store/schematics-core/utility/route-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as ts from 'typescript'; -import { findNodes, insertAfterLastOccurrence } from './ast-utils'; -import { Change, NoopChange } from './change'; - -/** - * Add Import `import { symbolName } from fileName` if the import doesn't exit - * already. Assumes fileToEdit can be resolved and accessed. - * @param fileToEdit (file we want to add import to) - * @param symbolName (item to import) - * @param fileName (path to the file) - * @param isDefault (if true, import follows style for importing default exports) - * @return Change - */ - -export function insertImport( - source: ts.SourceFile, - fileToEdit: string, - symbolName: string, - fileName: string, - isDefault = false -): Change { - const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); - - // get nodes that map to import statements from the file fileName - const relevantImports = allImports.filter(node => { - // StringLiteral of the ImportDeclaration is the import file (fileName in this case). - const importFiles = node - .getChildren() - .filter(child => child.kind === ts.SyntaxKind.StringLiteral) - .map(n => (n as ts.StringLiteral).text); - - return importFiles.filter(file => file === fileName).length === 1; - }); - - if (relevantImports.length > 0) { - let importsAsterisk = false; - // imports from import file - const imports: ts.Node[] = []; - relevantImports.forEach(n => { - Array.prototype.push.apply( - imports, - findNodes(n, ts.SyntaxKind.Identifier) - ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { - importsAsterisk = true; - } - }); - - // if imports * from fileName, don't add symbolName - if (importsAsterisk) { - return new NoopChange(); - } - - const importTextNodes = imports.filter( - n => (n as ts.Identifier).text === symbolName - ); - - // insert import if it's not there - if (importTextNodes.length === 0) { - const fallbackPos = - findNodes( - relevantImports[0], - ts.SyntaxKind.CloseBraceToken - )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); - - return insertAfterLastOccurrence( - imports, - `, ${symbolName}`, - fileToEdit, - fallbackPos - ); - } - - return new NoopChange(); - } - - // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - n => n.getText() === 'use strict' - ); - let fallbackPos = 0; - if (useStrict.length > 0) { - fallbackPos = useStrict[0].end; - } - const open = isDefault ? '' : '{ '; - const close = isDefault ? '' : ' }'; - // if there are no imports or 'use strict' statement, insert import at beginning of file - const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; - const separator = insertAtBeginning ? '' : ';\n'; - const toInsert = - `${separator}import ${open}${symbolName}${close}` + - ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; - - return insertAfterLastOccurrence( - allImports, - toInsert, - fileToEdit, - fallbackPos, - ts.SyntaxKind.StringLiteral - ); -} diff --git a/modules/router-store/schematics-core/utility/strings.ts b/modules/router-store/schematics-core/utility/strings.ts index dae37e563c..5ebec70706 100644 --- a/modules/router-store/schematics-core/utility/strings.ts +++ b/modules/router-store/schematics-core/utility/strings.ts @@ -110,6 +110,25 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.substr(1); } +/** + Returns the plural form of a string + + ```javascript + 'innerHTML'.pluralize() // 'InnerHTMLs' + 'action_name'.pluralize() // 'actionNames' + 'css-class-name'.pluralize() // 'cssClassNames' + 'regex'.pluralize() // 'regexes' + 'user'.pluralize() // 'users' + ``` + */ +export function pluralize(str: string): string { + return camelize( + [/([^aeiou])y$/, /()fe?$/, /([^aeiou]o|[sxz]|[cs]h)$/].map( + (c, i) => (str = str.replace(c, `$1${'iv'[i] || ''}e`)) + ) && str + 's' + ); +} + export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } diff --git a/modules/router-store/spec/BUILD b/modules/router-store/spec/BUILD index 3c3dd56903..bc244c6c61 100644 --- a/modules/router-store/spec/BUILD +++ b/modules/router-store/spec/BUILD @@ -10,10 +10,8 @@ ts_test_library( deps = [ "//modules/router-store", "//modules/store", - "@angular//packages/router", - "@angular//packages/router/testing", - "@rxjs", - "@rxjs//operators", + "@npm//@angular/router", + "@npm//rxjs", ], ) diff --git a/modules/router-store/spec/integration.spec.ts b/modules/router-store/spec/integration.spec.ts index dcaf4607c5..822b907346 100644 --- a/modules/router-store/spec/integration.spec.ts +++ b/modules/router-store/spec/integration.spec.ts @@ -253,7 +253,13 @@ describe('integration spec', () => { } else { const nextState = routerReducer(state, action); if (nextState && nextState.state) { - nextState.state.root = {}; + return { + ...nextState, + state: { + ...nextState.state, + root: {} as any, + }, + }; } return nextState; } @@ -383,7 +389,13 @@ describe('integration spec', () => { } else { const nextState = routerReducer(state, action); if (nextState && nextState.state) { - nextState.state.root = {}; + return { + ...nextState, + state: { + ...nextState.state, + root: {} as any, + }, + }; } return nextState; } diff --git a/modules/schematics-core/BUILD.bazel b/modules/schematics-core/BUILD.bazel new file mode 100644 index 0000000000..01f4701f2b --- /dev/null +++ b/modules/schematics-core/BUILD.bazel @@ -0,0 +1,17 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "schematics-core", + srcs = glob( + [ + "**/*.ts", + ], + ), + deps = [ + "@npm//@angular-devkit/core", + "@npm//@angular-devkit/schematics", + "@npm//typescript", + ], +) diff --git a/modules/schematics-core/index.ts b/modules/schematics-core/index.ts index 36cc0abbcf..9608baec44 100644 --- a/modules/schematics-core/index.ts +++ b/modules/schematics-core/index.ts @@ -15,6 +15,7 @@ export { getDecoratorMetadata, getContentOfKeyLiteral, insertAfterLastOccurrence, + insertImport, addBootstrapToModule, addDeclarationToModule, addExportToModule, @@ -49,7 +50,6 @@ export { } from './utility/ngrx-utils'; export { getProjectPath, getProject, isLib } from './utility/project'; -export { insertImport } from './utility/route-utils'; export const stringUtils = { dasherize, diff --git a/modules/schematics-core/testing/create-workspace.ts b/modules/schematics-core/testing/create-workspace.ts index 0bebb4d576..83e563f48f 100644 --- a/modules/schematics-core/testing/create-workspace.ts +++ b/modules/schematics-core/testing/create-workspace.ts @@ -7,6 +7,7 @@ export const defaultWorkspaceOptions = { name: 'workspace', newProjectRoot: 'projects', version: '6.0.0', + defaultProject: 'bar', }; export const defaultAppOptions = { diff --git a/modules/schematics-core/utility/ast-utils.ts b/modules/schematics-core/utility/ast-utils.ts index b1f263974e..f6174fc4b1 100644 --- a/modules/schematics-core/utility/ast-utils.ts +++ b/modules/schematics-core/utility/ast-utils.ts @@ -7,8 +7,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import { Change, InsertChange } from './change'; -import { insertImport } from './route-utils'; +import { Change, InsertChange, NoopChange } from './change'; /** * Find all nodes from the AST in the subtree of node of SyntaxKind kind. @@ -537,3 +536,103 @@ export function addBootstrapToModule( importPath ); } + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ + +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + const rootNode = source; + const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + + // get nodes that map to import statements from the file fileName + const relevantImports = allImports.filter(node => { + // StringLiteral of the ImportDeclaration is the import file (fileName in this case). + const importFiles = node + .getChildren() + .filter(child => child.kind === ts.SyntaxKind.StringLiteral) + .map(n => (n as ts.StringLiteral).text); + + return importFiles.filter(file => file === fileName).length === 1; + }); + + if (relevantImports.length > 0) { + let importsAsterisk = false; + // imports from import file + const imports: ts.Node[] = []; + relevantImports.forEach(n => { + Array.prototype.push.apply( + imports, + findNodes(n, ts.SyntaxKind.Identifier) + ); + if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + importsAsterisk = true; + } + }); + + // if imports * from fileName, don't add symbolName + if (importsAsterisk) { + return new NoopChange(); + } + + const importTextNodes = imports.filter( + n => (n as ts.Identifier).text === symbolName + ); + + // insert import if it's not there + if (importTextNodes.length === 0) { + const fallbackPos = + findNodes( + relevantImports[0], + ts.SyntaxKind.CloseBraceToken + )[0].getStart() || + findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + + return insertAfterLastOccurrence( + imports, + `, ${symbolName}`, + fileToEdit, + fallbackPos + ); + } + + return new NoopChange(); + } + + // no such import declaration exists + const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( + n => n.getText() === 'use strict' + ); + let fallbackPos = 0; + if (useStrict.length > 0) { + fallbackPos = useStrict[0].end; + } + const open = isDefault ? '' : '{ '; + const close = isDefault ? '' : ' }'; + // if there are no imports or 'use strict' statement, insert import at beginning of file + const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; + const separator = insertAtBeginning ? '' : ';\n'; + const toInsert = + `${separator}import ${open}${symbolName}${close}` + + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; + + return insertAfterLastOccurrence( + allImports, + toInsert, + fileToEdit, + fallbackPos, + ts.SyntaxKind.StringLiteral + ); +} diff --git a/modules/schematics-core/utility/ngrx-utils.ts b/modules/schematics-core/utility/ngrx-utils.ts index 28294e1110..d856f79346 100644 --- a/modules/schematics-core/utility/ngrx-utils.ts +++ b/modules/schematics-core/utility/ngrx-utils.ts @@ -4,8 +4,7 @@ import { InsertChange, Change, NoopChange } from './change'; import { Tree, SchematicsException, Rule } from '@angular-devkit/schematics'; import { normalize } from '@angular-devkit/core'; import { buildRelativePath } from './find-module'; -import { insertImport } from './route-utils'; -import { addImportToModule } from './ast-utils'; +import { addImportToModule, insertImport } from './ast-utils'; export function addReducerToState(options: any): Rule { return (host: Tree) => { @@ -79,7 +78,7 @@ export function addReducerToState(options: any): Rule { export function addReducerToStateInterface( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { const stateInterface = source.statements.find( stm => stm.kind === ts.SyntaxKind.InterfaceDeclaration @@ -90,11 +89,12 @@ export function addReducerToStateInterface( return new NoopChange(); } + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.State;'; + state + ': from' + stringUtils.classify(options.name) + '.State;'; const expr = node as any; let position; let toInsert; @@ -125,7 +125,7 @@ export function addReducerToStateInterface( export function addReducerToActionReducerMap( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { let initializer: any; const actionReducerMap: any = source.statements @@ -152,11 +152,12 @@ export function addReducerToActionReducerMap( let node = actionReducerMap.initializer; + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.reducer,'; + state + ': from' + stringUtils.classify(options.name) + '.reducer,'; const expr = node as any; let position; let toInsert; diff --git a/modules/schematics-core/utility/project.ts b/modules/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/schematics-core/utility/project.ts +++ b/modules/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/schematics-core/utility/route-utils.ts b/modules/schematics-core/utility/route-utils.ts deleted file mode 100644 index d25cc059a8..0000000000 --- a/modules/schematics-core/utility/route-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as ts from 'typescript'; -import { findNodes, insertAfterLastOccurrence } from './ast-utils'; -import { Change, NoopChange } from './change'; - -/** - * Add Import `import { symbolName } from fileName` if the import doesn't exit - * already. Assumes fileToEdit can be resolved and accessed. - * @param fileToEdit (file we want to add import to) - * @param symbolName (item to import) - * @param fileName (path to the file) - * @param isDefault (if true, import follows style for importing default exports) - * @return Change - */ - -export function insertImport( - source: ts.SourceFile, - fileToEdit: string, - symbolName: string, - fileName: string, - isDefault = false -): Change { - const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); - - // get nodes that map to import statements from the file fileName - const relevantImports = allImports.filter(node => { - // StringLiteral of the ImportDeclaration is the import file (fileName in this case). - const importFiles = node - .getChildren() - .filter(child => child.kind === ts.SyntaxKind.StringLiteral) - .map(n => (n as ts.StringLiteral).text); - - return importFiles.filter(file => file === fileName).length === 1; - }); - - if (relevantImports.length > 0) { - let importsAsterisk = false; - // imports from import file - const imports: ts.Node[] = []; - relevantImports.forEach(n => { - Array.prototype.push.apply( - imports, - findNodes(n, ts.SyntaxKind.Identifier) - ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { - importsAsterisk = true; - } - }); - - // if imports * from fileName, don't add symbolName - if (importsAsterisk) { - return new NoopChange(); - } - - const importTextNodes = imports.filter( - n => (n as ts.Identifier).text === symbolName - ); - - // insert import if it's not there - if (importTextNodes.length === 0) { - const fallbackPos = - findNodes( - relevantImports[0], - ts.SyntaxKind.CloseBraceToken - )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); - - return insertAfterLastOccurrence( - imports, - `, ${symbolName}`, - fileToEdit, - fallbackPos - ); - } - - return new NoopChange(); - } - - // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - n => n.getText() === 'use strict' - ); - let fallbackPos = 0; - if (useStrict.length > 0) { - fallbackPos = useStrict[0].end; - } - const open = isDefault ? '' : '{ '; - const close = isDefault ? '' : ' }'; - // if there are no imports or 'use strict' statement, insert import at beginning of file - const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; - const separator = insertAtBeginning ? '' : ';\n'; - const toInsert = - `${separator}import ${open}${symbolName}${close}` + - ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; - - return insertAfterLastOccurrence( - allImports, - toInsert, - fileToEdit, - fallbackPos, - ts.SyntaxKind.StringLiteral - ); -} diff --git a/modules/schematics-core/utility/strings.ts b/modules/schematics-core/utility/strings.ts index dae37e563c..5ebec70706 100644 --- a/modules/schematics-core/utility/strings.ts +++ b/modules/schematics-core/utility/strings.ts @@ -110,6 +110,25 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.substr(1); } +/** + Returns the plural form of a string + + ```javascript + 'innerHTML'.pluralize() // 'InnerHTMLs' + 'action_name'.pluralize() // 'actionNames' + 'css-class-name'.pluralize() // 'cssClassNames' + 'regex'.pluralize() // 'regexes' + 'user'.pluralize() // 'users' + ``` + */ +export function pluralize(str: string): string { + return camelize( + [/([^aeiou])y$/, /()fe?$/, /([^aeiou]o|[sxz]|[cs]h)$/].map( + (c, i) => (str = str.replace(c, `$1${'iv'[i] || ''}e`)) + ) && str + 's' + ); +} + export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } diff --git a/modules/schematics/BUILD b/modules/schematics/BUILD index a78273aaa9..05625f59f0 100644 --- a/modules/schematics/BUILD +++ b/modules/schematics/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "npm_package", "ts_library") +load("//tools:defaults.bzl", "jasmine_node_test", "npm_package", "ts_library", "ts_test_library") ts_library( name = "schematics", @@ -41,3 +41,29 @@ npm_package( ":schematics", ], ) + +ts_test_library( + name = "test_lib", + srcs = glob( + [ + "**/*.spec.ts", + ], + ), + data = glob([ + "**/src/*/files/**/*", + "**/*.json", + ]), + deps = [ + ":schematics", + "//modules/schematics-core", + "@npm//@angular-devkit/schematics", + "@npm//@schematics/angular", + ], +) + +jasmine_node_test( + name = "test", + deps = [ + ":test_lib", + ], +) diff --git a/modules/schematics/CHANGELOG.md b/modules/schematics/CHANGELOG.md index 3dce0fae6f..3b9c4d91aa 100644 --- a/modules/schematics/CHANGELOG.md +++ b/modules/schematics/CHANGELOG.md @@ -1,121 +1,3 @@ # Change Log -All notable changes to this project will be documented in this file. -See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - - -# 5.2.0 (2018-03-07) - - -### Bug Fixes - -* **Schematics:** Correct usage of upsert actions for entity blueprint (#821) ([1ffb5a9](https://github.com/ngrx/platform/commit/1ffb5a9)) - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Effects:** Make ofType operator strictFunctionTypes safe (#789) ([c8560e4](https://github.com/ngrx/platform/commit/c8560e4)), closes [#753](https://github.com/ngrx/platform/issues/753) -* **Schematics:** Add store import to container blueprint (#763) ([a140fa9](https://github.com/ngrx/platform/commit/a140fa9)), closes [#760](https://github.com/ngrx/platform/issues/760) -* **Schematics:** Remove extra braces from constructor for container blueprint (#791) ([945bf40](https://github.com/ngrx/platform/commit/945bf40)), closes [#778](https://github.com/ngrx/platform/issues/778) -* **Schematics:** Use correct paths for nested and grouped feature blueprint (#756) ([c219770](https://github.com/ngrx/platform/commit/c219770)) - - -### Features - -* **Schematics:** Add group option to entity blueprint (#792) ([0429276](https://github.com/ngrx/platform/commit/0429276)), closes [#779](https://github.com/ngrx/platform/issues/779) -* **Schematics:** Add upsert methods to entity blueprint (#809) ([7acdc79](https://github.com/ngrx/platform/commit/7acdc79)), closes [#592](https://github.com/ngrx/platform/issues/592) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Schematics:** Add group folder after feature name folder (#737) ([317fb94](https://github.com/ngrx/platform/commit/317fb94)) -* **Schematics:** Add handling of flat option to entity blueprint ([fb8d2c6](https://github.com/ngrx/platform/commit/fb8d2c6)) -* **Schematics:** Distinguish between root and feature effect arrays when registering (#718) ([95ff6c8](https://github.com/ngrx/platform/commit/95ff6c8)) -* **Schematics:** Don't add state import if not provided (#697) ([e5c2aed](https://github.com/ngrx/platform/commit/e5c2aed)) -* **Schematics:** Make variable naming consistent for entity blueprint (#716) ([765b15a](https://github.com/ngrx/platform/commit/765b15a)) - - -### Features - -* **Schematics:** Add alias for container, store and action blueprints (#685) ([dc64ac9](https://github.com/ngrx/platform/commit/dc64ac9)) -* **Schematics:** Add alias for reducer blueprint (#684) ([ea98fb7](https://github.com/ngrx/platform/commit/ea98fb7)) -* **Schematics:** Add effect to registered effects array (#717) ([f1082fe](https://github.com/ngrx/platform/commit/f1082fe)) -* **Schematics:** Add option to group feature blueprints in respective folders (#736) ([b82c35d](https://github.com/ngrx/platform/commit/b82c35d)) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) - - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Effects:** Make ofType operator strictFunctionTypes safe (#789) ([c8560e4](https://github.com/ngrx/platform/commit/c8560e4)), closes [#753](https://github.com/ngrx/platform/issues/753) -* **Schematics:** Add store import to container blueprint (#763) ([a140fa9](https://github.com/ngrx/platform/commit/a140fa9)), closes [#760](https://github.com/ngrx/platform/issues/760) -* **Schematics:** Remove extra braces from constructor for container blueprint (#791) ([945bf40](https://github.com/ngrx/platform/commit/945bf40)), closes [#778](https://github.com/ngrx/platform/issues/778) -* **Schematics:** Use correct paths for nested and grouped feature blueprint (#756) ([c219770](https://github.com/ngrx/platform/commit/c219770)) - - -### Features - -* **Schematics:** Add group option to entity blueprint (#792) ([0429276](https://github.com/ngrx/platform/commit/0429276)), closes [#779](https://github.com/ngrx/platform/issues/779) -* **Schematics:** Add upsert methods to entity blueprint (#809) ([7acdc79](https://github.com/ngrx/platform/commit/7acdc79)), closes [#592](https://github.com/ngrx/platform/issues/592) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Schematics:** Add group folder after feature name folder (#737) ([317fb94](https://github.com/ngrx/platform/commit/317fb94)) -* **Schematics:** Add handling of flat option to entity blueprint ([fb8d2c6](https://github.com/ngrx/platform/commit/fb8d2c6)) -* **Schematics:** Distinguish between root and feature effect arrays when registering (#718) ([95ff6c8](https://github.com/ngrx/platform/commit/95ff6c8)) -* **Schematics:** Don't add state import if not provided (#697) ([e5c2aed](https://github.com/ngrx/platform/commit/e5c2aed)) -* **Schematics:** Make variable naming consistent for entity blueprint (#716) ([765b15a](https://github.com/ngrx/platform/commit/765b15a)) - - -### Features - -* **Schematics:** Add alias for container, store and action blueprints (#685) ([dc64ac9](https://github.com/ngrx/platform/commit/dc64ac9)) -* **Schematics:** Add alias for reducer blueprint (#684) ([ea98fb7](https://github.com/ngrx/platform/commit/ea98fb7)) -* **Schematics:** Add effect to registered effects array (#717) ([f1082fe](https://github.com/ngrx/platform/commit/f1082fe)) -* **Schematics:** Add option to group feature blueprints in respective folders (#736) ([b82c35d](https://github.com/ngrx/platform/commit/b82c35d)) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) - - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Schematics:** Add group folder after feature name folder (#737) ([317fb94](https://github.com/ngrx/platform/commit/317fb94)) -* **Schematics:** Add handling of flat option to entity blueprint ([fb8d2c6](https://github.com/ngrx/platform/commit/fb8d2c6)) -* **Schematics:** Distinguish between root and feature effect arrays when registering (#718) ([95ff6c8](https://github.com/ngrx/platform/commit/95ff6c8)) -* **Schematics:** Don't add state import if not provided (#697) ([e5c2aed](https://github.com/ngrx/platform/commit/e5c2aed)) -* **Schematics:** Make variable naming consistent for entity blueprint (#716) ([765b15a](https://github.com/ngrx/platform/commit/765b15a)) - - -### Features - -* **Schematics:** Add alias for container, store and action blueprints (#685) ([dc64ac9](https://github.com/ngrx/platform/commit/dc64ac9)) -* **Schematics:** Add alias for reducer blueprint (#684) ([ea98fb7](https://github.com/ngrx/platform/commit/ea98fb7)) -* **Schematics:** Add effect to registered effects array (#717) ([f1082fe](https://github.com/ngrx/platform/commit/f1082fe)) -* **Schematics:** Add option to group feature blueprints in respective folders (#736) ([b82c35d](https://github.com/ngrx/platform/commit/b82c35d)) -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) +See [CHANGELOG.md](https://github.com/ngrx/platform/blob/master/CHANGELOG.md) diff --git a/modules/schematics/collection.json b/modules/schematics/collection.json index 9a87c2e259..fd19a4c03d 100644 --- a/modules/schematics/collection.json +++ b/modules/schematics/collection.json @@ -2,52 +2,59 @@ "extends": ["@schematics/angular"], "schematics": { "action": { - "aliases": [ "a" ], + "aliases": ["a"], "factory": "./src/action", "schema": "./src/action/schema.json", "description": "Add store actions" }, "container": { - "aliases": [ "co" ], + "aliases": ["co"], "factory": "./src/container", "schema": "./src/container/schema.json", "description": "Add store container component" }, "effect": { - "aliases": [ "ef" ], + "aliases": ["ef"], "factory": "./src/effect", "schema": "./src/effect/schema.json", "description": "Add side effect class" }, "entity": { - "aliases": [ "en" ], + "aliases": ["en"], "factory": "./src/entity", "schema": "./src/entity/schema.json", "description": "Add entity state" }, "feature": { - "aliases": [ "f" ], + "aliases": ["f"], "factory": "./src/feature", "schema": "./src/feature/schema.json", "description": "Add feature state" }, "reducer": { - "aliases": [ "r" ], + "aliases": ["r"], "factory": "./src/reducer", "schema": "./src/reducer/schema.json", "description": "Add state reducer" }, "store": { - "aliases": [ "st" ], + "aliases": ["st"], "factory": "./src/store", "schema": "./src/store/schema.json", - "description": "Adds initial setup for state managment" + "description": "Adds initial setup for state management" + }, + + "ng-add": { + "aliases": ["init"], + "factory": "./src/ng-add", + "schema": "./src/ng-add/schema.json", + "description": "Installs the NgRx schematics package" } } } diff --git a/modules/schematics/schematics-core/index.ts b/modules/schematics/schematics-core/index.ts index 36cc0abbcf..9608baec44 100644 --- a/modules/schematics/schematics-core/index.ts +++ b/modules/schematics/schematics-core/index.ts @@ -15,6 +15,7 @@ export { getDecoratorMetadata, getContentOfKeyLiteral, insertAfterLastOccurrence, + insertImport, addBootstrapToModule, addDeclarationToModule, addExportToModule, @@ -49,7 +50,6 @@ export { } from './utility/ngrx-utils'; export { getProjectPath, getProject, isLib } from './utility/project'; -export { insertImport } from './utility/route-utils'; export const stringUtils = { dasherize, diff --git a/modules/schematics/schematics-core/utility/ast-utils.ts b/modules/schematics/schematics-core/utility/ast-utils.ts index b1f263974e..f6174fc4b1 100644 --- a/modules/schematics/schematics-core/utility/ast-utils.ts +++ b/modules/schematics/schematics-core/utility/ast-utils.ts @@ -7,8 +7,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import { Change, InsertChange } from './change'; -import { insertImport } from './route-utils'; +import { Change, InsertChange, NoopChange } from './change'; /** * Find all nodes from the AST in the subtree of node of SyntaxKind kind. @@ -537,3 +536,103 @@ export function addBootstrapToModule( importPath ); } + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ + +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + const rootNode = source; + const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + + // get nodes that map to import statements from the file fileName + const relevantImports = allImports.filter(node => { + // StringLiteral of the ImportDeclaration is the import file (fileName in this case). + const importFiles = node + .getChildren() + .filter(child => child.kind === ts.SyntaxKind.StringLiteral) + .map(n => (n as ts.StringLiteral).text); + + return importFiles.filter(file => file === fileName).length === 1; + }); + + if (relevantImports.length > 0) { + let importsAsterisk = false; + // imports from import file + const imports: ts.Node[] = []; + relevantImports.forEach(n => { + Array.prototype.push.apply( + imports, + findNodes(n, ts.SyntaxKind.Identifier) + ); + if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + importsAsterisk = true; + } + }); + + // if imports * from fileName, don't add symbolName + if (importsAsterisk) { + return new NoopChange(); + } + + const importTextNodes = imports.filter( + n => (n as ts.Identifier).text === symbolName + ); + + // insert import if it's not there + if (importTextNodes.length === 0) { + const fallbackPos = + findNodes( + relevantImports[0], + ts.SyntaxKind.CloseBraceToken + )[0].getStart() || + findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + + return insertAfterLastOccurrence( + imports, + `, ${symbolName}`, + fileToEdit, + fallbackPos + ); + } + + return new NoopChange(); + } + + // no such import declaration exists + const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( + n => n.getText() === 'use strict' + ); + let fallbackPos = 0; + if (useStrict.length > 0) { + fallbackPos = useStrict[0].end; + } + const open = isDefault ? '' : '{ '; + const close = isDefault ? '' : ' }'; + // if there are no imports or 'use strict' statement, insert import at beginning of file + const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; + const separator = insertAtBeginning ? '' : ';\n'; + const toInsert = + `${separator}import ${open}${symbolName}${close}` + + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; + + return insertAfterLastOccurrence( + allImports, + toInsert, + fileToEdit, + fallbackPos, + ts.SyntaxKind.StringLiteral + ); +} diff --git a/modules/schematics/schematics-core/utility/ngrx-utils.ts b/modules/schematics/schematics-core/utility/ngrx-utils.ts index 28294e1110..d856f79346 100644 --- a/modules/schematics/schematics-core/utility/ngrx-utils.ts +++ b/modules/schematics/schematics-core/utility/ngrx-utils.ts @@ -4,8 +4,7 @@ import { InsertChange, Change, NoopChange } from './change'; import { Tree, SchematicsException, Rule } from '@angular-devkit/schematics'; import { normalize } from '@angular-devkit/core'; import { buildRelativePath } from './find-module'; -import { insertImport } from './route-utils'; -import { addImportToModule } from './ast-utils'; +import { addImportToModule, insertImport } from './ast-utils'; export function addReducerToState(options: any): Rule { return (host: Tree) => { @@ -79,7 +78,7 @@ export function addReducerToState(options: any): Rule { export function addReducerToStateInterface( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { const stateInterface = source.statements.find( stm => stm.kind === ts.SyntaxKind.InterfaceDeclaration @@ -90,11 +89,12 @@ export function addReducerToStateInterface( return new NoopChange(); } + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.State;'; + state + ': from' + stringUtils.classify(options.name) + '.State;'; const expr = node as any; let position; let toInsert; @@ -125,7 +125,7 @@ export function addReducerToStateInterface( export function addReducerToActionReducerMap( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { let initializer: any; const actionReducerMap: any = source.statements @@ -152,11 +152,12 @@ export function addReducerToActionReducerMap( let node = actionReducerMap.initializer; + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.reducer,'; + state + ': from' + stringUtils.classify(options.name) + '.reducer,'; const expr = node as any; let position; let toInsert; diff --git a/modules/schematics/schematics-core/utility/project.ts b/modules/schematics/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/schematics/schematics-core/utility/project.ts +++ b/modules/schematics/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/schematics/schematics-core/utility/route-utils.ts b/modules/schematics/schematics-core/utility/route-utils.ts deleted file mode 100644 index d25cc059a8..0000000000 --- a/modules/schematics/schematics-core/utility/route-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as ts from 'typescript'; -import { findNodes, insertAfterLastOccurrence } from './ast-utils'; -import { Change, NoopChange } from './change'; - -/** - * Add Import `import { symbolName } from fileName` if the import doesn't exit - * already. Assumes fileToEdit can be resolved and accessed. - * @param fileToEdit (file we want to add import to) - * @param symbolName (item to import) - * @param fileName (path to the file) - * @param isDefault (if true, import follows style for importing default exports) - * @return Change - */ - -export function insertImport( - source: ts.SourceFile, - fileToEdit: string, - symbolName: string, - fileName: string, - isDefault = false -): Change { - const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); - - // get nodes that map to import statements from the file fileName - const relevantImports = allImports.filter(node => { - // StringLiteral of the ImportDeclaration is the import file (fileName in this case). - const importFiles = node - .getChildren() - .filter(child => child.kind === ts.SyntaxKind.StringLiteral) - .map(n => (n as ts.StringLiteral).text); - - return importFiles.filter(file => file === fileName).length === 1; - }); - - if (relevantImports.length > 0) { - let importsAsterisk = false; - // imports from import file - const imports: ts.Node[] = []; - relevantImports.forEach(n => { - Array.prototype.push.apply( - imports, - findNodes(n, ts.SyntaxKind.Identifier) - ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { - importsAsterisk = true; - } - }); - - // if imports * from fileName, don't add symbolName - if (importsAsterisk) { - return new NoopChange(); - } - - const importTextNodes = imports.filter( - n => (n as ts.Identifier).text === symbolName - ); - - // insert import if it's not there - if (importTextNodes.length === 0) { - const fallbackPos = - findNodes( - relevantImports[0], - ts.SyntaxKind.CloseBraceToken - )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); - - return insertAfterLastOccurrence( - imports, - `, ${symbolName}`, - fileToEdit, - fallbackPos - ); - } - - return new NoopChange(); - } - - // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - n => n.getText() === 'use strict' - ); - let fallbackPos = 0; - if (useStrict.length > 0) { - fallbackPos = useStrict[0].end; - } - const open = isDefault ? '' : '{ '; - const close = isDefault ? '' : ' }'; - // if there are no imports or 'use strict' statement, insert import at beginning of file - const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; - const separator = insertAtBeginning ? '' : ';\n'; - const toInsert = - `${separator}import ${open}${symbolName}${close}` + - ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; - - return insertAfterLastOccurrence( - allImports, - toInsert, - fileToEdit, - fallbackPos, - ts.SyntaxKind.StringLiteral - ); -} diff --git a/modules/schematics/schematics-core/utility/strings.ts b/modules/schematics/schematics-core/utility/strings.ts index dae37e563c..5ebec70706 100644 --- a/modules/schematics/schematics-core/utility/strings.ts +++ b/modules/schematics/schematics-core/utility/strings.ts @@ -110,6 +110,25 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.substr(1); } +/** + Returns the plural form of a string + + ```javascript + 'innerHTML'.pluralize() // 'InnerHTMLs' + 'action_name'.pluralize() // 'actionNames' + 'css-class-name'.pluralize() // 'cssClassNames' + 'regex'.pluralize() // 'regexes' + 'user'.pluralize() // 'users' + ``` + */ +export function pluralize(str: string): string { + return camelize( + [/([^aeiou])y$/, /()fe?$/, /([^aeiou]o|[sxz]|[cs]h)$/].map( + (c, i) => (str = str.replace(c, `$1${'iv'[i] || ''}e`)) + ) && str + 's' + ); +} + export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } diff --git a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions__dot__spec.ts b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.spec.ts.template similarity index 100% rename from modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions__dot__spec.ts rename to modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.spec.ts.template diff --git a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts.template similarity index 100% rename from modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts rename to modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts.template diff --git a/modules/schematics/src/action/index.ts b/modules/schematics/src/action/index.ts index 53f4852e09..58b45ad5eb 100644 --- a/modules/schematics/src/action/index.ts +++ b/modules/schematics/src/action/index.ts @@ -2,6 +2,7 @@ import { Rule, SchematicsException, apply, + applyTemplates, branchAndMerge, chain, filter, @@ -29,17 +30,18 @@ export default function(options: ActionOptions): Rule { options.path = parsedPath.path; const templateSource = apply(url('./files'), [ - options.spec ? noop() : filter(path => !path.endsWith('__spec.ts')), - template({ + options.spec + ? noop() + : filter(path => !path.endsWith('.spec.ts.template')), + applyTemplates({ + ...stringUtils, 'if-flat': (s: string) => stringUtils.group( options.flat ? '' : s, options.group ? 'actions' : '' ), - ...stringUtils, - ...(options as object), - dot: () => '.', - } as any), + ...options, + }), move(parsedPath.path), ]); diff --git a/modules/schematics/src/container/files/__name@dasherize@if-flat__/__name@dasherize__.component__dot__spec.ts b/modules/schematics/src/container/files/__name@dasherize@if-flat__/__name@dasherize__.component.spec.ts.template similarity index 100% rename from modules/schematics/src/container/files/__name@dasherize@if-flat__/__name@dasherize__.component__dot__spec.ts rename to modules/schematics/src/container/files/__name@dasherize@if-flat__/__name@dasherize__.component.spec.ts.template diff --git a/modules/schematics/src/container/index.ts b/modules/schematics/src/container/index.ts index 7e9d112430..81ace4cfaa 100644 --- a/modules/schematics/src/container/index.ts +++ b/modules/schematics/src/container/index.ts @@ -6,6 +6,7 @@ import { chain, externalSchematic, apply, + applyTemplates, url, noop, filter, @@ -136,12 +137,13 @@ export default function(options: ContainerOptions): Rule { ); const templateSource = apply(url('./files'), [ - options.spec ? noop() : filter(path => !path.endsWith('__spec.ts')), - template({ + options.spec + ? noop() + : filter(path => !path.endsWith('.spec.ts.template')), + applyTemplates({ 'if-flat': (s: string) => (options.flat ? '' : s), ...stringUtils, ...(options as object), - dot: () => '.', } as any), move(parsedPath.path), ]); diff --git a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects__dot__spec.ts b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.spec.ts.template similarity index 100% rename from modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects__dot__spec.ts rename to modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.spec.ts.template diff --git a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts.template similarity index 51% rename from modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts rename to modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts.template index 5d9d9e84e2..09e7ebfcc3 100644 --- a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts +++ b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts.template @@ -1,9 +1,13 @@ import { Injectable } from '@angular/core'; import { Actions, Effect<% if (feature) { %>, ofType<% } %> } from '@ngrx/effects'; -<% if (feature && api) { %>import { catchError, map, concatMap } from 'rxjs/operators';<% } %> -<% if (feature && api) { %>import { EMPTY, of } from 'rxjs';<% } %> -<% if (feature && api) { %>import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> -<% if (feature && !api) { %>import { <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> +<% if (feature && api) { %>import { catchError, map, concatMap } from 'rxjs/operators'; +import { EMPTY, of } from 'rxjs'; +import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions'; +<% } %> +<% if (feature && !api) { %>import { concatMap } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions'; +<% } %> @Injectable() export class <%= classify(name) %>Effects { @@ -17,13 +21,16 @@ export class <%= classify(name) %>Effects { map(data => new Load<%= classify(name) %>sSuccess({ data })), catchError(error => of(new Load<%= classify(name) %>sFailure({ error })))) ) - ); -<% } %> + );<% } %> <% if (feature && !api) { %> @Effect() - load<%= classify(name) %>s$ = this.actions$.pipe(ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s)); + load<%= classify(name) %>s$ = this.actions$.pipe( + ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s), + /** An EMPTY observable only emits completion. Replace with your own observable API request */ + concatMap(() => EMPTY) + ); <% } %> -<% if (feature && api) { %> +<% if (feature) { %> constructor(private actions$: Actions<<%= classify(name) %>Actions>) {} <% } else { %> constructor(private actions$: Actions) {} diff --git a/modules/schematics/src/effect/index.spec.ts b/modules/schematics/src/effect/index.spec.ts index 76364a6fd2..909cae69fe 100644 --- a/modules/schematics/src/effect/index.spec.ts +++ b/modules/schematics/src/effect/index.spec.ts @@ -236,7 +236,7 @@ describe('Effect Schematic', () => { ); expect(content).toMatch( - /import \{ FooActionTypes } from \'\.\.\/\.\.\/actions\/foo\/foo\.actions';/ + /import \{ FooActionTypes, FooActions } from \'\.\.\/\.\.\/actions\/foo\/foo\.actions';/ ); }); @@ -250,12 +250,18 @@ describe('Effect Schematic', () => { expect(content).toMatch( /import { Actions, Effect, ofType } from '@ngrx\/effects';/ ); + expect(content).toMatch(/import { concatMap } from 'rxjs\/operators';/); + expect(content).toMatch(/import { EMPTY } from 'rxjs';/); expect(content).toMatch( - /import { FooActionTypes } from '\.\/foo.actions';/ + /import { FooActionTypes, FooActions } from '\.\/foo.actions';/ ); expect(content).toMatch(/export class FooEffects/); + expect(content).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); + expect(content).toMatch(/ofType\(FooActionTypes\.LoadFoos\)/); + expect(content).toMatch(/concatMap\(\(\) => EMPTY\)/); + expect(content).toMatch( - /loadFoos\$ = this\.actions\$.pipe\(ofType\(FooActionTypes\.LoadFoos\)\);/ + /constructor\(private actions\$: Actions\) {}/ ); }); @@ -274,7 +280,7 @@ describe('Effect Schematic', () => { ); expect(content).toMatch(/export class FooEffects/); expect(content).not.toMatch( - /loadFoos\$ = this\.actions\$.pipe\(ofType\(FooActionTypes\.LoadFoos\)\);/ + /loadFoos\$ = this\.actions\$.pipe\(ofType\(FooActionTypes\.LoadFoos/ ); }); diff --git a/modules/schematics/src/effect/index.ts b/modules/schematics/src/effect/index.ts index 40a599a191..6ac96571a5 100644 --- a/modules/schematics/src/effect/index.ts +++ b/modules/schematics/src/effect/index.ts @@ -4,6 +4,7 @@ import { SchematicsException, Tree, apply, + applyTemplates, branchAndMerge, chain, filter, @@ -105,8 +106,10 @@ export default function(options: EffectOptions): Rule { options.path = parsedPath.path; const templateSource = apply(url('./files'), [ - options.spec ? noop() : filter(path => !path.endsWith('__spec.ts')), - template({ + options.spec + ? noop() + : filter(path => !path.endsWith('.spec.ts.template')), + applyTemplates({ ...stringUtils, 'if-flat': (s: string) => stringUtils.group( @@ -114,7 +117,6 @@ export default function(options: EffectOptions): Rule { options.group ? 'effects' : '' ), ...(options as object), - dot: () => '.', } as any), move(parsedPath.path), ]); diff --git a/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-actions__.actions.ts b/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-actions__.actions.ts.template similarity index 100% rename from modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-actions__.actions.ts rename to modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-actions__.actions.ts.template diff --git a/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-models__.model.ts b/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-models__.model.ts.template similarity index 100% rename from modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-models__.model.ts rename to modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-models__.model.ts.template diff --git a/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer__dot__spec.ts b/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer.spec.ts.template similarity index 100% rename from modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer__dot__spec.ts rename to modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer.spec.ts.template diff --git a/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer.ts b/modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer.ts.template similarity index 100% rename from modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer.ts rename to modules/schematics/src/entity/files/__name@dasherize@if-flat__/__name@dasherize@group-reducers__.reducer.ts.template diff --git a/modules/schematics/src/entity/index.spec.ts b/modules/schematics/src/entity/index.spec.ts index 1ae89a8054..3933d604b6 100644 --- a/modules/schematics/src/entity/index.spec.ts +++ b/modules/schematics/src/entity/index.spec.ts @@ -127,6 +127,7 @@ describe('Entity Schematic', () => { const tree = schematicRunner.runSchematic('entity', options, appTree); const files = tree.files; + expect( files.indexOf(`${projectPath}/src/app/foo/actions/foo.actions.ts`) ).toBeGreaterThanOrEqual(0); @@ -146,6 +147,7 @@ describe('Entity Schematic', () => { const tree = schematicRunner.runSchematic('entity', options, appTree); const files = tree.files; + expect( files.indexOf(`${projectPath}/src/app/actions/foo.actions.ts`) ).toBeGreaterThanOrEqual(0); @@ -159,4 +161,34 @@ describe('Entity Schematic', () => { files.indexOf(`${projectPath}/src/app/reducers/foo.reducer.spec.ts`) ).toBeGreaterThanOrEqual(0); }); + + it('should update the state to plural', () => { + const options = { + ...defaultOptions, + name: 'user', + reducers: 'reducers/index.ts', + spec: true, + }; + + const reducerTree = schematicRunner.runSchematic('store', options, appTree); + const tree = schematicRunner.runSchematic('entity', options, appTree); + const files = tree.files; + const content = tree.readContent( + `${projectPath}/src/app/reducers/index.ts` + ); + expect( + files.indexOf(`${projectPath}/src/app/user.actions.ts`) + ).toBeGreaterThanOrEqual(0); + expect( + files.indexOf(`${projectPath}/src/app/user.model.ts`) + ).toBeGreaterThanOrEqual(0); + expect( + files.indexOf(`${projectPath}/src/app/user.reducer.ts`) + ).toBeGreaterThanOrEqual(0); + expect( + files.indexOf(`${projectPath}/src/app/user.reducer.spec.ts`) + ).toBeGreaterThanOrEqual(0); + expect(content).toMatch(/users\: fromUser.State/); + expect(content).toMatch(/users\: fromUser.reducer/); + }); }); diff --git a/modules/schematics/src/entity/index.ts b/modules/schematics/src/entity/index.ts index 6ecac95ed2..9cf5572a09 100644 --- a/modules/schematics/src/entity/index.ts +++ b/modules/schematics/src/entity/index.ts @@ -2,6 +2,7 @@ import { Rule, SchematicsException, apply, + applyTemplates, branchAndMerge, chain, filter, @@ -36,8 +37,10 @@ export default function(options: EntityOptions): Rule { } const templateSource = apply(url('./files'), [ - options.spec ? noop() : filter(path => !path.endsWith('__spec.ts')), - template({ + options.spec + ? noop() + : filter(path => !path.endsWith('.spec.ts.template')), + applyTemplates({ ...stringUtils, 'if-flat': (s: string) => (options.flat ? '' : s), 'group-actions': (name: string) => @@ -47,13 +50,12 @@ export default function(options: EntityOptions): Rule { 'group-reducers': (s: string) => stringUtils.group(s, options.group ? 'reducers' : ''), ...(options as object), - dot: () => '.', } as any), move(parsedPath.path), ]); return chain([ - addReducerToState({ ...options }), + addReducerToState({ ...options, plural: true }), addReducerImportToNgModule({ ...options }), branchAndMerge(chain([mergeWith(templateSource)])), ])(host, context); diff --git a/modules/schematics/src/ng-add/index.spec.ts b/modules/schematics/src/ng-add/index.spec.ts new file mode 100644 index 0000000000..9797fa9bad --- /dev/null +++ b/modules/schematics/src/ng-add/index.spec.ts @@ -0,0 +1,45 @@ +import { + SchematicTestRunner, + UnitTestTree, +} from '@angular-devkit/schematics/testing'; +import * as path from 'path'; +import { createWorkspace } from '../../../schematics-core/testing'; +import { Schema as SchematicOptions } from './schema'; + +describe('ng-add Schematic', () => { + const schematicRunner = new SchematicTestRunner( + '@ngrx/schematics', + path.join(__dirname, '../../collection.json') + ); + const defaultOptions: SchematicOptions = { + defaultCollection: true, + }; + + let appTree: UnitTestTree; + + beforeEach(() => { + appTree = createWorkspace(schematicRunner, appTree); + }); + + it(`should leave the workspace's cli as default`, () => { + const options: SchematicOptions = { + ...defaultOptions, + defaultCollection: false, + }; + + const tree = schematicRunner.runSchematic('ng-add', options, appTree); + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.cli).not.toBeDefined(); + }); + + it('should set workspace default cli to @ngrx/schematics', () => { + const options: SchematicOptions = { + ...defaultOptions, + defaultCollection: true, + }; + + const tree = schematicRunner.runSchematic('ng-add', options, appTree); + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.cli.defaultCollection).toEqual('@ngrx/schematics'); + }); +}); diff --git a/modules/schematics/src/ng-add/index.ts b/modules/schematics/src/ng-add/index.ts new file mode 100644 index 0000000000..f03d16ff4d --- /dev/null +++ b/modules/schematics/src/ng-add/index.ts @@ -0,0 +1,38 @@ +import { + Rule, + SchematicContext, + Tree, + chain, + noop, +} from '@angular-devkit/schematics'; +import { + WorkspaceSchema, + getWorkspacePath, + getWorkspace, +} from '../../schematics-core/utility/config'; +import { Schema as SchematicOptions } from './schema'; + +function updateWorkspace(host: Tree, key: keyof WorkspaceSchema, value: any) { + const workspace = getWorkspace(host); + const path = getWorkspacePath(host); + workspace[key] = value; + host.overwrite(path, JSON.stringify(workspace, null, 2)); +} + +function setAsDefaultSchematics() { + const cli = { + defaultCollection: '@ngrx/schematics', + }; + return (host: Tree) => { + updateWorkspace(host, 'cli', cli); + return host; + }; +} + +export default function(options: SchematicOptions): Rule { + return (host: Tree, context: SchematicContext) => { + return chain([ + options && options.defaultCollection ? setAsDefaultSchematics() : noop(), + ])(host, context); + }; +} diff --git a/modules/schematics/src/ng-add/schema.json b/modules/schematics/src/ng-add/schema.json new file mode 100644 index 0000000000..88a23ac9a3 --- /dev/null +++ b/modules/schematics/src/ng-add/schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "SchematicsNgRxSchematics", + "title": "Scaffolding library for Angular applications using NgRx libraries", + "type": "object", + "properties": { + "defaultCollection": { + "type": "boolean", + "default": true, + "description": "Use @ngrx/schematics as the default collection", + "x-prompt": + "Do you want to use @ngrx/schematics as the default collection?", + "alias": "d" + } + }, + "required": [] +} diff --git a/modules/schematics/src/ng-add/schema.ts b/modules/schematics/src/ng-add/schema.ts new file mode 100644 index 0000000000..3d0dc802b8 --- /dev/null +++ b/modules/schematics/src/ng-add/schema.ts @@ -0,0 +1,3 @@ +export interface Schema { + defaultCollection?: boolean; +} diff --git a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer__dot__spec.ts b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.spec.ts.template similarity index 100% rename from modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer__dot__spec.ts rename to modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.spec.ts.template diff --git a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts.template similarity index 100% rename from modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts rename to modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts.template diff --git a/modules/schematics/src/reducer/index.ts b/modules/schematics/src/reducer/index.ts index 60e1f852b2..0b9e9679f2 100644 --- a/modules/schematics/src/reducer/index.ts +++ b/modules/schematics/src/reducer/index.ts @@ -4,6 +4,7 @@ import { SchematicsException, Tree, apply, + applyTemplates, branchAndMerge, chain, filter, @@ -37,8 +38,10 @@ export default function(options: ReducerOptions): Rule { options.path = parsedPath.path; const templateSource = apply(url('./files'), [ - options.spec ? noop() : filter(path => !path.endsWith('__spec.ts')), - template({ + options.spec + ? noop() + : filter(path => !path.endsWith('.spec.ts.template')), + applyTemplates({ ...stringUtils, 'if-flat': (s: string) => stringUtils.group( @@ -46,7 +49,6 @@ export default function(options: ReducerOptions): Rule { options.group ? 'reducers' : '' ), ...(options as object), - dot: () => '.', } as any), move(parsedPath.path), ]); diff --git a/modules/schematics/src/store/files/__statePath__/index.ts b/modules/schematics/src/store/files/__statePath__/index.ts.template similarity index 100% rename from modules/schematics/src/store/files/__statePath__/index.ts rename to modules/schematics/src/store/files/__statePath__/index.ts.template diff --git a/modules/schematics/src/store/index.spec.ts b/modules/schematics/src/store/index.spec.ts index f342a4c917..741ae04756 100644 --- a/modules/schematics/src/store/index.spec.ts +++ b/modules/schematics/src/store/index.spec.ts @@ -37,7 +37,9 @@ describe('Store Schematic', () => { const options = { ...defaultOptions }; const tree = schematicRunner.runSchematic('store', options, appTree); + const files = tree.files; + expect( files.indexOf(`${projectPath}/src/app/reducers/index.ts`) ).toBeGreaterThanOrEqual(0); @@ -56,11 +58,32 @@ describe('Store Schematic', () => { const tree = schematicRunner.runSchematic('store', options, appTree); const files = tree.files; + expect( files.indexOf(`${specifiedProjectPath}/src/lib/reducers/index.ts`) ).toBeGreaterThanOrEqual(0); }); + it('should create the initial store to defaultProject if project is not provided', () => { + const options = { + ...defaultOptions, + project: undefined, + }; + + const specifiedProjectPath = getTestProjectPath(defaultWorkspaceOptions, { + ...defaultAppOptions, + name: defaultWorkspaceOptions.defaultProject, + }); + + const tree = schematicRunner.runSchematic('store', options, appTree); + + const files = tree.files; + + expect( + files.indexOf(`${specifiedProjectPath}/src/app/reducers/index.ts`) + ).toBeGreaterThanOrEqual(0); + }); + it('should not be provided by default', () => { const options = { ...defaultOptions }; diff --git a/modules/schematics/src/store/index.ts b/modules/schematics/src/store/index.ts index a56aff9ba6..db06f31df2 100644 --- a/modules/schematics/src/store/index.ts +++ b/modules/schematics/src/store/index.ts @@ -4,6 +4,7 @@ import { SchematicsException, Tree, apply, + applyTemplates, branchAndMerge, chain, mergeWith, @@ -156,12 +157,12 @@ export default function(options: StoreOptions): Rule { } const templateSource = apply(url('./files'), [ - template({ + applyTemplates({ ...stringUtils, ...(options as object), isLib: isLib(host, options), environmentsPath, - } as any), + }), move(parsedPath.path), ]); diff --git a/modules/store-devtools/BUILD b/modules/store-devtools/BUILD index 46055a1319..adb7754d15 100644 --- a/modules/store-devtools/BUILD +++ b/modules/store-devtools/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ng_module", "ng_package", "ts_library") +load("//tools:defaults.bzl", "ng_module", "ng_package") ng_module( name = "store-devtools", @@ -11,7 +11,8 @@ ng_module( module_name = "@ngrx/store-devtools", deps = [ "//modules/store", - "@rxjs", + "@npm//@angular/core", + "@npm//rxjs", ], ) diff --git a/modules/store-devtools/CHANGELOG.md b/modules/store-devtools/CHANGELOG.md index 9d6a0d8cae..3b9c4d91aa 100644 --- a/modules/store-devtools/CHANGELOG.md +++ b/modules/store-devtools/CHANGELOG.md @@ -1,235 +1,3 @@ # Change Log -All notable changes to this project will be documented in this file. -See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - - -# 5.2.0 (2018-03-07) - - -### Bug Fixes - -* **StoreDevtools:** Fix bug when exporting/importing state history (#855) ([a5dcdb1](https://github.com/ngrx/platform/commit/a5dcdb1)), closes [#855](https://github.com/ngrx/platform/issues/855) -* **StoreDevtools:** Recompute state history when reducers are updated (#844) ([10debcc](https://github.com/ngrx/platform/commit/10debcc)) - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Devtools:** Ensure Store is loaded eagerly (#801) ([ecf1ebf](https://github.com/ngrx/platform/commit/ecf1ebf)), closes [#624](https://github.com/ngrx/platform/issues/624) [#741](https://github.com/ngrx/platform/issues/741) -* **StoreDevtools:** Add internal support for ActionSanitizer and StateSanitizer (#795) ([a7de2a6](https://github.com/ngrx/platform/commit/a7de2a6)) -* **StoreDevtools:** Do not send full liftedState for application actions (#790) ([c11504f](https://github.com/ngrx/platform/commit/c11504f)) - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **StoreDevtools:** Only recompute current state when reducers are updated (#570) ([247ae1a](https://github.com/ngrx/platform/commit/247ae1a)), closes [#229](https://github.com/ngrx/platform/issues/229) [#487](https://github.com/ngrx/platform/issues/487) - - -### Features - -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **StoreDevtools:** Add option to configure extension in log-only mode (#712) ([1ecd658](https://github.com/ngrx/platform/commit/1ecd658)), closes [#643](https://github.com/ngrx/platform/issues/643) [#374](https://github.com/ngrx/platform/issues/374) -* **StoreDevtools:** Add support for custom instance name (#517) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) -* **StoreDevtools:** Add support for extension sanitizers (#544) ([6ed92b0](https://github.com/ngrx/platform/commit/6ed92b0)), closes [#494](https://github.com/ngrx/platform/issues/494) -* **StoreDevtools:** Add support for jumping to a specific action (#703) ([b9f6442](https://github.com/ngrx/platform/commit/b9f6442)), closes [#681](https://github.com/ngrx/platform/issues/681) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) -* **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) - - -### Features - -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Devtools:** Ensure Store is loaded eagerly (#801) ([ecf1ebf](https://github.com/ngrx/platform/commit/ecf1ebf)), closes [#624](https://github.com/ngrx/platform/issues/624) [#741](https://github.com/ngrx/platform/issues/741) -* **StoreDevtools:** Add internal support for ActionSanitizer and StateSanitizer (#795) ([a7de2a6](https://github.com/ngrx/platform/commit/a7de2a6)) -* **StoreDevtools:** Do not send full liftedState for application actions (#790) ([c11504f](https://github.com/ngrx/platform/commit/c11504f)) - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **StoreDevtools:** Only recompute current state when reducers are updated (#570) ([247ae1a](https://github.com/ngrx/platform/commit/247ae1a)), closes [#229](https://github.com/ngrx/platform/issues/229) [#487](https://github.com/ngrx/platform/issues/487) - - -### Features - -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **StoreDevtools:** Add option to configure extension in log-only mode (#712) ([1ecd658](https://github.com/ngrx/platform/commit/1ecd658)), closes [#643](https://github.com/ngrx/platform/issues/643) [#374](https://github.com/ngrx/platform/issues/374) -* **StoreDevtools:** Add support for custom instance name (#517) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) -* **StoreDevtools:** Add support for extension sanitizers (#544) ([6ed92b0](https://github.com/ngrx/platform/commit/6ed92b0)), closes [#494](https://github.com/ngrx/platform/issues/494) -* **StoreDevtools:** Add support for jumping to a specific action (#703) ([b9f6442](https://github.com/ngrx/platform/commit/b9f6442)), closes [#681](https://github.com/ngrx/platform/issues/681) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) -* **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) - - -### Features - -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - - - - -## 5.0.1 (2018-01-25) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **StoreDevtools:** Only recompute current state when reducers are updated (#570) ([247ae1a](https://github.com/ngrx/platform/commit/247ae1a)), closes [#229](https://github.com/ngrx/platform/issues/229) [#487](https://github.com/ngrx/platform/issues/487) - - -### Features - -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **StoreDevtools:** Add option to configure extension in log-only mode (#712) ([1ecd658](https://github.com/ngrx/platform/commit/1ecd658)), closes [#643](https://github.com/ngrx/platform/issues/643) [#374](https://github.com/ngrx/platform/issues/374) -* **StoreDevtools:** Add support for custom instance name (#517) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) -* **StoreDevtools:** Add support for extension sanitizers (#544) ([6ed92b0](https://github.com/ngrx/platform/commit/6ed92b0)), closes [#494](https://github.com/ngrx/platform/issues/494) -* **StoreDevtools:** Add support for jumping to a specific action (#703) ([b9f6442](https://github.com/ngrx/platform/commit/b9f6442)), closes [#681](https://github.com/ngrx/platform/issues/681) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) -* **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) - - -### Features - -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **StoreDevtools:** Only recompute current state when reducers are updated (#570) ([247ae1a](https://github.com/ngrx/platform/commit/247ae1a)), closes [#229](https://github.com/ngrx/platform/issues/229) [#487](https://github.com/ngrx/platform/issues/487) - - -### Features - -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **StoreDevtools:** Add option to configure extension in log-only mode (#712) ([1ecd658](https://github.com/ngrx/platform/commit/1ecd658)), closes [#643](https://github.com/ngrx/platform/issues/643) [#374](https://github.com/ngrx/platform/issues/374) -* **StoreDevtools:** Add support for custom instance name (#517) ([00be3d1](https://github.com/ngrx/platform/commit/00be3d1)), closes [#463](https://github.com/ngrx/platform/issues/463) -* **StoreDevtools:** Add support for extension sanitizers (#544) ([6ed92b0](https://github.com/ngrx/platform/commit/6ed92b0)), closes [#494](https://github.com/ngrx/platform/issues/494) -* **StoreDevtools:** Add support for jumping to a specific action (#703) ([b9f6442](https://github.com/ngrx/platform/commit/b9f6442)), closes [#681](https://github.com/ngrx/platform/issues/681) - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) -* **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) - - -### Features - -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) -* **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) - - -### Features - -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) - - - - - -# 4.0.0 (2017-07-18) - - -### Bug Fixes - -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **example-app:** Suppress StoreDevtoolsConfig compiler warning ([8804156](https://github.com/ngrx/platform/commit/8804156)) -* **StoreDevtools:** Type InjectionToken for AOT compilation ([e21d688](https://github.com/ngrx/platform/commit/e21d688)) - - -### Features - -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) +See [CHANGELOG.md](https://github.com/ngrx/platform/blob/master/CHANGELOG.md) diff --git a/modules/store-devtools/schematics-core/index.ts b/modules/store-devtools/schematics-core/index.ts index 36cc0abbcf..9608baec44 100644 --- a/modules/store-devtools/schematics-core/index.ts +++ b/modules/store-devtools/schematics-core/index.ts @@ -15,6 +15,7 @@ export { getDecoratorMetadata, getContentOfKeyLiteral, insertAfterLastOccurrence, + insertImport, addBootstrapToModule, addDeclarationToModule, addExportToModule, @@ -49,7 +50,6 @@ export { } from './utility/ngrx-utils'; export { getProjectPath, getProject, isLib } from './utility/project'; -export { insertImport } from './utility/route-utils'; export const stringUtils = { dasherize, diff --git a/modules/store-devtools/schematics-core/utility/ast-utils.ts b/modules/store-devtools/schematics-core/utility/ast-utils.ts index b1f263974e..f6174fc4b1 100644 --- a/modules/store-devtools/schematics-core/utility/ast-utils.ts +++ b/modules/store-devtools/schematics-core/utility/ast-utils.ts @@ -7,8 +7,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import { Change, InsertChange } from './change'; -import { insertImport } from './route-utils'; +import { Change, InsertChange, NoopChange } from './change'; /** * Find all nodes from the AST in the subtree of node of SyntaxKind kind. @@ -537,3 +536,103 @@ export function addBootstrapToModule( importPath ); } + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ + +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + const rootNode = source; + const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + + // get nodes that map to import statements from the file fileName + const relevantImports = allImports.filter(node => { + // StringLiteral of the ImportDeclaration is the import file (fileName in this case). + const importFiles = node + .getChildren() + .filter(child => child.kind === ts.SyntaxKind.StringLiteral) + .map(n => (n as ts.StringLiteral).text); + + return importFiles.filter(file => file === fileName).length === 1; + }); + + if (relevantImports.length > 0) { + let importsAsterisk = false; + // imports from import file + const imports: ts.Node[] = []; + relevantImports.forEach(n => { + Array.prototype.push.apply( + imports, + findNodes(n, ts.SyntaxKind.Identifier) + ); + if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + importsAsterisk = true; + } + }); + + // if imports * from fileName, don't add symbolName + if (importsAsterisk) { + return new NoopChange(); + } + + const importTextNodes = imports.filter( + n => (n as ts.Identifier).text === symbolName + ); + + // insert import if it's not there + if (importTextNodes.length === 0) { + const fallbackPos = + findNodes( + relevantImports[0], + ts.SyntaxKind.CloseBraceToken + )[0].getStart() || + findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + + return insertAfterLastOccurrence( + imports, + `, ${symbolName}`, + fileToEdit, + fallbackPos + ); + } + + return new NoopChange(); + } + + // no such import declaration exists + const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( + n => n.getText() === 'use strict' + ); + let fallbackPos = 0; + if (useStrict.length > 0) { + fallbackPos = useStrict[0].end; + } + const open = isDefault ? '' : '{ '; + const close = isDefault ? '' : ' }'; + // if there are no imports or 'use strict' statement, insert import at beginning of file + const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; + const separator = insertAtBeginning ? '' : ';\n'; + const toInsert = + `${separator}import ${open}${symbolName}${close}` + + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; + + return insertAfterLastOccurrence( + allImports, + toInsert, + fileToEdit, + fallbackPos, + ts.SyntaxKind.StringLiteral + ); +} diff --git a/modules/store-devtools/schematics-core/utility/ngrx-utils.ts b/modules/store-devtools/schematics-core/utility/ngrx-utils.ts index 28294e1110..d856f79346 100644 --- a/modules/store-devtools/schematics-core/utility/ngrx-utils.ts +++ b/modules/store-devtools/schematics-core/utility/ngrx-utils.ts @@ -4,8 +4,7 @@ import { InsertChange, Change, NoopChange } from './change'; import { Tree, SchematicsException, Rule } from '@angular-devkit/schematics'; import { normalize } from '@angular-devkit/core'; import { buildRelativePath } from './find-module'; -import { insertImport } from './route-utils'; -import { addImportToModule } from './ast-utils'; +import { addImportToModule, insertImport } from './ast-utils'; export function addReducerToState(options: any): Rule { return (host: Tree) => { @@ -79,7 +78,7 @@ export function addReducerToState(options: any): Rule { export function addReducerToStateInterface( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { const stateInterface = source.statements.find( stm => stm.kind === ts.SyntaxKind.InterfaceDeclaration @@ -90,11 +89,12 @@ export function addReducerToStateInterface( return new NoopChange(); } + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.State;'; + state + ': from' + stringUtils.classify(options.name) + '.State;'; const expr = node as any; let position; let toInsert; @@ -125,7 +125,7 @@ export function addReducerToStateInterface( export function addReducerToActionReducerMap( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { let initializer: any; const actionReducerMap: any = source.statements @@ -152,11 +152,12 @@ export function addReducerToActionReducerMap( let node = actionReducerMap.initializer; + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.reducer,'; + state + ': from' + stringUtils.classify(options.name) + '.reducer,'; const expr = node as any; let position; let toInsert; diff --git a/modules/store-devtools/schematics-core/utility/project.ts b/modules/store-devtools/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/store-devtools/schematics-core/utility/project.ts +++ b/modules/store-devtools/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/store-devtools/schematics-core/utility/route-utils.ts b/modules/store-devtools/schematics-core/utility/route-utils.ts deleted file mode 100644 index d25cc059a8..0000000000 --- a/modules/store-devtools/schematics-core/utility/route-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as ts from 'typescript'; -import { findNodes, insertAfterLastOccurrence } from './ast-utils'; -import { Change, NoopChange } from './change'; - -/** - * Add Import `import { symbolName } from fileName` if the import doesn't exit - * already. Assumes fileToEdit can be resolved and accessed. - * @param fileToEdit (file we want to add import to) - * @param symbolName (item to import) - * @param fileName (path to the file) - * @param isDefault (if true, import follows style for importing default exports) - * @return Change - */ - -export function insertImport( - source: ts.SourceFile, - fileToEdit: string, - symbolName: string, - fileName: string, - isDefault = false -): Change { - const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); - - // get nodes that map to import statements from the file fileName - const relevantImports = allImports.filter(node => { - // StringLiteral of the ImportDeclaration is the import file (fileName in this case). - const importFiles = node - .getChildren() - .filter(child => child.kind === ts.SyntaxKind.StringLiteral) - .map(n => (n as ts.StringLiteral).text); - - return importFiles.filter(file => file === fileName).length === 1; - }); - - if (relevantImports.length > 0) { - let importsAsterisk = false; - // imports from import file - const imports: ts.Node[] = []; - relevantImports.forEach(n => { - Array.prototype.push.apply( - imports, - findNodes(n, ts.SyntaxKind.Identifier) - ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { - importsAsterisk = true; - } - }); - - // if imports * from fileName, don't add symbolName - if (importsAsterisk) { - return new NoopChange(); - } - - const importTextNodes = imports.filter( - n => (n as ts.Identifier).text === symbolName - ); - - // insert import if it's not there - if (importTextNodes.length === 0) { - const fallbackPos = - findNodes( - relevantImports[0], - ts.SyntaxKind.CloseBraceToken - )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); - - return insertAfterLastOccurrence( - imports, - `, ${symbolName}`, - fileToEdit, - fallbackPos - ); - } - - return new NoopChange(); - } - - // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - n => n.getText() === 'use strict' - ); - let fallbackPos = 0; - if (useStrict.length > 0) { - fallbackPos = useStrict[0].end; - } - const open = isDefault ? '' : '{ '; - const close = isDefault ? '' : ' }'; - // if there are no imports or 'use strict' statement, insert import at beginning of file - const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; - const separator = insertAtBeginning ? '' : ';\n'; - const toInsert = - `${separator}import ${open}${symbolName}${close}` + - ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; - - return insertAfterLastOccurrence( - allImports, - toInsert, - fileToEdit, - fallbackPos, - ts.SyntaxKind.StringLiteral - ); -} diff --git a/modules/store-devtools/schematics-core/utility/strings.ts b/modules/store-devtools/schematics-core/utility/strings.ts index dae37e563c..5ebec70706 100644 --- a/modules/store-devtools/schematics-core/utility/strings.ts +++ b/modules/store-devtools/schematics-core/utility/strings.ts @@ -110,6 +110,25 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.substr(1); } +/** + Returns the plural form of a string + + ```javascript + 'innerHTML'.pluralize() // 'InnerHTMLs' + 'action_name'.pluralize() // 'actionNames' + 'css-class-name'.pluralize() // 'cssClassNames' + 'regex'.pluralize() // 'regexes' + 'user'.pluralize() // 'users' + ``` + */ +export function pluralize(str: string): string { + return camelize( + [/([^aeiou])y$/, /()fe?$/, /([^aeiou]o|[sxz]|[cs]h)$/].map( + (c, i) => (str = str.replace(c, `$1${'iv'[i] || ''}e`)) + ) && str + 's' + ); +} + export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } diff --git a/modules/store-devtools/spec/BUILD b/modules/store-devtools/spec/BUILD index 6ffc4c7301..3c712c8563 100644 --- a/modules/store-devtools/spec/BUILD +++ b/modules/store-devtools/spec/BUILD @@ -10,8 +10,7 @@ ts_test_library( deps = [ "//modules/store", "//modules/store-devtools", - "@rxjs", - "@rxjs//operators", + "@npm//rxjs", ], ) diff --git a/modules/store-devtools/src/devtools.ts b/modules/store-devtools/src/devtools.ts index 4fc485b374..114aa8741d 100644 --- a/modules/store-devtools/src/devtools.ts +++ b/modules/store-devtools/src/devtools.ts @@ -21,7 +21,12 @@ import * as Actions from './actions'; import { STORE_DEVTOOLS_CONFIG, StoreDevtoolsConfig } from './config'; import { DevtoolsExtension } from './extension'; import { LiftedState, liftInitialState, liftReducerWith } from './reducer'; -import { liftAction, unliftState, shouldFilterActions, filterLiftedState } from './utils'; +import { + liftAction, + unliftState, + shouldFilterActions, + filterLiftedState, +} from './utils'; import { DevtoolsDispatcher } from './devtools-dispatcher'; import { PERFORM_ACTION } from './actions'; @@ -73,25 +78,25 @@ export class StoreDevtools implements Observer { state: LiftedState; action: any; } - >( - ({ state: liftedState }, [action, reducer]) => { - let reducedLiftedState = reducer(liftedState, action); - // On full state update - // If we have actions filters, we must filter completly our lifted state to be sync with the extension - if (action.type !== PERFORM_ACTION && shouldFilterActions(config)) { - reducedLiftedState = filterLiftedState( - reducedLiftedState, - config.predicate, - config.actionsWhitelist, - config.actionsBlacklist - ); - } - // Extension should be sent the sanitized lifted state - extension.notify(action, reducedLiftedState); - return { state: reducedLiftedState, action }; - }, - { state: liftedInitialState, action: null as any } - ) + >( + ({ state: liftedState }, [action, reducer]) => { + let reducedLiftedState = reducer(liftedState, action); + // On full state update + // If we have actions filters, we must filter completly our lifted state to be sync with the extension + if (action.type !== PERFORM_ACTION && shouldFilterActions(config)) { + reducedLiftedState = filterLiftedState( + reducedLiftedState, + config.predicate, + config.actionsWhitelist, + config.actionsBlacklist + ); + } + // Extension should be sent the sanitized lifted state + extension.notify(action, reducedLiftedState); + return { state: reducedLiftedState, action }; + }, + { state: liftedInitialState, action: null as any } + ) ) .subscribe(({ state, action }) => { liftedStateSubject.next(state); @@ -109,7 +114,7 @@ export class StoreDevtools implements Observer { const liftedState$ = liftedStateSubject.asObservable() as Observable< LiftedState - >; + >; const state$ = liftedState$.pipe(map(unliftState)); this.extensionStartSubscription = extensionStartSubscription; @@ -127,9 +132,9 @@ export class StoreDevtools implements Observer { this.dispatcher.next(action); } - error(error: any) { } + error(error: any) {} - complete() { } + complete() {} performAction(action: any) { this.dispatch(new Actions.PerformAction(action, +Date.now())); diff --git a/modules/store/BUILD b/modules/store/BUILD index 1fd7be4bc1..fd6838cd2f 100644 --- a/modules/store/BUILD +++ b/modules/store/BUILD @@ -10,8 +10,8 @@ ng_module( ]), module_name = "@ngrx/store", deps = [ - "@angular//packages/core", - "@rxjs", + "@npm//@angular/core", + "@npm//rxjs", ], ) diff --git a/modules/store/CHANGELOG.md b/modules/store/CHANGELOG.md index dfa58ba868..3b9c4d91aa 100644 --- a/modules/store/CHANGELOG.md +++ b/modules/store/CHANGELOG.md @@ -1,878 +1,3 @@ # Change Log -All notable changes to this project will be documented in this file. -See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - - -# 5.2.0 (2018-03-07) - - -### Bug Fixes - -* **Store:** only default to initialValue when store value is undefined (#886) ([51a1547](https://github.com/ngrx/platform/commit/51a1547)) - - -### Features - -* **Store:** Added feature name to Update Reducers action ([730361e](https://github.com/ngrx/platform/commit/730361e)) - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Devtools:** Ensure Store is loaded eagerly (#801) ([ecf1ebf](https://github.com/ngrx/platform/commit/ecf1ebf)), closes [#624](https://github.com/ngrx/platform/issues/624) [#741](https://github.com/ngrx/platform/issues/741) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Store:** Compose provided metareducers for a feature reducer (#704) ([1454620](https://github.com/ngrx/platform/commit/1454620)), closes [#701](https://github.com/ngrx/platform/issues/701) - - -### Features - -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) -* **Store:** Add support for generating custom createSelector functions (#734) ([cb0d185](https://github.com/ngrx/platform/commit/cb0d185)), closes [#478](https://github.com/ngrx/platform/issues/478) [#724](https://github.com/ngrx/platform/issues/724) - - -### BREAKING CHANGES - -* **Store:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **combineSelectors:** Remove default parameter from function signature for Closure ([ae7d5e1](https://github.com/ngrx/platform/commit/ae7d5e1)) -* **Store:** Fix typing for feature to accept InjectionToken (#375) ([38b2f95](https://github.com/ngrx/platform/commit/38b2f95)), closes [#375](https://github.com/ngrx/platform/issues/375) -* **Store:** Refactor parameter initialization in combineReducers for Closure ([5c60cba](https://github.com/ngrx/platform/commit/5c60cba)) -* **Store:** Set initial value for state action pair to object (#480) ([100a8ef](https://github.com/ngrx/platform/commit/100a8ef)), closes [#477](https://github.com/ngrx/platform/issues/477) - - -### Features - -* **createSelector:** Expose projector function on selectors to improve testability ([56cb21f](https://github.com/ngrx/platform/commit/56cb21f)), closes [#290](https://github.com/ngrx/platform/issues/290) -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Store:** createSelector with an array of selectors (#340) ([2f6a035](https://github.com/ngrx/platform/commit/2f6a035)), closes [#192](https://github.com/ngrx/platform/issues/192) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Store:** Add type signature for metareducer (#270) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) -* **Store:** Set initial state for feature modules (#235) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) -* **Store:** Update usage of compose for reducer factory (#252) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) -* **Store:** Use existing reducers when providing reducers without an InjectionToken (#254) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) -* **Store:** Use injector to get reducers provided via InjectionTokens (#259) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **createSelector:** memoize projector function (#228) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **Store:** Exported initial state tokens (#65) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector (#74) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) -* **Store:** Remove parameter destructuring for strict mode (#33) (#77) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type (#72) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils (#10) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) -* **Store:** Added initial state function support for features. Added more tests (#85) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) -* **Store:** Allow initial state function for AoT compatibility (#59) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens (#36) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers (#87) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ - EffectsModule.run(SourceA), - EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ - EffectsModule.forRoot([ - SourceA, - SourceB, - SourceC, - ]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ - EffectsModule.forFeature([ - FeatureSourceA, - FeatureSourceB, - FeatureSourceC, - ]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -# 5.1.0 (2018-02-13) - - -### Bug Fixes - -* **Devtools:** Ensure Store is loaded eagerly (#801) ([ecf1ebf](https://github.com/ngrx/platform/commit/ecf1ebf)), closes [#624](https://github.com/ngrx/platform/issues/624) [#741](https://github.com/ngrx/platform/issues/741) - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Store:** Compose provided metareducers for a feature reducer (#704) ([1454620](https://github.com/ngrx/platform/commit/1454620)), closes [#701](https://github.com/ngrx/platform/issues/701) - - -### Features - -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) -* **Store:** Add support for generating custom createSelector functions (#734) ([cb0d185](https://github.com/ngrx/platform/commit/cb0d185)), closes [#478](https://github.com/ngrx/platform/issues/478) [#724](https://github.com/ngrx/platform/issues/724) - - -### BREAKING CHANGES - -* **Store:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **combineSelectors:** Remove default parameter from function signature for Closure ([ae7d5e1](https://github.com/ngrx/platform/commit/ae7d5e1)) -* **Store:** Fix typing for feature to accept InjectionToken (#375) ([38b2f95](https://github.com/ngrx/platform/commit/38b2f95)), closes [#375](https://github.com/ngrx/platform/issues/375) -* **Store:** Refactor parameter initialization in combineReducers for Closure ([5c60cba](https://github.com/ngrx/platform/commit/5c60cba)) -* **Store:** Set initial value for state action pair to object (#480) ([100a8ef](https://github.com/ngrx/platform/commit/100a8ef)), closes [#477](https://github.com/ngrx/platform/issues/477) - - -### Features - -* **createSelector:** Expose projector function on selectors to improve testability ([56cb21f](https://github.com/ngrx/platform/commit/56cb21f)), closes [#290](https://github.com/ngrx/platform/issues/290) -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Store:** createSelector with an array of selectors (#340) ([2f6a035](https://github.com/ngrx/platform/commit/2f6a035)), closes [#192](https://github.com/ngrx/platform/issues/192) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Store:** Add type signature for metareducer (#270) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) -* **Store:** Set initial state for feature modules (#235) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) -* **Store:** Update usage of compose for reducer factory (#252) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) -* **Store:** Use existing reducers when providing reducers without an InjectionToken (#254) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) -* **Store:** Use injector to get reducers provided via InjectionTokens (#259) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **createSelector:** memoize projector function (#228) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **Store:** Exported initial state tokens (#65) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector (#74) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) -* **Store:** Remove parameter destructuring for strict mode (#33) (#77) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type (#72) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils (#10) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) -* **Store:** Added initial state function support for features. Added more tests (#85) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) -* **Store:** Allow initial state function for AoT compatibility (#59) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens (#36) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers (#87) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ - SourceA, - SourceB, - SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ - FeatureSourceA, - FeatureSourceB, - FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -# 5.0.0 (2018-01-22) - - -### Bug Fixes - -* **Store:** Compose provided metareducers for a feature reducer (#704) ([1454620](https://github.com/ngrx/platform/commit/1454620)), closes [#701](https://github.com/ngrx/platform/issues/701) - - -### Features - -* **Schematics:** Introduce [@ngrx](https://github.com/ngrx)/schematics (#631) ([1837dba](https://github.com/ngrx/platform/commit/1837dba)), closes [#53](https://github.com/ngrx/platform/issues/53) -* **Store:** Add lettable select operator ([77eed24](https://github.com/ngrx/platform/commit/77eed24)) -* **Store:** Add support for generating custom createSelector functions (#734) ([cb0d185](https://github.com/ngrx/platform/commit/cb0d185)), closes [#478](https://github.com/ngrx/platform/issues/478) [#724](https://github.com/ngrx/platform/issues/724) - - -### BREAKING CHANGES - -* **Store:** Updates minimum version of RxJS dependency. - -BEFORE: - -Minimum peer dependency of RxJS ^5.0.0 - -AFTER: - -Minimum peer dependency of RxJS ^5.5.0 - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **combineSelectors:** Remove default parameter from function signature for Closure ([ae7d5e1](https://github.com/ngrx/platform/commit/ae7d5e1)) -* **Store:** Fix typing for feature to accept InjectionToken (#375) ([38b2f95](https://github.com/ngrx/platform/commit/38b2f95)), closes [#375](https://github.com/ngrx/platform/issues/375) -* **Store:** Refactor parameter initialization in combineReducers for Closure ([5c60cba](https://github.com/ngrx/platform/commit/5c60cba)) -* **Store:** Set initial value for state action pair to object (#480) ([100a8ef](https://github.com/ngrx/platform/commit/100a8ef)), closes [#477](https://github.com/ngrx/platform/issues/477) - - -### Features - -* **createSelector:** Expose projector function on selectors to improve testability ([56cb21f](https://github.com/ngrx/platform/commit/56cb21f)), closes [#290](https://github.com/ngrx/platform/issues/290) -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Store:** createSelector with an array of selectors (#340) ([2f6a035](https://github.com/ngrx/platform/commit/2f6a035)), closes [#192](https://github.com/ngrx/platform/issues/192) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Store:** Add type signature for metareducer (#270) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) -* **Store:** Set initial state for feature modules (#235) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) -* **Store:** Update usage of compose for reducer factory (#252) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) -* **Store:** Use existing reducers when providing reducers without an InjectionToken (#254) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) -* **Store:** Use injector to get reducers provided via InjectionTokens (#259) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **createSelector:** memoize projector function (#228) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **Store:** Exported initial state tokens (#65) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector (#74) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) -* **Store:** Remove parameter destructuring for strict mode (#33) (#77) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type (#72) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils (#10) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) -* **Store:** Added initial state function support for features. Added more tests (#85) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) -* **Store:** Allow initial state function for AoT compatibility (#59) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens (#36) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers (#87) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -## 4.1.1 (2017-11-07) - - -### Bug Fixes - -* Add support for Angular 5 ([30a8c56](https://github.com/ngrx/platform/commit/30a8c56)) - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **combineSelectors:** Remove default parameter from function signature for Closure ([ae7d5e1](https://github.com/ngrx/platform/commit/ae7d5e1)) -* **Store:** Fix typing for feature to accept InjectionToken (#375) ([38b2f95](https://github.com/ngrx/platform/commit/38b2f95)), closes [#375](https://github.com/ngrx/platform/issues/375) -* **Store:** Refactor parameter initialization in combineReducers for Closure ([5c60cba](https://github.com/ngrx/platform/commit/5c60cba)) -* **Store:** Set initial value for state action pair to object (#480) ([100a8ef](https://github.com/ngrx/platform/commit/100a8ef)), closes [#477](https://github.com/ngrx/platform/issues/477) - - -### Features - -* **createSelector:** Expose projector function on selectors to improve testability ([56cb21f](https://github.com/ngrx/platform/commit/56cb21f)), closes [#290](https://github.com/ngrx/platform/issues/290) -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Store:** createSelector with an array of selectors (#340) ([2f6a035](https://github.com/ngrx/platform/commit/2f6a035)), closes [#192](https://github.com/ngrx/platform/issues/192) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Store:** Add type signature for metareducer (#270) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) -* **Store:** Set initial state for feature modules (#235) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) -* **Store:** Update usage of compose for reducer factory (#252) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) -* **Store:** Use existing reducers when providing reducers without an InjectionToken (#254) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) -* **Store:** Use injector to get reducers provided via InjectionTokens (#259) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **createSelector:** memoize projector function (#228) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **Store:** Exported initial state tokens (#65) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector (#74) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) -* **Store:** Remove parameter destructuring for strict mode (#33) (#77) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type (#72) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils (#10) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) -* **Store:** Added initial state function support for features. Added more tests (#85) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) -* **Store:** Allow initial state function for AoT compatibility (#59) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens (#36) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers (#87) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -# 4.1.0 (2017-10-19) - - -### Bug Fixes - -* **combineSelectors:** Remove default parameter from function signature for Closure ([ae7d5e1](https://github.com/ngrx/platform/commit/ae7d5e1)) -* **Store:** Fix typing for feature to accept InjectionToken (#375) ([38b2f95](https://github.com/ngrx/platform/commit/38b2f95)), closes [#375](https://github.com/ngrx/platform/issues/375) -* **Store:** Refactor parameter initialization in combineReducers for Closure ([5c60cba](https://github.com/ngrx/platform/commit/5c60cba)) -* **Store:** Set initial value for state action pair to object (#480) ([100a8ef](https://github.com/ngrx/platform/commit/100a8ef)), closes [#477](https://github.com/ngrx/platform/issues/477) - - -### Features - -* **createSelector:** Expose projector function on selectors to improve testability ([56cb21f](https://github.com/ngrx/platform/commit/56cb21f)), closes [#290](https://github.com/ngrx/platform/issues/290) -* **Entity:** Add default selectId function for EntityAdapter (#405) ([2afb792](https://github.com/ngrx/platform/commit/2afb792)) -* **Store:** createSelector with an array of selectors (#340) ([2f6a035](https://github.com/ngrx/platform/commit/2f6a035)), closes [#192](https://github.com/ngrx/platform/issues/192) - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Store:** Add type signature for metareducer (#270) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) -* **Store:** Set initial state for feature modules (#235) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) -* **Store:** Update usage of compose for reducer factory (#252) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) -* **Store:** Use existing reducers when providing reducers without an InjectionToken (#254) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) -* **Store:** Use injector to get reducers provided via InjectionTokens (#259) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **createSelector:** memoize projector function (#228) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **Store:** Exported initial state tokens (#65) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector (#74) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) -* **Store:** Remove parameter destructuring for strict mode (#33) (#77) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type (#72) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils (#10) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) -* **Store:** Added initial state function support for features. Added more tests (#85) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) -* **Store:** Allow initial state function for AoT compatibility (#59) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens (#36) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers (#87) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -## 4.0.3 (2017-08-16) - - -### Bug Fixes - -* **Store:** Add type signature for metareducer (#270) ([57633d2](https://github.com/ngrx/platform/commit/57633d2)), closes [#264](https://github.com/ngrx/platform/issues/264) [#170](https://github.com/ngrx/platform/issues/170) -* **Store:** Set initial state for feature modules (#235) ([4aec80c](https://github.com/ngrx/platform/commit/4aec80c)), closes [#206](https://github.com/ngrx/platform/issues/206) [#233](https://github.com/ngrx/platform/issues/233) -* **Store:** Update usage of compose for reducer factory (#252) ([683013c](https://github.com/ngrx/platform/commit/683013c)), closes [#247](https://github.com/ngrx/platform/issues/247) -* **Store:** Use existing reducers when providing reducers without an InjectionToken (#254) ([c409252](https://github.com/ngrx/platform/commit/c409252)), closes [#250](https://github.com/ngrx/platform/issues/250) [#116](https://github.com/ngrx/platform/issues/116) -* **Store:** Use injector to get reducers provided via InjectionTokens (#259) ([bd968fa](https://github.com/ngrx/platform/commit/bd968fa)) - - - - -## 4.0.2 (2017-08-02) - - -### Bug Fixes - -* **createSelector:** memoize projector function (#228) ([e2f1e57](https://github.com/ngrx/platform/commit/e2f1e57)), closes [#226](https://github.com/ngrx/platform/issues/226) -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **Store:** Exported initial state tokens (#65) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector (#74) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove auto-memoization of selector functions ([90899f7](https://github.com/ngrx/platform/commit/90899f7)), closes [#118](https://github.com/ngrx/platform/issues/118) -* **Store:** Remove parameter destructuring for strict mode (#33) (#77) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type (#72) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils (#10) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Add injection token option for feature modules (#153) ([7f77693](https://github.com/ngrx/platform/commit/7f77693)), closes [#116](https://github.com/ngrx/platform/issues/116) [#141](https://github.com/ngrx/platform/issues/141) [#147](https://github.com/ngrx/platform/issues/147) -* **Store:** Added initial state function support for features. Added more tests (#85) ([5e5d7dd](https://github.com/ngrx/platform/commit/5e5d7dd)) -* **Store:** Allow initial state function for AoT compatibility (#59) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens (#36) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers (#87) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` - - - - - -# 4.0.0 (2017-07-18) - - -### Bug Fixes - -* **Devtools:** Removed SHOULD_INSTRUMENT token used to eagerly inject providers (#57) ([b90df34](https://github.com/ngrx/platform/commit/b90df34)) -* **omit:** Strengthen the type checking of the omit utility function ([3982038](https://github.com/ngrx/platform/commit/3982038)) -* **Store:** Exported initial state tokens (#65) ([4b27b6d](https://github.com/ngrx/platform/commit/4b27b6d)) -* **Store:** pass all required arguments to projector (#74) ([9b82b3a](https://github.com/ngrx/platform/commit/9b82b3a)) -* **Store:** Remove parameter destructuring for strict mode (#33) (#77) ([c9d6a45](https://github.com/ngrx/platform/commit/c9d6a45)) -* **Store:** Removed readonly from type (#72) ([68274c9](https://github.com/ngrx/platform/commit/68274c9)) - - -### Code Refactoring - -* **Effects:** Simplified AP, added better error reporting and effects stream control ([015107f](https://github.com/ngrx/platform/commit/015107f)) - - -### Features - -* **build:** Updated build pipeline for modules ([68bd9df](https://github.com/ngrx/platform/commit/68bd9df)) -* **Effects:** Introduce new Effects testing module (#70) ([7dbb571](https://github.com/ngrx/platform/commit/7dbb571)) -* **store:** Add 'createSelector' and 'createFeatureSelector' utils (#10) ([41758b1](https://github.com/ngrx/platform/commit/41758b1)) -* **Store:** Allow initial state function for AoT compatibility (#59) ([1a166ec](https://github.com/ngrx/platform/commit/1a166ec)), closes [#51](https://github.com/ngrx/platform/issues/51) -* **Store:** Allow parent modules to provide reducers with tokens (#36) ([069b12f](https://github.com/ngrx/platform/commit/069b12f)), closes [#34](https://github.com/ngrx/platform/issues/34) -* **Store:** Simplify API for adding meta-reducers (#87) ([d2295c7](https://github.com/ngrx/platform/commit/d2295c7)) - - -### BREAKING CHANGES - -* **Effects:** Effects API for registering effects has been updated to allow for multiple classes to be provided. - -BEFORE: -```ts -@NgModule({ -imports: [ -EffectsModule.run(SourceA), -EffectsModule.run(SourceB) -] -}) -export class AppModule { } -``` - -AFTER: -```ts -@NgModule({ -imports: [ -EffectsModule.forRoot([ -SourceA, -SourceB, -SourceC, -]) -] -}) -export class AppModule { } - -@NgModule({ -imports: [ -EffectsModule.forFeature([ -FeatureSourceA, -FeatureSourceB, -FeatureSourceC, -]) -] -}) -export class SomeFeatureModule { } -``` +See [CHANGELOG.md](https://github.com/ngrx/platform/blob/master/CHANGELOG.md) diff --git a/modules/store/schematics-core/index.ts b/modules/store/schematics-core/index.ts index 36cc0abbcf..9608baec44 100644 --- a/modules/store/schematics-core/index.ts +++ b/modules/store/schematics-core/index.ts @@ -15,6 +15,7 @@ export { getDecoratorMetadata, getContentOfKeyLiteral, insertAfterLastOccurrence, + insertImport, addBootstrapToModule, addDeclarationToModule, addExportToModule, @@ -49,7 +50,6 @@ export { } from './utility/ngrx-utils'; export { getProjectPath, getProject, isLib } from './utility/project'; -export { insertImport } from './utility/route-utils'; export const stringUtils = { dasherize, diff --git a/modules/store/schematics-core/utility/ast-utils.ts b/modules/store/schematics-core/utility/ast-utils.ts index b1f263974e..f6174fc4b1 100644 --- a/modules/store/schematics-core/utility/ast-utils.ts +++ b/modules/store/schematics-core/utility/ast-utils.ts @@ -7,8 +7,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import { Change, InsertChange } from './change'; -import { insertImport } from './route-utils'; +import { Change, InsertChange, NoopChange } from './change'; /** * Find all nodes from the AST in the subtree of node of SyntaxKind kind. @@ -537,3 +536,103 @@ export function addBootstrapToModule( importPath ); } + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ + +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + const rootNode = source; + const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + + // get nodes that map to import statements from the file fileName + const relevantImports = allImports.filter(node => { + // StringLiteral of the ImportDeclaration is the import file (fileName in this case). + const importFiles = node + .getChildren() + .filter(child => child.kind === ts.SyntaxKind.StringLiteral) + .map(n => (n as ts.StringLiteral).text); + + return importFiles.filter(file => file === fileName).length === 1; + }); + + if (relevantImports.length > 0) { + let importsAsterisk = false; + // imports from import file + const imports: ts.Node[] = []; + relevantImports.forEach(n => { + Array.prototype.push.apply( + imports, + findNodes(n, ts.SyntaxKind.Identifier) + ); + if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + importsAsterisk = true; + } + }); + + // if imports * from fileName, don't add symbolName + if (importsAsterisk) { + return new NoopChange(); + } + + const importTextNodes = imports.filter( + n => (n as ts.Identifier).text === symbolName + ); + + // insert import if it's not there + if (importTextNodes.length === 0) { + const fallbackPos = + findNodes( + relevantImports[0], + ts.SyntaxKind.CloseBraceToken + )[0].getStart() || + findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + + return insertAfterLastOccurrence( + imports, + `, ${symbolName}`, + fileToEdit, + fallbackPos + ); + } + + return new NoopChange(); + } + + // no such import declaration exists + const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( + n => n.getText() === 'use strict' + ); + let fallbackPos = 0; + if (useStrict.length > 0) { + fallbackPos = useStrict[0].end; + } + const open = isDefault ? '' : '{ '; + const close = isDefault ? '' : ' }'; + // if there are no imports or 'use strict' statement, insert import at beginning of file + const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; + const separator = insertAtBeginning ? '' : ';\n'; + const toInsert = + `${separator}import ${open}${symbolName}${close}` + + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; + + return insertAfterLastOccurrence( + allImports, + toInsert, + fileToEdit, + fallbackPos, + ts.SyntaxKind.StringLiteral + ); +} diff --git a/modules/store/schematics-core/utility/ngrx-utils.ts b/modules/store/schematics-core/utility/ngrx-utils.ts index 28294e1110..d856f79346 100644 --- a/modules/store/schematics-core/utility/ngrx-utils.ts +++ b/modules/store/schematics-core/utility/ngrx-utils.ts @@ -4,8 +4,7 @@ import { InsertChange, Change, NoopChange } from './change'; import { Tree, SchematicsException, Rule } from '@angular-devkit/schematics'; import { normalize } from '@angular-devkit/core'; import { buildRelativePath } from './find-module'; -import { insertImport } from './route-utils'; -import { addImportToModule } from './ast-utils'; +import { addImportToModule, insertImport } from './ast-utils'; export function addReducerToState(options: any): Rule { return (host: Tree) => { @@ -79,7 +78,7 @@ export function addReducerToState(options: any): Rule { export function addReducerToStateInterface( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { const stateInterface = source.statements.find( stm => stm.kind === ts.SyntaxKind.InterfaceDeclaration @@ -90,11 +89,12 @@ export function addReducerToStateInterface( return new NoopChange(); } + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.State;'; + state + ': from' + stringUtils.classify(options.name) + '.State;'; const expr = node as any; let position; let toInsert; @@ -125,7 +125,7 @@ export function addReducerToStateInterface( export function addReducerToActionReducerMap( source: ts.SourceFile, reducersPath: string, - options: { name: string } + options: { name: string; plural: boolean } ): Change { let initializer: any; const actionReducerMap: any = source.statements @@ -152,11 +152,12 @@ export function addReducerToActionReducerMap( let node = actionReducerMap.initializer; + const state = options.plural + ? stringUtils.pluralize(options.name) + : stringUtils.camelize(options.name); + const keyInsert = - stringUtils.camelize(options.name) + - ': from' + - stringUtils.classify(options.name) + - '.reducer,'; + state + ': from' + stringUtils.classify(options.name) + '.reducer,'; const expr = node as any; let position; let toInsert; diff --git a/modules/store/schematics-core/utility/project.ts b/modules/store/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/store/schematics-core/utility/project.ts +++ b/modules/store/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/store/schematics-core/utility/route-utils.ts b/modules/store/schematics-core/utility/route-utils.ts deleted file mode 100644 index d25cc059a8..0000000000 --- a/modules/store/schematics-core/utility/route-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as ts from 'typescript'; -import { findNodes, insertAfterLastOccurrence } from './ast-utils'; -import { Change, NoopChange } from './change'; - -/** - * Add Import `import { symbolName } from fileName` if the import doesn't exit - * already. Assumes fileToEdit can be resolved and accessed. - * @param fileToEdit (file we want to add import to) - * @param symbolName (item to import) - * @param fileName (path to the file) - * @param isDefault (if true, import follows style for importing default exports) - * @return Change - */ - -export function insertImport( - source: ts.SourceFile, - fileToEdit: string, - symbolName: string, - fileName: string, - isDefault = false -): Change { - const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); - - // get nodes that map to import statements from the file fileName - const relevantImports = allImports.filter(node => { - // StringLiteral of the ImportDeclaration is the import file (fileName in this case). - const importFiles = node - .getChildren() - .filter(child => child.kind === ts.SyntaxKind.StringLiteral) - .map(n => (n as ts.StringLiteral).text); - - return importFiles.filter(file => file === fileName).length === 1; - }); - - if (relevantImports.length > 0) { - let importsAsterisk = false; - // imports from import file - const imports: ts.Node[] = []; - relevantImports.forEach(n => { - Array.prototype.push.apply( - imports, - findNodes(n, ts.SyntaxKind.Identifier) - ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { - importsAsterisk = true; - } - }); - - // if imports * from fileName, don't add symbolName - if (importsAsterisk) { - return new NoopChange(); - } - - const importTextNodes = imports.filter( - n => (n as ts.Identifier).text === symbolName - ); - - // insert import if it's not there - if (importTextNodes.length === 0) { - const fallbackPos = - findNodes( - relevantImports[0], - ts.SyntaxKind.CloseBraceToken - )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); - - return insertAfterLastOccurrence( - imports, - `, ${symbolName}`, - fileToEdit, - fallbackPos - ); - } - - return new NoopChange(); - } - - // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - n => n.getText() === 'use strict' - ); - let fallbackPos = 0; - if (useStrict.length > 0) { - fallbackPos = useStrict[0].end; - } - const open = isDefault ? '' : '{ '; - const close = isDefault ? '' : ' }'; - // if there are no imports or 'use strict' statement, insert import at beginning of file - const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; - const separator = insertAtBeginning ? '' : ';\n'; - const toInsert = - `${separator}import ${open}${symbolName}${close}` + - ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`; - - return insertAfterLastOccurrence( - allImports, - toInsert, - fileToEdit, - fallbackPos, - ts.SyntaxKind.StringLiteral - ); -} diff --git a/modules/store/schematics-core/utility/strings.ts b/modules/store/schematics-core/utility/strings.ts index dae37e563c..5ebec70706 100644 --- a/modules/store/schematics-core/utility/strings.ts +++ b/modules/store/schematics-core/utility/strings.ts @@ -110,6 +110,25 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.substr(1); } +/** + Returns the plural form of a string + + ```javascript + 'innerHTML'.pluralize() // 'InnerHTMLs' + 'action_name'.pluralize() // 'actionNames' + 'css-class-name'.pluralize() // 'cssClassNames' + 'regex'.pluralize() // 'regexes' + 'user'.pluralize() // 'users' + ``` + */ +export function pluralize(str: string): string { + return camelize( + [/([^aeiou])y$/, /()fe?$/, /([^aeiou]o|[sxz]|[cs]h)$/].map( + (c, i) => (str = str.replace(c, `$1${'iv'[i] || ''}e`)) + ) && str + 's' + ); +} + export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } diff --git a/modules/store/schematics/ng-add/files/__statePath__/index.ts b/modules/store/schematics/ng-add/files/__statePath__/index.ts.template similarity index 100% rename from modules/store/schematics/ng-add/files/__statePath__/index.ts rename to modules/store/schematics/ng-add/files/__statePath__/index.ts.template diff --git a/modules/store/schematics/ng-add/index.spec.ts b/modules/store/schematics/ng-add/index.spec.ts index 156a345693..32ecc24754 100644 --- a/modules/store/schematics/ng-add/index.spec.ts +++ b/modules/store/schematics/ng-add/index.spec.ts @@ -22,7 +22,6 @@ describe('Store ng-add Schematic', () => { }; const projectPath = getTestProjectPath(); - let appTree: UnitTestTree; beforeEach(() => { @@ -33,6 +32,7 @@ describe('Store ng-add Schematic', () => { const options = { ...defaultOptions }; const tree = schematicRunner.runSchematic('ng-add', options, appTree); + const packageJson = JSON.parse(tree.readContent('/package.json')); expect(packageJson.dependencies['@ngrx/store']).toBeDefined(); @@ -105,11 +105,11 @@ describe('Store ng-add Schematic', () => { it('should support a default root state interface name', () => { const options = { ...defaultOptions, name: 'State' }; - const tree = schematicRunner.runSchematic('ng-add', options, appTree); const content = tree.readContent( `${projectPath}/src/app/reducers/index.ts` ); + expect(content).toMatch(/export interface State {/); }); @@ -121,9 +121,11 @@ describe('Store ng-add Schematic', () => { }; const tree = schematicRunner.runSchematic('ng-add', options, appTree); + const content = tree.readContent( `${projectPath}/src/app/reducers/index.ts` ); + expect(content).toMatch(/export interface AppState {/); }); }); diff --git a/modules/store/schematics/ng-add/index.ts b/modules/store/schematics/ng-add/index.ts index 4bf04f81e1..c12caa1a4b 100644 --- a/modules/store/schematics/ng-add/index.ts +++ b/modules/store/schematics/ng-add/index.ts @@ -4,6 +4,7 @@ import { SchematicsException, Tree, apply, + applyTemplates, branchAndMerge, chain, mergeWith, @@ -121,11 +122,11 @@ export default function(options: RootStoreOptions): Rule { } const templateSource = apply(url('./files'), [ - template({ + applyTemplates({ ...stringUtils, - ...(options as object), + ...options, environmentsPath, - } as any), + }), move(parsedPath.path), ]); diff --git a/modules/store/spec/BUILD b/modules/store/spec/BUILD index 0c9cf39696..9895a5cd3f 100644 --- a/modules/store/spec/BUILD +++ b/modules/store/spec/BUILD @@ -11,8 +11,8 @@ ts_test_library( deps = [ "//modules/store", "//modules/store/testing", - "@rxjs", - "@rxjs//operators", + "@npm//rxjs", + "@npm//ts-snippet", ], ) diff --git a/modules/store/spec/action_creator.spec.ts b/modules/store/spec/action_creator.spec.ts new file mode 100644 index 0000000000..802fffa755 --- /dev/null +++ b/modules/store/spec/action_creator.spec.ts @@ -0,0 +1,145 @@ +import { createAction, props, union } from '@ngrx/store'; +import { expecter } from 'ts-snippet'; + +describe('Action Creators', () => { + let originalTimeout: number; + + beforeEach(() => { + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; + jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000; + }); + + afterEach(() => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; + }); + + const expectSnippet = expecter( + code => ` + // path goes from root + import {createAction, props, union} from './modules/store/src/action_creator'; + ${code}`, + { + moduleResolution: 'node', + target: 'es2015', + } + ); + + describe('createAction', () => { + it('should create an action', () => { + const foo = createAction('FOO', (foo: number) => ({ foo })); + const fooAction = foo(42); + + expect(fooAction).toEqual({ type: 'FOO', foo: 42 }); + }); + + it('should narrow the action', () => { + const foo = createAction('FOO', (foo: number) => ({ foo })); + const bar = createAction('BAR', (bar: number) => ({ bar })); + const both = union({ foo, bar }); + const narrow = (action: typeof both) => { + if (action.type === foo.type) { + expect(action.foo).toEqual(42); + } else { + throw new Error('Should not get here.'); + } + }; + + narrow(foo(42)); + }); + + it('should be serializable', () => { + const foo = createAction('FOO', (foo: number) => ({ foo })); + const fooAction = foo(42); + const text = JSON.stringify(fooAction); + + expect(JSON.parse(text)).toEqual({ type: 'FOO', foo: 42 }); + }); + + it('should enforce ctor parameters', () => { + expectSnippet(` + const foo = createAction('FOO', (foo: number) => ({ foo })); + const fooAction = foo('42'); + `).toFail(/not assignable to parameter of type 'number'/); + }); + + it('should enforce action property types', () => { + expectSnippet(` + const foo = createAction('FOO', (foo: number) => ({ foo })); + const fooAction = foo(42); + const value: string = fooAction.foo; + `).toFail(/'number' is not assignable to type 'string'/); + }); + + it('should enforce action property names', () => { + expectSnippet(` + const foo = createAction('FOO', (foo: number) => ({ foo })); + const fooAction = foo(42); + const value = fooAction.bar; + `).toFail(/'bar' does not exist on type/); + }); + }); + + describe('empty', () => { + it('should allow empty action', () => { + const foo = createAction('FOO'); + const fooAction = foo(); + + expect(fooAction).toEqual({ type: 'FOO' }); + }); + }); + + describe('props', () => { + it('should create an action', () => { + const foo = createAction('FOO', props<{ foo: number }>()); + const fooAction = foo({ foo: 42 }); + + expect(fooAction).toEqual({ type: 'FOO', foo: 42 }); + }); + + it('should narrow the action', () => { + const foo = createAction('FOO', props<{ foo: number }>()); + const bar = createAction('BAR', props<{ bar: number }>()); + const both = union({ foo, bar }); + const narrow = (action: typeof both) => { + if (action.type === foo.type) { + expect(action.foo).toEqual(42); + } else { + throw new Error('Should not get here.'); + } + }; + + narrow(foo({ foo: 42 })); + }); + + it('should be serializable', () => { + const foo = createAction('FOO', props<{ foo: number }>()); + const fooAction = foo({ foo: 42 }); + const text = JSON.stringify(fooAction); + + expect(JSON.parse(text)).toEqual({ foo: 42, type: 'FOO' }); + }); + + it('should enforce ctor parameters', () => { + expectSnippet(` + const foo = createAction('FOO', props<{ foo: number }>()); + const fooAction = foo({ foo: '42' }); + `).toFail(/'string' is not assignable to type 'number'/); + }); + + it('should enforce action property types', () => { + expectSnippet(` + const foo = createAction('FOO', props<{ foo: number }>()); + const fooAction = foo({ foo: 42 }); + const value: string = fooAction.foo; + `).toFail(/'number' is not assignable to type 'string'/); + }); + + it('should enforce action property names', () => { + expectSnippet(` + const foo = createAction('FOO', props<{ foo: number }>()); + const fooAction = foo({ foo: 42 }); + const value = fooAction.bar; + `).toFail(/'bar' does not exist on type/); + }); + }); +}); diff --git a/modules/store/spec/meta-reducers/action_serialization_reducer.spec.ts b/modules/store/spec/meta-reducers/action_serialization_reducer.spec.ts new file mode 100644 index 0000000000..90511ba9ce --- /dev/null +++ b/modules/store/spec/meta-reducers/action_serialization_reducer.spec.ts @@ -0,0 +1,23 @@ +import { actionSerializationCheckMetaReducer } from '../../src/meta-reducers'; + +describe('actionSerializationCheckMetaReducer:', () => { + describe('valid action:', () => { + it('should not throw', () => { + expect(() => + invokeReducer({ type: 'valid', payload: { id: 47 } }) + ).not.toThrow(); + }); + }); + + describe('invalid action:', () => { + it('should throw', () => { + expect(() => + invokeReducer({ type: 'invalid', payload: { date: new Date() } }) + ).toThrow(); + }); + }); + + function invokeReducer(action: any) { + actionSerializationCheckMetaReducer(() => {})(undefined, action); + } +}); diff --git a/modules/store/spec/meta-reducers/immutability_reducer.spec.ts b/modules/store/spec/meta-reducers/immutability_reducer.spec.ts new file mode 100644 index 0000000000..b86dd6d193 --- /dev/null +++ b/modules/store/spec/meta-reducers/immutability_reducer.spec.ts @@ -0,0 +1,57 @@ +import { immutabilityCheckMetaReducer } from '../../src/meta-reducers'; + +describe('immutabilityCheckMetaReducer:', () => { + describe('actions:', () => { + it('should not throw if left untouched', () => { + expect(() => invokeReducer((action: any) => action)).not.toThrow(); + }); + + it('should throw when mutating an action', () => { + expect(() => + invokeReducer((action: any) => { + action.foo = '123'; + }) + ).toThrow(); + expect(() => + invokeReducer((action: any) => { + action.numbers.push(4); + }) + ).toThrow(); + }); + + function invokeReducer(reduce: Function) { + immutabilityCheckMetaReducer((state, action) => { + reduce(action); + return state; + })({}, { type: 'invoke', numbers: [1, 2, 3] }); + } + }); + + describe('state:', () => { + it('should not throw if left untouched', () => { + expect(() => + invokeReducer((state: any) => ({ ...state, foo: 'bar' })) + ).not.toThrow(); + }); + + it('should throw when mutating state', () => { + expect(() => + invokeReducer((state: any) => { + state.foo = '123'; + }) + ).toThrow(); + expect(() => + invokeReducer((state: any) => { + state.numbers.push(4); + }) + ).toThrow(); + }); + + function invokeReducer(reduce: Function) { + immutabilityCheckMetaReducer((state, _action) => reduce(state))( + { numbers: [1, 2, 3] }, + { type: 'invoke' } + ); + } + }); +}); diff --git a/modules/store/spec/meta-reducers/state_serialization_reducer.spec.ts b/modules/store/spec/meta-reducers/state_serialization_reducer.spec.ts new file mode 100644 index 0000000000..77fc48f6cc --- /dev/null +++ b/modules/store/spec/meta-reducers/state_serialization_reducer.spec.ts @@ -0,0 +1,25 @@ +import { stateSerializationCheckMetaReducer } from '../../src/meta-reducers'; + +describe('stateSerializationCheckMetaReducer:', () => { + describe('valid next state:', () => { + it('should not throw', () => { + expect(() => + invokeReducer({ + nested: { number: 1, null: null }, + }) + ).not.toThrow(); + }); + }); + + describe('invalid next state:', () => { + it('should throw', () => { + expect(() => invokeReducer({ nested: { class: new Date() } })).toThrow(); + }); + }); + + function invokeReducer(nextState?: any) { + stateSerializationCheckMetaReducer(() => nextState)(undefined, { + type: 'invokeReducer', + }); + } +}); diff --git a/modules/store/spec/meta-reducers/utils.spec.ts b/modules/store/spec/meta-reducers/utils.spec.ts new file mode 100644 index 0000000000..5dab90cd6b --- /dev/null +++ b/modules/store/spec/meta-reducers/utils.spec.ts @@ -0,0 +1,82 @@ +import { + getUnserializable, + throwIfUnserializable, +} from '../../src/meta-reducers/utils'; + +describe('getUnserializable:', () => { + describe('serializable value:', () => { + it('should not throw', () => { + expect(getUnserializable(1)).toBe(false); + expect(getUnserializable(true)).toBe(false); + expect(getUnserializable('string')).toBe(false); + expect(getUnserializable([1, 2, 3])).toBe(false); + expect(getUnserializable({})).toBe(false); + expect( + getUnserializable({ + nested: { number: 1, undefined: undefined, null: null }, + }) + ).toBe(false); + }); + }); + + describe('unserializable value:', () => { + it('should throw', () => { + class TestClass {} + + expect(getUnserializable()).toEqual({ value: undefined, path: ['root'] }); + expect(getUnserializable(null)).toEqual({ value: null, path: ['root'] }); + + const date = new Date(); + expect(getUnserializable({ date })).toEqual({ + value: date, + path: ['date'], + }); + expect(getUnserializable({ set: new Set([]) })).toEqual({ + value: new Set([]), + path: ['set'], + }); + expect(getUnserializable({ map: new Map([]) })).toEqual({ + value: new Map([]), + path: ['map'], + }); + expect(getUnserializable({ class: new TestClass() })).toEqual({ + value: new TestClass(), + path: ['class'], + }); + expect( + getUnserializable({ + nested: { valid: true, class: new TestClass(), alsoValid: '' }, + valid: [3], + }) + ).toEqual({ value: new TestClass(), path: ['nested', 'class'] }); + }); + }); +}); + +describe('throwIfUnserializable', () => { + describe('serializable', () => { + it('should not throw an error', () => { + expect(() => throwIfUnserializable(false, 'state')).not.toThrow(); + }); + }); + + describe('unserializable', () => { + it('should throw an error', () => { + expect(() => + throwIfUnserializable({ path: ['root'], value: undefined }, 'state') + ).toThrowError(`Detected unserializable state at "root"`); + expect(() => + throwIfUnserializable({ path: ['date'], value: new Date() }, 'action') + ).toThrowError(`Detected unserializable action at "date"`); + expect(() => + throwIfUnserializable( + { + path: ['one', 'two', 'three'], + value: new Date(), + }, + 'state' + ) + ).toThrowError(`Detected unserializable state at "one.two.three"`); + }); + }); +}); diff --git a/modules/store/spec/runtime_checks.spec.ts b/modules/store/spec/runtime_checks.spec.ts new file mode 100644 index 0000000000..23a4fddec0 --- /dev/null +++ b/modules/store/spec/runtime_checks.spec.ts @@ -0,0 +1,294 @@ +import * as ngCore from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { Store, StoreModule, META_REDUCERS } from '..'; +import { createActiveRuntimeChecks } from '../src/runtime_checks'; +import { RuntimeChecks } from '../src/models'; + +describe('Runtime checks:', () => { + describe('createActiveRuntimeChecks:', () => { + it('should disable all checks by default', () => { + expect(createActiveRuntimeChecks()).toEqual({ + strictStateSerializability: false, + strictActionSerializability: false, + strictImmutability: false, + }); + }); + + it('should log a warning in dev mode when no configuration is provided', () => { + const spy = spyOn(console, 'warn'); + + createActiveRuntimeChecks(); + + expect(spy).toHaveBeenCalled(); + }); + + it('should not log a warning in dev mode when configuration is provided', () => { + const spy = spyOn(console, 'warn'); + + createActiveRuntimeChecks({}); + + expect(spy).not.toHaveBeenCalled(); + }); + + it('should not log a warning when not dev mode when no configuration is provided', () => { + spyOn(ngCore, 'isDevMode').and.returnValue(false); + const spy = spyOn(console, 'warn'); + + createActiveRuntimeChecks(); + + expect(spy).not.toHaveBeenCalled(); + }); + + it('should allow the user to override the config', () => { + expect( + createActiveRuntimeChecks({ + strictStateSerializability: true, + strictActionSerializability: true, + strictImmutability: true, + }) + ).toEqual({ + strictStateSerializability: true, + strictActionSerializability: true, + strictImmutability: true, + }); + }); + + it('should disable runtime checks in production', () => { + spyOn(ngCore, 'isDevMode').and.returnValue(false); + + expect(createActiveRuntimeChecks()).toEqual({ + strictStateSerializability: false, + strictActionSerializability: false, + strictImmutability: false, + }); + }); + }); + + describe('Registering custom meta-reducers:', () => { + it('should invoke internal meta reducers before user defined meta reducers', () => { + let logs: string[] = []; + function metaReducerFactory(logMessage: string) { + return function metaReducer(reducer: any) { + return function(state: any, action: any) { + logs.push(logMessage); + return reducer(state, action); + }; + }; + } + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + {}, + { + metaReducers: [metaReducerFactory('user')], + } + ), + ], + providers: [ + { + provide: META_REDUCERS, + useValue: metaReducerFactory('internal-single-one'), + multi: true, + }, + { + provide: META_REDUCERS, + useValue: metaReducerFactory('internal-single-two'), + multi: true, + }, + ], + }); + + const store: Store = TestBed.get(Store); + const expected = ['internal-single-one', 'internal-single-two', 'user']; + + expect(logs).toEqual(expected); + logs = []; + + store.dispatch({ type: 'foo' }); + expect(logs).toEqual(expected); + }); + }); + + describe('State Serialization:', () => { + const invalidAction = () => ({ type: ErrorTypes.UnserializableState }); + + it('should throw when enabled', (done: DoneFn) => { + const store = setupStore({ strictStateSerializability: true }); + + store.subscribe({ + error: err => { + expect(err).toMatch(/Detected unserializable state/); + done(); + }, + }); + + store.dispatch(invalidAction()); + }); + + it('should not throw when disabled', (done: DoneFn) => { + const store = setupStore({ strictStateSerializability: false }); + + store.subscribe({ + next: ({ state }) => { + if (state.invalidSerializationState) { + done(); + } + }, + }); + + store.dispatch(invalidAction()); + }); + }); + + describe('Action Serialization:', () => { + const invalidAction = () => ({ + type: ErrorTypes.UnserializableAction, + invalid: new Date(), + }); + + it('should throw when enabled', (done: DoneFn) => { + const store = setupStore({ strictActionSerializability: true }); + + store.subscribe({ + error: err => { + expect(err).toMatch(/Detected unserializable action/); + done(); + }, + }); + store.dispatch(invalidAction()); + }); + + it('should not throw when disabled', (done: DoneFn) => { + const store = setupStore({ strictActionSerializability: false }); + + store.subscribe({ + next: ({ state }) => { + if (state.invalidSerializationAction) { + done(); + } + }, + }); + + store.dispatch(invalidAction()); + }); + }); + + describe('State Mutations', () => { + const invalidAction = () => ({ + type: ErrorTypes.MutateState, + }); + + it('should throw when enabled', (done: DoneFn) => { + const store = setupStore({ strictImmutability: true }); + + store.subscribe({ + error: _ => { + done(); + }, + }); + + store.dispatch(invalidAction()); + }); + + it('should not throw when disabled', (done: DoneFn) => { + const store = setupStore({ strictImmutability: false }); + + store.subscribe({ + next: ({ state }) => { + if (state.invalidMutationState) { + done(); + } + }, + }); + + store.dispatch(invalidAction()); + }); + }); + + describe('Action Mutations', () => { + const invalidAction = () => ({ + type: ErrorTypes.MutateAction, + foo: 'foo', + }); + + it('should throw when enabled', (done: DoneFn) => { + const store = setupStore({ strictImmutability: true }); + + store.subscribe({ + error: _ => { + done(); + }, + }); + + store.dispatch(invalidAction()); + }); + + it('should not throw when disabled', (done: DoneFn) => { + const store = setupStore({ strictImmutability: false }); + + store.subscribe({ + next: ({ state }) => { + if (state.invalidMutationAction) { + done(); + } + }, + }); + + store.dispatch(invalidAction()); + }); + }); +}); + +function setupStore(runtimeChecks?: Partial): Store { + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + state: reducerWithBugs, + }, + { runtimeChecks } + ), + ], + }); + + return TestBed.get(Store); +} + +enum ErrorTypes { + UnserializableState = 'Action type producing unserializable state', + UnserializableAction = 'Action type producing unserializable action', + MutateAction = 'Action type producing action mutation', + MutateState = 'Action type producing state mutation', +} + +function reducerWithBugs(state: any = {}, action: any) { + switch (action.type) { + case ErrorTypes.UnserializableState: + return { + invalidSerializationState: true, + invalid: new Date(), + }; + + case ErrorTypes.UnserializableAction: { + return { + invalidSerializationAction: true, + }; + } + + case ErrorTypes.MutateAction: { + action.foo = 'foo'; + return { + invalidMutationAction: true, + }; + } + + case ErrorTypes.MutateState: { + state.invalidMutationState = true; + return state; + } + + default: + return state; + } +} diff --git a/modules/store/spec/store.spec.ts b/modules/store/spec/store.spec.ts index 18d91df57b..9af15062ef 100644 --- a/modules/store/spec/store.spec.ts +++ b/modules/store/spec/store.spec.ts @@ -1,4 +1,4 @@ -import { ReflectiveInjector, InjectionToken } from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { hot } from 'jasmine-marbles'; import { diff --git a/modules/store/src/action_creator.ts b/modules/store/src/action_creator.ts new file mode 100644 index 0000000000..117a2aff59 --- /dev/null +++ b/modules/store/src/action_creator.ts @@ -0,0 +1,67 @@ +import { + Creator, + ActionCreator, + TypedAction, + FunctionWithParametersType, + ParametersType, +} from './models'; + +/** + * Action creators taken from ts-action library and modified a bit to better + * fit current NgRx usage. Thank you Nicholas Jamieson (@cartant). + */ +export function createAction( + type: T +): ActionCreator TypedAction>; +export function createAction( + type: T, + config: { _as: 'props'; _p: P } +): ActionCreator P & TypedAction>; +export function createAction( + type: T, + creator: C +): FunctionWithParametersType< + ParametersType, + ReturnType & TypedAction +> & + TypedAction; +export function createAction( + type: T, + config?: { _as: 'props' } | Creator +): Creator { + if (typeof config === 'function') { + return defineType(type, (...args: unknown[]) => ({ + ...config(...args), + type, + })); + } + const as = config ? config._as : 'empty'; + switch (as) { + case 'empty': + return defineType(type, () => ({ type })); + case 'props': + return defineType(type, (props: unknown) => ({ + ...(props as object), + type, + })); + default: + throw new Error('Unexpected config.'); + } +} + +export function props

(): { _as: 'props'; _p: P } { + return { _as: 'props', _p: undefined! }; +} + +export function union< + C extends { [key: string]: ActionCreator } +>(creators: C): ReturnType { + return undefined!; +} + +function defineType(type: string, creator: Creator): Creator { + return Object.defineProperty(creator, 'type', { + value: type, + writable: false, + }); +} diff --git a/modules/store/src/index.ts b/modules/store/src/index.ts index ce02914c93..6db51ad83a 100644 --- a/modules/store/src/index.ts +++ b/modules/store/src/index.ts @@ -1,12 +1,15 @@ export { Action, + ActionCreator, ActionReducer, ActionReducerMap, ActionReducerFactory, + Creator, MetaReducer, Selector, SelectorWithProps, } from './models'; +export { createAction, props, union } from './action_creator'; export { Store, select } from './store'; export { combineReducers, compose, createReducerFactory } from './utils'; export { ActionsSubject, INIT } from './actions_subject'; @@ -43,6 +46,7 @@ export { _FEATURE_REDUCERS, FEATURE_REDUCERS, _FEATURE_REDUCERS_TOKEN, + USER_PROVIDED_META_REDUCERS, } from './tokens'; export { StoreModule, diff --git a/modules/store/src/meta-reducers/action_serialization_reducer.ts b/modules/store/src/meta-reducers/action_serialization_reducer.ts new file mode 100644 index 0000000000..d01452b41c --- /dev/null +++ b/modules/store/src/meta-reducers/action_serialization_reducer.ts @@ -0,0 +1,13 @@ +import { ActionReducer } from '../models'; +import { getUnserializable, throwIfUnserializable } from './utils'; + +export function actionSerializationCheckMetaReducer( + reducer: ActionReducer +): ActionReducer { + return function(state, action) { + const unserializable = getUnserializable(action); + throwIfUnserializable(unserializable, 'action'); + + return reducer(state, action); + }; +} diff --git a/modules/store/src/meta-reducers/immutability_reducer.ts b/modules/store/src/meta-reducers/immutability_reducer.ts new file mode 100644 index 0000000000..44616268b7 --- /dev/null +++ b/modules/store/src/meta-reducers/immutability_reducer.ts @@ -0,0 +1,32 @@ +import { ActionReducer } from '../models'; +import { isFunction, hasOwnProperty, isObjectLike } from './utils'; + +export function immutabilityCheckMetaReducer( + reducer: ActionReducer +): ActionReducer { + return function(state, action) { + const nextState = reducer(state, freeze(action)); + return freeze(nextState); + }; +} + +function freeze(target: any) { + Object.freeze(target); + + const targetIsFunction = isFunction(target); + + Object.getOwnPropertyNames(target).forEach(prop => { + const propValue = target[prop]; + if ( + hasOwnProperty(target, prop) && targetIsFunction + ? prop !== 'caller' && prop !== 'callee' && prop !== 'arguments' + : true && + (isObjectLike(propValue) || isFunction(propValue)) && + !Object.isFrozen(propValue) + ) { + freeze(propValue); + } + }); + + return target; +} diff --git a/modules/store/src/meta-reducers/index.ts b/modules/store/src/meta-reducers/index.ts new file mode 100644 index 0000000000..425789d973 --- /dev/null +++ b/modules/store/src/meta-reducers/index.ts @@ -0,0 +1,7 @@ +export { + stateSerializationCheckMetaReducer, +} from './state_serialization_reducer'; +export { + actionSerializationCheckMetaReducer, +} from './action_serialization_reducer'; +export { immutabilityCheckMetaReducer } from './immutability_reducer'; diff --git a/modules/store/src/meta-reducers/state_serialization_reducer.ts b/modules/store/src/meta-reducers/state_serialization_reducer.ts new file mode 100644 index 0000000000..4b8fe2b2ce --- /dev/null +++ b/modules/store/src/meta-reducers/state_serialization_reducer.ts @@ -0,0 +1,15 @@ +import { ActionReducer } from '../models'; +import { getUnserializable, throwIfUnserializable } from './utils'; + +export function stateSerializationCheckMetaReducer( + reducer: ActionReducer +): ActionReducer { + return function(state, action) { + const nextState = reducer(state, action); + + const unserializable = getUnserializable(nextState); + throwIfUnserializable(unserializable, 'state'); + + return nextState; + }; +} diff --git a/modules/store/src/meta-reducers/utils.ts b/modules/store/src/meta-reducers/utils.ts new file mode 100644 index 0000000000..b3e1af2735 --- /dev/null +++ b/modules/store/src/meta-reducers/utils.ts @@ -0,0 +1,111 @@ +export function getUnserializable( + target?: any, + path: string[] = [] +): false | { path: string[]; value: any } { + // Guard against undefined and null, e.g. a reducer that returns undefined + if ((isUndefined(target) || isNull(target)) && path.length === 0) { + return { + path: ['root'], + value: target, + }; + } + + const keys = Object.keys(target); + return keys.reduce((result, key) => { + if (result) { + return result; + } + + const value = (target as any)[key]; + + if ( + isUndefined(value) || + isNull(value) || + isNumber(value) || + isBoolean(value) || + isString(value) || + isArray(value) + ) { + return false; + } + + if (isPlainObject(value)) { + return getUnserializable(value, [...path, key]); + } + + return { + path: [...path, key], + value, + }; + }, false); +} + +export function throwIfUnserializable( + unserializable: false | { path: string[]; value: any }, + context: 'state' | 'action' +) { + if (unserializable === false) { + return; + } + + const unserializablePath = unserializable.path.join('.'); + const error: any = new Error( + `Detected unserializable ${context} at "${unserializablePath}"` + ); + error.value = unserializable.value; + error.unserializablePath = unserializablePath; + throw error; +} + +/** + * Object Utilities + */ + +export function isUndefined(target: any): target is undefined { + return target === undefined; +} + +export function isNull(target: any): target is null { + return target === null; +} + +export function isArray(target: any): target is Array { + return Array.isArray(target); +} + +export function isString(target: any): target is string { + return typeof target === 'string'; +} + +export function isBoolean(target: any): target is boolean { + return typeof target === 'boolean'; +} + +export function isNumber(target: any): target is number { + return typeof target === 'number'; +} + +export function isObjectLike(target: any): target is object { + return typeof target === 'object' && target !== null; +} + +export function isObject(target: any): target is object { + return isObjectLike(target) && !isArray(target); +} + +export function isPlainObject(target: any): target is object { + if (!isObject(target)) { + return false; + } + + const targetPrototype = Object.getPrototypeOf(target); + return targetPrototype === Object.prototype || targetPrototype === null; +} + +export function isFunction(target: any): target is Function { + return typeof target === 'function'; +} + +export function hasOwnProperty(target: object, propertyName: string): boolean { + return Object.prototype.hasOwnProperty.call(target, propertyName); +} diff --git a/modules/store/src/models.ts b/modules/store/src/models.ts index 34413a0139..43e13f104b 100644 --- a/modules/store/src/models.ts +++ b/modules/store/src/models.ts @@ -2,6 +2,11 @@ export interface Action { type: string; } +// declare to make it property-renaming safe +export declare interface TypedAction extends Action { + readonly type: T; +} + export type TypeId = () => T; export type InitialState = Partial | TypeId> | void; @@ -21,7 +26,7 @@ export interface ActionReducerFactory { ): ActionReducer; } -export type MetaReducer = ( +export type MetaReducer = ( reducer: ActionReducer ) => ActionReducer; @@ -39,3 +44,21 @@ export type SelectorWithProps = ( state: State, props: Props ) => Result; + +export type Creator = (...args: any[]) => object; + +export type ActionCreator = C & + TypedAction; + +export type FunctionWithParametersType

= ( + ...args: P +) => R; + +export type ParametersType = T extends (...args: infer U) => unknown + ? U + : never; +export interface RuntimeChecks { + strictStateSerializability: boolean; + strictActionSerializability: boolean; + strictImmutability: boolean; +} diff --git a/modules/store/src/runtime_checks.ts b/modules/store/src/runtime_checks.ts new file mode 100644 index 0000000000..674b9abed2 --- /dev/null +++ b/modules/store/src/runtime_checks.ts @@ -0,0 +1,95 @@ +import { isDevMode, Provider } from '@angular/core'; +import { + stateSerializationCheckMetaReducer, + actionSerializationCheckMetaReducer, + immutabilityCheckMetaReducer, +} from './meta-reducers'; +import { RuntimeChecks, MetaReducer } from './models'; +import { + _USER_RUNTIME_CHECKS, + _ACTIVE_RUNTIME_CHECKS, + META_REDUCERS, +} from './tokens'; + +export function createActiveRuntimeChecks( + runtimeChecks?: Partial +): RuntimeChecks { + if (isDevMode()) { + if (runtimeChecks === undefined) { + console.warn( + '@ngrx/store: runtime checks are currently opt-in but will be the default in the next major version, see https://ngrx.io/guide/migration/v8 for more information.' + ); + } + return { + strictStateSerializability: false, + strictActionSerializability: false, + strictImmutability: false, + ...runtimeChecks, + }; + } + + return { + strictStateSerializability: false, + strictActionSerializability: false, + strictImmutability: false, + }; +} + +export function createStateSerializationCheckMetaReducer({ + strictStateSerializability, +}: RuntimeChecks): MetaReducer { + return reducer => + strictStateSerializability + ? stateSerializationCheckMetaReducer(reducer) + : reducer; +} + +export function createActionSerializationCheckMetaReducer({ + strictActionSerializability, +}: RuntimeChecks): MetaReducer { + return reducer => + strictActionSerializability + ? actionSerializationCheckMetaReducer(reducer) + : reducer; +} + +export function createImmutabilityCheckMetaReducer({ + strictImmutability, +}: RuntimeChecks): MetaReducer { + return reducer => + strictImmutability ? immutabilityCheckMetaReducer(reducer) : reducer; +} + +export function provideRuntimeChecks( + runtimeChecks?: Partial +): Provider[] { + return [ + { + provide: _USER_RUNTIME_CHECKS, + useValue: runtimeChecks, + }, + { + provide: _ACTIVE_RUNTIME_CHECKS, + deps: [_USER_RUNTIME_CHECKS], + useFactory: createActiveRuntimeChecks, + }, + { + provide: META_REDUCERS, + multi: true, + deps: [_ACTIVE_RUNTIME_CHECKS], + useFactory: createStateSerializationCheckMetaReducer, + }, + { + provide: META_REDUCERS, + multi: true, + deps: [_ACTIVE_RUNTIME_CHECKS], + useFactory: createActionSerializationCheckMetaReducer, + }, + { + provide: META_REDUCERS, + multi: true, + deps: [_ACTIVE_RUNTIME_CHECKS], + useFactory: createImmutabilityCheckMetaReducer, + }, + ]; +} diff --git a/modules/store/src/state.ts b/modules/store/src/state.ts index c0a7fc9b50..0eeba2dd25 100644 --- a/modules/store/src/state.ts +++ b/modules/store/src/state.ts @@ -47,9 +47,12 @@ export class State extends BehaviorSubject implements OnDestroy { ) ); - this.stateSubscription = stateAndAction$.subscribe(({ state, action }) => { - this.next(state); - scannedActions.next(action); + this.stateSubscription = stateAndAction$.subscribe({ + next: ({ state, action }) => { + this.next(state); + scannedActions.next(action); + }, + error: err => this.error(err), }); } diff --git a/modules/store/src/store_module.ts b/modules/store/src/store_module.ts index 407f78e409..121de3516a 100644 --- a/modules/store/src/store_module.ts +++ b/modules/store/src/store_module.ts @@ -14,6 +14,7 @@ import { StoreFeature, InitialState, MetaReducer, + RuntimeChecks, } from './models'; import { compose, combineReducers, createReducerFactory } from './utils'; import { @@ -31,6 +32,8 @@ import { _FEATURE_REDUCERS_TOKEN, _STORE_FEATURES, _FEATURE_CONFIGS, + USER_PROVIDED_META_REDUCERS, + _RESOLVED_META_REDUCERS, } from './tokens'; import { ACTIONS_SUBJECT_PROVIDERS, ActionsSubject } from './actions_subject'; import { @@ -44,6 +47,7 @@ import { } from './scanned_actions_subject'; import { STATE_PROVIDERS } from './state'; import { STORE_PROVIDERS, Store } from './store'; +import { provideRuntimeChecks } from './runtime_checks'; @NgModule({}) export class StoreRootModule { @@ -82,23 +86,28 @@ export class StoreFeatureModule implements OnDestroy { } } -export type StoreConfig = { +export interface StoreConfig { initialState?: InitialState; reducerFactory?: ActionReducerFactory; metaReducers?: MetaReducer[]; -}; +} + +export interface RootStoreConfig + extends StoreConfig { + runtimeChecks?: Partial; +} @NgModule({}) export class StoreModule { static forRoot( reducers: ActionReducerMap | InjectionToken>, - config?: StoreConfig + config?: RootStoreConfig ): ModuleWithProviders; static forRoot( reducers: | ActionReducerMap | InjectionToken>, - config: StoreConfig = {} + config: RootStoreConfig = {} ): ModuleWithProviders { return { ngModule: StoreRootModule, @@ -121,9 +130,14 @@ export class StoreModule { useFactory: _createStoreReducers, }, { - provide: META_REDUCERS, + provide: USER_PROVIDED_META_REDUCERS, useValue: config.metaReducers ? config.metaReducers : [], }, + { + provide: _RESOLVED_META_REDUCERS, + deps: [META_REDUCERS, USER_PROVIDED_META_REDUCERS], + useFactory: _concatMetaReducers, + }, { provide: _REDUCER_FACTORY, useValue: config.reducerFactory @@ -132,7 +146,7 @@ export class StoreModule { }, { provide: REDUCER_FACTORY, - deps: [_REDUCER_FACTORY, META_REDUCERS], + deps: [_REDUCER_FACTORY, _RESOLVED_META_REDUCERS], useFactory: createReducerFactory, }, ACTIONS_SUBJECT_PROVIDERS, @@ -140,6 +154,7 @@ export class StoreModule { SCANNED_ACTIONS_SUBJECT_PROVIDERS, STATE_PROVIDERS, STORE_PROVIDERS, + provideRuntimeChecks(config.runtimeChecks), ], }; } @@ -219,8 +234,7 @@ export class StoreModule { export function _createStoreReducers( injector: Injector, - reducers: ActionReducerMap, - tokenReducers: ActionReducerMap + reducers: ActionReducerMap ) { return reducers instanceof InjectionToken ? injector.get(reducers) : reducers; } @@ -248,10 +262,9 @@ export function _createFeatureStore( export function _createFeatureReducers( injector: Injector, - reducerCollection: ActionReducerMap[], - tokenReducerCollection: ActionReducerMap[] + reducerCollection: ActionReducerMap[] ) { - const reducers = reducerCollection.map((reducer, index) => { + const reducers = reducerCollection.map(reducer => { return reducer instanceof InjectionToken ? injector.get(reducer) : reducer; }); @@ -265,3 +278,10 @@ export function _initialStateFactory(initialState: any): any { return initialState; } + +export function _concatMetaReducers( + metaReducers: MetaReducer[], + userProvidedMetaReducers: MetaReducer[] +): MetaReducer[] { + return metaReducers.concat(userProvidedMetaReducers); +} diff --git a/modules/store/src/tokens.ts b/modules/store/src/tokens.ts index ae5f43fe6d..5e45f54597 100644 --- a/modules/store/src/tokens.ts +++ b/modules/store/src/tokens.ts @@ -1,4 +1,5 @@ import { InjectionToken } from '@angular/core'; +import { RuntimeChecks, MetaReducer } from './models'; export const _INITIAL_STATE = new InjectionToken( '@ngrx/store Internal Initial State' @@ -16,7 +17,6 @@ export const INITIAL_REDUCERS = new InjectionToken( export const _INITIAL_REDUCERS = new InjectionToken( '@ngrx/store Internal Initial Reducers' ); -export const META_REDUCERS = new InjectionToken('@ngrx/store Meta Reducers'); export const STORE_FEATURES = new InjectionToken('@ngrx/store Store Features'); export const _STORE_REDUCERS = new InjectionToken( '@ngrx/store Internal Store Reducers' @@ -39,3 +39,39 @@ export const _FEATURE_REDUCERS_TOKEN = new InjectionToken( export const FEATURE_REDUCERS = new InjectionToken( '@ngrx/store Feature Reducers' ); + +/** + * User-defined meta reducers from StoreModule.forRoot() + */ +export const USER_PROVIDED_META_REDUCERS = new InjectionToken( + '@ngrx/store User Provided Meta Reducers' +); + +/** + * Meta reducers defined either internally by @ngrx/store or by library authors + */ +export const META_REDUCERS = new InjectionToken( + '@ngrx/store Meta Reducers' +); + +/** + * Concats the user provided meta reducers and the meta reducers provided on the multi + * injection token + */ +export const _RESOLVED_META_REDUCERS = new InjectionToken( + '@ngrx/store Internal Resolved Meta Reducers' +); + +/** + * Runtime checks defined by the user + */ +export const _USER_RUNTIME_CHECKS = new InjectionToken( + '@ngrx/store Internal User Runtime Checks Config' +); + +/** + * Runtime checks currently in use + */ +export const _ACTIVE_RUNTIME_CHECKS = new InjectionToken( + '@ngrx/store Internal Runetime Checks' +); diff --git a/modules/store/testing/BUILD b/modules/store/testing/BUILD index 7c740f0458..41694f6668 100644 --- a/modules/store/testing/BUILD +++ b/modules/store/testing/BUILD @@ -14,7 +14,7 @@ ng_module( visibility = ["//visibility:public"], deps = [ "//modules/store", - "@angular//packages/core", - "@rxjs", + "@npm//@angular/core", + "@npm//rxjs", ], ) diff --git a/package.json b/package.json index 51fb693a2a..6a85e8fa42 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,16 @@ { "name": "@ngrx/platform", - "version": "7.2.0", + "version": "7.4.0", "description": "monorepo for ngrx development", "scripts": { "precommit": "lint-staged", - "build": "yarn bazel build ...", + "build": "bazel build //modules/...", "deploy:builds": "ts-node ./build/deploy-build.ts", "deploy:preview": "ts-node ./build/deploy-preview.ts", + "cleanup:previews": "ts-node ./build/cleanup-previews.ts", "test:unit": "node ./tests.js", "test": "nyc yarn run test:unit", + "test:bazel": "bazel test //modules/...", "clean": "git clean -xdf", "cli": "ng", "coverage:html": "nyc report --reporter=html", @@ -16,22 +18,26 @@ "example:start": "yarn run cli serve", "example:start:aot": "yarn run cli serve --prod", "example:test": "jest -c projects/example-app/jest.config.js --watch", - "example:build":"yarn cli build --prod", - "example:build:prod": "yarn example:build -- --base-href \"/platform/example-app/\"", + "example:cypress:open": "cypress open --project=projects/example-app-cypress", + "example:cypress:run": "cypress run --project=projects/example-app-cypress", + "example:cypress:ci": "npm-run-all --parallel --race example:server \"example:cypress:run -- --config=baseUrl=http://localhost:4000\"", + "example:build": "yarn cli build --prod", + "example:build:prod": "yarn example:build --no-progress --base-href \"/platform/example-app/\"", + "example:server": "node build/example-app-server", "ci": "yarn run test && nyc report --reporter=text-lcov | coveralls", "prettier": "prettier --write \"**/*.ts\"", "watch:tests": "chokidar \"modules/**/*.ts\" --initial --command \"yarn run test:unit\"", "postinstall": "opencollective postinstall", + "prepublish": "ngc -p angular-metadata.tsconfig.json", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", - "preskylint": "yarn bazel build --noshow_progress @io_bazel//src/tools/skylark/java/com/google/devtools/skylark/skylint:Skylint", - "skylint": "find . -type f -name \"*.bzl\" ! -path \"*/node_modules/*\" ! -path \"./dist/*\" | xargs $(bazel info bazel-bin)/external/io_bazel/src/tools/skylark/java/com/google/devtools/skylark/skylint/Skylint --disable-checks=deprecated-api", - "prebuildifier": "yarn bazel build --noshow_progress @com_github_bazelbuild_buildtools//buildifier", - "buildifier": "find . -type f \\( -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/com_github_bazelbuild_buildtools/buildifier/*/buildifier", + "bazel:format": "find . -type f \\( -name \"*.bzl\" -or -name WORKSPACE -or -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" ! -path \"./dist/*\" | xargs buildifier -v --warnings=attr-cfg,attr-license,attr-non-empty,attr-output-default,attr-single-file,constant-glob,ctx-actions,ctx-args,depset-iteration,depset-union,dict-concatenation,duplicated-name,filetype,git-repository,http-archive,integer-division,load,load-on-top,native-build,native-package,out-of-order-load,output-group,package-name,package-on-top,positional-args,redefined-variable,repository-name,same-origin-load,string-iteration,unsorted-dict-items,unused-variable", + "bazel:lint": "yarn bazel:format --lint=warn", + "bazel:lint-fix": "yarn bazel:format --lint=fix", "copy:schematics": "ts-node ./build/copy-schematics-core.ts", "build:stackblitz": "ts-node ./build/stackblitz.ts && git add ./stackblitz.html" }, "engines": { - "node": ">=10.9.0 <11.2.0", + "node": ">=10.9.0 <=11.12.0", "npm": ">=5.3.0", "yarn": ">=1.9.2 <2.0.0" }, @@ -39,6 +45,9 @@ "*.{ts,json,md}": [ "prettier --write", "git add" + ], + "*.{bazel}": [ + "buildifier" ] }, "keywords": [ @@ -69,7 +78,7 @@ }, "dependencies": { "@angular/animations": "^7.0.1", - "@angular/bazel": "^7.0.1", + "@angular/bazel": "^8.0.0-beta.10", "@angular/cdk": "^7.0.1", "@angular/cli": "^7.0.1", "@angular/common": "^7.0.1", @@ -83,6 +92,8 @@ "@angular/platform-browser-dynamic": "^7.0.1", "@angular/platform-server": "^7.0.1", "@angular/router": "^7.0.1", + "@applitools/eyes-cypress": "^3.4.12", + "@bazel/buildifier": "^0.22.0", "@ngrx/db": "^2.2.0-beta.0", "core-js": "^2.5.4", "hammerjs": "^2.0.8", @@ -92,7 +103,9 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^0.10.0", - "@bazel/bazel": "^0.19.1", + "@bazel/bazel": "^0.24.0", + "@bazel/typescript": "^0.27.8", + "@cypress/webpack-preprocessor": "^4.0.3", "@octokit/rest": "^15.17.0", "@types/fs-extra": "^2.1.0", "@types/glob": "^5.0.33", @@ -112,11 +125,12 @@ "conventional-changelog-cli": "^1.3.21", "coveralls": "^2.13.0", "cpy-cli": "^1.0.1", + "cypress": "^3.1.5", "deep-freeze": "^0.0.1", - "deep-freeze-strict": "^1.1.1", + "express": "^4.16.4", "fs-extra": "^2.1.2", "glob": "^7.1.2", - "husky": "^0.14.3", + "husky": "^1.2.0", "jasmine": "^2.5.3", "jasmine-core": "~2.5.2", "jasmine-marbles": "^0.4.0", @@ -132,6 +146,7 @@ "karma-jasmine-html-reporter": "^0.2.2", "lint-staged": "^8.0.0", "ncp": "^2.0.0", + "npm-run-all": "^4.1.5", "nyc": "^10.1.2", "ora": "^1.3.0", "prettier": "^1.11.1", @@ -141,9 +156,11 @@ "rimraf": "^2.5.4", "rollup": "^0.50.0", "sorcery": "^0.10.0", + "ts-loader": "^5.3.3", "ts-node": "^5.0.1", + "ts-snippet": "^4.1.0", "tsconfig-paths": "^3.1.3", - "tsickle": "^0.32.1", + "tsickle": "^0.34.3", "tslib": "^1.7.1", "tslint": "^5.7.0", "tsutils": "2.20.0", @@ -154,5 +171,11 @@ "type": "opencollective", "url": "https://opencollective.com/ngrx", "logo": "https://opencollective.com/opencollective/logo.txt" + }, + "resolutions": { + "listr": "^0.14.2", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "lodash": "^4.17.11" } } diff --git a/projects/example-app-cypress/cypress.json b/projects/example-app-cypress/cypress.json new file mode 100644 index 0000000000..e100722097 --- /dev/null +++ b/projects/example-app-cypress/cypress.json @@ -0,0 +1,12 @@ +{ + "baseUrl": "http://localhost:4200", + "fixturesFolder": "fixtures", + "integrationFolder": "integration", + "pluginsFile": "plugins/index.js", + "supportFile": "support/index.js", + "screenshotsFolder": "screenshots", + "videosFolder": "videos", + "video": false, + "projectId": "w65h7e", + "eyesTimeout": 180000 +} diff --git a/projects/example-app-cypress/integration/round-trip.spec.ts b/projects/example-app-cypress/integration/round-trip.spec.ts new file mode 100644 index 0000000000..bdccc874c8 --- /dev/null +++ b/projects/example-app-cypress/integration/round-trip.spec.ts @@ -0,0 +1,89 @@ +context('Full round trip', () => { + before(() => { + (cy as any).eyesOpen({ + appName: 'books_app', + testName: 'round-trip', + browser: { width: 800, height: 600 }, + }); + window.indexedDB.deleteDatabase('books_app'); + cy.visit('/'); + }); + + after(() => { + (cy as any).eyesClose(); + }); + + it('shows a message when the credentials are wrong', () => { + cy.get('[placeholder=Username]').type('wronguser'); + cy.get('[placeholder=Password]').type('supersafepassword'); + cy.get('[type="submit"]').click(); + + (cy as any).eyesCheckWindow( + 'show a message when the credentials are wrong' + ); + cy.contains('Invalid username or password').should('be.visible'); + }); + + it('is possible to login', () => { + cy.get('[placeholder=Username]') + .clear() + .type('test'); + cy.get('[type="submit"]').click(); + }); + + it('is possible to search for books', () => { + cy.contains('My Collection'); + cy.contains('menu').click(); + cy.contains('Browse Books').click(); + + (cy as any).eyesCheckWindow('is possible to search for books'); + cy.get('[placeholder="Search for a book"]').type('The Alchemist'); + cy.get('bc-book-preview') + .its('length') + .should('be.gte', 1); + }); + + it('is possible to add books', () => { + cy.get('bc-book-preview') + .eq(2) + .click(); + + cy.contains('Add Book to Collection').click(); + (cy as any).eyesCheckWindow('is possible to add books'); + cy.contains('Add Book to Collection').should('not.exist'); + }); + + it('is possible to remove books', () => { + cy.go('back'); + + cy.get('bc-book-preview') + .eq(4) + .click(); + + cy.contains('Add Book to Collection').click(); + cy.contains('Remove Book from Collection').click(); + + (cy as any).eyesCheckWindow('is possible to remove books'); + cy.contains('Remove Book from Collection').should('not.exist'); + }); + + it('is possible to show the collection', () => { + cy.contains('menu').click(); + cy.contains('My Collection').click(); + + (cy as any).eyesCheckWindow('is possible to show the collection'); + cy.get('bc-book-preview') + .its('length') + .should('be', 1); + }); + + it('is possible to sign out', () => { + cy.contains('menu').click(); + cy.contains('Sign Out').click(); + cy.contains('OK').click(); + + (cy as any).eyesCheckWindow('is possible to sign out'); + cy.get('[placeholder=Username]').should('exist'); + cy.get('[placeholder=Password]').should('exist'); + }); +}); diff --git a/projects/example-app-cypress/plugins/cy-ts-preprocessor.js b/projects/example-app-cypress/plugins/cy-ts-preprocessor.js new file mode 100644 index 0000000000..02ab5016c1 --- /dev/null +++ b/projects/example-app-cypress/plugins/cy-ts-preprocessor.js @@ -0,0 +1,26 @@ +const wp = require('@cypress/webpack-preprocessor'); + +const webpackOptions = { + resolve: { + extensions: ['.ts', '.js'], + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: [/node_modules/], + use: [ + { + loader: 'ts-loader', + }, + ], + }, + ], + }, +}; + +const options = { + webpackOptions, +}; + +module.exports = wp(options); diff --git a/projects/example-app-cypress/plugins/index.js b/projects/example-app-cypress/plugins/index.js new file mode 100644 index 0000000000..20d85e40ad --- /dev/null +++ b/projects/example-app-cypress/plugins/index.js @@ -0,0 +1,6 @@ +const cypressTypeScriptPreprocessor = require('./cy-ts-preprocessor'); + +module.exports = on => + on('file:preprocessor', cypressTypeScriptPreprocessor); + +require('@applitools/eyes-cypress')(module); diff --git a/projects/example-app-cypress/support/index.js b/projects/example-app-cypress/support/index.js new file mode 100644 index 0000000000..5b36f0c1a8 --- /dev/null +++ b/projects/example-app-cypress/support/index.js @@ -0,0 +1,3 @@ +import'@applitools/eyes-cypress/commands'; + + diff --git a/projects/example-app-cypress/tsconfig.json b/projects/example-app-cypress/tsconfig.json new file mode 100644 index 0000000000..2a6ea9b8db --- /dev/null +++ b/projects/example-app-cypress/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "strict": true, + "baseUrl": "../../node_modules", + "target": "es5", + "experimentalDecorators": true, + "skipLibCheck": true, + "noImplicitAny": false, + "lib": ["es6", "dom"], + "types": ["cypress"] + }, + "include": ["**/*.ts"] +} diff --git a/projects/example-app-e2e/protractor.conf.js b/projects/example-app-e2e/protractor.conf.js deleted file mode 100644 index 23cd9398c4..0000000000 --- a/projects/example-app-e2e/protractor.conf.js +++ /dev/null @@ -1,31 +0,0 @@ -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -/*global jasmine */ -const { SpecReporter } = require('jasmine-spec-reporter'); - -exports.config = { - allScriptsTimeout: 11000, - specs: [ - './src/**/*.e2e-spec.ts' - ], - capabilities: { - 'browserName': 'chrome' - }, - directConnect: true, - baseUrl: 'http://localhost:4200/', - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function() {} - }, - beforeLaunch: function() { - require('ts-node').register({ - project: require('path').join(__dirname, './tsconfig.e2e.json') - }); - }, - onPrepare() { - jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); - } -}; diff --git a/projects/example-app-e2e/src/app.e2e-spec.ts b/projects/example-app-e2e/src/app.e2e-spec.ts deleted file mode 100644 index 7dddcd57ab..0000000000 --- a/projects/example-app-e2e/src/app.e2e-spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ExampleAppPage } from './app.po'; - -describe('example-app App', function() { - let page: ExampleAppPage; - - beforeEach(() => { - page = new ExampleAppPage(); - }); - - it('should display the app title in the menu', () => { - page.navigateTo(); - expect(page.getAppDescription()).toContain('Book Collection'); - }); -}); diff --git a/projects/example-app-e2e/src/app.po.ts b/projects/example-app-e2e/src/app.po.ts deleted file mode 100644 index e9462e994b..0000000000 --- a/projects/example-app-e2e/src/app.po.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { browser, element, by } from 'protractor'; - -export class ExampleAppPage { - navigateTo() { - return browser.get('/'); - } - - getAppDescription() { - return element(by.css('mat-toolbar')).getText(); - } -} diff --git a/projects/example-app-e2e/tsconfig.e2e.json b/projects/example-app-e2e/tsconfig.e2e.json deleted file mode 100644 index c331400bf8..0000000000 --- a/projects/example-app-e2e/tsconfig.e2e.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "sourceMap": true, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": ["es2016"], - "outDir": "../dist/out-tsc-e2e", - "module": "commonjs", - "target": "es6", - "types": ["jasmine", "node"] - } -} diff --git a/projects/example-app/jest.config.js b/projects/example-app/jest.config.js index bffd342d18..efa8588d41 100644 --- a/projects/example-app/jest.config.js +++ b/projects/example-app/jest.config.js @@ -1,38 +1,24 @@ module.exports = { - "rootDir": ".", - "setupTestFrameworkScriptFile": "/src/setup-jest.ts", - "globals": { - "ts-jest": { - "tsConfigFile": "projects/example-app/tsconfig.spec.json" + rootDir: '.', + setupTestFrameworkScriptFile: '/src/setup-jest.ts', + globals: { + 'ts-jest': { + tsConfigFile: 'projects/example-app/tsconfig.spec.json', }, - "__TRANSFORM_HTML__": true + __TRANSFORM_HTML__: true, }, - "transform": { - "^.+\\.(ts|js|html)$": "/../../node_modules/jest-preset-angular/preprocessor.js" + transform: { + '^.+\\.(ts|js|html)$': + '/../../node_modules/jest-preset-angular/preprocessor.js', }, - "testMatch": [ - "/**/*.spec.ts" - ], - "moduleFileExtensions": [ - "ts", - "js", - "html", - "json" - ], - "mapCoverage": true, - "coveragePathIgnorePatterns": [ - "/node_modules/", - "/modules/*.*/" - ], - "moduleNameMapper": { - "^@ngrx/(?!db)(.*)": "/../../modules/$1", - "^@example-app/(.*)": "/src/app/$1", - "ngrx-store-freeze": "/../../projects/ngrx-store-freeze/" + testMatch: ['/**/*.spec.ts'], + moduleFileExtensions: ['ts', 'js', 'html', 'json'], + mapCoverage: true, + coveragePathIgnorePatterns: ['/node_modules/', '/modules/*.*/'], + moduleNameMapper: { + '^@ngrx/(?!db)(.*)': '/../../modules/$1', + '^@example-app/(.*)': '/src/app/$1', }, - "transformIgnorePatterns": [ - "node_modules/(?!@ngrx)" - ], - "modulePathIgnorePatterns": [ - "dist" - ] + transformIgnorePatterns: ['node_modules/(?!@ngrx)'], + modulePathIgnorePatterns: ['dist'], }; diff --git a/projects/example-app/src/app/app.module.ts b/projects/example-app/src/app/app.module.ts index a2f60a4bca..bcfd886ce6 100644 --- a/projects/example-app/src/app/app.module.ts +++ b/projects/example-app/src/app/app.module.ts @@ -64,7 +64,7 @@ import { AppRoutingModule } from '@example-app/app-routing.module'; * sets up the effects class to be initialized immediately when the * application starts. * - * See: https://github.com/ngrx/platform/blob/master/docs/effects/api.md#forroot + * See: https://ngrx.io/guide/effects#registering-root-effects */ EffectsModule.forRoot([]), diff --git a/projects/example-app/src/app/auth/actions/auth-api.actions.ts b/projects/example-app/src/app/auth/actions/auth-api.actions.ts index 48c19b3696..b21260157c 100644 --- a/projects/example-app/src/app/auth/actions/auth-api.actions.ts +++ b/projects/example-app/src/app/auth/actions/auth-api.actions.ts @@ -1,26 +1,20 @@ -import { Action } from '@ngrx/store'; +import { props, createAction } from '@ngrx/store'; import { User } from '@example-app/auth/models/user'; -export enum AuthApiActionTypes { - LoginSuccess = '[Auth/API] Login Success', - LoginFailure = '[Auth/API] Login Failure', - LoginRedirect = '[Auth/API] Login Redirect', -} +export const loginSuccess = createAction( + '[Auth/API] Login Success', + props<{ user: User }>() +); -export class LoginSuccess implements Action { - readonly type = AuthApiActionTypes.LoginSuccess; +export const loginFailure = createAction( + '[Auth/API] Login Failure', + props<{ error: any }>() +); - constructor(public payload: { user: User }) {} -} +export const loginRedirect = createAction('[Auth/API] Login Redirect'); -export class LoginFailure implements Action { - readonly type = AuthApiActionTypes.LoginFailure; - - constructor(public payload: { error: any }) {} -} - -export class LoginRedirect implements Action { - readonly type = AuthApiActionTypes.LoginRedirect; -} - -export type AuthApiActionsUnion = LoginSuccess | LoginFailure | LoginRedirect; +// This is an alternative to union() type export. Work great when you need +// to export only a single Action type. +export type AuthApiActionsUnion = ReturnType< + typeof loginSuccess | typeof loginFailure | typeof loginRedirect +>; diff --git a/projects/example-app/src/app/auth/actions/auth.actions.ts b/projects/example-app/src/app/auth/actions/auth.actions.ts index 5151d08f34..cd75a1ea76 100644 --- a/projects/example-app/src/app/auth/actions/auth.actions.ts +++ b/projects/example-app/src/app/auth/actions/auth.actions.ts @@ -1,24 +1,10 @@ -import { Action } from '@ngrx/store'; +import { createAction, union } from '@ngrx/store'; -export enum AuthActionTypes { - Logout = '[Auth] Logout', - LogoutConfirmation = '[Auth] Logout Confirmation', - LogoutConfirmationDismiss = '[Auth] Logout Confirmation Dismiss', -} +export const logout = createAction('[Auth] Logout'); +export const logoutConfirmation = createAction('[Auth] Logout Confirmation'); +export const logoutConfirmationDismiss = createAction( + '[Auth] Logout Confirmation Dismiss' +); -export class Logout implements Action { - readonly type = AuthActionTypes.Logout; -} - -export class LogoutConfirmation implements Action { - readonly type = AuthActionTypes.LogoutConfirmation; -} - -export class LogoutConfirmationDismiss implements Action { - readonly type = AuthActionTypes.LogoutConfirmationDismiss; -} - -export type AuthActionsUnion = - | Logout - | LogoutConfirmation - | LogoutConfirmationDismiss; +const all = union({ logout, logoutConfirmation, logoutConfirmationDismiss }); +export type AuthActionsUnion = typeof all; diff --git a/projects/example-app/src/app/auth/actions/login-page.actions.ts b/projects/example-app/src/app/auth/actions/login-page.actions.ts index 2a70296d7a..f881552f50 100644 --- a/projects/example-app/src/app/auth/actions/login-page.actions.ts +++ b/projects/example-app/src/app/auth/actions/login-page.actions.ts @@ -1,14 +1,9 @@ -import { Action } from '@ngrx/store'; +import { createAction, props, union } from '@ngrx/store'; import { Credentials } from '@example-app/auth/models/user'; -export enum LoginPageActionTypes { - Login = '[Login Page] Login', -} +export const login = createAction( + '[Login Page] Login', + props<{ credentials: Credentials }>() +); -export class Login implements Action { - readonly type = LoginPageActionTypes.Login; - - constructor(public payload: { credentials: Credentials }) {} -} - -export type LoginPageActionsUnion = Login; +export type LoginPageActionsUnion = ReturnType; diff --git a/projects/example-app/src/app/auth/containers/login-page.component.spec.ts b/projects/example-app/src/app/auth/containers/login-page.component.spec.ts index 9da3433266..5ef167af53 100644 --- a/projects/example-app/src/app/auth/containers/login-page.component.spec.ts +++ b/projects/example-app/src/app/auth/containers/login-page.component.spec.ts @@ -57,7 +57,7 @@ describe('Login Page', () => { it('should dispatch a login event on submit', () => { const credentials: any = {}; - const action = new LoginPageActions.Login({ credentials }); + const action = LoginPageActions.login({ credentials }); instance.onSubmit(credentials); diff --git a/projects/example-app/src/app/auth/containers/login-page.component.ts b/projects/example-app/src/app/auth/containers/login-page.component.ts index f56a2577f6..4eded3bf77 100644 --- a/projects/example-app/src/app/auth/containers/login-page.component.ts +++ b/projects/example-app/src/app/auth/containers/login-page.component.ts @@ -24,6 +24,6 @@ export class LoginPageComponent implements OnInit { ngOnInit() {} onSubmit(credentials: Credentials) { - this.store.dispatch(new LoginPageActions.Login({ credentials })); + this.store.dispatch(LoginPageActions.login({ credentials })); } } diff --git a/projects/example-app/src/app/auth/effects/auth.effects.spec.ts b/projects/example-app/src/app/auth/effects/auth.effects.spec.ts index 55dd1bb1f4..79818f5675 100644 --- a/projects/example-app/src/app/auth/effects/auth.effects.spec.ts +++ b/projects/example-app/src/app/auth/effects/auth.effects.spec.ts @@ -54,11 +54,11 @@ describe('AuthEffects', () => { }); describe('login$', () => { - it('should return an auth.LoginSuccess action, with user information if login succeeds', () => { + it('should return an auth.loginSuccess action, with user information if login succeeds', () => { const credentials: Credentials = { username: 'test', password: '' }; const user = { name: 'User' } as User; - const action = new LoginPageActions.Login({ credentials }); - const completion = new AuthApiActions.LoginSuccess({ user }); + const action = LoginPageActions.login({ credentials }); + const completion = AuthApiActions.loginSuccess({ user }); actions$ = hot('-a---', { a: action }); const response = cold('-a|', { a: user }); @@ -68,10 +68,10 @@ describe('AuthEffects', () => { expect(effects.login$).toBeObservable(expected); }); - it('should return a new auth.LoginFailure if the login service throws', () => { + it('should return a new auth.loginFailure if the login service throws', () => { const credentials: Credentials = { username: 'someOne', password: '' }; - const action = new LoginPageActions.Login({ credentials }); - const completion = new AuthApiActions.LoginFailure({ + const action = LoginPageActions.login({ credentials }); + const completion = AuthApiActions.loginFailure({ error: 'Invalid username or password', }); const error = 'Invalid username or password'; @@ -88,7 +88,7 @@ describe('AuthEffects', () => { describe('loginSuccess$', () => { it('should dispatch a RouterNavigation action', (done: any) => { const user = { name: 'User' } as User; - const action = new AuthApiActions.LoginSuccess({ user }); + const action = AuthApiActions.loginSuccess({ user }); actions$ = of(action); @@ -100,8 +100,8 @@ describe('AuthEffects', () => { }); describe('loginRedirect$', () => { - it('should dispatch a RouterNavigation action when auth.LoginRedirect is dispatched', (done: any) => { - const action = new AuthApiActions.LoginRedirect(); + it('should dispatch a RouterNavigation action when auth.loginRedirect is dispatched', (done: any) => { + const action = AuthApiActions.loginRedirect(); actions$ = of(action); @@ -111,8 +111,8 @@ describe('AuthEffects', () => { }); }); - it('should dispatch a RouterNavigation action when auth.Logout is dispatched', (done: any) => { - const action = new AuthActions.Logout(); + it('should dispatch a RouterNavigation action when auth.logout is dispatched', (done: any) => { + const action = AuthActions.logout(); actions$ = of(action); @@ -125,8 +125,8 @@ describe('AuthEffects', () => { describe('logoutConfirmation$', () => { it('should dispatch a Logout action if dialog closes with true result', () => { - const action = new AuthActions.LogoutConfirmation(); - const completion = new AuthActions.Logout(); + const action = AuthActions.logoutConfirmation(); + const completion = AuthActions.logout(); actions$ = hot('-a', { a: action }); const expected = cold('-b', { b: completion }); @@ -139,8 +139,8 @@ describe('AuthEffects', () => { }); it('should dispatch a LogoutConfirmationDismiss action if dialog closes with falsy result', () => { - const action = new AuthActions.LogoutConfirmation(); - const completion = new AuthActions.LogoutConfirmationDismiss(); + const action = AuthActions.logoutConfirmation(); + const completion = AuthActions.logoutConfirmationDismiss(); actions$ = hot('-a', { a: action }); const expected = cold('-b', { b: completion }); diff --git a/projects/example-app/src/app/auth/effects/auth.effects.ts b/projects/example-app/src/app/auth/effects/auth.effects.ts index 7db06fe730..1cdbad8e19 100644 --- a/projects/example-app/src/app/auth/effects/auth.effects.ts +++ b/projects/example-app/src/app/auth/effects/auth.effects.ts @@ -17,28 +17,25 @@ import { LogoutConfirmationDialogComponent } from '@example-app/auth/components/ export class AuthEffects { @Effect() login$ = this.actions$.pipe( - ofType(LoginPageActions.LoginPageActionTypes.Login), - map(action => action.payload.credentials), + ofType(LoginPageActions.login.type), + map(action => action.credentials), exhaustMap((auth: Credentials) => this.authService.login(auth).pipe( - map(user => new AuthApiActions.LoginSuccess({ user })), - catchError(error => of(new AuthApiActions.LoginFailure({ error }))) + map(user => AuthApiActions.loginSuccess({ user })), + catchError(error => of(AuthApiActions.loginFailure({ error }))) ) ) ); @Effect({ dispatch: false }) loginSuccess$ = this.actions$.pipe( - ofType(AuthApiActions.AuthApiActionTypes.LoginSuccess), + ofType(AuthApiActions.loginSuccess.type), tap(() => this.router.navigate(['/'])) ); @Effect({ dispatch: false }) loginRedirect$ = this.actions$.pipe( - ofType( - AuthApiActions.AuthApiActionTypes.LoginRedirect, - AuthActions.AuthActionTypes.Logout - ), + ofType(AuthApiActions.loginRedirect.type, AuthActions.logout.type), tap(authed => { this.router.navigate(['/login']); }) @@ -46,7 +43,7 @@ export class AuthEffects { @Effect() logoutConfirmation$ = this.actions$.pipe( - ofType(AuthActions.AuthActionTypes.LogoutConfirmation), + ofType(AuthActions.logoutConfirmation.type), exhaustMap(() => { const dialogRef = this.dialog.open< LogoutConfirmationDialogComponent, @@ -58,9 +55,7 @@ export class AuthEffects { }), map( result => - result - ? new AuthActions.Logout() - : new AuthActions.LogoutConfirmationDismiss() + result ? AuthActions.logout() : AuthActions.logoutConfirmationDismiss() ) ); diff --git a/projects/example-app/src/app/auth/reducers/auth.reducer.spec.ts b/projects/example-app/src/app/auth/reducers/auth.reducer.spec.ts index 6b9b9846c7..1af5f3d1ad 100644 --- a/projects/example-app/src/app/auth/reducers/auth.reducer.spec.ts +++ b/projects/example-app/src/app/auth/reducers/auth.reducer.spec.ts @@ -25,7 +25,7 @@ describe('AuthReducer', () => { describe('LOGIN_SUCCESS', () => { it('should add a user set loggedIn to true in auth state', () => { const user = { name: 'test' } as User; - const createAction = new AuthApiActions.LoginSuccess({ user }); + const createAction = AuthApiActions.loginSuccess({ user }); const expectedResult = { user: { name: 'test' }, @@ -42,7 +42,7 @@ describe('AuthReducer', () => { const initialState = { user: { name: 'test' }, } as fromAuth.State; - const createAction = new AuthActions.Logout(); + const createAction = AuthActions.logout(); const expectedResult = fromAuth.initialState; diff --git a/projects/example-app/src/app/auth/reducers/auth.reducer.ts b/projects/example-app/src/app/auth/reducers/auth.reducer.ts index 797ab9f0af..461c730f55 100644 --- a/projects/example-app/src/app/auth/reducers/auth.reducer.ts +++ b/projects/example-app/src/app/auth/reducers/auth.reducer.ts @@ -14,14 +14,14 @@ export function reducer( action: AuthApiActions.AuthApiActionsUnion | AuthActions.AuthActionsUnion ): State { switch (action.type) { - case AuthApiActions.AuthApiActionTypes.LoginSuccess: { + case AuthApiActions.loginSuccess.type: { return { ...state, - user: action.payload.user, + user: action.user, }; } - case AuthActions.AuthActionTypes.Logout: { + case AuthActions.logout.type: { return initialState; } diff --git a/projects/example-app/src/app/auth/reducers/login-page.reducer.spec.ts b/projects/example-app/src/app/auth/reducers/login-page.reducer.spec.ts index c81149bbcc..628edb73d0 100644 --- a/projects/example-app/src/app/auth/reducers/login-page.reducer.spec.ts +++ b/projects/example-app/src/app/auth/reducers/login-page.reducer.spec.ts @@ -19,7 +19,7 @@ describe('LoginPageReducer', () => { describe('LOGIN', () => { it('should make pending to true', () => { const user = { username: 'test' } as Credentials; - const createAction = new LoginPageActions.Login({ credentials: user }); + const createAction = LoginPageActions.login({ credentials: user }); const expectedResult = { error: null, @@ -35,7 +35,7 @@ describe('LoginPageReducer', () => { describe('LOGIN_SUCCESS', () => { it('should have no error and no pending state', () => { const user = { name: 'test' } as User; - const createAction = new AuthApiActions.LoginSuccess({ user }); + const createAction = AuthApiActions.loginSuccess({ user }); const expectedResult = { error: null, @@ -51,7 +51,7 @@ describe('LoginPageReducer', () => { describe('LOGIN_FAILURE', () => { it('should have an error and no pending state', () => { const error = 'login failed'; - const createAction = new AuthApiActions.LoginFailure({ error }); + const createAction = AuthApiActions.loginFailure({ error }); const expectedResult = { error: error, diff --git a/projects/example-app/src/app/auth/reducers/login-page.reducer.ts b/projects/example-app/src/app/auth/reducers/login-page.reducer.ts index 8e84ab37f7..452d4b5167 100644 --- a/projects/example-app/src/app/auth/reducers/login-page.reducer.ts +++ b/projects/example-app/src/app/auth/reducers/login-page.reducer.ts @@ -17,7 +17,7 @@ export function reducer( | LoginPageActions.LoginPageActionsUnion ): State { switch (action.type) { - case LoginPageActions.LoginPageActionTypes.Login: { + case LoginPageActions.login.type: { return { ...state, error: null, @@ -25,7 +25,7 @@ export function reducer( }; } - case AuthApiActions.AuthApiActionTypes.LoginSuccess: { + case AuthApiActions.loginSuccess.type: { return { ...state, error: null, @@ -33,10 +33,10 @@ export function reducer( }; } - case AuthApiActions.AuthApiActionTypes.LoginFailure: { + case AuthApiActions.loginFailure.type: { return { ...state, - error: action.payload.error, + error: action.error, pending: false, }; } diff --git a/projects/example-app/src/app/auth/services/auth-guard.service.spec.ts b/projects/example-app/src/app/auth/services/auth-guard.service.spec.ts index 6b505bf979..4dd60b26cb 100644 --- a/projects/example-app/src/app/auth/services/auth-guard.service.spec.ts +++ b/projects/example-app/src/app/auth/services/auth-guard.service.spec.ts @@ -1,27 +1,29 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { StoreModule, Store, combineReducers } from '@ngrx/store'; +import { TestBed } from '@angular/core/testing'; +import { Store } from '@ngrx/store'; import { cold } from 'jasmine-marbles'; import { AuthGuard } from '@example-app/auth/services/auth-guard.service'; -import { AuthApiActions } from '@example-app/auth/actions'; import * as fromRoot from '@example-app/reducers'; import * as fromAuth from '@example-app/auth/reducers'; +import * as fromLoginPage from '@example-app/auth/reducers/login-page.reducer'; +import { provideMockStore, MockStore } from '@ngrx/store/testing'; describe('Auth Guard', () => { let guard: AuthGuard; - let store: Store; + let store: MockStore; + const initialState = { + auth: { + status: { + user: null, + }, + }, + } as fromAuth.State; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({ - ...fromRoot.reducers, - auth: combineReducers(fromAuth.reducers), - }), - ], + providers: [AuthGuard, provideMockStore({ initialState })], }); store = TestBed.get(Store); - spyOn(store, 'dispatch').and.callThrough(); guard = TestBed.get(AuthGuard); }); @@ -32,9 +34,17 @@ describe('Auth Guard', () => { }); it('should return true if the user state is logged in', () => { - const user: any = {}; - const action = new AuthApiActions.LoginSuccess({ user }); - store.dispatch(action); + store.setState({ + ...initialState, + auth: { + loginPage: {} as fromLoginPage.State, + status: { + user: { + name: 'John', + }, + }, + }, + }); const expected = cold('(a|)', { a: true }); diff --git a/projects/example-app/src/app/auth/services/auth-guard.service.ts b/projects/example-app/src/app/auth/services/auth-guard.service.ts index c0402b1670..0537d667bd 100644 --- a/projects/example-app/src/app/auth/services/auth-guard.service.ts +++ b/projects/example-app/src/app/auth/services/auth-guard.service.ts @@ -17,7 +17,7 @@ export class AuthGuard implements CanActivate { select(fromAuth.getLoggedIn), map(authed => { if (!authed) { - this.store.dispatch(new AuthApiActions.LoginRedirect()); + this.store.dispatch(AuthApiActions.loginRedirect()); return false; } diff --git a/projects/example-app/src/app/books/actions/book.actions.ts b/projects/example-app/src/app/books/actions/book.actions.ts index 9926fc62cf..24c04fc9a3 100644 --- a/projects/example-app/src/app/books/actions/book.actions.ts +++ b/projects/example-app/src/app/books/actions/book.actions.ts @@ -1,14 +1,9 @@ -import { Action } from '@ngrx/store'; +import { createAction, props } from '@ngrx/store'; import { Book } from '@example-app/books/models/book'; -export enum BookActionTypes { - LoadBook = '[Book Exists Guard] Load Book', -} +export const loadBook = createAction( + '[Book Exists Guard] Load Book', + props<{ book: Book }>() +); -export class LoadBook implements Action { - readonly type = BookActionTypes.LoadBook; - - constructor(public payload: Book) {} -} - -export type BookActionsUnion = LoadBook; +export type BookActionsUnion = ReturnType; diff --git a/projects/example-app/src/app/books/actions/books-api.actions.ts b/projects/example-app/src/app/books/actions/books-api.actions.ts index e3a438ad33..4f141a4ba7 100644 --- a/projects/example-app/src/app/books/actions/books-api.actions.ts +++ b/projects/example-app/src/app/books/actions/books-api.actions.ts @@ -1,32 +1,19 @@ -import { Action } from '@ngrx/store'; +import { createAction, union, props } from '@ngrx/store'; import { Book } from '@example-app/books/models/book'; -export enum BooksApiActionTypes { - SearchSuccess = '[Books/API] Search Success', - SearchFailure = '[Books/API] Search Failure', -} +export const searchSuccess = createAction( + '[Books/API] Search Success', + props<{ books: Book[] }>() +); -/** - * Every action is comprised of at least a type and an optional - * payload. Expressing actions as classes enables powerful - * type checking in reducer functions. - * - * See Discriminated Unions: https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions - */ -export class SearchSuccess implements Action { - readonly type = BooksApiActionTypes.SearchSuccess; - - constructor(public payload: Book[]) {} -} - -export class SearchFailure implements Action { - readonly type = BooksApiActionTypes.SearchFailure; - - constructor(public payload: string) {} -} +export const searchFailure = createAction( + '[Books/API] Search Failure', + props<{ errorMsg: string }>() +); /** * Export a type alias of all actions in this action group * so that reducers can easily compose action types */ -export type BooksApiActionsUnion = SearchSuccess | SearchFailure; +const all = union({ searchSuccess, searchFailure }); +export type BooksApiActionsUnion = typeof all; diff --git a/projects/example-app/src/app/books/actions/collection-api.actions.ts b/projects/example-app/src/app/books/actions/collection-api.actions.ts index 39412f5a1c..f5165abf6a 100644 --- a/projects/example-app/src/app/books/actions/collection-api.actions.ts +++ b/projects/example-app/src/app/books/actions/collection-api.actions.ts @@ -1,64 +1,51 @@ -import { Action } from '@ngrx/store'; +import { createAction, props, union } from '@ngrx/store'; import { Book } from '@example-app/books/models/book'; -export enum CollectionApiActionTypes { - AddBookSuccess = '[Collection/API] Add Book Success', - AddBookFailure = '[Collection/API] Add Book Failure', - RemoveBookSuccess = '[Collection/API] Remove Book Success', - RemoveBookFailure = '[Collection/API] Remove Book Failure', - LoadBooksSuccess = '[Collection/API] Load Books Success', - LoadBooksFailure = '[Collection/API] Load Books Failure', -} - /** * Add Book to Collection Actions */ -export class AddBookSuccess implements Action { - readonly type = CollectionApiActionTypes.AddBookSuccess; - - constructor(public payload: Book) {} -} - -export class AddBookFailure implements Action { - readonly type = CollectionApiActionTypes.AddBookFailure; +export const addBookSuccess = createAction( + '[Collection/API] Add Book Success', + props<{ book: Book }>() +); - constructor(public payload: Book) {} -} +export const addBookFailure = createAction( + '[Collection/API] Add Book Failure', + props<{ book: Book }>() +); /** * Remove Book from Collection Actions */ -export class RemoveBookSuccess implements Action { - readonly type = CollectionApiActionTypes.RemoveBookSuccess; - - constructor(public payload: Book) {} -} - -export class RemoveBookFailure implements Action { - readonly type = CollectionApiActionTypes.RemoveBookFailure; +export const removeBookSuccess = createAction( + '[Collection/API] Remove Book Success', + props<{ book: Book }>() +); - constructor(public payload: Book) {} -} +export const removeBookFailure = createAction( + '[Collection/API] Remove Book Failure', + props<{ book: Book }>() +); /** * Load Collection Actions */ -export class LoadBooksSuccess implements Action { - readonly type = CollectionApiActionTypes.LoadBooksSuccess; - - constructor(public payload: Book[]) {} -} - -export class LoadBooksFailure implements Action { - readonly type = CollectionApiActionTypes.LoadBooksFailure; - - constructor(public payload: any) {} -} - -export type CollectionApiActionsUnion = - | AddBookSuccess - | AddBookFailure - | RemoveBookSuccess - | RemoveBookFailure - | LoadBooksSuccess - | LoadBooksFailure; +export const loadBooksSuccess = createAction( + '[Collection/API] Load Books Success', + props<{ books: Book[] }>() +); + +export const loadBooksFailure = createAction( + '[Collection/API] Load Books Failure', + props<{ error: any }>() +); + +const all = union({ + addBookSuccess, + addBookFailure, + removeBookSuccess, + removeBookFailure, + loadBooksSuccess, + loadBooksFailure, +}); +export type CollectionApiActionsUnion = typeof all; diff --git a/projects/example-app/src/app/books/actions/collection-page.actions.ts b/projects/example-app/src/app/books/actions/collection-page.actions.ts index 9a789799ea..7bfd6174ca 100644 --- a/projects/example-app/src/app/books/actions/collection-page.actions.ts +++ b/projects/example-app/src/app/books/actions/collection-page.actions.ts @@ -1,14 +1,8 @@ -import { Action } from '@ngrx/store'; - -export enum CollectionPageActionTypes { - LoadCollection = '[Collection Page] Load Collection', -} +import { createAction } from '@ngrx/store'; /** * Load Collection Action */ -export class LoadCollection implements Action { - readonly type = CollectionPageActionTypes.LoadCollection; -} +export const loadCollection = createAction('[Collection Page] Load Collection'); -export type CollectionPageActionsUnion = LoadCollection; +export type CollectionPageActionsUnion = ReturnType; diff --git a/projects/example-app/src/app/books/actions/find-book-page.actions.ts b/projects/example-app/src/app/books/actions/find-book-page.actions.ts index a6387cdf7c..f1ab45d3ff 100644 --- a/projects/example-app/src/app/books/actions/find-book-page.actions.ts +++ b/projects/example-app/src/app/books/actions/find-book-page.actions.ts @@ -1,13 +1,8 @@ -import { Action } from '@ngrx/store'; +import { createAction, props } from '@ngrx/store'; -export enum FindBookPageActionTypes { - SearchBooks = '[Find Book Page] Search Books', -} +export const searchBooks = createAction( + '[Find Book Page] Search Books', + props<{ query: string }>() +); -export class SearchBooks implements Action { - readonly type = FindBookPageActionTypes.SearchBooks; - - constructor(public payload: string) {} -} - -export type FindBookPageActionsUnion = SearchBooks; +export type FindBookPageActionsUnion = ReturnType; diff --git a/projects/example-app/src/app/books/actions/selected-book-page.actions.ts b/projects/example-app/src/app/books/actions/selected-book-page.actions.ts index 1698a909df..353c38431b 100644 --- a/projects/example-app/src/app/books/actions/selected-book-page.actions.ts +++ b/projects/example-app/src/app/books/actions/selected-book-page.actions.ts @@ -1,27 +1,22 @@ -import { Action } from '@ngrx/store'; +import { createAction, union, props } from '@ngrx/store'; import { Book } from '@example-app/books/models/book'; -export enum SelectedBookPageActionTypes { - AddBook = '[Selected Book Page] Add Book', - RemoveBook = '[Selected Book Page] Remove Book', -} - /** * Add Book to Collection Action */ -export class AddBook implements Action { - readonly type = SelectedBookPageActionTypes.AddBook; - - constructor(public payload: Book) {} -} +export const addBook = createAction( + '[Selected Book Page] Add Book', + props<{ book: Book }>() +); /** * Remove Book from Collection Action */ -export class RemoveBook implements Action { - readonly type = SelectedBookPageActionTypes.RemoveBook; +export const removeBook = createAction( + '[Selected Book Page] Remove Book', + props<{ book: Book }>() +); - constructor(public payload: Book) {} -} +const all = union({ addBook, removeBook }); -export type SelectedBookPageActionsUnion = AddBook | RemoveBook; +export type SelectedBookPageActionsUnion = typeof all; diff --git a/projects/example-app/src/app/books/actions/view-book-page.actions.ts b/projects/example-app/src/app/books/actions/view-book-page.actions.ts index 1d15fa2074..38a43b6626 100644 --- a/projects/example-app/src/app/books/actions/view-book-page.actions.ts +++ b/projects/example-app/src/app/books/actions/view-book-page.actions.ts @@ -1,13 +1,8 @@ -import { Action } from '@ngrx/store'; +import { createAction, props } from '@ngrx/store'; -export enum ViewBookPageActionTypes { - SelectBook = '[View Book Page] Select Book', -} +export const selectBook = createAction( + '[View Book Page] Select Book', + props<{ id: string }>() +); -export class SelectBook implements Action { - readonly type = ViewBookPageActionTypes.SelectBook; - - constructor(public payload: string) {} -} - -export type ViewBookPageActionsUnion = SelectBook; +export type ViewBookPageActionsUnion = ReturnType; diff --git a/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap b/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap index c726290936..945329d0be 100644 --- a/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap +++ b/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap @@ -8,6 +8,7 @@ exports[`Selected Book Page should compile 1`] = ` > diff --git a/projects/example-app/src/app/books/containers/collection-page.component.spec.ts b/projects/example-app/src/app/books/containers/collection-page.component.spec.ts index 1047f68381..9db1d0ab4a 100644 --- a/projects/example-app/src/app/books/containers/collection-page.component.spec.ts +++ b/projects/example-app/src/app/books/containers/collection-page.component.spec.ts @@ -52,7 +52,7 @@ describe('Collection Page', () => { }); it('should dispatch a collection.Load on init', () => { - const action = new CollectionPageActions.LoadCollection(); + const action = CollectionPageActions.loadCollection(); fixture.detectChanges(); diff --git a/projects/example-app/src/app/books/containers/collection-page.component.ts b/projects/example-app/src/app/books/containers/collection-page.component.ts index d238835f0a..f0ebfd39e7 100644 --- a/projects/example-app/src/app/books/containers/collection-page.component.ts +++ b/projects/example-app/src/app/books/containers/collection-page.component.ts @@ -39,6 +39,6 @@ export class CollectionPageComponent implements OnInit { } ngOnInit() { - this.store.dispatch(new CollectionPageActions.LoadCollection()); + this.store.dispatch(CollectionPageActions.loadCollection()); } } diff --git a/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts b/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts index 126ccc4e99..76652658ec 100644 --- a/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts +++ b/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts @@ -63,7 +63,7 @@ describe('Find Book Page', () => { it('should dispatch a book.Search action on search', () => { const $event = 'book name'; - const action = new FindBookPageActions.SearchBooks($event); + const action = FindBookPageActions.searchBooks({ query: $event }); instance.search($event); diff --git a/projects/example-app/src/app/books/containers/find-book-page.component.ts b/projects/example-app/src/app/books/containers/find-book-page.component.ts index 72cc1ea52f..3e260678ed 100644 --- a/projects/example-app/src/app/books/containers/find-book-page.component.ts +++ b/projects/example-app/src/app/books/containers/find-book-page.component.ts @@ -39,6 +39,6 @@ export class FindBookPageComponent { } search(query: string) { - this.store.dispatch(new FindBookPageActions.SearchBooks(query)); + this.store.dispatch(FindBookPageActions.searchBooks({ query })); } } diff --git a/projects/example-app/src/app/books/containers/selected-book-page.component.spec.ts b/projects/example-app/src/app/books/containers/selected-book-page.component.spec.ts index db23d0738f..e33dfa6919 100644 --- a/projects/example-app/src/app/books/containers/selected-book-page.component.spec.ts +++ b/projects/example-app/src/app/books/containers/selected-book-page.component.spec.ts @@ -48,7 +48,7 @@ describe('Selected Book Page', () => { it('should dispatch a collection.AddBook action when addToCollection is called', () => { const $event: Book = generateMockBook(); - const action = new SelectedBookPageActions.AddBook($event); + const action = SelectedBookPageActions.addBook({ book: $event }); instance.addToCollection($event); @@ -57,7 +57,7 @@ describe('Selected Book Page', () => { it('should dispatch a collection.RemoveBook action on removeFromCollection', () => { const $event: Book = generateMockBook(); - const action = new SelectedBookPageActions.RemoveBook($event); + const action = SelectedBookPageActions.removeBook({ book: $event }); instance.removeFromCollection($event); diff --git a/projects/example-app/src/app/books/containers/selected-book-page.component.ts b/projects/example-app/src/app/books/containers/selected-book-page.component.ts index fb7471ffaf..727f5e4d73 100644 --- a/projects/example-app/src/app/books/containers/selected-book-page.component.ts +++ b/projects/example-app/src/app/books/containers/selected-book-page.component.ts @@ -32,10 +32,10 @@ export class SelectedBookPageComponent { } addToCollection(book: Book) { - this.store.dispatch(new SelectedBookPageActions.AddBook(book)); + this.store.dispatch(SelectedBookPageActions.addBook({ book })); } removeFromCollection(book: Book) { - this.store.dispatch(new SelectedBookPageActions.RemoveBook(book)); + this.store.dispatch(SelectedBookPageActions.removeBook({ book })); } } diff --git a/projects/example-app/src/app/books/containers/view-book-page.component.spec.ts b/projects/example-app/src/app/books/containers/view-book-page.component.spec.ts index 4bd5118347..c66c5dba32 100644 --- a/projects/example-app/src/app/books/containers/view-book-page.component.spec.ts +++ b/projects/example-app/src/app/books/containers/view-book-page.component.spec.ts @@ -56,7 +56,7 @@ describe('View Book Page', () => { }); it('should dispatch a book.Select action on init', () => { - const action = new ViewBookPageActions.SelectBook('2'); + const action = ViewBookPageActions.selectBook({ id: '2' }); params.next({ id: '2' }); fixture.detectChanges(); diff --git a/projects/example-app/src/app/books/containers/view-book-page.component.ts b/projects/example-app/src/app/books/containers/view-book-page.component.ts index 5d50407e94..b1e13c353b 100644 --- a/projects/example-app/src/app/books/containers/view-book-page.component.ts +++ b/projects/example-app/src/app/books/containers/view-book-page.component.ts @@ -29,7 +29,7 @@ export class ViewBookPageComponent implements OnDestroy { constructor(store: Store, route: ActivatedRoute) { this.actionsSubscription = route.params - .pipe(map(params => new ViewBookPageActions.SelectBook(params.id))) + .pipe(map(params => ViewBookPageActions.selectBook({ id: params.id }))) .subscribe(store); } diff --git a/projects/example-app/src/app/books/effects/book.effects.spec.ts b/projects/example-app/src/app/books/effects/book.effects.spec.ts index 73b3a37fc3..9147011d6f 100644 --- a/projects/example-app/src/app/books/effects/book.effects.spec.ts +++ b/projects/example-app/src/app/books/effects/book.effects.spec.ts @@ -35,12 +35,12 @@ describe('BookEffects', () => { }); describe('search$', () => { - it('should return a new book.SearchComplete, with the books, on success, after the de-bounce', () => { + it('should return a book.SearchComplete, with the books, on success, after the de-bounce', () => { const book1 = { id: '111', volumeInfo: {} } as Book; const book2 = { id: '222', volumeInfo: {} } as Book; const books = [book1, book2]; - const action = new FindBookPageActions.SearchBooks('query'); - const completion = new BooksApiActions.SearchSuccess(books); + const action = FindBookPageActions.searchBooks({ query: 'query' }); + const completion = BooksApiActions.searchSuccess({ books }); actions$ = hot('-a---', { a: action }); const response = cold('-a|', { a: books }); @@ -55,11 +55,11 @@ describe('BookEffects', () => { ).toBeObservable(expected); }); - it('should return a new book.SearchError if the books service throws', () => { - const action = new FindBookPageActions.SearchBooks('query'); - const completion = new BooksApiActions.SearchFailure( - 'Unexpected Error. Try again later.' - ); + it('should return a book.SearchError if the books service throws', () => { + const action = FindBookPageActions.searchBooks({ query: 'query' }); + const completion = BooksApiActions.searchFailure({ + errorMsg: 'Unexpected Error. Try again later.', + }); const error = 'Unexpected Error. Try again later.'; actions$ = hot('-a---', { a: action }); @@ -76,7 +76,7 @@ describe('BookEffects', () => { }); it(`should not do anything if the query is an empty string`, () => { - const action = new FindBookPageActions.SearchBooks(''); + const action = FindBookPageActions.searchBooks({ query: '' }); actions$ = hot('-a---', { a: action }); const expected = cold('---'); diff --git a/projects/example-app/src/app/books/effects/book.effects.ts b/projects/example-app/src/app/books/effects/book.effects.ts index bee500a9af..d1063c365a 100644 --- a/projects/example-app/src/app/books/effects/book.effects.ts +++ b/projects/example-app/src/app/books/effects/book.effects.ts @@ -36,23 +36,24 @@ export class BookEffects { Action > => this.actions$.pipe( - ofType(FindBookPageActions.FindBookPageActionTypes.SearchBooks), + ofType(FindBookPageActions.searchBooks.type), debounceTime(debounce, scheduler), - map(action => action.payload), - switchMap(query => { + switchMap(({ query }) => { if (query === '') { return empty; } const nextSearch$ = this.actions$.pipe( - ofType(FindBookPageActions.FindBookPageActionTypes.SearchBooks), + ofType(FindBookPageActions.searchBooks.type), skip(1) ); return this.googleBooks.searchBooks(query).pipe( takeUntil(nextSearch$), - map((books: Book[]) => new BooksApiActions.SearchSuccess(books)), - catchError(err => of(new BooksApiActions.SearchFailure(err))) + map((books: Book[]) => BooksApiActions.searchSuccess({ books })), + catchError(err => + of(BooksApiActions.searchFailure({ errorMsg: err })) + ) ); }) ); diff --git a/projects/example-app/src/app/books/effects/collection.effects.spec.ts b/projects/example-app/src/app/books/effects/collection.effects.spec.ts index 62bd9e4ca9..5f6b5fec90 100644 --- a/projects/example-app/src/app/books/effects/collection.effects.spec.ts +++ b/projects/example-app/src/app/books/effects/collection.effects.spec.ts @@ -52,11 +52,10 @@ describe('CollectionEffects', () => { describe('loadCollection$', () => { it('should return a collection.LoadSuccess, with the books, on success', () => { - const action = new CollectionPageActions.LoadCollection(); - const completion = new CollectionApiActions.LoadBooksSuccess([ - book1, - book2, - ]); + const action = CollectionPageActions.loadCollection(); + const completion = CollectionApiActions.loadBooksSuccess({ + books: [book1, book2], + }); actions$ = hot('-a', { a: action }); const response = cold('-a-b|', { a: book1, b: book2 }); @@ -67,9 +66,9 @@ describe('CollectionEffects', () => { }); it('should return a collection.LoadFail, if the query throws', () => { - const action = new CollectionPageActions.LoadCollection(); + const action = CollectionPageActions.loadCollection(); const error = 'Error!'; - const completion = new CollectionApiActions.LoadBooksFailure(error); + const completion = CollectionApiActions.loadBooksFailure({ error }); actions$ = hot('-a', { a: action }); const response = cold('-#', {}, error); @@ -82,8 +81,8 @@ describe('CollectionEffects', () => { describe('addBookToCollection$', () => { it('should return a collection.AddBookSuccess, with the book, on success', () => { - const action = new SelectedBookPageActions.AddBook(book1); - const completion = new CollectionApiActions.AddBookSuccess(book1); + const action = SelectedBookPageActions.addBook({ book: book1 }); + const completion = CollectionApiActions.addBookSuccess({ book: book1 }); actions$ = hot('-a', { a: action }); const response = cold('-b', { b: true }); @@ -95,8 +94,8 @@ describe('CollectionEffects', () => { }); it('should return a collection.AddBookFail, with the book, when the db insert throws', () => { - const action = new SelectedBookPageActions.AddBook(book1); - const completion = new CollectionApiActions.AddBookFailure(book1); + const action = SelectedBookPageActions.addBook({ book: book1 }); + const completion = CollectionApiActions.addBookFailure({ book: book1 }); const error = 'Error!'; actions$ = hot('-a', { a: action }); @@ -109,8 +108,10 @@ describe('CollectionEffects', () => { describe('removeBookFromCollection$', () => { it('should return a collection.RemoveBookSuccess, with the book, on success', () => { - const action = new SelectedBookPageActions.RemoveBook(book1); - const completion = new CollectionApiActions.RemoveBookSuccess(book1); + const action = SelectedBookPageActions.removeBook({ book: book1 }); + const completion = CollectionApiActions.removeBookSuccess({ + book: book1, + }); actions$ = hot('-a', { a: action }); const response = cold('-b', { b: true }); @@ -124,8 +125,10 @@ describe('CollectionEffects', () => { }); it('should return a collection.RemoveBookFail, with the book, when the db insert throws', () => { - const action = new SelectedBookPageActions.RemoveBook(book1); - const completion = new CollectionApiActions.RemoveBookFailure(book1); + const action = SelectedBookPageActions.removeBook({ book: book1 }); + const completion = CollectionApiActions.removeBookFailure({ + book: book1, + }); const error = 'Error!'; actions$ = hot('-a', { a: action }); diff --git a/projects/example-app/src/app/books/effects/collection.effects.ts b/projects/example-app/src/app/books/effects/collection.effects.ts index f38494e20c..4711f2ddd5 100644 --- a/projects/example-app/src/app/books/effects/collection.effects.ts +++ b/projects/example-app/src/app/books/effects/collection.effects.ts @@ -31,15 +31,15 @@ export class CollectionEffects { @Effect() loadCollection$: Observable = this.actions$.pipe( - ofType(CollectionPageActions.CollectionPageActionTypes.LoadCollection), + ofType(CollectionPageActions.loadCollection.type), switchMap(() => this.db.query('books').pipe( toArray(), - map( - (books: Book[]) => new CollectionApiActions.LoadBooksSuccess(books) + map((books: Book[]) => + CollectionApiActions.loadBooksSuccess({ books }) ), catchError(error => - of(new CollectionApiActions.LoadBooksFailure(error)) + of(CollectionApiActions.loadBooksFailure({ error })) ) ) ) @@ -47,24 +47,22 @@ export class CollectionEffects { @Effect() addBookToCollection$: Observable = this.actions$.pipe( - ofType(SelectedBookPageActions.SelectedBookPageActionTypes.AddBook), - map(action => action.payload), - mergeMap(book => + ofType(SelectedBookPageActions.addBook.type), + mergeMap(({ book }) => this.db.insert('books', [book]).pipe( - map(() => new CollectionApiActions.AddBookSuccess(book)), - catchError(() => of(new CollectionApiActions.AddBookFailure(book))) + map(() => CollectionApiActions.addBookSuccess({ book })), + catchError(() => of(CollectionApiActions.addBookFailure({ book }))) ) ) ); @Effect() removeBookFromCollection$: Observable = this.actions$.pipe( - ofType(SelectedBookPageActions.SelectedBookPageActionTypes.RemoveBook), - map(action => action.payload), - mergeMap(book => + ofType(SelectedBookPageActions.removeBook.type), + mergeMap(({ book }) => this.db.executeWrite('books', 'delete', [book.id]).pipe( - map(() => new CollectionApiActions.RemoveBookSuccess(book)), - catchError(() => of(new CollectionApiActions.RemoveBookFailure(book))) + map(() => CollectionApiActions.removeBookSuccess({ book })), + catchError(() => of(CollectionApiActions.removeBookFailure({ book }))) ) ) ); diff --git a/projects/example-app/src/app/books/guards/book-exists.guard.ts b/projects/example-app/src/app/books/guards/book-exists.guard.ts index d20856240f..6a33f24615 100644 --- a/projects/example-app/src/app/books/guards/book-exists.guard.ts +++ b/projects/example-app/src/app/books/guards/book-exists.guard.ts @@ -54,8 +54,8 @@ export class BookExistsGuard implements CanActivate { */ hasBookInApi(id: string): Observable { return this.googleBooks.retrieveBook(id).pipe( - map(bookEntity => new BookActions.LoadBook(bookEntity)), - tap((action: BookActions.LoadBook) => this.store.dispatch(action)), + map(bookEntity => BookActions.loadBook({ book: bookEntity })), + tap(action => this.store.dispatch(action)), map(book => !!book), catchError(() => { this.router.navigate(['/404']); diff --git a/projects/example-app/src/app/books/reducers/__snapshots__/books.reducer.spec.ts.snap b/projects/example-app/src/app/books/reducers/__snapshots__/books.reducer.spec.ts.snap index 3ebd4bd978..0582de529a 100644 --- a/projects/example-app/src/app/books/reducers/__snapshots__/books.reducer.spec.ts.snap +++ b/projects/example-app/src/app/books/reducers/__snapshots__/books.reducer.spec.ts.snap @@ -160,7 +160,7 @@ Object { } `; -exports[`BooksReducer SEARCH_COMPLETE & LOAD_SUCCESS should add only new books when books already exist 1`] = ` +exports[`BooksReducer SEARCH_COMPLETE & LOAD_SUCCESS should add only books when books already exist 1`] = ` Object { "entities": Object { "1": Object { @@ -230,7 +230,7 @@ Object { } `; -exports[`BooksReducer SEARCH_COMPLETE & LOAD_SUCCESS should add only new books when books already exist 2`] = ` +exports[`BooksReducer SEARCH_COMPLETE & LOAD_SUCCESS should add only books when books already exist 2`] = ` Object { "entities": Object { "1": Object { diff --git a/projects/example-app/src/app/books/reducers/books.reducer.spec.ts b/projects/example-app/src/app/books/reducers/books.reducer.spec.ts index 13724e8c8e..fc6429e840 100644 --- a/projects/example-app/src/app/books/reducers/books.reducer.spec.ts +++ b/projects/example-app/src/app/books/reducers/books.reducer.spec.ts @@ -30,22 +30,29 @@ describe('BooksReducer', () => { }); describe('SEARCH_COMPLETE & LOAD_SUCCESS', () => { + type BooksActions = + | typeof BooksApiActions.searchSuccess + | typeof CollectionApiActions.loadBooksSuccess; function noExistingBooks( - action: any, + action: BooksActions, booksInitialState: any, books: Book[] ) { - const createAction = new action(books); + const createAction = action({ books }); const result = reducer(booksInitialState, createAction); expect(result).toMatchSnapshot(); } - function existingBooks(action: any, booksInitialState: any, books: Book[]) { + function existingBooks( + action: BooksActions, + booksInitialState: any, + books: Book[] + ) { // should not replace existing books const differentBook2 = { ...books[0], foo: 'bar' }; - const createAction = new action([books[1], differentBook2]); + const createAction = action({ books: [books[1], differentBook2] }); const expectedResult = { ids: [...booksInitialState.ids, books[1].id], @@ -62,24 +69,24 @@ describe('BooksReducer', () => { } it('should add all books in the payload when none exist', () => { - noExistingBooks(BooksApiActions.SearchSuccess, initialState, [ + noExistingBooks(BooksApiActions.searchSuccess, initialState, [ book1, book2, ]); - noExistingBooks(CollectionApiActions.LoadBooksSuccess, initialState, [ + noExistingBooks(CollectionApiActions.loadBooksSuccess, initialState, [ book1, book2, ]); }); - it('should add only new books when books already exist', () => { - existingBooks(BooksApiActions.SearchSuccess, initialState, [ + it('should add only books when books already exist', () => { + existingBooks(BooksApiActions.searchSuccess, initialState, [ book2, book3, ]); - existingBooks(CollectionApiActions.LoadBooksSuccess, initialState, [ + existingBooks(CollectionApiActions.loadBooksSuccess, initialState, [ book2, book3, ]); @@ -96,7 +103,7 @@ describe('BooksReducer', () => { }; it('should add a single book, if the book does not exist', () => { - const action = new BookActions.LoadBook(book1); + const action = BookActions.loadBook({ book: book1 }); const result = reducer(fromBooks.initialState, action); @@ -104,7 +111,7 @@ describe('BooksReducer', () => { }); it('should return the existing state if the book exists', () => { - const action = new BookActions.LoadBook(book1); + const action = BookActions.loadBook({ book: book1 }); const result = reducer(expectedResult, action); @@ -114,7 +121,7 @@ describe('BooksReducer', () => { describe('SELECT', () => { it('should set the selected book id on the state', () => { - const action = new ViewBookPageActions.SelectBook(book1.id); + const action = ViewBookPageActions.selectBook({ id: book1.id }); const result = reducer(initialState, action); diff --git a/projects/example-app/src/app/books/reducers/books.reducer.ts b/projects/example-app/src/app/books/reducers/books.reducer.ts index 847702a719..ec73016799 100644 --- a/projects/example-app/src/app/books/reducers/books.reducer.ts +++ b/projects/example-app/src/app/books/reducers/books.reducer.ts @@ -49,8 +49,8 @@ export function reducer( | CollectionApiActions.CollectionApiActionsUnion ): State { switch (action.type) { - case BooksApiActions.BooksApiActionTypes.SearchSuccess: - case CollectionApiActions.CollectionApiActionTypes.LoadBooksSuccess: { + case BooksApiActions.searchSuccess.type: + case CollectionApiActions.loadBooksSuccess.type: { /** * The addMany function provided by the created adapter * adds many records to the entity dictionary @@ -58,10 +58,10 @@ export function reducer( * the collection is to be sorted, the adapter will * sort each record upon entry into the sorted array. */ - return adapter.addMany(action.payload, state); + return adapter.addMany(action.books, state); } - case BookActions.BookActionTypes.LoadBook: { + case BookActions.loadBook.type: { /** * The addOne function provided by the created adapter * adds one record to the entity dictionary @@ -69,13 +69,13 @@ export function reducer( * exist already. If the collection is to be sorted, the adapter will * insert the new record into the sorted array. */ - return adapter.addOne(action.payload, state); + return adapter.addOne(action.book, state); } - case ViewBookPageActions.ViewBookPageActionTypes.SelectBook: { + case ViewBookPageActions.selectBook.type: { return { ...state, - selectedBookId: action.payload, + selectedBookId: action.id, }; } diff --git a/projects/example-app/src/app/books/reducers/collection.reducer.ts b/projects/example-app/src/app/books/reducers/collection.reducer.ts index 9c246f697e..32889e4f54 100644 --- a/projects/example-app/src/app/books/reducers/collection.reducer.ts +++ b/projects/example-app/src/app/books/reducers/collection.reducer.ts @@ -24,38 +24,38 @@ export function reducer( | CollectionApiActions.CollectionApiActionsUnion ): State { switch (action.type) { - case CollectionPageActions.CollectionPageActionTypes.LoadCollection: { + case CollectionPageActions.loadCollection.type: { return { ...state, loading: true, }; } - case CollectionApiActions.CollectionApiActionTypes.LoadBooksSuccess: { + case CollectionApiActions.loadBooksSuccess.type: { return { loaded: true, loading: false, - ids: action.payload.map(book => book.id), + ids: action.books.map(book => book.id), }; } - case CollectionApiActions.CollectionApiActionTypes.AddBookSuccess: - case CollectionApiActions.CollectionApiActionTypes.RemoveBookFailure: { - if (state.ids.indexOf(action.payload.id) > -1) { + case CollectionApiActions.addBookSuccess.type: + case CollectionApiActions.removeBookFailure.type: { + if (state.ids.indexOf(action.book.id) > -1) { return state; } return { ...state, - ids: [...state.ids, action.payload.id], + ids: [...state.ids, action.book.id], }; } - case CollectionApiActions.CollectionApiActionTypes.RemoveBookSuccess: - case CollectionApiActions.CollectionApiActionTypes.AddBookFailure: { + case CollectionApiActions.removeBookSuccess.type: + case CollectionApiActions.addBookFailure.type: { return { ...state, - ids: state.ids.filter(id => id !== action.payload.id), + ids: state.ids.filter(id => id !== action.book.id), }; } diff --git a/projects/example-app/src/app/books/reducers/index.ts b/projects/example-app/src/app/books/reducers/index.ts index 97e25c7178..73146eab03 100644 --- a/projects/example-app/src/app/books/reducers/index.ts +++ b/projects/example-app/src/app/books/reducers/index.ts @@ -156,6 +156,6 @@ export const isSelectedBookInCollection = createSelector( getCollectionBookIds, getSelectedBookId, (ids, selected) => { - return selected && ids.indexOf(selected) > -1; + return !!selected && ids.indexOf(selected) > -1; } ); diff --git a/projects/example-app/src/app/books/reducers/search.reducer.ts b/projects/example-app/src/app/books/reducers/search.reducer.ts index 4869fdbbc7..6081e245bd 100644 --- a/projects/example-app/src/app/books/reducers/search.reducer.ts +++ b/projects/example-app/src/app/books/reducers/search.reducer.ts @@ -24,8 +24,8 @@ export function reducer( | FindBookPageActions.FindBookPageActionsUnion ): State { switch (action.type) { - case FindBookPageActions.FindBookPageActionTypes.SearchBooks: { - const query = action.payload; + case FindBookPageActions.searchBooks.type: { + const query = action.query; if (query === '') { return { @@ -44,20 +44,20 @@ export function reducer( }; } - case BooksApiActions.BooksApiActionTypes.SearchSuccess: { + case BooksApiActions.searchSuccess.type: { return { - ids: action.payload.map(book => book.id), + ids: action.books.map(book => book.id), loading: false, error: '', query: state.query, }; } - case BooksApiActions.BooksApiActionTypes.SearchFailure: { + case BooksApiActions.searchFailure.type: { return { ...state, loading: false, - error: action.payload, + error: action.errorMsg, }; } diff --git a/projects/example-app/src/app/core/actions/layout.actions.ts b/projects/example-app/src/app/core/actions/layout.actions.ts index c5f055b1b3..1dd87dc536 100644 --- a/projects/example-app/src/app/core/actions/layout.actions.ts +++ b/projects/example-app/src/app/core/actions/layout.actions.ts @@ -1,16 +1,7 @@ -import { Action } from '@ngrx/store'; +import { createAction, union } from '@ngrx/store'; -export enum LayoutActionTypes { - OpenSidenav = '[Layout] Open Sidenav', - CloseSidenav = '[Layout] Close Sidenav', -} +export const openSidenav = createAction('[Layout] Open Sidenav'); +export const closeSidenav = createAction('[Layout] Close Sidenav'); -export class OpenSidenav implements Action { - readonly type = LayoutActionTypes.OpenSidenav; -} - -export class CloseSidenav implements Action { - readonly type = LayoutActionTypes.CloseSidenav; -} - -export type LayoutActionsUnion = OpenSidenav | CloseSidenav; +const all = union({ openSidenav, closeSidenav }); +export type LayoutActionsUnion = typeof all; diff --git a/projects/example-app/src/app/core/containers/app.component.ts b/projects/example-app/src/app/core/containers/app.component.ts index fa2acfd019..1797ce9fdb 100644 --- a/projects/example-app/src/app/core/containers/app.component.ts +++ b/projects/example-app/src/app/core/containers/app.component.ts @@ -38,7 +38,7 @@ export class AppComponent { showSidenav$: Observable; loggedIn$: Observable; - constructor(private store: Store) { + constructor(private store: Store) { /** * Selectors can be applied with the `select` operator which passes the state * tree to the provided selector @@ -54,16 +54,16 @@ export class AppComponent { * updates and user interaction through the life of our * application. */ - this.store.dispatch(new LayoutActions.CloseSidenav()); + this.store.dispatch(LayoutActions.closeSidenav()); } openSidenav() { - this.store.dispatch(new LayoutActions.OpenSidenav()); + this.store.dispatch(LayoutActions.openSidenav()); } logout() { this.closeSidenav(); - this.store.dispatch(new AuthActions.LogoutConfirmation()); + this.store.dispatch(AuthActions.logoutConfirmation()); } } diff --git a/projects/example-app/src/app/core/reducers/layout.reducer.ts b/projects/example-app/src/app/core/reducers/layout.reducer.ts index 3ea44fd0dc..b128a041bd 100644 --- a/projects/example-app/src/app/core/reducers/layout.reducer.ts +++ b/projects/example-app/src/app/core/reducers/layout.reducer.ts @@ -1,6 +1,5 @@ -import { - LayoutActions -} from '@example-app/core/actions'; +import { Action } from '@ngrx/store'; +import { LayoutActions } from '@example-app/core/actions'; export interface State { showSidenav: boolean; @@ -10,17 +9,16 @@ const initialState: State = { showSidenav: false, }; -export function reducer( - state: State = initialState, - action: LayoutActions.LayoutActionsUnion -): State { - switch (action.type) { - case LayoutActions.LayoutActionTypes.CloseSidenav: +export function reducer(state: State = initialState, action: Action): State { + const specificAction = action as LayoutActions.LayoutActionsUnion; + + switch (specificAction.type) { + case LayoutActions.closeSidenav.type: return { showSidenav: false, }; - case LayoutActions.LayoutActionTypes.OpenSidenav: + case LayoutActions.openSidenav.type: return { showSidenav: true, }; diff --git a/projects/example-app/src/app/core/services/google-books.service.spec.ts b/projects/example-app/src/app/core/services/google-books.service.spec.ts index a74c36f0c0..3a10724b09 100644 --- a/projects/example-app/src/app/core/services/google-books.service.spec.ts +++ b/projects/example-app/src/app/core/services/google-books.service.spec.ts @@ -38,7 +38,7 @@ describe('Service: GoogleBooks', () => { expect(service.searchBooks(queryTitle)).toBeObservable(expected); expect(http.get).toHaveBeenCalledWith( - `https://www.googleapis.com/books/v1/volumes?q=${queryTitle}` + `https://www.googleapis.com/books/v1/volumes?orderBy=newest&q=${queryTitle}` ); }); diff --git a/projects/example-app/src/app/core/services/google-books.service.ts b/projects/example-app/src/app/core/services/google-books.service.ts index 3d5423ebad..5643744ee8 100644 --- a/projects/example-app/src/app/core/services/google-books.service.ts +++ b/projects/example-app/src/app/core/services/google-books.service.ts @@ -15,7 +15,7 @@ export class GoogleBooksService { searchBooks(queryTitle: string): Observable { return this.http - .get<{ items: Book[] }>(`${this.API_PATH}?q=${queryTitle}`) + .get<{ items: Book[] }>(`${this.API_PATH}?orderBy=newest&q=${queryTitle}`) .pipe(map(books => books.items || [])); } diff --git a/projects/example-app/src/app/reducers/index.ts b/projects/example-app/src/app/reducers/index.ts index 3afb1a641a..8f8256f696 100644 --- a/projects/example-app/src/app/reducers/index.ts +++ b/projects/example-app/src/app/reducers/index.ts @@ -8,13 +8,6 @@ import { import { environment } from '../../environments/environment'; import * as fromRouter from '@ngrx/router-store'; -/** - * storeFreeze prevents state from being mutated. When mutation occurs, an - * exception will be thrown. This is useful during development mode to - * ensure that none of the reducers accidentally mutates the state. - */ -import { storeFreeze } from 'ngrx-store-freeze'; - /** * Every reducer module's default export is the reducer function itself. In * addition, each module should export a type or interface that describes @@ -45,7 +38,7 @@ export const reducers: ActionReducerMap = { // console.log all actions export function logger(reducer: ActionReducer): ActionReducer { - return (state: State, action: any): any => { + return (state, action) => { const result = reducer(state, action); console.groupCollapsed(action.type); console.log('prev state', state); @@ -63,7 +56,7 @@ export function logger(reducer: ActionReducer): ActionReducer { * that will be composed to form the root meta-reducer. */ export const metaReducers: MetaReducer[] = !environment.production - ? [logger, storeFreeze] + ? [logger] : []; /** diff --git a/projects/example-app/tsconfig.app.json b/projects/example-app/tsconfig.app.json index af2f470570..6673d1c4e8 100644 --- a/projects/example-app/tsconfig.app.json +++ b/projects/example-app/tsconfig.app.json @@ -1,5 +1,7 @@ { "compilerOptions": { + "strict": true, + "strictPropertyInitialization": false, "sourceMap": true, "declaration": false, "moduleResolution": "node", @@ -18,8 +20,7 @@ "@ngrx/router-store": ["../../modules/router-store"], "@ngrx/entity": ["../../modules/entity"], "@ngrx/schematics": ["../../modules/schematics"], - "@example-app/*": ["./src/app/*"], - "ngrx-store-freeze": ["../../projects/ngrx-store-freeze"] + "@example-app/*": ["./src/app/*"] } }, "exclude": [ diff --git a/projects/ngrx-store-freeze/README.md b/projects/ngrx-store-freeze/README.md deleted file mode 100755 index 168569ff14..0000000000 --- a/projects/ngrx-store-freeze/README.md +++ /dev/null @@ -1,56 +0,0 @@ -## ngrx-store-freeze - -[![npm version](https://badge.fury.io/js/ngrx-store-freeze.svg)](https://badge.fury.io/js/ngrx-store-freeze) -[![CircleCI](https://circleci.com/gh/brandonroberts/ngrx-store-freeze/tree/master.svg?style=svg&circle-token=6ba0f6b74d2186f7896a58377b8607346c07cee6)](https://circleci.com/gh/brandonroberts/ngrx-store-freeze/tree/master) - -ngrx-store-freeze is a meta-reducer that prevents state from being mutated - -- Recursively freezes the **current state**, the dispatched **action payload** if provided and the **new state**. -- When mutation occurs, an exception will be thrown. -- Should be used **only in development** to ensure that the state remains immutable. - -### Installation - -```sh -npm i --save-dev ngrx-store-freeze -``` - -OR - -```sh -yarn add ngrx-store-freeze --dev -``` - -### Setup - -```ts -import { StoreModule, MetaReducer, ActionReducerMap } from '@ngrx/store'; -import { storeFreeze } from 'ngrx-store-freeze'; -import { environment } from '../environments/environment'; // Angular CLI environment - -export interface State { - // reducer interfaces -} - -export const reducers: ActionReducerMap = { - // reducers -}; - -export const metaReducers: MetaReducer[] = !environment.production - ? [storeFreeze] - : []; - -@NgModule({ - imports: [StoreModule.forRoot(reducers, { metaReducers })], -}) -export class AppModule {} -``` - -## Additional Documentation - -- [Usage with `@ngrx/router-store`](./docs/docs.md#router-store-compatibility) - -## Credits - -[redux-freeze](https://github.com/buunguyen/redux-freeze) - Redux middleware that prevents state from being mutated -[Attila Egyed](https://github.com/tsm91) - The original maintainer of this project diff --git a/projects/ngrx-store-freeze/index.ts b/projects/ngrx-store-freeze/index.ts deleted file mode 100644 index cba1843545..0000000000 --- a/projects/ngrx-store-freeze/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './src/index'; diff --git a/projects/ngrx-store-freeze/package.json b/projects/ngrx-store-freeze/package.json deleted file mode 100755 index fb825c5331..0000000000 --- a/projects/ngrx-store-freeze/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "ngrx-store-freeze", - "version": "0.2.4" -} diff --git a/projects/ngrx-store-freeze/src/index.ts b/projects/ngrx-store-freeze/src/index.ts deleted file mode 100755 index b53cad56c5..0000000000 --- a/projects/ngrx-store-freeze/src/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -declare var require: any; -import { ActionReducer, Action } from '@ngrx/store'; -const deepFreeze = require('deep-freeze-strict'); - -/** - * Meta-reducer that prevents state from being mutated anywhere in the app. - */ -export function storeFreeze( - reducer: ActionReducer -): ActionReducer; -export function storeFreeze( - reducer: ActionReducer -): ActionReducer { - return function freeze(state, action): any { - state = state || {}; - - deepFreeze(state); - - // guard against trying to freeze null or undefined types - if (action.payload) { - deepFreeze(action.payload); - } - - const nextState = reducer(state, action); - - deepFreeze(nextState); - - return nextState; - }; -} diff --git a/projects/ngrx.io/README.md b/projects/ngrx.io/README.md index 295e83e1ac..99c33f837d 100644 --- a/projects/ngrx.io/README.md +++ b/projects/ngrx.io/README.md @@ -42,6 +42,10 @@ Here are the most important tasks you might need to use: - `yarn build-ie-polyfills` - generates a js file of polyfills that can be loaded in Internet Explorer. +## Developing on Windows + +It is necessary to run `yarn setup` and `yarn boilerplate:add` using Administrator rights as Linux-specific symlinks are used. + ## Using ServiceWorker locally Running `yarn start` (even when explicitly targeting production mode) does not set up the diff --git a/projects/ngrx.io/content/guide/effects/testing.md b/projects/ngrx.io/content/guide/effects/testing.md index 85c4dcad33..20ed86d2fa 100644 --- a/projects/ngrx.io/content/guide/effects/testing.md +++ b/projects/ngrx.io/content/guide/effects/testing.md @@ -12,8 +12,7 @@ Usage: import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; -import { ReplaySubject } from 'rxjs/ReplaySubject'; -import { hot, cold } from 'jasmine-marbles'; +import { cold, hot } from 'jasmine-marbles'; import { Observable } from 'rxjs'; import { MyEffects } from './my-effects'; @@ -48,14 +47,44 @@ describe('My Effects', () => { expect(effects.someSource$).toBeObservable(expected); }); +}); + - it('should work also', () => { - actions = new ReplaySubject(1); +It is also possible to use `ReplaySubject` as an alternative for marble tests: + + +import { TestBed } from '@angular/core/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { ReplaySubject } from 'rxjs'; + +import { MyEffects } from './my-effects'; +import * as MyActions from '../actions/my-actions'; + +describe('My Effects', () => { + let effects: MyEffects; + let actions: ReplaySubject<any>; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + // any modules needed + ], + providers: [ + MyEffects, + provideMockActions(() => actions), + // other providers + ], + }); - actions.next(SomeAction); + effects = TestBed.get(MyEffects); + }); + + it('should work', () => { + actions = new ReplaySubject(1); + actions.next(new MyActions.ExampleAction()); effects.someSource$.subscribe(result => { - expect(result).toEqual(AnotherAction); + expect(result).toEqual(new MyActions.ExampleActionSuccess()); }); }); }); diff --git a/projects/ngrx.io/content/guide/entity/index.md b/projects/ngrx.io/content/guide/entity/index.md index 550a25750c..60a1c87797 100644 --- a/projects/ngrx.io/content/guide/entity/index.md +++ b/projects/ngrx.io/content/guide/entity/index.md @@ -11,3 +11,13 @@ Entity provides an API to manipulate and query entity collections. ## Installation Detailed installation instructions can be found on the [Installation](guide/entity/install) page. + +## Entity and class instances + +Entity promotes the use of plain JavaScript objects when managing collections. *ES6 class instances will be transformed into plain JavaScript objects when entities are managed in a collection*. This provides you with some assurances when managing these entities: + +1. Guarantee that the data structures contained in state don't themselves contain logic, reducing the chance that they'll mutate themselves. +2. State will always be serializable allowing you to store and rehydrate from browser storage mechanisms like local storage. +3. State can be inspected via the Redux Devtools. + +This is one of the [core principles](docs#core-principles) of NgRx. The [Redux docs](https://redux.js.org/faq/organizingstate#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state) also offers some more insight into this constraint. diff --git a/projects/ngrx.io/content/guide/entity/interfaces.md b/projects/ngrx.io/content/guide/entity/interfaces.md index cce9f27604..f360df7e3a 100644 --- a/projects/ngrx.io/content/guide/entity/interfaces.md +++ b/projects/ngrx.io/content/guide/entity/interfaces.md @@ -14,7 +14,7 @@ interface EntityState<V> { - `ids`: An array of all the primary ids in the collection - `entities`: A dictionary of entities in the collection indexed by the primary id -Extend this interface to provided any additional properties for the entity state. +Extend this interface to provide any additional properties for the entity state. Usage: diff --git a/projects/ngrx.io/content/guide/router-store/configuration.md b/projects/ngrx.io/content/guide/router-store/configuration.md index 3064875484..c9050c2d97 100644 --- a/projects/ngrx.io/content/guide/router-store/configuration.md +++ b/projects/ngrx.io/content/guide/router-store/configuration.md @@ -17,8 +17,6 @@ interface StoreRouterConfig { During each navigation cycle, a `RouterNavigationAction` is dispatched with a snapshot of the state in its payload, the `RouterStateSnapshot`. The `RouterStateSnapshot` is a large complex structure, containing many pieces of information about the current state and what's rendered by the router. This can cause performance issues when used with the Store Devtools. In most cases, you may only need a piece of information from the `RouterStateSnapshot`. In order to pare down the `RouterStateSnapshot` provided during navigation, you provide a custom serializer for the snapshot to only return what you need to be added to the payload and store. -Additionally, the router state snapshot is a mutable object, which can cause issues when developing with [store freeze](https://github.com/brandonroberts/ngrx-store-freeze) to prevent direct state mutations. This can be avoided by using a custom serializer. - Your custom serializer should implement the abstract class `RouterStateSerializer` and return a snapshot which should have an interface extending `BaseRouterStoreState`. You then provide the serializer through the config. diff --git a/projects/ngrx.io/content/guide/schematics/action.md b/projects/ngrx.io/content/guide/schematics/action.md index 3a1c4d808e..25351d67fd 100644 --- a/projects/ngrx.io/content/guide/schematics/action.md +++ b/projects/ngrx.io/content/guide/schematics/action.md @@ -40,6 +40,13 @@ Group the action file within an `actions` folder. - Type: `boolean` - Default: `false` +Specifies if api success and failure actions should be generated. + +- `--api` + - Alias: `-a` + - Type: `boolean` + - Default: `false` + Generate a spec file alongside the action file. - `--spec` diff --git a/projects/ngrx.io/content/guide/schematics/container.md b/projects/ngrx.io/content/guide/schematics/container.md index d3d9d2268e..f7220afcd1 100644 --- a/projects/ngrx.io/content/guide/schematics/container.md +++ b/projects/ngrx.io/content/guide/schematics/container.md @@ -42,3 +42,13 @@ Generate a `UsersPage` container component with your reducers imported and the ` ```sh ng generate container UsersPage --state reducers/index.ts --stateInterface MyState ``` + +If you want to generate a container with an scss file, add `@ngrx/schematics:container` to the `schematics` in your `angular.json`. + +```json +"schematics": { + "@ngrx/schematics:container": { + "styleext": "scss" + } +} +``` diff --git a/projects/ngrx.io/content/guide/schematics/effect.md b/projects/ngrx.io/content/guide/schematics/effect.md index 3b62d951ee..0ceedf7c8b 100644 --- a/projects/ngrx.io/content/guide/schematics/effect.md +++ b/projects/ngrx.io/content/guide/schematics/effect.md @@ -51,6 +51,13 @@ When used with the `--module` option, it registers an effect within the `Angular - Type: `boolean` - Default: `false` +Specifies if effect has api success and failure actions wired up. + +- `--api` + - Alias: `-a` + - Type: `boolean` + - Default: `false` + Generate a spec file alongside the action file. - `--spec` diff --git a/projects/ngrx.io/content/guide/schematics/feature.md b/projects/ngrx.io/content/guide/schematics/feature.md index bb0e50dff6..cf0f618b60 100644 --- a/projects/ngrx.io/content/guide/schematics/feature.md +++ b/projects/ngrx.io/content/guide/schematics/feature.md @@ -51,6 +51,13 @@ Provide the path to a `reducers` file containing a state interface and a object - Alias: `-r` - Type: `string` +Specifies if api success and failure `actions`, `reducer`, and `effects` should be generated as part of this feature. + +- `--api` + - Alias: `-a` + - Type: `boolean` + - Default: `false` + Generate spec files associated with the feature files. - `--spec` diff --git a/projects/ngrx.io/content/guide/schematics/reducer.md b/projects/ngrx.io/content/guide/schematics/reducer.md index 6f8385277f..3f40776241 100644 --- a/projects/ngrx.io/content/guide/schematics/reducer.md +++ b/projects/ngrx.io/content/guide/schematics/reducer.md @@ -52,6 +52,13 @@ Provide the path to a `reducers` file containing a state interface and an object - Alias: `-r` - Type: `string` +Specifies if api success and failure actions should be added to the reducer. + +- `--api` + - Alias: `-a` + - Type: `boolean` + - Default: `false` + Generate a spec file alongside the reducer file. - `--spec` diff --git a/projects/ngrx.io/content/guide/store/testing.md b/projects/ngrx.io/content/guide/store/testing.md index 71d37a99bc..13e24f3f9c 100644 --- a/projects/ngrx.io/content/guide/store/testing.md +++ b/projects/ngrx.io/content/guide/store/testing.md @@ -1,6 +1,65 @@ # Testing -### Providing Store for testing +### Using a Mock Store + +The `provideMockStore()` function registers providers that allow you to mock out the `Store` for testing functionality that has a dependency on `Store` without setting up reducers. +You can write tests validating behaviors corresponding to the specific state snapshot easily. + +

+ +**Note:** All dispatched actions don't affect to the state, but you can see them in the `Actions` stream. + +
+ +Usage: + + +import { TestBed } from '@angular/core/testing'; +import { Store } from '@ngrx/store'; +import { provideMockStore } from '@ngrx/store/testing'; +import { cold } from 'jasmine-marbles'; + +import { AuthGuard } from '../guards/auth.guard'; +import * as AuthActions from '../actions/auth-actions'; + +describe('Auth Guard', () => { + let guard: AuthGuard; + let store: MockStore<{ loggedIn: boolean }>; + const initialState = { loggedIn: false }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + // any modules needed + ], + providers: [ + AuthGuard, + provideMockStore({ initialState }), + // other providers + ], + }); + + guard = TestBed.get(AuthGuard); + store = TestBed.get(Store); + }); + + it('should return false if the user state is not logged in', () => { + const expected = cold('(a|)', { a: false }); + + expect(guard.canActivate()).toBeObservable(expected); + }); + + it('should return true if the user state is logged in', () => { + store.setState({ loggedIn: true }); + + const expected = cold('(a|)', { a: true }); + + expect(guard.canActivate()).toBeObservable(expected); + }); +}); + + +### Using Store for Integration Testing Use the `StoreModule.forRoot` in your `TestBed` configuration when testing components or services that inject `Store`. diff --git a/projects/ngrx.io/content/marketing/events.html b/projects/ngrx.io/content/marketing/events.html index 5f1756cec3..436c358dc7 100755 --- a/projects/ngrx.io/content/marketing/events.html +++ b/projects/ngrx.io/content/marketing/events.html @@ -2,73 +2,5 @@

Events

-

Upcoming Events presenting about NgRx:

- - - - - - - - - - - - - - - - - - - - - - - - - -
EventLocationDate
ngAtlantaAtlanta, GeorgiaJanuary 9 - 12, 2019
ng-IndiaGurgaon, IndiaFebruary 23, 2019
ng-confSalt Lake City, UtahMay 1 - 3, 2019
-

Past Events:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventLocationDate
NgColombiaMedellín, ColombiaSeptember 6 - 7th, 2018
DevFestATLAtlanta, GASeptember 22nd, 2018
Framework SummitPark City, UTSeptember 22nd, 2018
DevFestATLAtlanta, GAOctober 2 - 3rd, 2018
AngularMix - Use the discount code "RYAN" or "ROBERTS" to receive $50 off your registration!Orlando, FLOctober 10 - 12th, 2018
AngularConnectExcel, LondonNovember 6 - 7th, 2018
+
diff --git a/projects/ngrx.io/content/marketing/events.json b/projects/ngrx.io/content/marketing/events.json new file mode 100644 index 0000000000..74e3b6c033 --- /dev/null +++ b/projects/ngrx.io/content/marketing/events.json @@ -0,0 +1,115 @@ +[ + { + "name": "NgColombia", + "url": "http://www.ngcolombia.com", + "location": "Medellín, Colombia", + "startDate": "2018-09-06", + "endDate": "2018-09-07" + }, + { + "name": "DevFestATL", + "url": "http://devfestatl.com", + "location": "Atlanta, Georgia", + "endDate": "2018-09-22" + }, + { + "name": "Framework Summit", + "url": "http://frameworksummit.com", + "location": "Park City, Utah", + "endDate": "2018-09-22" + }, + { + "name": "DevFestATL", + "url": "http://devfestatl.com", + "location": "Atlanta, Georgia", + "startDate": "2018-10-02", + "endDate": "2018-10-03" + }, + { + "name": "AngularMix", + "url": "http://www.angularmix.com", + "location": "Orlando, Florida", + "startDate": "2018-10-10", + "endDate": "2018-10-12" + }, + { + "name": "AngularConnect", + "url": "https://www.angularconnect.com", + "location": "Excel, London", + "startDate": "2018-11-06", + "endDate": "2018-11-07" + }, + { + "name": "ngAtlanta", + "url": "http://ng-atl.org/", + "location": "Atlanta, Georgia", + "startDate": "2019-01-09", + "endDate": "2019-01-12" + }, + { + "name": "ng-India", + "url": "https://www.ng-ind.com", + "location": "Gurgaon, India", + "endDate": "2019-02-23" + }, + { + "name": "Open Source 101", + "url": "https://opensource101.com/", + "location": "Columbia, South Carolina", + "endDate": "2019-04-18" + }, + { + "name": "NG-Conf", + "url": "https://www.ng-conf.org", + "location": "Salt Lake City, Utah", + "startDate": "2019-05-01", + "endDate": "2019-05-03" + }, + { + "name": "ngVikings", + "url": "https://ngvikings.org/", + "location": "Copenhagen, Denmark", + "startDate": "2019-05-26", + "endDate": "2019-05-28" + }, + { + "name": "REFACTR.TECH", + "url": "https://refactr.tech/", + "location": "Atlanta, Georgia", + "startDate": "2019-06-05", + "endDate": "2019-06-07" + }, + { + "name": "AngularUP", + "url": "https://angular-up.com/", + "location": "Tel Aviv, Israel", + "endDate": "2019-06-12" + }, + { + "name": "NG-MY", + "url": "https://ng-my.org/", + "location": "Kuala Lumpur, Malaysia", + "startDate": "2019-07-06", + "endDate": "2019-07-07" + }, + { + "name": "ngDenver", + "url": "http://angulardenver.com/", + "location": "Denver, Colorado", + "startDate": "2019-08-01", + "endDate": "2019-08-02" + }, + { + "name": "AngularConnect", + "url": "https://www.angularconnect.com/", + "location": "London, United Kingdom", + "startDate": "2019-09-19", + "endDate": "2019-09-20" + }, + { + "name": "NG-Rome", + "url": "https://ngrome.io/", + "location": "Rome, Italy", + "endDate": "2019-10-07" + } +] diff --git a/projects/ngrx.io/content/marketing/resources.json b/projects/ngrx.io/content/marketing/resources.json index 1fbd94651d..c246127fa0 100644 --- a/projects/ngrx.io/content/marketing/resources.json +++ b/projects/ngrx.io/content/marketing/resources.json @@ -14,7 +14,7 @@ "ngrx-best-practices-for-enterprise-angular-applications": { "title": "NgRx — Best Practices for Enterprise Angular Applications", "desc": "Enterprise NgRx pattern for organizing store into modules and sub modules", - "url": "https://itnext.io/ngrx-best-practices-for-enterprise-angular-applications-6f00bcdf36d7", + "url": "https://wesleygrimes.com/angular/2018/05/30/ngrx-best-practices-for-enterprise-angular-applications", "rev": true } } @@ -69,6 +69,12 @@ "url": "https://github.com/avatsaev/angular-contacts-app-example", "rev": true }, + "angular-checklist": { + "title": "Angular Checklist", + "desc": "Curated list of common mistakes made when developing Angular applications", + "url": "https://angular-checklist.io", + "rev": true + }, "online-training": { "title": "Online Training website using ASP.Net Core 2.0 & Angular 4", @@ -87,6 +93,20 @@ "Use a Pizza Provider of your choice and add/edit orders in real time with friends/colleagues", "url": "https://github.com/maxime1992/pizza-sync", "rev": true + }, + "goose-weather": { + "title": "Goose Weather", + "desc": + "Angular App that uses NOAA and the OpenWeatherMapAPI to create a weather forecast", + "url": "https://github.com/andrewevans02/goose-weather", + "rev": true + }, + "mdb-angular-boilerplate": { + "title": "MDB Angular Boilerplate", + "desc": + "Angular CRUD application starter with NgRx state management and Firebase backend", + "url": "https://github.com/mdbootstrap/Angular-Bootstrap-Boilerplate", + "rev": true } } }, diff --git a/projects/ngrx.io/src/404-body.html b/projects/ngrx.io/src/404-body.html index 3e6cf878fb..7794bc9c08 100644 --- a/projects/ngrx.io/src/404-body.html +++ b/projects/ngrx.io/src/404-body.html @@ -42,7 +42,7 @@

Resource Not Found